예제 #1
0
 def get_azel(self):
     """ Translate the boresight az/el quaternions into azimuth and
     elevation
     """
     quats = self.cache.reference("boresight_azel")
     theta, phi = qa.to_position(quats)
     self._az = (-phi % (2 * np.pi))
     self._el = np.pi / 2 - theta
     if len(self._az) > 0:
         azmin = np.amin(self._az)
         azmax = np.amax(self._az)
         elmin = np.amin(self._el)
         elmax = np.amax(self._el)
     else:
         azmin = 1000
         azmax = -1000
         elmin = 1000
         elmax = -1000
     if self.mpicomm is not None:
         azmin = self.mpicomm.allreduce(azmin, MPI.MIN)
         azmax = self.mpicomm.allreduce(azmax, MPI.MAX)
         elmin = self.mpicomm.allreduce(elmin, MPI.MIN)
         elmax = self.mpicomm.allreduce(elmax, MPI.MAX)
     self.scan_range = (azmin, azmax, elmin, elmax)
     return
예제 #2
0
    def _observe_sso(self, sso_az, sso_el, sso_dist, sso_dia, tod, comm,
                     prefix):
        """
        Observe the SSO with each detector in tod
        """
        log = Logger.get()
        rank = 0
        if comm is not None:
            rank = comm.rank
        tmr = Timer()
        if self._report_timing:
            if comm is not None:
                comm.Barrier()
            tmr.start()

        nsamp = tod.local_samples[1]

        if rank == 0:
            log.info("{}Observing the SSO signal".format(prefix))

        for det in tod.local_dets:
            # Cache the output signal
            cachename = "{}_{}".format(self._out, det)
            if tod.cache.exists(cachename):
                ref = tod.cache.reference(cachename)
            else:
                ref = tod.cache.create(cachename, np.float64, (nsamp, ))

            try:
                # Some TOD classes provide a shortcut to Az/El
                az, el = tod.read_azel(detector=det)
            except Exception as e:
                azelquat = tod.read_pntg(detector=det, azel=True)
                # Convert Az/El quaternion of the detector back into
                # angles for the simulation.
                theta, phi = qa.to_position(azelquat)
                # Azimuth is measured in the opposite direction
                # than longitude
                az = 2 * np.pi - phi
                el = np.pi / 2 - theta

            beam, radius = self._get_beam_map(det, sso_dia)

            # Interpolate the beam map at appropriate locations
            x = (az - sso_az) * np.cos(el)
            y = el - sso_el
            r = np.sqrt(x**2 + y**2)
            good = r < radius
            sig = beam(x[good], y[good], grid=False)
            ref[:][good] += sig

            del ref, sig, beam

        if self._report_timing:
            if comm is not None:
                comm.Barrier()
            if rank == 0:
                tmr.stop()
                tmr.report("{}OpSimSSO: Observe signal".format(prefix))
        return
예제 #3
0
def get_elevation_noise(args, comm, data, key="noise"):
    """ Insert elevation-dependent noise

    """
    timer = Timer()
    timer.start()
    # fsample = args.sample_rate
    for obs in data.obs:
        tod = obs["tod"]
        fp = obs["focalplane"]
        noise = obs[key]
        for det in tod.local_dets:
            if det not in noise.keys:
                raise RuntimeError(
                    'Detector "{}" does not have a PSD in the noise object'.
                    format(det))
            A = fp[det]["A"]
            C = fp[det]["C"]
            psd = noise.psd(det)
            try:
                # Some TOD classes provide a shortcut to Az/El
                _, el = tod.read_azel(detector=det)
            except Exception:
                azelquat = tod.read_pntg(detector=det, azel=True)
                # Convert Az/El quaternion of the detector back into
                # angles for the simulation.
                theta, _ = qa.to_position(azelquat)
                el = np.pi / 2 - theta
            el = np.median(el)
            # Scale the analytical noise PSD. Pivot is at el = 50 deg.
            psd[:] *= (A / np.sin(el) + C)**2
    timer.stop()
    if comm.world_rank == 0:
        timer.report("Elevation noise")
    return
예제 #4
0
    def subtract_signal(self, tod, cworld, rank, masksampler, mapsampler,
                        local_intervals):
        """ Subtract a signal estimate from the TOD and update the
        flags for noise estimation.
        """

        start_signal_subtract = MPI.Wtime()
        for det in tod.local_dets:
            if rank == 0:
                print('Subtracting signal for {}'.format(det), flush=True)
                tod.cache.report()
            fsample = self._rimo[det].fsample
            epsilon = self._rimo[det].epsilon
            eta = (1 - epsilon) / (1 + epsilon)
            signal = tod.local_signal(det, name=self._signal)
            flags = tod.local_flags(det, name=self._flags)
            flags &= self._detmask
            for ival in local_intervals:
                ind = slice(ival.first, ival.last + 1)
                sig = signal[ind]
                flg = flags[ind]
                quat = tod.local_pointing(det)[ind]
                if self._pol:
                    theta, phi, psi = qa.to_angles(quat)
                    iw = np.ones_like(theta)
                    qw = eta * np.cos(2 * psi)
                    uw = eta * np.sin(2 * psi)
                    iquw = np.column_stack([iw, qw, uw])
                else:
                    theta, phi = qa.to_position(quat)
                if masksampler is not None:
                    maskflg = masksampler.at(theta, phi) < 0.5
                    flg[maskflg] |= 255
                if mapsampler is not None:
                    if self._pol:
                        bg = mapsampler.atpol(theta, phi, iquw)
                    else:
                        bg = mapsampler.at(theta, phi)
                    if self._calibrate_signal_estimate:
                        good = flg == 0
                        ngood = np.sum(good)
                        if ngood > 1:
                            templates = np.vstack([np.ones(ngood), bg[good]])
                            invcov = np.dot(templates, templates.T)
                            cov = np.linalg.inv(invcov)
                            proj = np.dot(templates, sig[good])
                            coeff = np.dot(cov, proj)
                            bg = coeff[0] + coeff[1] * bg
                    sig -= bg
        cworld.barrier()
        stop_signal_subtract = MPI.Wtime()
        if rank == 0:
            print('TOD signal-subtracted in {:.2f} s'.format(
                stop_signal_subtract - start_signal_subtract),
                  flush=True)
        return fsample
