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 aberrate(imap, dir, beta, mode="wrap", order=3, recenter=False, modulation=True): pol = imap.ndim > 2 pos = imap.posmap() # The ::-1 stuff switches between dec,ra and ra,dec ordering. # It is a bit confusing to have different conventions in enmap # and coordinates. pos = remap(pos[::-1], dir, beta, pol=pol, recenter=recenter, modulation=modulation) pos[:2] = pos[1::-1] pix = imap.sky2pix(pos[:2], corner=True) # interpol needs corners omap = en.ndmap(utils.interpol(imap, pix, mode=mode, order=order), imap.wcs) if pol: c, s = np.cos(2 * pos[2]), np.sin(2 * pos[2]) omap[1] = c * omap[1] + s * omap[2] omap[2] = -s * omap[1] + c * omap[2] if modulation: omap *= pos[2 + pol] return omap
def get_samples(self, verbose=False): """Return the actual detector samples. Slow! Data is read from disk and calibrated on the fly, so store the result if you need to reuse it.""" # Because we've read the tod_shape field earlier, we know that reading tod # won't cause any additional truncation of the samples or detectors. # tags is only needed here for read_combo support, but that is mostly broken # anyway. t1 = time.time() self.d += actdata.read(self.entry, fields=["tod", "tags"], dets=self.d.dets) t2 = time.time() if verbose: print "read %-14s in %6.3f s" % ("tod", t2-t1) if config.get("tod_skip_deconv"): ops = ["tod_real"] else: ops = ["tod"] actdata.calibrate(self.d, operations=ops, verbose=verbose) tod = self.d.tod # Remove tod from our local d, so we won't end up hauling it around forever del self.d.tod # HWP resample if needed if self.mapping is not None: tod = np.ascontiguousarray(utils.interpol(tod, self.mapping.oimap[None], order=1, mask_nan=False)) method = config.get("downsample_method") for s in self.sampslices: srange = slice(s.start, s.stop, np.sign(s.step) if s.step else None) tod = tod[:,srange] tod = resample.resample(tod, 1.0/np.abs(s.step or 1), method=method) tod = np.ascontiguousarray(tod) return tod
def __call__(self, poss, amps, taus, dets=None): if dets is None: dets = np.arange(len(self.rdata.dets)) rmask = np.in1d(self.rdata.detmap, dets) if np.sum(rmask) == 0: return np.zeros([0, self.rdata.pos.shape[1]], float) rpos = self.rdata.pos[rmask] mask = self.mask[rmask] detinds = build_detinds(self.rdata.detmap[rmask], dets) # Evaluate the plain beam r = np.sum((rpos - poss[detinds][:, None])**2, -1)**0.5 bpix = r / self.dr model = utils.interpol(self.rdata.beam[1], bpix[None], mask_nan=False, order=1) # Must mask invalid regions *before* fourier stuff model *= mask # Apply the butterworth filter and time constants fmodel = fft.rfft(model) tfilters = filters.tconst_filter(self.rdata.freqs[None], taus[:, None]) * self.rdata.butter fmodel *= tfilters[detinds] fft.ifft(fmodel, model, normalize=True) # Apply the amplitudes model *= amps[detinds, None] return model
def get_samples(self, verbose=False): """Return the actual detector samples. Slow! Data is read from disk and calibrated on the fly, so store the result if you need to reuse it.""" # Because we've read the tod_shape field earlier, we know that reading tod # won't cause any additional truncation of the samples or detectors. # tags is only needed here for read_combo support, but that is mostly broken # anyway. t1 = time.time() self.d += actdata.read(self.entry, fields=["tod", "tags"], dets=self.d.dets) #if debug_inject is not None: self.d.tod += debug_inject t2 = time.time() if verbose: print("read %-14s in %6.3f s" % ("tod", t2 - t1)) if config.get("tod_skip_deconv"): ops = ["tod_real"] else: ops = ["tod"] actdata.calibrate(self.d, operations=ops, verbose=verbose) tod = self.d.tod # Remove tod from our local d, so we won't end up hauling it around forever del self.d.tod # HWP resample if needed if self.mapping is not None: tod = np.ascontiguousarray( utils.interpol(tod, self.mapping.oimap[None], order=1, mask_nan=False)) method = config.get("downsample_method") for s in self.sampslices: tod = scan.slice_tod_samps(tod, s, method=method) tod = np.ascontiguousarray(tod) return tod
def __init__(self, shape, inspec, scale): freqs = fft.rfftfreq(shape[-2]) * scale # Should check units of fourier space here. Should # rescaling from samples to az change the value of the # spectrum? How much of that is handled by the hitcounts? self.spec_full = utils.interpol(inspec, freqs[None]) self.scale = scale
def eval_srcs_loop(posmap, poss, amps, beam, cres, nhit, cell_srcs): # Loop through each cell ncy, ncx = nhit.shape model = enmap.zeros(amps.shape[-1:] + posmap.shape[-2:], posmap.wcs, amps.dtype) for cy in range(ncy): for cx in range(ncx): nsrc = nhit[cy, cx] if nsrc == 0: continue srcs = cell_srcs[cy, cx, :nsrc] y1, y2 = (cy + 0) * cres[0], (cy + 1) * cres[0] x1, x2 = (cx + 0) * cres[1], (cx + 1) * cres[1] pixpos = posmap[:, y1:y2, x1:x2] srcpos = poss[srcs].T # [2,nsrc] srcamp = amps[srcs].T # [ncomp,nsrc] diff = pixpos[:, None, :, :] - srcpos[:, :, None, None] r = (diff[0]**2 + (diff[1] * np.cos(pixpos[0, None, :, :]))**2)**0.5 bpix = (r - beam[0, 0]) / (beam[0, 1] - beam[0, 0]) # Evaluate the beam at these locations bval = utils.interpol(beam[1], bpix[None], mode="constant", order=1) # [nsrc,ry,rx] cmodel = srcamp[:, :, None, None] * bval cmodel = np.sum(cmodel, -3) model[:, y1:y2, x1:x2] += cmodel return model
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 __init__(self, shape, inspec, scale): freqs = fft.rfftfreq(shape[-2]) * scale # Should check units of fourier space here. Should # rescaling from samples to az change the value of the # spectrum? How much of that is handled by the hitcounts? self.spec_full = utils.interpol(inspec, freqs[None]) self.scale = scale
def __init__(self, shape, inspec, scale, corrfun): freqs = np.abs(fft.fftfreq(shape[-2]) * scale) spec_full = utils.interpol(inspec, np.abs(freqs[None])) # Build our 2d noise spectrum. First get the stripy part. ps_stripe = np.tile(1 / spec_full[:, None], [1, shape[-1]]) # Then get our common mode ps_cmode = fft.fft(corrfun * 1j, axes=[-2, -1]) # Scale common mode to have the same DC level as the striping ps_cmode *= ps_stripe[0, 0] / ps_cmode[0, 0] ps_tot = ps_stripe + ps_cmode self.inv_ps = 1 / ps_tot
def __init__(self, shape, inspec, scale, corrfun): freqs = np.abs(fft.fftfreq(shape[-2]) * scale) spec_full = utils.interpol(inspec, np.abs(freqs[None])) # Build our 2d noise spectrum. First get the stripy part. ps_stripe = np.tile(1/spec_full[:,None], [1,shape[-1]]) # Then get our common mode ps_cmode = fft.fft(corrfun*1j,axes=[-2,-1]) # Scale common mode to have the same DC level as the striping ps_cmode *= ps_stripe[0,0]/ps_cmode[0,0] ps_tot = ps_stripe + ps_cmode self.inv_ps = 1/ps_tot
def lens_map_flat(cmb_map, phi_map): raw_pix = cmb_map.pixmap() + enmap.grad_pix(phi_map) # And extract the interpolated values. Because of a bug in map_pixels with # mode="wrap", we must handle wrapping ourselves. npad = int( np.ceil( max(np.max(-raw_pix), np.max(raw_pix - np.array(cmb_map.shape[-2:])[:, None, None])))) pmap = enmap.pad(cmb_map, npad, wrap=True) return enmap.samewcs( utils.interpol(pmap, raw_pix + npad, order=4, mode="wrap"), cmb_map)
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 ephem_vec(objname, mjd, dt=10): """Computes the earth-relative position vector[{x,y,z},ntime] for the given object. Uses interpolation in steps dt (seconds) to speed things up. Set dt to 0 to disable this. The resulting vector 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) # Convert to low-res [x,y,z] sub_vec = utils.ang2rect(sub_pos[:2], zenith=False) * sub_pos[2] # Interpolate to target resolution full_vec = utils.interpol(sub_vec, inds[None]) return full_vec
def eval(self, rvec): """Evaluate beam at positions rvec[{dra,dec},...] relative to beam center""" # Decompose into parallel and orthogonal parts rvec = np.asanyarray(rvec).copy() rvec[0] *= np.cos(self.dec_ref) rpara = np.sum(rvec*self.e_para[:,None,None],0) rorto = np.sum(rvec*self.e_orto[:,None,None],0) # Evaluate each beam component ipara = rpara/self.res+self.vbeam.size/2 bpara = utils.interpol(self.vbeam, ipara[None], mask_nan=False, order=self.order, prefilter=False) borto = np.exp(-0.5*rorto**2/self.sigma**2) res = enmap.samewcs(bpara*borto, rvec) return res
def eval(self, rvec): """Evaluate beam at positions rvec[{dra,dec},...] relative to beam center""" # Decompose into parallel and orthogonal parts rvec = np.asanyarray(rvec).copy() rvec[0] *= np.cos(self.dec_ref) rpara = np.sum(rvec * self.e_para[:, None, None], 0) rorto = np.sum(rvec * self.e_orto[:, None, None], 0) # Evaluate each beam component ipara = rpara / self.res + self.vbeam.size / 2 bpara = utils.interpol(self.vbeam, ipara[None], mask_nan=False, order=self.order, prefilter=False) borto = np.exp(-0.5 * rorto**2 / self.sigma**2) res = enmap.samewcs(bpara * borto, rvec) return res
def get_samples(self, verbose=False): """Return the actual detector samples. Slow! Data is read from disk and calibrated on the fly, so store the result if you need to reuse it.""" # Because we've read the tod_shape field earlier, we know that reading tod # won't cause any additional truncation of the samples or detectors. # tags is only needed here for read_combo support, but that is mostly broken # anyway. t1 = time.time() self.d += actdata.read(self.entry, fields=["tod", "tags"], dets=self.d.dets) t2 = time.time() if verbose: print("read %-14s in %6.3f s" % ("tod", t2 - t1)) if config.get("tod_skip_deconv"): ops = ["tod_real"] else: ops = ["tod"] actdata.calibrate(self.d, operations=ops, verbose=verbose) tod = self.d.tod # Remove tod from our local d, so we won't end up hauling it around forever del self.d.tod # HWP resample if needed if self.mapping is not None: tod = np.ascontiguousarray( utils.interpol(tod, self.mapping.oimap[None], order=1, mask_nan=False)) method = config.get("downsample_method") for s in self.sampslices: srange = slice(s.start, s.stop, np.sign(s.step) if s.step else None) tod = tod[:, srange] # make sure we get exactly the same length the cuts will be expecting step = np.abs(s.step or 1) olen = (tod.shape[1] + step - 1) // step tod = resample.resample(tod, float(olen) / tod.shape[1], method=method) tod = np.ascontiguousarray(tod) return tod
def make_equispaced(d, t, quantile=0.1, order=3, mask_nan=False): """Given an array d[...,nt] of data that has been sampled at times t[nt], return an array that has been resampled to have a constant sampling rate.""" # Find the typical sampling rate of the input. We will lose information if # we don't use a sampling rate that's higher than the highest rate in the # input. But we also don't want to exaggerate the number of samples. Use a # configurable quantile as a compromise. dt = np.percentile(np.abs(t[1:] - t[:-1]), quantile * 100) # Modify so we get a whole number of samples nout = utils.nint(np.abs(t[-1] - t[0]) / dt) + 1 dt = (t[-1] - t[0]) / (nout - 1) # Construct our output time steps tout = np.arange(nout) * dt + t[0] # To interpolate, we need the input sample number as a function of time samples = np.interp(tout, t, np.arange(len(t))) # Now that we have the samples we can finally evaluate the function dout = utils.interpol(d, samples[None], mode="nearest", order=order, mask_nan=mask_nan) return dout, tout
def eval_srcs_vectorized(posmap, poss, amps, beam, cres, nhit, cell_srcs): # Find the coordinates of each pixel in each cell cposmap = cellify(posmap, cres) # [2,cy,cx,ry,rx] csrcpos = poss[cell_srcs] # [cy,cx,nmax,2] csrcpos = utils.moveaxis(csrcpos, -1, 0) # [2,cy,cx,nmax] csrcamp = amps[cell_srcs] # [cy,cx,nmax,ncomp2] csrcamp = utils.moveaxis(csrcamp, -1, 0) # [ncomp,cy,cx,nmax] # Ok, we can now compute the total # Get the beam radial position for each pixel for each source. [cy,cx,nmax,ry,rx] # Express this in beam resolution units diff = cposmap[:, :, :, None, :, :] - csrcpos[:, :, :, :, None, None] bpix = (diff[0]**2 + (diff[1] * np.cos(cposmap[0, :, :, None, :, :]))**2)**0.5 bpix = (bpix - beam[0, 0]) / (beam[0, 1] - beam[0, 0]) # Evaluate the beam at these locations bval = utils.interpol(beam[1], bpix[None], mode="constant", order=1) model = csrcamp[:, :, :, :, None, None] * bval # Mask invalid sources mask = np.arange(model.shape[-3]) < nhit[:, :, None] model *= mask[:, :, :, None, None] model = np.sum(model, -3) # [ncomp,cy,cx,ry,rx] model = uncellify(model) return model
def __call__(self, x): ix = ((x.T - self.box[0]) / (self.box[1] - self.box[0]) * (np.array(self.y.shape[1:]) - 1)).T return utils.interpol(self.y, ix, *self.args, **self.kwargs)
def calc_profile(self, off): pos = self.pos + off[:,None,None] r = np.sum(pos**2,0)**0.5 pix = r/self.dr return enmap.samewcs(utils.interpol(self.beam_pre, pix[None], prefilter=False, mask_nan=False), pos)
def __init__(self, shape, inspec, scale): freqs = np.abs(fft.fftfreq(shape[-2]) * scale) self.spec_full = utils.interpol(inspec, freqs[None]) self.scale = scale
def eval_beam(beam, l, raw=False): res = utils.interpol(beam, l[None], order=1, mask_nan=False) if not raw: res = np.exp(res) return res
def calc_profile(self, off): pos = self.pos + off[:,None,None] r = np.sum(pos**2,0)**0.5 pix = r/self.dr return enmap.samewcs(utils.interpol(self.beam_pre, pix[None], prefilter=False, mask_nan=False), pos)
def upscale(pos, factor): if factor == 1: return pos pix = np.arange(pos.shape[-1]*factor)/float(factor) return utils.interpol(pos, pix[None], mask_nan=False, order=1)
def get_model(self, point): pix = self.map.sky2pix(point.T[::-1]) return utils.interpol(self.map, pix, order=0).T
def __init__(self, shape, inspec, scale): freqs = np.abs(fft.fftfreq(shape[-2]) * scale) self.spec_full = utils.interpol(inspec, freqs[None]) self.scale = scale