def __call__(self, ipos): """Transform ipos[{t,az,el},nsamp] into opix[{y,x,c,s},nsamp].""" shape = ipos.shape[1:] ipos = ipos.reshape(ipos.shape[0], -1) time = self.scan.mjd0 + ipos[0] / utils.day2sec # We support sidelobe mapping by passing the detector pointing "ipos" as the "boresight" # pointing, which is only used in boresight-relative coordinates or sidelobe mapping. # This actually results in a better coordinate system than if we had passed in the actual # boresight, since we don't really want boresight-centered coordinates, we want detector # centered coordinates. opos = coordinates.transform(self.scan.sys, self.sys, ipos[1:], time=time, site=self.scan.site, pol=True, bore=ipos[1:]) # Parallax correction sundist = config.get("pmat_parallax_au") if sundist: # Transform to a sun-centered coordinate system, assuming all objects # are at a distance of sundist from the sun opos[1::-1] = parallax.earth2sun(opos[1::-1], self.scan.mjd0, sundist) opix = np.zeros((4, ) + ipos.shape[1:]) if self.template is not None: opix[:2] = self.template.sky2pix(opos[1::-1], safe=2) # When mapping the full sky, angle wraps can't be hidden # ouside the image. We must therefore unwind along each # interpolation axis to avoid discontinuous interpolation nx = int(np.round(np.abs(360 / self.template.wcs.wcs.cdelt[0]))) opix[1] = utils.unwind(opix[1].reshape(shape), period=nx, axes=range(len(shape))).reshape(-1) # Prefer positive numbers opix[1] -= np.floor(opix[1].reshape(-1)[0] / nx) * nx # but not if they put everything outside our patch if np.min(opix[1]) > self.template.shape[-1]: opix[1] -= nx else: # If we have no template, output angles instead of pixels. # Make sure the angles don't have any jumps in them opix[:2] = opos[1::-1] # output order is dec,ra opix[1] = utils.rewind(opix[1], self.ref_phi) opix[2] = np.cos(2 * opos[2]) opix[3] = np.sin(2 * opos[2]) return opix.reshape((opix.shape[0], ) + shape)
def __init__(self, scan, srcs, sys=None, tmul=None, pmul=None): # We support a srcs which is either [nsrc,nparam], [nsrc,ndir,nparam] or [nsrc,ndir,ndet,nparam], where # ndir is either 1 or 2 depending on whether one wants to separate different # scanning directions. srcs = np.array(srcs) while srcs.ndim < 4: srcs = srcs[:, None] # srcs is [nsrc,ndir,ndet_or_1,{dec,ra,T,Q,U,ibeams}] sys = config.get("map_sys", sys) cres = config.get("pmat_ptsrc_cell_res") * utils.arcmin nsrc, ndir, src_ndet = srcs.shape[:3] self.scan = scan maxcell = 50 # max numer of sources per cell # Compute parallax displacement if necessary sundist = config.get("pmat_parallax_au") self.dpos = 0 if sundist: # Transformation to a sun-centered system self.dpos = parallax.earth2sun(srcs.T[:2], self.scan.mjd0, sundist, diff=True).T srcs[..., :2] += self.dpos # Investigate the beam to find the max relevant radius sigma_lim = config.get("pmat_ptsrc_rsigma") value_lim = np.exp(-0.5 * sigma_lim**2) rmax = np.where(scan.beam[1] >= value_lim)[0][-1] * scan.beam[0, 1] rmul = max([ utils.expand_beam(src[-3:])[0][0] for src in srcs.reshape(-1, srcs.shape[-1]) ]) rmax *= rmul # Build interpolator (dec,ra output ordering) transform = build_pos_transform(scan, sys=config.get("map_sys", sys)) ipol, obox, err = build_interpol(transform, scan.box, scan.entry.id, posunit=0.5 * utils.arcsec) self.rbox, self.nbox, self.yvals = extract_interpol_params( ipol, srcs.dtype) self.cbox = obox[:, :2] self.ref = np.mean(self.cbox, 0) self.ncell, self.cells = pointsrcs.build_src_cells(self.cbox, srcs[..., :2], cres, unwind=True) ## Build source hit grid #cbox = obox[:,:2] #cshape = tuple(np.ceil(((cbox[1]-cbox[0])/cres)).astype(int)) #self.ref = np.mean(cbox,0) #srcs[...,:2] = utils.rewind(srcs[...,:2], self.ref) ## A cell is hit if it overlaps both horizontally and vertically ## with the point source +- rmax ## ncell is [ndir,nsrc_det,ncy,ncx] #ncell = np.zeros((ndir,src_ndet)+cshape,dtype=np.int32) ## cells is [ndir,nsrc_det,ncy,ncx,maxcell] #cells = np.zeros((ndir,src_ndet)+cshape+(maxcell,),dtype=np.int32) #c0 = cbox[0]; inv_dc = cshape/(cbox[1]-cbox[0]) #for si in range(nsrc): # for sdir in range(ndir): # for sdi in range(src_ndet): # src = srcs[si,sdir,sdi] # i1 = (src[:2]-rmax-c0)*inv_dc # i2 = (src[:2]+rmax-c0)*inv_dc+1 # +1 because this is a half-open interval # # Truncate to edges - any source outside of our region # # will be put on one of the edge cells # i1 = np.maximum(i1.astype(int), 0) # i2 = np.minimum(i2.astype(int), np.array(cshape)-1) # #print si, sdir, i1, i2, cshape # if np.any(i1 >= cshape) or np.any(i2 < 0): continue # sel= (sdir,sdi,slice(i1[0],i2[0]),slice(i1[1],i2[1])) # cells[sel][:,:,ncell[sel]] = si # ncell[sel] += 1 #self.cells, self.ncell = cells, ncell #print self.cells.shape, self.ncell.shape self.rmax = rmax self.tmul = 1 if tmul is None else tmul self.pmul = 1 if pmul is None else pmul self.err = err
def trf(pos, time): opos = pos.copy() opos[:2] = parallax.earth2sun(pos[:2], time, dist) return opos