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
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.info("{}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 min_az_bore == max_az_bore: # log.info("You are in the spin_scan modality. Feature in Beta version azmin={} and azmax={}".format(azmin, azmax)) # Add some controls on the limits # else: # log.info("Not in spin_scan Mod azmin={} and azmax={}".format(azmin, azmax)) # 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 # # Detector Az/El: [-3.13988, 3.14109], [1.22173, 1.22173] is not contained in [-7.28828, 1.00495], [1.04720 1.39626] # 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: print("{}WARNING: Observe atmosphere FAILED on {:.2f}% of samples". format(prefix, nbad_tot * 100 / ngood_tot)) if self._report_timing: if rank == 0: tmr.report_clear( "{}OpSimAtmosphere: Observe atmosphere".format(prefix)) return