예제 #5
0
    def _save_tod(self, obsname, tod, times, istart, nind, ind, comm,
                  common_ref):
        import pickle

        rank = 0
        if comm is not None:
            rank = comm.rank

        t = times[ind]
        tmin, tmax = t[0], t[-1]
        outdir = "snapshots"
        if rank == 0:
            try:
                os.makedirs(outdir)
            except FileExistsError:
                pass

        try:
            good = common_ref[ind] & tod.UNSTABLE == 0
        except:
            good = slice(0, nind)

        for det in tod.local_dets:
            # Cache the output signal
            cachename = "{}_{}".format(self._out, det)
            ref = tod.cache.reference(cachename)[ind]
            try:
                # Some TOD classes provide a shortcut to Az/El
                az, el = tod.read_azel(detector=det,
                                       local_start=istart,
                                       n=nind)
            except Exception as e:
                azelquat = tod.read_pntg(detector=det,
                                         local_start=istart,
                                         n=nind,
                                         azel=True)
                # Convert Az/El quaternion of the detector back into
                # angles for the simulation.
                theta, phi = qa.to_position(azelquat)
                # Azimuth is measured in the opposite direction
                # than longitude
                az = 2 * np.pi - phi
                el = np.pi / 2 - theta

            fn = os.path.join(
                outdir,
                "atm_tod_{}_{}_t_{}_{}.pck".format(obsname, det, int(tmin),
                                                   int(tmax)),
            )
            with open(fn, "wb") as fout:
                pickle.dump([det, t[good], az[good], el[good], ref[good]],
                            fout)

        return
예제 #6
0
파일: sss.py 프로젝트: ziotom78/toast
    def _observe_sss(self, sssmap, tod, comm, prefix):
        """
        Use healpy bilinear interpolation to observe the ground signal map
        """
        log = Logger.get()
        rank = 0
        if comm is not None:
            rank = comm.rank
        timer = Timer()
        if self._report_timing:
            if comm is not None:
                comm.Barrier()
            timer.start()

        nsamp = tod.local_samples[1]

        if rank == 0:
            log.info("{}Observing the scan-synchronous signal".format(prefix))

        for det in tod.local_dets:
            # Cache the output signal
            cachename = "{}_{}".format(self._out, det)
            if tod.cache.exists(cachename):
                ref = tod.cache.reference(cachename)
            else:
                ref = tod.cache.create(cachename, np.float64, (nsamp, ))

            try:
                # Some TOD classes provide a shortcut to Az/El
                az, el = tod.read_azel(detector=det)
                phi = 2 * np.pi - az
                theta = np.pi / 2 - el
            except Exception as e:
                azelquat = tod.read_pntg(detector=det, azel=True)
                # Convert Az/El quaternion of the detector back into
                # angles for the simulation.
                theta, phi = qa.to_position(azelquat)
                # Azimuth is measured in the opposite direction
                # than longitude
                # az = 2 * np.pi - phi
                # el = np.pi / 2 - theta

            ref[:] += hp.get_interp_val(sssmap, theta, phi)

            del ref

        if self._report_timing:
            if comm is not None:
                comm.Barrier()
            if rank == 0:
                timer.stop()
                timer.report("{}OpSimSSS: Observe signal".format(prefix))
        return
예제 #7
0
    def _get_weights(self, obs):
        """ Evaluate the special pointing matrix
        """

        tod = obs["tod"]
        nsample = tod.local_samples[1]
        focalplane = obs["focalplane"]
        # Create one constant signal for the observation and make it an
        # alias for all detectors
        tod.cache.put(
            self.dummy_name,
            np.ones(nsample, dtype=np.float64),
            replace=True,
        )

        for det in tod.local_dets:
            # measure the scan direction wrt the local meridian
            # for each sample
            quat = tod.read_pntg(detector=det)
            theta, phi = qa.to_position(quat)
            theta = np.pi / 2 - theta
            # scan direction across the reference sample
            dphi = (np.roll(phi, -1) - np.roll(phi, 1))
            dtheta = np.roll(theta, -1) - np.roll(theta, 1)
            # except first and last sample
            for dx, x in (dphi, phi), (dtheta, theta):
                dx[0] = x[1] - x[0]
                dx[-1] = x[-1] - x[-2]
            # scale dphi to on-sky
            dphi *= np.cos(theta)
            # Avoid overflows
            tiny = np.abs(dphi) < 1e-30
            if np.any(tiny):
                ang = np.zeros(nsample)
                ang[tiny] = np.sign(dtheta) * np.sign(dphi) * np.pi / 2
                not_tiny = np.logical_not(tiny)
                ang[not_tiny] = np.arctan(dtheta[not_tiny] / dphi[not_tiny])
            else:
                ang = np.arctan(dtheta / dphi)

            weights_out = np.vstack(
                [np.ones(nsample),
                 np.cos(2 * ang),
                 np.sin(2 * ang)]).T
            weights_name_out = f"{self.weight_name}_{det}"
            tod.cache.put(weights_name_out, weights_out, replace=True)

            # Need a constant signal to map
            signal_name = f"{self.signal_name}_{det}"
            tod.cache.add_alias(signal_name, self.dummy_name)
        return
