def build_interpol(transform, box, id="none", posunit=1.0, sys=None): sys = config.get("map_sys", sys) # We widen the bounding box slightly to avoid samples falling outside it # due to rounding errors. box = utils.widen_box(np.array(box), 1e-3) box[:, 1:] = utils.widen_box(box[:, 1:], config.get("pmat_interpol_pad") * utils.arcmin, relative=False) acc = config.get("pmat_accuracy") ip_size = config.get("pmat_interpol_max_size") ip_time = config.get("pmat_interpol_max_time") # Build pointing interpolator errlim = np.array( [1e-3 * posunit, 1e-3 * posunit, utils.arcmin, utils.arcmin]) * acc ipol, obox, ok, err = interpol.build(transform, interpol.ip_linear, box, errlim, maxsize=ip_size, maxtime=ip_time, return_obox=True, return_status=True) if not ok and np.any(err > errlim): print "Warning: Accuracy %g was specified, but only reached %g for tod %s" % ( acc, np.max(err / errlim) * acc, id) return ipol, obox, err
def interpol_pos(from_sys, to_sys, name_or_pos, mjd, site=None, dt=10): """Given the name of an ephemeris object or a [ra,dec]-type position in radians in from_sys, compute its position in the specified coordinate system for each mjd. The mjds are assumed to be sampled densely enough that interpolation will work. For ephemeris objects, positions are computed in steps of 10 seconds by default (controlled by the dt argument).""" box = utils.widen_box([np.min(mjd), np.max(mjd)], 1e-2) sub_nsamp = max(3, int((box[1] - box[0]) * 24. * 3600 / dt)) sub_mjd = np.linspace(box[0], box[1], sub_nsamp, endpoint=True) if isinstance(name_or_pos, basestring): sub_from = ephem_pos(name_or_pos, sub_mjd) else: pos = np.asarray(name_or_pos) assert pos.ndim == 1 sub_from = np.zeros([2, sub_nsamp]) sub_from[:] = np.asarray(name_or_pos)[:, None] sub_pos = transform_raw(from_sys, to_sys, sub_from, time=sub_mjd, site=site) sub_pos[1] = utils.rewind(sub_pos[1], ref="auto") inds = (mjd - box[0]) * (sub_nsamp - 1) / (box[1] - box[0]) full_pos = utils.interpol(sub_pos, inds[None], order=3) return full_pos
def define_subsamples(t, dt=10): t = np.asarray(t) if t.ndim == 0: return np.array([t]), np.array([0]) if dt == 0: return t, np.arange(len(t)) box = utils.widen_box([np.min(t), np.max(t)], 1e-2) sub_nsamp = max(3, int((box[1] - box[0]) / dt)) if sub_nsamp > len(t): return t, np.arange(len(t)) sub_t = np.linspace(box[0], box[1], sub_nsamp, endpoint=True) return sub_t, (t - box[0]) * (sub_nsamp - 1) / (box[1] - box[0])
def calc_sky_bbox_scan(scan, osys, nsamp=100): """Compute the bounding box of the scan in the osys coordinate system. Returns [{from,to},{dec,ra}].""" ipoints = utils.box2contour(scan.box, nsamp) opoints = np.array([coordinates.transform(scan.sys,osys,b[1:,None],time=scan.mjd0+b[0,None]/3600/24,site=scan.site)[::-1,0] for b in ipoints]) # Take care of angle wrapping along the ra direction opoints[...,1] = utils.rewind(opoints[...,1], ref="auto") obox = utils.bounding_box(opoints) # Grow slighly to account for non-infinite nsamp obox = utils.widen_box(obox, 5*utils.arcmin, relative=False) return obox
def __init__(self, scans, pids, patterns, array_shape, res, dtype, comm, cuts=None, name="phase", ofmt="{name}_{pid:02}_{az0:.0f}_{az1:.0f}_{el:.0f}", output=True, ext="fits", col_major=True, hysteresis=True): Signal.__init__(self, name, ofmt, output, ext) nrow, ncol = array_shape ndet = nrow * ncol self.pids = pids self.patterns = patterns self.comm = comm self.dtype = dtype self.col_major = col_major self.cuts = cuts self.data = {} self.areas = [] # Set up an area for each scanning pattern. We assume that these are constant # elevation scans, so only azimuth matters. This setup is ugly and would be # nicer if passed in, but then the ugliness would only be moved to the calling # code instead. for pattern in patterns: az0, az1 = utils.widen_box(pattern)[:, 1] naz = int(np.ceil((az1 - az0) / res)) az1 = az0 + naz * res det_unit = nrow if col_major else ncol shape, wcs = enmap.geometry( pos=[[0, az0], [ndet / det_unit * utils.degree, az1]], shape=(ndet, naz), proj="car") if hysteresis: area = enmap.zeros((2, ) + shape, wcs, dtype=dtype) else: area = enmap.zeros(shape, wcs, dtype=dtype) self.areas.append(area) for pid, scan in zip(pids, scans): dets = scan.dets if col_major: dets = utils.transpose_inds(dets, nrow, ncol) mat = pmat.PmatScan(scan, self.areas[pid], dets) self.data[scan] = [pid, mat] self.dof = zipper.MultiZipper( [zipper.ArrayZipper(area, comm=comm) for area in self.areas], comm=comm)
def build_work_shift(transform, hor_box, scan_period): """Given a transofrmation that takes [{t,az,el},nsamp] into [{y,x,...},nsamp], and a bounding box [{from,to},{t,az,el}], compute the parameters for a per-y shift in x that makes scans roughly straight. These parameters are returned in the form of wbox[{from,to},{y,x'}] and wshift[{up,down},ny]. They are used in the shifted pmat implementation.""" # The problem with using the real scanning profile is that it can't be adjusted to # cover all the detectors, and at any y, the az where a detector hits that y will # be different. So only one of them can faithfully follow the profile after all. # So I think I'll stay with the simple model I use here, and just take the travel # time into account, through an extra parameter. # Find the pixel bounds corresponding to our hor bounds hor_corn = utils.box2contour(hor_box, 100) pix_corn = transform(hor_corn.T)[:2].T pix_box = utils.bounding_box(pix_corn) pix_box = utils.widen_box(pix_box, 10, relative=False) # The y bounds are the most relevant. Our wshift must # be defined for every output y in the range. y0 = int(np.floor(pix_box[0, 0])) y1 = int(np.ceil(pix_box[1, 0])) + 1 mean_t, mean_az, mean_el = np.mean(hor_box, 0) # Get a forward and backwards sweep. So index 0 is az increasing, index 1 is az decreasing # Divide scan period by 2 because there is a forwards and backward sweep per period. wshift = np.array([ measure_sweep_pixels(transform, [mean_t, mean_t + scan_period / 2], hor_box[:, 1], mean_el, [y0, y1]), measure_sweep_pixels(transform, [mean_t, mean_t + scan_period / 2], hor_box[::-1, 1], mean_el, [y0, y1]) ]) # For each of these, find the pixel bounds. The total # bounds will be the union of these wboxes = [] for wshift_single in wshift: # Use this shift to transform the pixel corners into shifted # coordinates. This wil give us the bounds of the shifted system shift_corn = pix_corn.copy() np.set_printoptions(suppress=True) shift_corn[:, 1] -= wshift_single[np.round(shift_corn[:, 0] - y0).astype(int)] wboxes.append(utils.bounding_box(shift_corn)) # Merge wboxes wbox = utils.bounding_box(wboxes) wbox[0] = np.floor(wbox[0]) wbox[1] = np.ceil(wbox[1]) wbox = wbox.astype(int) print "wbox" print wbox print "wshift" print wshift return wbox, wshift
def measure_sweep_pixels(transform, trange, azrange, el, yrange, padstep=None, nsamp=None, ntry=None): """Helper function for build_work_shift. Measure the x for each y of an azimuth sweep.""" if nsamp is None: nsamp = 10000 if padstep is None: padstep = 4 * utils.degree if ntry is None: ntry = 5 y0, y1 = yrange pad = padstep for i in range(ntry): print "FIXME: This will break near north. Padding of the box earlier" print "may make it impossible to reach the upper y bound" print "Need to implement extrapolation" az0, az1 = utils.widen_box(azrange, pad, relative=False) ipos = np.zeros([3, nsamp]) # Forward sweep ipos[0] = np.linspace(trange[0], trange[1], nsamp) ipos[1] = np.linspace(az0, az1, nsamp) ipos[2] = el opix = np.round(transform(ipos)[:2]).astype(int) # Get the entries with unique y values uy, ui = np.unique(opix[0], return_index=True) if uy[0] > y0 or uy[-1] <= y1: # We didn't cover the range, so try again pad += padstep continue # Restrict to relevant pixel range yi = ui[(uy >= y0) & (uy < y1)] if len(ui) < y1 - y0: # We didn't hit every pixel. Try again nsamp *= 2 continue wshift = opix[1, yi] # Shift is defined to start at zero, since we will put # the absolute offset into wbox. wshift -= wshift[0] break else: # We didn't find a match! Just use a constant shift of zero. # This shouldn't happen, though. raise RuntimeError("Failed to find sweep") wshift = np.zeros(y1 - y0, int) return wshift
def generate_sweep_by_dec_pix(hor_box, iy_box, trans, padstep=None, nsamp=None, ntry=None): """Given hor_box[{from,to},{t,az,el}] and a hor2{ra,dec,y,x} transformer trans, and a integer y-pixel range iy_box[{from,to}]. Compute an azimuth sweep that samples every y pixel once and covers the whole dec_range.""" if nsamp is None: nsamp = 100000 if padstep is None: padstep = 4 * utils.degree if ntry is None: ntry = 10 pad = padstep for i in range(ntry): t_range, az_range, el_range = np.array(hor_box).T az_range = utils.widen_box(az_range, pad, relative=False) # Generate a test sweep, which hopefully is wide enough and dense enough time = np.linspace(t_range[0], t_range[1], nsamp) ipos = [ np.linspace(az_range[0], az_range[1], nsamp), np.linspace(el_range[0], el_range[1], nsamp) ] opos = trans(ipos, time) opos = np.concatenate([[time], ipos, opos], 0) # Make sure we cover the whole dec range we should. # We all our samples are in the range we want to use, # then we probably didn't cover the whole range. # ....|..++++....|... vs. ...--|+++++++|--... iy = np.round(opos[6]).astype(int) if not (np.any(iy < iy_box[0]) and np.any(iy >= iy_box[1])): pad += padstep continue good = (iy >= iy_box[0]) & (iy < iy_box[1]) opos = opos[:, good] # Sort by output y pixel (not rounded) order = np.argsort(opos[6]) opos = opos[:, order] # See if we hit every y pixel iy = np.round(opos[6]).astype(int) uy = np.arange(iy_box[0], iy_box[1]) ui = np.searchsorted(iy, uy) if len(np.unique(ui)) < len(uy): nsamp *= 2 continue opos = opos[:, ui] return opos
def generate_sweep_by_dec_pix(hor_box, iy_box, trans, padstep=None,nsamp=None,ntry=None): """Given hor_box[{from,to},{t,az,el}] and a hor2{ra,dec,y,x} transformer trans, and a integer y-pixel range iy_box[{from,to}]. Compute an azimuth sweep that samples every y pixel once and covers the whole dec_range.""" if nsamp is None: nsamp = 100000 if padstep is None: padstep = 4*utils.degree if ntry is None: ntry = 10 pad = padstep for i in range(ntry): t_range, az_range, el_range = np.array(hor_box).T az_range = utils.widen_box(az_range, pad, relative=False) # Generate a test sweep, which hopefully is wide enough and dense enough time = np.linspace(t_range[0],t_range[1], nsamp) ipos = [ np.linspace(az_range[0],az_range[1], nsamp), np.linspace(el_range[0],el_range[1], nsamp)] opos = trans(ipos, time) opos = np.concatenate([[time],ipos,opos],0) # Make sure we cover the whole dec range we should. # We all our samples are in the range we want to use, # then we probably didn't cover the whole range. # ....|..++++....|... vs. ...--|+++++++|--... iy = np.round(opos[6]).astype(int) if not (np.any(iy < iy_box[0]) and np.any(iy >= iy_box[1])): pad += padstep continue good = (iy >= iy_box[0]) & (iy < iy_box[1]) opos = opos[:,good] # Sort by output y pixel (not rounded) order = np.argsort(opos[6]) opos = opos[:,order] # See if we hit every y pixel iy = np.round(opos[6]).astype(int) uy = np.arange(iy_box[0],iy_box[1]) ui = np.searchsorted(iy, uy) if len(np.unique(ui)) < len(uy): nsamp *= 2 continue opos = opos[:,ui] return opos
"grad": interpol.ip_grad, "bilinear": interpol.ip_linear, }[args.interpolator] for iaz in range(naz): for iel in range(nel): az_mid = (args.az1 + args.daz*iaz)*utils.degree el_mid = (args.el1 + args.delta_el*iel)*utils.degree t_mid = args.t # Bounds box = np.array([ [-args.wt/2./60/24, args.wt/2./60/24], [az_mid-utils.degree*args.waz/2, az_mid+utils.degree*args.waz/2], [el_mid-utils.degree*args.wel/2, el_mid+utils.degree*args.wel/2]]).T # Build an interpolator wbox = utils.widen_box(box) errlim = np.array([utils.arcsec, utils.arcsec, utils.arcmin, utils.arcmin])*acc t1 = time.time() ipol, obox, ok, err = interpol.build(hor2cel, interpolator, wbox, errlim, maxsize=max_size, maxtime=max_time, return_obox=True, return_status=True) t2 = time.time() # Choose some points to evaluate the model at hor_test = box[0,:,None] + np.random.uniform(0,1,size=(3,args.ntest))*(box[1]-box[0])[:,None] cel_exact = hor2cel(hor_test) cel_interpol = ipol(hor_test) #cel_interpol2 = eval_ipol(ipol, hor_test) diff = np.max(np.abs(cel_interpol-cel_exact),1) print (" %9.4f"*(2+4+1) + " %d") % ( (az_mid/utils.degree,el_mid/utils.degree) + tuple(diff/errlim) + (t2-t1,ok))
import numpy as np, argparse from enlib import enmap, utils parser = argparse.ArgumentParser() parser.add_argument("imap") parser.add_argument("template") parser.add_argument("omap") parser.add_argument("-O", "--order", type=int, default=3) parser.add_argument("-m", "--mode", type=str, default="constant") #parser.add_argument("-M", "--mem", type=float, default=1e8) parser.add_argument("-I", "--ivar", action="store_true") args = parser.parse_args() shape, wcs = enmap.read_map_geometry(args.template) box = enmap.box(shape, wcs) box = utils.widen_box(box, 1 * utils.degree, relative=False) imap = enmap.read_map(args.imap, box=box) if args.ivar: imap /= imap.pixsizemap() omap = imap.project(shape, wcs, order=args.order, mode=args.mode) if args.ivar: omap *= omap.pixsizemap() enmap.write_map(args.omap, omap) #blockpix = np.product(shape[:-2])*shape[-1] #bsize = max(1,utils.nint(args.mem/(blockpix*imap.dtype.itemsize))) # #nblock = (shape[-2]+bsize-1)//bsize #for b in range(nblock): # r1, r2 = b*bsize, (b+1)*bsize # osub = omap[...,r1:r2,:] # omap[...,r1:r2,:] = enmap.project(imap, osub.shape, osub.wcs, order=args.order, mode=args.mode) ##o = enmap.project(m, t.shape, t.wcs, order=args.order, mode=args.mode)
det_pos[:, 0] = 0 det_box = np.array([np.min(det_pos, 0), np.max(det_pos, 0)]) det_comps = np.full((ndet, 3), 1, dtype=dtype) wt = args.wt * 60.0 # input box t0 = args.t # In mjd ibox = np.array([ [0, wt], [args.az - args.waz / 2., args.az + args.waz / 2.], [args.el - args.wel / 2., args.el + args.wel / 2.], ]).T + det_box / utils.degree # units ibox[:, 1:] *= utils.degree wibox = ibox.copy() wibox[:, :] = utils.widen_box(ibox[:, :]) srate = nsamp / wt # output box icorners = utils.box2corners(ibox) ocorners = hor2cel(icorners.T, t0) obox = utils.minmax(ocorners, -1)[:, :2] wobox = utils.widen_box(obox) # define a pixelization shape, wcs = enmap.geometry(pos=wobox[:, ::-1], res=args.res * utils.arcmin, proj="cea") nphi = int(2 * np.pi / (args.res * utils.arcmin)) map_orig = enmap.rand_gauss((ncomp, ) + shape, wcs).astype(dtype) print "map shape %s" % str(map_orig.shape)
free_blocks = np.where(block_ownership<0)[0] nfixed = len(fixed_blocks) nfree = len(free_blocks) sys.stderr.write("splitting %d:[%s] tods into %d splits via %d blocks%s" % ( ntod, atolist(nper), nsplit, nblock, (" with %d:%d free:fixed" % (nfree,nfixed)) if nfixed > 0 else "") + "\n") # We assume that site and pointing offsets are the same for all tods, # so get them based on the first one entry = filedb.data[ids[0]] site = actdata.read(entry, ["site"]).site # Determine the bounding box of our selected data bounds = db.data["bounds"].reshape(2,-1).copy() bounds[0] = utils.rewind(bounds[0], bounds[0,0], 360) box = utils.widen_box(utils.bounding_box(bounds.T), 4*args.rad, relative=False) waz, wel = box[1]-box[0] # Use fullsky horizontally if we wrap too far if waz <= 180: shape, wcs = enmap.geometry(pos=box[:,::-1]*utils.degree, res=args.res*utils.degree, proj="car", ref=(0,0)) else: shape, wcs = enmap.fullsky_geometry(res=args.res*utils.degree) y1, y2 = np.sort(enmap.sky2pix(shape, wcs, [box[:,1]*utils.degree,[0,0]])[0].astype(int)) shape, wcs = enmap.slice_geometry(shape, wcs, (slice(y1,y2),slice(None))) sys.stderr.write("using %s workspace with resolution %.2f deg" % (str(shape), args.res) + "\n") # Get the hitmap for each block hits = enmap.zeros((nblock,narray)+shape, wcs) ndig = calc_ndig(nblock) sys.stderr.write("estimating hitmap for block %*d/%d" % (ndig,0,nblock))
# Read in our focalplane layouts so we can define our output map bounds dets, offs, boxes, imaps = [], [], [], [] for i in range(nfile): det, off = files.read_point_template(ilayfiles[i]) imap = enmap.read_map(imapfiles[i]) if args.slice: imap = eval("imap" + args.slice) # We want y,x-ordering off = off[:, ::-1] box = utils.minmax(off, 0) dets.append(det) offs.append(off) boxes.append(box) imaps.append(imap) box = utils.bounding_box(boxes) box = utils.widen_box(box, rad * 5, relative=False) # We assume that the two maps have the same pixelization imaps = enmap.samewcs(np.array(imaps), imaps[0]) # Downsample by averaging imaps = enmap.downgrade(imaps, (1, args.step)) naz = imaps.shape[-1] # Ok, build our output geometry shape, wcs = enmap.geometry(pos=box, res=args.res * utils.arcmin, proj="car", pre=(naz, )) omap = enmap.zeros(shape, wcs, dtype=dtype) # Normalization
# Read in our focalplane layouts so we can define our output map bounds dets, offs, boxes, imaps = [], [], [], [] for i in range(nfile): det, off = files.read_point_template(ilayfiles[i]) imap = enmap.read_map(imapfiles[i]) if args.slice: imap = eval("imap"+args.slice) # We want y,x-ordering off = off[:,::-1] box = utils.minmax(off,0) dets.append(det) offs.append(off) boxes.append(box) imaps.append(imap) box = utils.bounding_box(boxes) box = utils.widen_box(box, rad*5, relative=False) # We assume that the two maps have the same pixelization imaps = enmap.samewcs(np.array(imaps), imaps[0]) # Downsample by averaging imaps = enmap.downgrade(imaps, (1,args.step)) naz = imaps.shape[-1] # Ok, build our output geometry shape, wcs = enmap.geometry(pos=box, res=args.res*utils.arcmin, proj="car", pre=(naz,)) omap = enmap.zeros(shape, wcs, dtype=dtype) # Normalization norm = enmap.zeros(shape[-2:],wcs) norm[0,0] = 1 norm = enmap.smooth_gauss(norm, rad)[0,0]
for iel in range(nel): az_mid = (args.az1 + args.daz * iaz) * utils.degree el_mid = (args.el1 + args.delta_el * iel) * utils.degree t_mid = args.t # Bounds box = np.array([[-args.wt / 2. / 60 / 24, args.wt / 2. / 60 / 24], [ az_mid - utils.degree * args.waz / 2, az_mid + utils.degree * args.waz / 2 ], [ el_mid - utils.degree * args.wel / 2, el_mid + utils.degree * args.wel / 2 ]]).T # Build an interpolator wbox = utils.widen_box(box) errlim = np.array( [utils.arcsec, utils.arcsec, utils.arcmin, utils.arcmin]) * acc t1 = time.time() ipol, obox, ok, err = interpol.build(hor2cel, interpolator, wbox, errlim, maxsize=max_size, maxtime=max_time, return_obox=True, return_status=True) t2 = time.time() # Choose some points to evaluate the model at hor_test = box[0, :, None] + np.random.uniform( 0, 1, size=(3, args.ntest)) * (box[1] - box[0])[:, None]
det_pos[:,0] = 0 det_box = np.array([np.min(det_pos,0),np.max(det_pos,0)]) det_comps = np.full((ndet,3),1,dtype=dtype) wt = args.wt * 60.0 # input box t0 = args.t # In mjd ibox = np.array([ [0, wt], [args.az-args.waz/2., args.az+args.waz/2.], [args.el-args.wel/2., args.el+args.wel/2.], ]).T + det_box/utils.degree # units ibox[:,1:] *= utils.degree wibox = ibox.copy() wibox[:,:] = utils.widen_box(ibox[:,:]) srate = nsamp/wt # output box icorners = utils.box2corners(ibox) ocorners = hor2cel(icorners.T, t0) obox = utils.minmax(ocorners, -1)[:,:2] wobox = utils.widen_box(obox) # define a pixelization shape, wcs = enmap.geometry(pos=wobox[:,::-1], res=args.res*utils.arcmin, proj="cea") nphi = int(2*np.pi/(args.res*utils.arcmin)) map_orig = enmap.rand_gauss((ncomp,)+shape, wcs).astype(dtype) print "map shape %s" % str(map_orig.shape) pbox = np.array([[0,0],shape],dtype=int)