def __call__(self, ipos, time): opos = coordinates.transform(self.isys, self.osys, ipos, time=time, site=self.site) x, y = self.wcs.wcs_world2pix(opos[0]/utils.degree,opos[1]/utils.degree,0) nx = int(np.abs(360.0/self.wcs.wcs.cdelt[0])) x = utils.unwind(x, nx, ref=nx/2) opos[0] = utils.unwind(opos[0]) return np.array([opos[0],opos[1],x,y])
def __call__(self, ipos, time): opos = coordinates.transform(self.isys, self.osys, ipos, time=time, site=self.site) x, y = self.wcs.wcs_world2pix(opos[0] / utils.degree, opos[1] / utils.degree, 0) nx = int(np.abs(360.0 / self.wcs.wcs.cdelt[0])) x = utils.unwind(x, nx, ref=nx / 2) opos[0] = utils.unwind(opos[0]) return np.array([opos[0], opos[1], x, y])
def get_moby_pointing(entry, bore, dets, downgrade=1): # Set up moby2 import moby2 moby2.pointing.set_bulletin_A() params = { "detector_offsets": { "format": "fp_file", "filename": entry.point_template }, "pol_source": { "source": "file", "filename": entry.polangle, "format": "ascii", "fail_value": -1 }, "shift_generator": { "source": "file", "filename": entry.point_offsets, "columns": [0, 5, 6], "rescale_degrees": 180 / np.pi }, } bore = np.ascontiguousarray(bore[::downgrade].T) fplane = moby2.scripting.get_focal_plane(params, det_uid=dets, tod=entry.id) res = fplane.get_coords(bore[0], bore[1], bore[2], fields=['ra', 'dec', 'cos_2gamma', 'sin_2gamma']) res[0][:] = utils.unwind(res[0]) return np.array(res)
def calc_az_sweep(pattern, offset, site, pad=2.0, subsample=1.0): """Helper function. Given a pattern and mean focalplane offset, computes the shape of an azimuth sweep on the sky.""" el1 = pattern[0] + offset[0] az1 = pattern[1] + offset[1] - pad az2 = pattern[2] + offset[1] + pad daz = rhs.pixshape()[0] / np.cos(el1) / subsample naz = int(np.ceil((az2 - az1) / daz)) naz = fft.fft_len(naz, "above", [2, 3, 5, 7]) # Simulate a single sweep at arbitrary time sweep_az = np.arange(naz) * daz + az1 sweep_el = np.full(naz, el1) sweep_cel = coordinates.transform("hor", "cel", np.array([sweep_az, sweep_el]), time=ref_time, site=site) # Make ra safe sweep_cel = utils.unwind(sweep_cel) return bunch.Bunch(sweep_cel=sweep_cel, sweep_hor=np.array([sweep_az, sweep_el]), el=el1, az1=az1, az2=az2, naz=naz, daz=daz)
def ephem_pos(objname, mjd, dt=10): """Computes the earth-relative angular position and radius [{ra,dec,r},ntime] for the given object. Uses interpolation in steps dt (seconds) to sepeed things up. Set dt to 0 to disable this. r has units of AU.""" # Get low-res [ra,dec,r] sub_time, inds = define_subsamples(mjd, dt=dt / (24. * 3600)) sub_pos = ephem_raw(objname, sub_time) # Avoid angle wraps, as they will mess up the interpolation sub_pos[0] = utils.unwind(sub_pos[0]) # Interpolate to target resolution full_pos = utils.interpol(sub_pos, inds[None]) return full_pos
def calc_pbox(shape, wcs, box, n=10): nphi = utils.nint(np.abs(360 / wcs.wcs.cdelt[0])) dec = np.linspace(box[0, 0], box[1, 0], n) ra = np.linspace(box[0, 1], box[1, 1], n) y = enmap.sky2pix(shape, wcs, [dec, dec * 0 + box[0, 1]])[0] x = enmap.sky2pix(shape, wcs, [ra * 0 + box[0, 0], ra])[1] x = utils.unwind(x, nphi) pbox = np.array([[np.min(y), np.min(x)], [np.max(y), np.max(x)]]) xm1 = np.mean(pbox[:, 1]) xm2 = utils.rewind(xm1, shape[-1] / 2, nphi) pbox[:, 1] += xm2 - xm1 pbox = utils.nint(pbox) return pbox
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 opos = coordinates.transform("hor", "cel", ipos[1:], time=time, site=self.scan.site, pol=True) opix = np.zeros((4,)+ipos.shape[1:]) opix[:2] = self.wcs.wcs_world2pix(*tuple(opos[:2]/utils.degree)+(0,))[::-1] nx = int(np.abs(360/self.wcs.wcs.cdelt[0])) opix[1] = utils.unwind(opix[1], period=nx, ref=nx/2) opix[2] = np.cos(2*opos[2]) opix[3] = np.sin(2*opos[2]) return opix.reshape((opix.shape[0],)+shape)
def resample(self, mapping): res = cpy.deepcopy(self) res.boresight = np.ascontiguousarray(utils.interpol(res.boresight.T, mapping.oimap[None], order=1).T) res.hwp = utils.interpol(utils.unwind(res.hwp), mapping.oimap[None], order=1) res.hwp_phase = np.ascontiguousarray(utils.interpol(res.hwp_phase.T, mapping.oimap[None], order=1).T) try: res.dark_tod = utils.interpol(res.dark_tod, mapping.oimap[None]) res.dark_cut = resample_cut(res.dark_cut, mapping) except AttributeError as e: pass res.cut = resample_cut(res.cut, mapping) res.cut_noiseest = resample_cut(res.cut_noiseest, mapping) res.noise = res.noise.resample(mapping) res.mapping = mapping return res
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 calc_az_sweep(pattern, offset, site, pad=2.0, subsample=1.0): """Helper function. Given a pattern and mean focalplane offset, computes the shape of an azimuth sweep on the sky.""" el1 = pattern[0] + offset[0] az1 = pattern[1] + offset[1] - pad az2 = pattern[2] + offset[1] + pad daz = rhs.pixshape()[0]/np.cos(el1)/subsample naz = int(np.ceil((az2-az1)/daz)) naz = fft.fft_len(naz, "above", [2,3,5,7]) # Simulate a single sweep at arbitrary time sweep_az = np.arange(naz)*daz + az1 sweep_el = np.full(naz,el1) sweep_cel = coordinates.transform("hor","cel", np.array([sweep_az,sweep_el]),time=ref_time,site=site) # Make ra safe sweep_cel = utils.unwind(sweep_cel) return bunch.Bunch(sweep_cel=sweep_cel, sweep_hor=np.array([sweep_az,sweep_el]), el=el1, az1=az1, az2=az2, naz=naz, daz=daz)
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 opos = coordinates.transform("hor", "cel", ipos[1:], time=time, site=self.scan.site, pol=True) opix = np.zeros((4, ) + ipos.shape[1:]) opix[:2] = self.wcs.wcs_world2pix(*tuple(opos[:2] / utils.degree) + (0, ))[::-1] nx = int(np.abs(360 / self.wcs.wcs.cdelt[0])) opix[1] = utils.unwind(opix[1], period=nx, ref=nx / 2) opix[2] = np.cos(2 * opos[2]) opix[3] = np.sin(2 * opos[2]) return opix.reshape((opix.shape[0], ) + shape)
def build_hwp_sample_mapping(hwp, quantile=0.1): """Given a HWP angle, return an array with shape [nout] containing the original sample index (float) corresponding to each sample in the remapped array, along with the resulting hwp sample rate. The remapping also truncates the end to ensure that there is an integer number of HWP rotations in the data.""" # Make sure there are no angle wraps in the hwp hwp = utils.unwind(hwp) # interp requires hwp to be monotonically increasing. In practice # it could be monotonically decreasing too, but our final result # does not depend on the direction of rotation, so we simply flip it here # if necessary hwp = np.abs(hwp) # Find the target hwp speed speed = np.percentile(hwp[1:]-hwp[:-1], 100*quantile) # We want a whole number of samples per revolution, and # a whole number of revolutions in the whole tod a = hwp - hwp[0] nrev = int(np.floor(a[-1]/(2*np.pi))) nper = utils.nint(2*np.pi/speed) # Make each of these numbers fourier-friendly nrev = fft.fft_len(nrev, "below") nper = fft.fft_len(nper, "above") # Set up our output samples speed = 2*np.pi/nper nout = nrev*nper ohwp = hwp[0] + np.arange(nout)*speed # Find the input sample for each output sample res = bunch.Bunch() res.oimap = np.interp(ohwp, hwp, np.arange(len(hwp))) # Find the output sampe for each input sample too. Because of # cropping, the last of these will be invalid res.iomap = np.interp(np.arange(len(hwp)), res.oimap, np.arange(len(res.oimap))) # Find the average sampling rate change fsamp_rel = fsamp_out/fsamp_in res.fsamp_rel = 1/np.mean(res.oimap[1:]-res.oimap[:-1]) res.insamp = len(hwp) res.onsamp = nout res.nrev = nrev res.nper = nper return res
subdets = None absdets = None if args.absdets is not None: absdets = [int(w) for w in args.absdets.split(",")] elif args.dets is not None: subdets = [int(w) for w in args.dets.split(",")] fields = ["gain","tconst","cut","tod","boresight"] if args.fields: fields = args.fields.split(",") d = actdata.read(entry, fields=fields) if absdets: d.restrict(dets=absdets) if subdets: d.restrict(dets=d.dets[subdets]) if args.calib: d = actdata.calibrate(d, exclude=["autocut"]) elif args.manual_calib: ops = args.manual_calib.split(",") if "safe" in ops: d.boresight[1:] = utils.unwind(d.boresight[1:], period=360) if "rad" in ops: d.boresight[1:] *= np.pi/180 if "bgap" in ops: bad = (d.flags!=0)*(d.flags!=0x10) for b in d.boresight: gapfill.gapfill_linear(b, bad, inplace=True) if "gain" in ops: d.tod *= d.gain[:,None] if "tgap" in ops: gapfiller = {"copy":gapfill.gapfill_copy, "linear":gapfill.gapfill_linear}[config.get("gapfill")] gapfiller(d.tod, d.cut, inplace=True) if "slope" in ops: utils.deslope(d.tod, w=8, inplace=True) if "deconv" in ops: d = actdata.calibrate(d, operations=["tod_fourier"]) if args.bin > 1: d.tod = resample.downsample_bin(d.tod, steps=[args.bin]) d.boresight = resample.downsample_bin(d.boresight, steps=[args.bin])
def fixx(yx, nphi): yx = np.array(yx) yx[1] = utils.unwind(yx[1], nphi) return yx
absdets = None if args.absdets is not None: absdets = [int(w) for w in args.absdets.split(",")] elif args.dets is not None: subdets = [int(w) for w in args.dets.split(",")] fields = ["gain", "tconst", "cut", "tod", "boresight"] if args.fields: fields = args.fields.split(",") d = actdata.read(entry, fields=fields) if absdets: d.restrict(dets=absdets) if subdets: d.restrict(dets=d.dets[subdets]) if args.calib: d = actdata.calibrate(d, exclude=["autocut"]) elif args.manual_calib: ops = args.manual_calib.split(",") if "safe" in ops: d.boresight[1:] = utils.unwind(d.boresight[1:], period=360) if "rad" in ops: d.boresight[1:] *= np.pi / 180 if "bgap" in ops: bad = (d.flags != 0) * (d.flags != 0x10) for b in d.boresight: gapfill.gapfill_linear(b, bad, inplace=True) if "gain" in ops: d.tod *= d.gain[:, None] if "tgap" in ops: gapfiller = { "copy": gapfill.gapfill_copy, "linear": gapfill.gapfill_linear }[config.get("gapfill")] gapfiller(d.tod, d.cut, inplace=True) if "slope" in ops: utils.deslope(d.tod, w=8, inplace=True) if "deconv" in ops: