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 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 classify_scanning_patterns(myscans, tol=0.5*utils.degree, comm=None): """Classify scans into scanning patterns based on [az,el] bounds. Returns patterns[:,{ftom,to},{el,az}] and pids[len(myscans)], where pids contains the index of each myscan into patterns.""" boxes = get_scan_bounds(myscans) rank = np.full(len(boxes),comm.rank) if comm is not None: boxes = utils.allgatherv(boxes, comm) rank = utils.allgatherv(rank, comm) pids = utils.label_unique(boxes, axes=(1,2), atol=tol) npattern = np.max(pids)+1 # For each scanning pattern, define a bounding box pboxes = np.array([utils.bounding_box(boxes[pids==pid]) for pid in xrange(npattern)]) # Get the ids for the scans that we have if comm is not None: pids = pids[rank==comm.rank] return pboxes, pids
def distribute_scans(myinds, mycosts, myboxes, comm): """Given the costs[nmyscan] and bounding boxes[nmyscan,2,2] of our local scans, compute a new scan distribution that distributes costs relatively evenly while keeping all scans a task owns in a local area of the sky. Returns the new myinds[nmyscan2] (indices into global scans array), mysubs[nmyscan2] (workspace index for each of my new scans), mybbox [nmyscan2,2,2] (bounding boxes for the new scans). This function does not move the scan data to the new processes. This is up tot he caller.""" all_costs = np.array(comm.allreduce(mycosts)) all_inds = np.array(comm.allreduce(myinds)) if myboxes is None: myinds = all_inds[utils.equal_split(all_costs, comm.size)[comm.rank]] return myinds else: #hfile = h5py.File("tmp%02d.hdf" % comm.rank, "w") all_boxes = np.array(comm.allreduce(myboxes)) #hfile["all1"] = all_boxes/utils.degree # Avoid angle wraps. We assume that the boxes are all correctly wrapped # individually. ras = all_boxes[:, :, 1] ra_ref = np.median(np.mean(ras, 1)) rashift = ra_ref + (ras[:, 0] - ra_ref + np.pi) % (2 * np.pi) - np.pi - ras[:, 0] ras += rashift[:, None] all_boxes[:, :, 1] = ras #hfile["all2"] = all_boxes/utils.degree myinds_old = myinds #hfile["myinds1"] = myinds # Split into nearby scans mygroups = dmap.split_boxes_rimwise(all_boxes, all_costs, comm.size)[comm.rank] myinds = [all_inds[i] for group in mygroups for i in group] #hfile["myinds2"] = myinds mysubs = [gi for gi, group in enumerate(mygroups) for i in group] #hfile["mysubs"] = mysubs #hfile["myboxes"] = np.array([all_boxes[i] for i in mygroups[0]])/utils.degree mybbox = [ utils.bounding_box([all_boxes[i] for i in group]) for group in mygroups ] #hfile["mybbox"] = mybbox[0]/utils.degree #hfile.close() return myinds, mysubs, mybbox
continue # Reorder from az,el to el,az boxes[ind] = [np.min(d.boresight[2:0:-1],1),np.max(d.boresight[2:0:-1],1)] L.info("%5d: %s" % (ind, id)) boxes = utils.allreduce(boxes, comm_world) # Prune null boxes usable = np.all(boxes!=0,(1,2)) moo = ids[usable] cow = boxes[usable] ids, boxes = ids[usable], boxes[usable] pattern_ids = utils.label_unique(boxes, axes=(1,2), atol=tol) npattern = np.max(pattern_ids)+1 pboxes = np.array([utils.bounding_box(boxes[pattern_ids==pid]) for pid in xrange(npattern)]) pscans = [np.where(pattern_ids==pid)[0] for pid in xrange(npattern)] L.info("Found %d scanning patterns" % npattern) # Build the set of tasks we should go through. This effectively # collapses these two loops, avoiding giving rank 0 much more # to do than the last ranks. tasks = [] for pid, group in enumerate(pscans): # Start at pattern p0 if pid < args.p0: continue ngroup = (len(group)+tods_per_map-1)/tods_per_map for gind in range(ngroup): tasks.append([pid,gind,group[gind*tods_per_map:(gind+1)*tods_per_map]])
np.max(d.boresight[2:0:-1], 1) ] L.info("%5d: %s" % (ind, id)) boxes = utils.allreduce(boxes, comm_world) # Prune null boxes usable = np.all(boxes != 0, (1, 2)) moo = ids[usable] cow = boxes[usable] ids, boxes = ids[usable], boxes[usable] pattern_ids = utils.label_unique(boxes, axes=(1, 2), atol=tol) npattern = np.max(pattern_ids) + 1 pboxes = np.array([ utils.bounding_box(boxes[pattern_ids == pid]) for pid in xrange(npattern) ]) pscans = [np.where(pattern_ids == pid)[0] for pid in xrange(npattern)] L.info("Found %d scanning patterns" % npattern) # Build the set of tasks we should go through. This effectively # collapses these two loops, avoiding giving rank 0 much more # to do than the last ranks. tasks = [] for pid, group in enumerate(pscans): # Start at pattern p0 if pid < args.p0: continue ngroup = (len(group) + tods_per_map - 1) / tods_per_map for gind in range(ngroup): tasks.append(
ilayfiles = args.ifiles[1::2] # 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)
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))
ilayfiles = args.ifiles[1::2] # 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