예제 #8
0
파일: noise.py 프로젝트: CMB-S4/s4sim
def get_elevation_noise(args, comm, data, key="noise"):
    """ Insert elevation-dependent noise

    """
    if args.no_elevation_noise:
        return
    timer = Timer()
    timer.start()
    # fsample = args.sample_rate
    for obs in data.obs:
        tod = obs["tod"]
        fp = obs["focalplane"]
        noise = obs[key]
        for det in tod.local_dets:
            if det not in noise.keys:
                raise RuntimeError(
                    'Detector "{}" does not have a PSD in the noise object'.
                    format(det))
            A = fp[det]["A"]
            C = fp[det]["C"]
            psd = noise.psd(det)
            # We only consider a small range of samples for the elevation
            n = tod.local_samples[1]
            istart = max(0, n // 2 - 1000)
            istop = min(n, n // 2 + 1000)
            try:
                # Some TOD classes provide a shortcut to Az/El
                el = tod.read_azel(detector=det,
                                   local_start=istart,
                                   n=istop - istart)[1]
            except Exception:
                azelquat = tod.read_pntg(detector=det,
                                         azel=True,
                                         local_start=istart,
                                         n=istop - istart)
                # Convert Az/El quaternion of the detector back into
                # angles for the simulation.
                theta = qa.to_position(azelquat)[0]
                el = np.pi / 2 - theta
            el = np.median(el)
            # Scale the analytical noise PSD. Pivot is at el = 50 deg.
            psd[:] *= (A / np.sin(el) + C)**2
    if comm.world_rank == 0:
        timer.report_clear("Elevation noise")
    return
예제 #9
0
    def _save_tod(self, obsname, tod, times, istart, nind, ind, comm, common_ref):
        import pickle

        t = times[ind]
        tmin, tmax = t[0], t[-1]
        outdir = "snapshots"
        if comm.rank == 0:
            try:
                os.makedirs(outdir)
            except FileExistsError:
                pass

        try:
            good = common_ref[ind] & tod.UNSTABLE == 0
        except:
            good = slice(0, nind)

        for det in tod.local_dets:
            # Cache the output signal
            cachename = "{}_{}".format(self._out, det)
            ref = tod.cache.reference(cachename)[ind]
            try:
                # Some TOD classes provide a shortcut to Az/El
                az, el = tod.read_azel(detector=det, local_start=istart, n=nind)
            except Exception as e:
                azelquat = tod.read_pntg(
                    detector=det, local_start=istart, n=nind, azel=True
                )
                # Convert Az/El quaternion of the detector back into
                # angles for the simulation.
                theta, phi = qa.to_position(azelquat)
                # Azimuth is measured in the opposite direction
                # than longitude
                az = 2 * np.pi - phi
                el = np.pi / 2 - theta

            fn = os.path.join(
                outdir,
                "atm_tod_{}_{}_t_{}_{}.pck".format(obsname, det, int(tmin), int(tmax)),
            )
            with open(fn, "wb") as fout:
                pickle.dump([det, t[good], az[good], el[good], ref[good]], fout)

        return
예제 #10
0
    def _flag_ssos(self, sso_azs, sso_els, tod, focalplane):
        """
        Flag the SSO for each detector in tod
        """

        nsamp = tod.local_samples[1]

        for det in tod.local_dets:
            # Cache the output signal
            cachename = "{}_{}".format(self.flag_name, det)
            if tod.cache.exists(cachename):
                ref = tod.cache.reference(cachename)
            else:
                ref = tod.cache.create(cachename, np.uint8, (nsamp, ))

            try:
                # Some TOD classes provide a shortcut to Az/El
                az, el = tod.read_azel(detector=det)
            except Exception as e:
                azelquat = tod.read_pntg(detector=det, azel=True)
                # Convert Az/El quaternion of the detector back into
                # angles for the simulation.
                theta, phi = qa.to_position(azelquat)
                # Azimuth is measured in the opposite direction
                # than longitude
                az = 2 * np.pi - phi
                el = np.pi / 2 - theta

            cosel = np.cos(el)
            for sso_az, sso_el, sso_radius in zip(sso_azs, sso_els,
                                                  self.sso_radii):
                # Flag samples within search radius
                x = (az - sso_az) * cosel
                y = el - sso_el
                rsquared = x**2 + y**2
                good = rsquared < sso_radius**2
                ref[good] |= self.flag_mask

            del ref

        return
예제 #11
0
    def exec(self, data):

        for obs in data.obs:
            tod = obs["tod"]
            focalplane = obs["focalplane"]
            # Get HWP angle
            chi = tod.local_hwp_angle()
            for det in tod.local_dets:
                signal = tod.local_signal(det, self._name)
                band = focalplane[det]["band"]
                freq = {
                    "SAT_f030": "027",
                    "SAT_f040": "039",
                    "SAT_f090": "093",
                    "SAT_f150": "145",
                    "SAT_f230": "225",
                    "SAT_f290": "278",
                }[band]

                # Get incident angle

                det_quat = focalplane[det]["quat"]
                det_theta, det_phi, det_psi = qa.to_angles(det_quat)

                # Get observing elevation

                azelquat = tod.read_pntg(detector=det, azel=True)
                el = np.pi / 2 - qa.to_position(azelquat)[0]

                # Get polarization weights

                iweights = np.ones(signal.size)
                qweights = np.cos(2 * det_psi)
                uweights = np.sin(2 * det_psi)

                # Interpolate HWPSS to incident angle

                theta_deg = np.degrees(det_theta)
                itheta_high = np.searchsorted(self.thetas, theta_deg)
                itheta_low = itheta_high - 1

                theta_low = self.thetas[itheta_low]
                theta_high = self.thetas[itheta_high]
                r = (theta_deg - theta_low) / (theta_high - theta_low)

                transmission = (
                    (1 - r) * self.all_stokes[freq]["transmission"][itheta_low]
                    + r * self.all_stokes[freq]["transmission"][itheta_high])
                reflection = (
                    (1 - r) * self.all_stokes[freq]["reflection"][itheta_low] +
                    r * self.all_stokes[freq]["reflection"][itheta_high])
                emission = (
                    (1 - r) * self.all_stokes[freq]["emission"][itheta_low] +
                    r * self.all_stokes[freq]["emission"][itheta_high])

                # Scale HWPSS for observing elevation

                el_ref = np.radians(50)
                scale = np.sin(el_ref) / np.sin(el)

                # Observe HWPSS with the detector

                iquv = (transmission + reflection).T
                iquss = (iweights * np.interp(chi, self.chis, iquv[0]) +
                         qweights * np.interp(chi, self.chis, iquv[1]) +
                         uweights * np.interp(chi, self.chis, iquv[2])) * scale

                iquv = emission.T
                iquss += (iweights * np.interp(chi, self.chis, iquv[0]) +
                          qweights * np.interp(chi, self.chis, iquv[1]) +
                          uweights * np.interp(chi, self.chis, iquv[2]))

                iquss -= np.median(iquss)

                # Co-add with the cached signal

                signal += iquss

        return
예제 #12
0
    def _observe_atmosphere(
        self,
        sim,
        tod,
        comm,
        prefix,
        common_ref,
        istart,
        nind,
        ind,
        scan_range,
        times,
        absorption,
    ):

        azmin, azmax, elmin, elmax = scan_range

        nsamp = tod.local_samples[1]

        if self._report_timing:
            comm.Barrier()
            tstart = MPI.Wtime()

        if comm.rank == 0:
            print(prefix + "Observing the atmosphere", flush=self._flush)

        for det in tod.local_dets:

            # Cache the output signal
            cachename = "{}_{}".format(self._out, det)
            if tod.cache.exists(cachename):
                ref = tod.cache.reference(cachename)
            else:
                ref = tod.cache.create(cachename, np.float64, (nsamp,))

            # Cache the output flags
            flag_ref = tod.local_flags(det, self._flag_name)

            if self._apply_flags:
                good = np.logical_and(
                    common_ref[ind] & self._common_flag_mask == 0,
                    flag_ref[ind] & self._flag_mask == 0,
                )
                ngood = np.sum(good)
            else:
                try:
                    good = common_ref[ind] & tod.UNSTABLE == 0
                    ngood = np.sum(good)
                except:
                    good = slice(0, nind)
                    ngood = nind
            if ngood == 0:
                continue

            try:
                # Some TOD classes provide a shortcut to Az/El
                az, el = tod.read_azel(detector=det, local_start=istart, n=nind)
                az = az[good]
                el = el[good]
            except Exception as e:
                azelquat = tod.read_pntg(
                    detector=det, local_start=istart, n=nind, azel=True
                )[good]
                # Convert Az/El quaternion of the detector back into
                # angles for the simulation.
                theta, phi = qa.to_position(azelquat)
                # Azimuth is measured in the opposite direction
                # than longitude
                az = 2 * np.pi - phi
                el = np.pi / 2 - theta

            atmdata = np.zeros(ngood, dtype=np.float64)

            if np.ptp(az) < np.pi:
                azmin_det = np.amin(az)
                azmax_det = np.amax(az)
            else:
                # Scanning across the zero azimuth.
                azmin_det = np.amin(az[az > np.pi]) - 2 * np.pi
                azmax_det = np.amax(az[az < np.pi])
            elmin_det = np.amin(el)
            elmax_det = np.amax(el)
            if (
                not (azmin <= azmin_det and azmax_det <= azmax)
                and not (
                    azmin <= azmin_det - 2 * np.pi and azmax_det - 2 * np.pi <= azmax
                )
            ) or not (elmin <= elmin_det and elmin_det <= elmax):
                raise RuntimeError(
                    prefix + "Detector Az/El: [{:.5f}, {:.5f}], "
                    "[{:.5f}, {:.5f}] is not contained in "
                    "[{:.5f}, {:.5f}], [{:.5f} {:.5f}]"
                    "".format(
                        azmin_det,
                        azmax_det,
                        elmin_det,
                        elmax_det,
                        azmin,
                        azmax,
                        elmin,
                        elmax,
                    )
                )

            # Integrate detector signal

            err = atm_sim_observe(sim, times[ind], az, el, atmdata, ngood, 0)
            if err != 0:
                # Observing failed
                print(
                    prefix + "OpSimAtmosphere: Observing FAILED. "
                    "det = {}, rank = {}".format(det, comm.rank),
                    flush=self._flush,
                )
                atmdata[:] = 0
                flag_ref[ind] = 255

            if self._gain:
                atmdata *= self._gain

            if absorption is not None:
                # Apply the frequency-dependent absorption-coefficient
                atmdata *= absorption

            ref[ind][good] += atmdata

            del ref

        err = atm_sim_free(sim)
        if err != 0:
            raise RuntimeError(prefix + "Failed to free simulation.")

        if self._report_timing:
            comm.Barrier()
            tstop = MPI.Wtime()
            if comm.rank == 0 and tstop - tstart > 1:
                print(
                    prefix + "OpSimAtmosphere: Observed atmosphere "
                    "in {:.2f} s".format(tstop - tstart),
                    flush=self._flush,
                )
        return
예제 #13
0
    def _observe_atmosphere(
        self,
        sim,
        tod,
        comm,
        prefix,
        common_ref,
        istart,
        nind,
        ind,
        scan_range,
        times,
        absorption,
    ):
        log = Logger.get()
        rank = 0
        if comm is not None:
            rank = comm.rank
        tmr = Timer()
        if self._report_timing:
            if comm is not None:
                comm.Barrier()
            tmr.start()

        azmin, azmax, elmin, elmax = scan_range

        nsamp = tod.local_samples[1]

        if rank == 0:
            log.debug("{}Observing the atmosphere".format(prefix))

        ngood_tot = 0
        nbad_tot = 0

        for det in tod.local_dets:
            # Cache the output signal
            cachename = "{}_{}".format(self._out, det)
            if tod.cache.exists(cachename):
                ref = tod.cache.reference(cachename)
            else:
                ref = tod.cache.create(cachename, np.float64, (nsamp,))

            # Cache the output flags
            flag_ref = tod.local_flags(det, self._flag_name)

            if self._apply_flags:
                good = np.logical_and(
                    common_ref[ind] & self._common_flag_mask == 0,
                    flag_ref[ind] & self._flag_mask == 0,
                )
                ngood = np.sum(good)
            else:
                try:
                    good = common_ref[ind] & tod.UNSTABLE == 0
                    ngood = np.sum(good)
                except:
                    good = slice(0, nind)
                    ngood = nind
            if ngood == 0:
                continue

            try:
                # Some TOD classes provide a shortcut to Az/El
                az, el = tod.read_azel(detector=det, local_start=istart, n=nind)
                az = az[good]
                el = el[good]
            except Exception as e:
                azelquat = tod.read_pntg(
                    detector=det, local_start=istart, n=nind, azel=True
                )[good]
                # Convert Az/El quaternion of the detector back into
                # angles for the simulation.
                theta, phi = qa.to_position(azelquat)
                # Azimuth is measured in the opposite direction
                # than longitude
                az = 2 * np.pi - phi
                el = np.pi / 2 - theta

            if np.ptp(az) < np.pi:
                azmin_det = np.amin(az)
                azmax_det = np.amax(az)
            else:
                # Scanning across the zero azimuth.
                azmin_det = np.amin(az[az > np.pi]) - 2 * np.pi
                azmax_det = np.amax(az[az < np.pi])
            elmin_det = np.amin(el)
            elmax_det = np.amax(el)
            if (
                not (azmin <= azmin_det and azmax_det <= azmax)
                and not (
                    azmin <= azmin_det - 2 * np.pi and azmax_det - 2 * np.pi <= azmax
                )
            ) or not (elmin <= elmin_det and elmin_det <= elmax):
                # DEBUG begin
                import pickle

                with open("bad_quats_{}_{}.pck".format(rank, det), "wb") as fout:
                    pickle.dump(
                        [scan_range, az, el, azelquat, tod._boresight_azel], fout
                    )
                # DEBUG end
                raise RuntimeError(
                    prefix + "Detector Az/El: [{:.5f}, {:.5f}], "
                    "[{:.5f}, {:.5f}] is not contained in "
                    "[{:.5f}, {:.5f}], [{:.5f} {:.5f}]"
                    "".format(
                        azmin_det,
                        azmax_det,
                        elmin_det,
                        elmax_det,
                        azmin,
                        azmax,
                        elmin,
                        elmax,
                    )
                )

            # Integrate detector signal

            atmdata = np.zeros(ngood, dtype=np.float64)

            err = sim.observe(times[ind][good], az, el, atmdata, -1.0)
            if err != 0:
                # Observing failed
                bad = np.abs(atmdata) < 1e-30
                nbad = np.sum(bad)
                log.error(
                    "{}OpSimAtmosphere: Observing FAILED for {} ({:.2f} %) samples. "
                    "det = {}, rank = {}".format(
                        prefix, nbad, nbad * 100 / ngood, det, rank
                    )
                )
                atmdata[bad] = 0
                flag_ref[ind][good][bad] = 255
                nbad_tot += nbad
            ngood_tot += ngood

            if self._gain:
                atmdata *= self._gain

            if absorption is not None:
                # Apply the frequency-dependent absorption-coefficient
                atmdata *= absorption

            ref[ind][good] += atmdata

            del ref

        if comm is not None:
            comm.Barrier()
            ngood_tot = comm.reduce(ngood_tot)
            nbad_tot = comm.reduce(nbad_tot)
        if rank == 0 and nbad_tot > 0:
            log.error(
                "{}: Observe atmosphere FAILED on {:.2f}% of samples".format(
                    prefix, nbad_tot * 100 / ngood_tot
                )
            )
        if self._report_timing:
            if rank == 0:
                tmr.stop()
                log.debug(
                    "{}OpSimAtmosphere: Observe atmosphere: {} seconds".format(
                        prefix, tmr.seconds()
                    )
                )
        return
예제 #14
0
    def _observe_sso(self, sso_az, sso_el, sso_dist, sso_dia, tod, comm, prefix, focalplane):
        """
        Observe the SSO with each detector in tod
        """
        log = Logger.get()
        rank = 0
        if comm is not None:
            rank = comm.rank
        tmr = Timer()
        if self._report_timing:
            if comm is not None:
                comm.Barrier()
            tmr.start()

        nsamp = tod.local_samples[1]

        if rank == 0:
            log.info("{}Observing the SSO signal".format(prefix))

        # FIXME: we should get the center frequency from the bandpass
        band_dict = {'f030' : 27, 'f040': 39, 'f090': 93,
             'f150': 145 , 'f230': 225, 'f290': 285}

        for band in band_dict.keys():
            if band in prefix:
                # FIXME we use the same, approximate center frequency for
                # SAT and LAT
                freq = band_dict[band[4:]]
                break

        for det in tod.local_dets:
            # Cache the output signal
            cachename = "{}_{}".format(self._out, det)
            if tod.cache.exists(cachename):
                ref = tod.cache.reference(cachename)
            else:
                ref = tod.cache.create(cachename, np.float64, (nsamp,))

            try:
                # Some TOD classes provide a shortcut to Az/El
                az, el = tod.read_azel(detector=det)
            except Exception as e:
                azelquat = tod.read_pntg(detector=det, azel=True)
                # Convert Az/El quaternion of the detector back into
                # angles for the simulation.
                theta, phi = qa.to_position(azelquat)
                # Azimuth is measured in the opposite direction
                # than longitude
                az = 2 * np.pi - phi
                el = np.pi / 2 - theta

            if "bandpass_transmission" in focalplane[det]:
                # We have full bandpasses for the detector
                bandpass_freqs = focalplane[det]["bandpass_freq_ghz"]
                bandpass = focalplane[det]["bandpass_transmission"]
            else:
                if "bandcenter_ghz" in focalplane[det]:
                    # Use detector bandpass from the focalplane
                    center = focalplane[det]["bandcenter_ghz"]
                    width = focalplane[det]["bandwidth_ghz"]
                else:
                    # Use default values for the entire focalplane
                    if freq is None:
                        raise RuntimeError(
                            "You must supply the nominal frequency if bandpasses "
                            "are not available"
                        )
                    center = freq
                    width = 0.2 * freq
                bandpass_freqs = np.array([center - width / 2, center + width / 2])
                bandpass = np.ones(2)   
        
            nstep = 1001
            fmin, fmax = bandpass_freqs[0], bandpass_freqs[-1]
            det_freqs = np.linspace(fmin, fmax, nstep)
            det_bandpass = np.interp(det_freqs, bandpass_freqs, bandpass)
            det_bandpass /= np.sum(det_bandpass)

            self._get_planet_temp(self.sso_name)
            ttemp_det = np.interp(det_freqs, self.t_freqs, self.ttemp)
            ttemp_det = np.sum(ttemp_det * det_bandpass)
            beam, radius = self._get_beam_map(det, sso_dia, ttemp_det)

            # Interpolate the beam map at appropriate locations
            x = (az - sso_az) * np.cos(el)
            y = el - sso_el
            r = np.sqrt(x ** 2 + y ** 2)
            good = r < radius
            sig = beam(x[good], y[good], grid=False)
            ref[:][good] += sig

            del ref, sig, beam

        if self._report_timing:
            if comm is not None:
                comm.Barrier()
            if rank == 0:
                tmr.stop()
                tmr.report("{}OpSimSSO: Observe signal".format(prefix))
        return
예제 #15
0
    def exec(self, data):
        
        for obs in data.obs:
            tod = obs["tod"]
            focalplane = obs["focalplane"]
            # Get HWP angle
            chi = tod.local_hwp_angle()
            for det in tod.local_dets:
                signal = tod.local_signal(det, self._name)
                band = focalplane[det]["band"]
                freq = {
                    "f030" : "027",
                    "f040" : "039",
                    "f090" : "093",
                    "f150" : "145",
                    "f230" : "225",
                    "f290" : "278",
                }[band]

                # Get incident angle
                
                det_quat = focalplane[det]["quat"]
                theta, phi = qa.to_position(det_quat)
                
                # Get observing elevation
                
                try:
                    # Some TOD classes provide a shortcut to Az/El
                    az, el = tod.read_azel(detector=det)
                except Exception as e:
                    azelquat = tod.read_pntg(detector=det, azel=True)
                    el = np.pi / 2 - qa.to_position(azelquat)[0]

                # Get polarization weights

                weights = tod.cache.reference("weights_{}".format(det))
                iweights, qweights, uweights = weights.T
        
                # Interpolate HWPSS to incident angle

                theta_deg = np.degrees(theta)
                itheta_high = np.searchsorted(self.thetas, theta_deg)
                itheta_low = itheta_high - 1

                theta_low = self.thetas[itheta_low]
                theta_high = self.thetas[itheta_high]
                r = (theta_deg - theta_low) / (theta_high - theta_low)

                transmission = (
                    (1 - r) * self.all_stokes[freq]["transmission"][itheta_low]
                    + r * self.all_stokes[freq]["transmission"][itheta_high]
                )
                reflection = (
                    (1 - r) * self.all_stokes[freq]["reflection"][itheta_low]
                    + r * self.all_stokes[freq]["reflection"][itheta_high]
                )
                emission = (
                    (1 - r) * self.all_stokes[freq]["emission"][itheta_low]
                    + r * self.all_stokes[freq]["emission"][itheta_high]
                )
                
                # Scale HWPSS for observing elevation

                el_ref = np.radians(50)
                scale = np.sin(el_ref) / np.sin(el)
                
                # Observe HWPSS with the detector

                iquv = (transmission + reflection).T
                iquss = (
                    iweights * np.interp(chi, self.chis, iquv[0]) +
                    qweights * np.interp(chi, self.chis, iquv[1]) +
                    uweights * np.interp(chi, self.chis, iquv[2])
                ) * scale

                iquv = emission.T
                iquss += (
                    iweights * np.interp(chi, self.chis, iquv[0]) +
                    qweights * np.interp(chi, self.chis, iquv[1]) +
                    uweights * np.interp(chi, self.chis, iquv[2])
                )

                iquss -= np.median(iquss)

                # Co-add with the cached signal

                signal += iquss

        return
예제 #16
0
    def _sample_maps(self, tod, det, quat, weights=None):
        """ Perform bilinear interpolation of the stored map.

        """
        thetaname = "theta_{}".format(det)
        phiname = "phi_{}".format(det)
        if tod.cache.exists(thetaname):
            theta = tod.cache.reference(thetaname)
            phi = tod.cache.reference(phiname)
        else:
            theta, phi = qa.to_position(quat)
            theta = tod.cache.put(thetaname,
                                  theta.astype(np.float32, copy=False))
            phi = tod.cache.put(phiname, phi.astype(np.float32, copy=False))
        if self.scale_skymodel:
            self.skymodel *= self.scale_skymodel
            self.skymodel_deriv *= self.scale_skymodel
        # Temporarily co-add the CMB and the foregrounds
        self.mapsampler += self.skymodel
        # bandpass mismatch
        try:
            freq = self._freqs[det]
        except Exception:
            freq = self._freq
        delta = freq - self._freq
        if delta != 0:
            self.skymodel_deriv *= delta
            self.mapsampler += self.skymodel_deriv
        if self._bpm_extra:
            fn_bpm = self._bpm_extra.replace("DETECTOR", det)
            if self._global_rank == 0:
                print("  Adding bandpass mismatch from {}".format(fn_bpm),
                      flush=True)
            bpm = MapSampler(
                fn_bpm,
                pol=False,
                comm=self._comm,
                nest=True,
                nside=self._nside,
                plug_holes=False,
                # Work around a bug in the default cray-mpich library that does
                # not allow releasing MPI shared memory.
                use_shmem=False,
            )
            self.mapsampler += bpm
        # Sample the aggregate map
        if self._global_rank == 0:
            print("  Sampling signal map", flush=True)
        signal = self.mapsampler.atpol(theta, phi, weights)
        # restore original CMB
        if self._bpm_extra:
            self.mapsampler -= bpm
            del bpm
        self.mapsampler -= self.skymodel
        if delta != 0:
            self.mapsampler -= self.skymodel_deriv
            self.skymodel_deriv /= delta
        if self.scale_skymodel:
            self.skymodel /= self.scale_skymodel
            self.skymodel_deriv /= self.scale_skymodel
        return signal
예제 #17
0
    def exec(self, data):
        # the two-level pytoast communicator
        comm = data.comm
        # the global communicator
        cworld = comm.comm_world

        rank = cworld.Get_rank()

        margin = self._margin

        pnt2planets = []
        for target in self._targets:
            pnt2planets.append(Pnt2Planeter(target))

        for obs in data.obs:

            tod = obs['tod']
            nsamp = tod.local_samples[1]

            if self._effdir_out is not None:
                tod.cache_metadata(self._effdir_out, comm=cworld)

            timestamps = tod.local_times(margin=margin)
            if len(timestamps) != nsamp + 2 * margin:
                raise Exception('Cached time stamps do not include margins.')

            commonflags = tod.local_common_flags(margin=margin)
            if len(commonflags) != nsamp + 2 * margin:
                raise Exception('Cached common flags do not include margins.')

            phase = tod.local_phase(margin=margin)
            if len(phase) != nsamp + 2 * margin:
                raise Exception('Cached phases do not include margins.')

            velocity = tod.local_velocity(margin=margin)
            if len(velocity) != nsamp + 2 * margin:
                raise Exception('Cached velocities do not include margins.')

            if self._pntmask is not None:
                pntflag = (commonflags & self._pntmask) != 0
            else:
                pntflag = None

            intervals = tod.local_intervals(obs['intervals'])
            starts = [ival.start for ival in intervals]
            stops = [ival.stop + 1 for ival in intervals]
            local_starts = np.array(starts)
            local_stops = np.array(stops)

            ring_offset = tod.globalfirst_ring
            for interval in intervals:
                if interval.last < tod.local_samples[0]:
                    ring_offset += 1

            if self._lfi_mode:
                dipoler = Dipoler(full4pi=True, comm=cworld, RIMO=tod.RIMO)
            else:
                dipoler = Dipoler(freq=int(self._freq))

            if self._bad_rings is not None:
                ringmasker = RingMasker(self._bad_rings)
            else:
                ringmasker = None

            if self._bg_map_path is not None \
               and 'DETECTOR' not in self._bg_map_path:
                # All detectors share the same template map
                mapsampler = MapSampler(self._bg_map_path,
                                        pol=self._bg_pol,
                                        nside=self._bg_nside,
                                        comm=cworld,
                                        cache=tod.cache)
            else:
                mapsampler = None

            if self._maskfile:
                masksampler = MapSampler(self._maskfile,
                                         comm=cworld,
                                         dtype=np.byte,
                                         cache=tod.cache)
                maskflag = np.zeros(nsamp + 2 * margin, dtype=np.bool)
            else:
                masksampler = None
                maskflag = None

            # Now the optical channels

            for det in tod.local_dets:

                if rank == 0:
                    print('Setting up processing for {}'.format(det),
                          flush=True)

                if self._lfi_mode:
                    bolo_id = None
                else:
                    bolo_id = bolo_to_pnt(det)

                psi_pol = np.radians(
                    (tod.RIMO[det].psi_uv + tod.RIMO[det].psi_pol))
                beampar = {}
                beampar['savebeamobj'] = self._savebeamobj
                beampar['bsverbose'] = self._verbose
                beampar['savepath'] = self._out
                beampar['savedir'] = 'beams'
                beampar['prefix'] = ''
                beampar['boloID'] = bolo_id
                beampar['bsdebug'] = False
                beampar['datarad'] = self._datarad
                beampar['dstrrad'] = self._dstrrad
                beampar['dstrtol'] = self._dstrtol
                beampar['jupthr'] = self._jupthr
                beampar['radrms'] = self._radrms
                beampar['xtfthr'] = self._xtfthr
                beampar['nslices'] = self._nslices
                beampar['ntf'] = self._ntf
                beampar['hybthd'] = self._hybthd
                beampar['xtfthr'] = self._xtfthr
                beampar['trans'] = self._trans
                beampar['hrmax'] = self._hrmax
                beampar['optical'] = self._optical
                beampar['bsorder'] = self._bsorder
                beampar['pixsize'] = self._pixsize
                beampar['sqmaphpix'] = self._sqmaphpix
                beampar['rectmaphpixx'] = self._rectmaphpixx
                beampar['rectmaphpixy'] = self._rectmaphpixy
                beampar['knotstep'] = self._knotstep
                beampar['knotextframe'] = self._knotextframe
                beampar['knotextframex'] = self._knotextframex
                beampar['knotextframey'] = self._knotextframey

                beamobj = Beam_Reconstructor(bolo_id, beampar, mpicomm=cworld)

                if self._bg_map_path is not None \
                   and 'DETECTOR' in self._bg_map_path:
                    # Detectors have separete template maps
                    mapsampler = MapSampler(self._bg_map_path.replace(
                        'DETECTOR', det),
                                            pol=self._bg_pol,
                                            nside=self._bg_nside,
                                            comm=cworld,
                                            cache=tod.cache)

                # Read all of the data for this process and process
                # interval by interval

                signal = tod.local_signal(det, margin=margin)
                if len(signal) != nsamp + 2 * margin:
                    raise Exception('Cached signal does not include margins.')

                flags = tod.local_flags(det, margin=margin)
                if len(flags) != nsamp + 2 * margin:
                    raise Exception('Cached flags do not include margins.')

                quat = tod.local_pointing(det, margin=margin)
                if len(quat) != nsamp + 2 * margin:
                    raise Exception('Cached quats do not include margins.')

                iquweights = tod.local_weights(det)
                if len(iquweights) != nsamp + 2 * margin:
                    raise Exception('Cached weights do not include margins.')

                # Cast the flags into boolean vectors

                if self._detmask:
                    detflag = (flags & self._detmask) != 0
                else:
                    detflag = flags != 0

                if self._commonmask is not None:
                    detflag[(commonflags & self._commonmask) != 0] = True

                if self._ssomask is not None:
                    ssoflag = (flags & self._ssomask) != 0
                else:
                    ssoflag = np.zeros(nsamp, dtype=np.bool)

                # Add ring flags

                if ringmasker is not None:
                    ringflag = ringmasker.get_mask(timestamps, det)
                    detflag[ringflag] = True
                else:
                    ringflag = None

                # Process

                if rank == 0:
                    print('Processing {}'.format(det), flush=True)

                signal_out = np.zeros(nsamp + 2 * margin, dtype=np.float64)
                flags_out = np.zeros(nsamp + 2 * margin, dtype=np.uint8)

                ring_number = ring_offset - 1

                for ring_start, ring_stop in zip(local_starts, local_stops):

                    ring_number += 1

                    if self._verbose:
                        print('{:4} : Processing ring {:4}'.format(
                            rank, ring_number),
                              flush=True)

                    # Slice without margins
                    ind = slice(ring_start + margin, ring_stop + margin)

                    tme = timestamps[ind]
                    sig = signal[ind].copy()
                    flg = detflag[ind].copy()

                    # Require at least 10% of the signal to be unflagged to
                    # even attempt processing.

                    if np.sum(flg == 0) < 0.1 * len(flg):
                        raise Exception('Too many samples are flagged.')

                    if pntflag is not None:
                        pntflg = pntflag[ind].copy()
                    else:
                        pntflg = np.zeros_like(flg)
                    if margin > 0:
                        pntflg[:margin] = True
                        pntflg[-margin:] = True

                    if np.sum(pntflg == 0) < 10000:
                        raise Exception('Pointing is unstable')

                    q = quat[ind]
                    if self._bg_pol:
                        iquw = iquweights[ind]
                    v = velocity[ind]

                    # Get the dipole

                    dipo = dipoler.dipole(q, velocity=v, det=det)
                    if self._bg_has_dipole:
                        dipo -= dipoler.dipole(q, det=det)

                    # Convert pointing to angles

                    theta, phi = qa.to_position(q)

                    # Sample the (polarized) background map

                    if mapsampler is not None:
                        if self._bg_pol:
                            bg = mapsampler.atpol(theta, phi, iquw)
                        else:
                            bg = mapsampler.at(theta, phi)
                    else:
                        bg = None

                    # Sample the processing mask

                    if masksampler is not None:
                        maskflg = masksampler.at(theta, phi) < 0.5
                        maskflag[ind] = maskflg
                    else:
                        maskflg = None

                    # Cache planet data here

                    for pnt2planet in pnt2planets:
                        target = pnt2planet.target
                        az, el = pnt2planet.translate(q, tme, psi_pol=psi_pol)

                        beamobj.preproc(tme, sig - dipo - bg, flg + maskflg,
                                        az, el, target)

                # Collect planet data

                beamobj.cache = [beamobj.cache]
                cworld.Barrier()
                beamobj.cache = cworld.gather(beamobj.cache, root=0)

                # Build the beam and/or solve for the transfer function

                if rank == 0:
                    try:
                        beamobj.recache()
                        if len(beamobj.cache) == 0:
                            print('WARNING: No samples in cache for {}. No '
                                  'beam reconstructed.'.format(det))
                            continue
                        beamobj.scache = beamobj.cache
                        for iiter in range(int(self._bsiter)):
                            if iiter > 0:
                                print('Beam reconstruction, iteration # {}'
                                      ''.format(iiter + 1))
                                t_iter_start = time.time()
                                beamobj.cache = beamobj.scache
                            beamobj.mergedata()
                            beamobj.reconstruct(iiter)
                            t_iter_finish = time.time()
                            print('Beam Reconstruction iteration # {} '
                                  'completed in a total of {:.2f} s.'.format(
                                      iiter, t_iter_finish - t_iter_start))
                            if iiter < int(self._bsiter):
                                beamobj.update(iiter)
                        if self._beamtofits:
                            beamobj.hmapsave(self._beamtofits, polar=False)
                        if self._beamtofits_polar:
                            beamobj.hmapsave(self._beamtofits_polar,
                                             polar=True)
                    except Exception as e:
                        print('Beam reconsruction for {} failed: "{}"'
                              ''.format(det, e))

                # If necessary pass through the data again, applying the new
                # transfer function

                # If new transfer function was applied, cache and optionally
                # write out the new TOD

                # Write detector data

                signal_out[:] = signal[:]
                flags_out |= np.uint8(1) * detflag
                if ssoflag is not None:
                    flags_out |= np.uint8(2) * ssoflag
                if maskflag is not None:
                    flags_out |= np.uint8(4) * maskflag

                ind = slice(margin, len(signal_out) - margin)

                cachename = "{}_{}".format(tod.SIGNAL_NAME, det)
                tod.cache.put(cachename, signal_out[ind], replace=True)

                cachename = "{}_{}".format(tod.FLAG_NAME, det)
                tod.cache.put(cachename, flags_out[ind], replace=True)

                if self._effdir_out is not None:
                    if rank == 0:
                        print('Saving detector data to {}'.format(
                            self._effdir_out),
                              flush=True)
                    tod.write_tod_and_flags(detector=det,
                                            data=signal_out[ind],
                                            flags=flags_out[ind],
                                            effdir_out=self._effdir_out)

            commonflags_out = np.zeros_like(commonflags)
            commonflags_out |= np.uint8(1) * ((commonflags &
                                               (255 - self._pntmask)) != 0)
            if pntflag is not None:
                commonflags_out |= np.uint8(2) * pntflag

            if self._output_common_flags is not None:
                tod.cache.put(tod.COMMON_FLAG_NAME,
                              commonflags_out[ind],
                              replace=True)

            if self._effdir_out is not None:
                tod.write_common_flags(flags=commonflags_out[ind],
                                       effdir_out=self._effdir_out)