def test_sim_full(self): hw = get_example() hw.data["detectors"] = OrderedDict() for tele, teleprops in hw.data["telescopes"].items(): if tele != "SAT1": continue dets = sim_telescope_detectors(hw, tele) hw.data["detectors"].update(dets) dbpath = os.path.join(self.outdir, "hardware_SAT1.toml.gz") hw.dump(dbpath, overwrite=True, compress=True) check = Hardware(dbpath) # Test selection of 90GHz detectors on wafers 25 and 26 which have # "A" polarization configuration and are located in pixels 20-29. wbhw = hw.select( match={ "wafer_slot": ["w25", "w26"], "band": "SAT_f090", "pol": "A", "pixel": "02." }) dbpath = os.path.join(self.outdir, "w25-26_p20-29_SAT_f090_A.toml.gz") wbhw.dump(dbpath, overwrite=True, compress=True) check = Hardware(dbpath) self.assertTrue(len(check.data["detectors"]) == 20) chkpath = os.path.join(self.outdir, "w25-26_p20-29_SAT_f090_A.txt") with open(chkpath, "w") as f: for d in check.data["detectors"]: f.write("{}\n".format(d)) return
def test_sim_telescope(self): fullhw = get_example() fullhw.data["detectors"] = sim_telescope_detectors(fullhw, "SAT1") hw = fullhw.select(match={ "wafer_slot": [ "w25", ], }) outpath = os.path.join(self.outdir, "telescope_SAT1_w25.toml.gz") hw.dump(outpath, overwrite=True, compress=True) if not self.skip_plots: outpath = os.path.join(self.outdir, "telescope_SAT1_w25.pdf") plot_detectors(hw.data["detectors"], outpath, labels=False) return
def main(): parser = argparse.ArgumentParser( description="This program measures the median offset of subset of " "detectors from boresight.", usage="get_wafer_offset [options] (use --help for details)") group = parser.add_mutually_exclusive_group(required=True) group.add_argument( "--tube_slots", help="Comma-separated list of optics tube slots: c1 (UHF), i5 (UHF), " " i6 (MF), i1 (MF), i3 (MF), i4 (MF), o6 (LF). ") group.add_argument("--wafer_slots", help="Comma-separated list of optics tube slots. ") parser.add_argument("--reverse", action="store_true", help="Reverse offsets") # LAT specific params parser.add_argument( "--corotate-lat", required=False, action="store_true", help="Rotate LAT receiver to maintain focalplane orientation", dest="corotate_lat", ) parser.add_argument( "--no-corotate-lat", required=False, action="store_false", help="Do not Rotate LAT receiver to maintain focalplane orientation", dest="corotate_lat", ) parser.set_defaults(corotate_lat=True) parser.add_argument( "--elevation-deg", required=False, type=np.float, help="Observing elevation", ) args = parser.parse_args() hw = hardware.get_example() # Which telescope? if args.wafer_slots is not None: wafer_slots = args.wafer_slots.split(",") wafer_map = hw.wafer_map() tube_slots = [wafer_map["tube_slots"][ws] for ws in wafer_slots] else: tube_slots = args.tube_slots.split(",") telescope = None for tube_slot in tube_slots: for telescope_name, telescope_data in hw.data["telescopes"].items(): if tube_slot in telescope_data["tube_slots"]: if telescope is None: telescope = telescope_name elif telescope != telescope.name: raise RuntimeError( f"Tubes '{tube_slots}' span more than one telescope") if telescope is None: raise RuntimeError( f"Failed to match tube_slot = '{tube_slot}' with a telescope") # Which detectors? hw.data["detectors"] = hardware.sim_telescope_detectors(hw, telescope) match = {} tube_slots = None if args.wafer_slots is not None: match["wafer_slot"] = args.wafer_slots.split(",") elif args.tube_slots is not None: tube_slots = args.tube_slots.split(",") hw = hw.select(tube_slots=tube_slots, match=match) ndet = len(hw.data["detectors"]) # print(f"tube_slots = {tube_slots}, match = {match} leaves {ndet} detectors") # Optional corotator rotation if telescope == "LAT": if args.corotate_lat: rot = qa.rotation(ZAXIS, np.radians(LAT_COROTATOR_OFFSET_DEG)) else: if args.elevation_deg is None: raise RuntimeError( "You must set the observing elevation when not co-rotating." ) rot = qa.rotation( ZAXIS, np.radians(args.elevation_deg - 60 + LAT_COROTATOR_OFFSET_DEG)) else: if args.elevation_deg is not None: raise RuntimeError("Observing elevation does not matter for SAT") rot = None # Average detector offset vec_mean = np.zeros(3) for det_name, det_data in hw.data["detectors"].items(): quat = det_data["quat"] if rot is not None: quat = qa.mult(rot, quat) vec = qa.rotate(quat, ZAXIS) vec_mean += vec vec_mean /= ndet # Radius all_dist = [] for det_name, det_data in hw.data["detectors"].items(): quat = det_data["quat"] if rot is not None: quat = qa.mult(rot, quat) vec = qa.rotate(quat, ZAXIS) all_dist.append(np.degrees(np.arccos(np.dot(vec_mean, vec)))) dist_max = np.amax(all_dist) # Wafers if args.tube_slots is None: wafer_slots = set(wafer_slots) else: wafer_slots = set() for tube_slot in tube_slots: wafer_slots.update(hw.data["tube_slots"][tube_slot]["wafer_slots"]) waferstring = "" for wafer_slot in sorted(wafer_slots): waferstring += f" {wafer_slot}" # Translate into Az/El offsets at el=0 rot = hp.Rotator(rot=[0, 90, 0]) vec_mean = rot(vec_mean) az_offset, el_offset = hp.vec2dir(vec_mean, lonlat=True) el_offset *= -1 if args.reverse: az_offset *= -1 el_offset *= -1 print(f"{az_offset:.3f} {el_offset:.3f} {dist_max:.3f}" + waferstring) return
if cworld.rank == 0: print("Binned map done", flush=True) return # Our toast communicator- use the default for now, which is one # process group spanning all processes. comm = toast.Comm() if comm.world_rank == 0: print("Simulating all detector properties...", flush=True) # First, get the list of detectors we want to use # (Eventually we would load this from disk. Here we simulate it.) hw = get_example() dets = sim_telescope_detectors(hw, "LAT") hw.data["detectors"] = dets if comm.world_rank == 0: print("Selecting detectors...", flush=True) # Downselect to just 10 pixels on one wafer #small_hw = hw.select(match={"wafer_slot": "41", "pixel": "00."}) #small_hw = hw.select(match={"wafer_slot": "41"}) small_hw = hw.select(match={"wafer_slot": "40"}) #small_hw = hw.select(match={"band": "LF1"}) if comm.world_rank == 0: small_hw.dump("selected.toml", overwrite=True) # The data directory (this is a single band) # dir = "/project/projectdirs/sobs/sims/pipe-s0001/datadump_LAT_LF1" if len(sys.argv) > 1:
def setUp(self): fixture_name = os.path.splitext(os.path.basename(__file__))[0] if not toast_available: print( "toast cannot be imported ({})- skipping unit test".format( toast_import_error), flush=True, ) return self.outdir = None if MPI.COMM_WORLD.rank == 0: self.outdir = create_outdir(fixture_name) self.outdir = MPI.COMM_WORLD.bcast(self.outdir, root=0) toastcomm = toast.Comm() self.data = toast.Data(toastcomm) # Focalplane hwfull = get_example() dets = sim_telescope_detectors(hwfull, "SAT4") hwfull.data["detectors"] = dets hw = hwfull.select(match={ "wafer_slot": "w42", "band": "f030", "pixel": "00[01]" }) # print(hw.data["detectors"], flush=True) detquats = {k: v["quat"] for k, v in hw.data["detectors"].items()} # Samples per observation self.totsamp = 10000 # Scan properties self.site_lon = '-67:47:10' self.site_lat = '-22:57:30' self.site_alt = 5200. self.coord = 'C' self.azmin = 45 self.azmax = 55 self.el = 60 self.scanrate = 1.0 self.scan_accel = 0.1 self.CES_start = None # Noise properties self.rate = 100.0 self.NET = 1e-3 # 1 mK NET self.epsilon = 0.0 self.fmin = 1.0e-5 self.alpha = 1.0 self.fknee = 0.05 for ob in range(3): ftime = (self.totsamp / self.rate) * ob + 1564015655.88 tod = TODGround(self.data.comm.comm_group, detquats, self.totsamp, detranks=self.data.comm.group_size, firsttime=ftime, rate=self.rate, site_lon=self.site_lon, site_lat=self.site_lat, site_alt=self.site_alt, azmin=self.azmin, azmax=self.azmax, el=self.el, coord=self.coord, scanrate=self.scanrate, scan_accel=self.scan_accel, CES_start=self.CES_start) # Analytic noise model detnames = list(detquats.keys()) drate = {x: self.rate for x in detnames} dfmin = {x: self.fmin for x in detnames} dfknee = {x: self.fknee for x in detnames} dalpha = {x: self.alpha for x in detnames} dnet = {x: self.NET for x in detnames} nse = AnalyticNoise(rate=drate, fmin=dfmin, detectors=detnames, fknee=dfknee, alpha=dalpha, NET=dnet) # Single observation obs = dict() obs["tod"] = tod obs["noise"] = nse obs["id"] = 12345 obs["intervals"] = tod.subscans obs["site"] = "SimonsObs" obs["telescope"] = "SAT4" obs["site_id"] = 1 obs["telescope_id"] = 4 obs["fpradius"] = 5.0 obs["start_time"] = ftime obs["altitude"] = self.site_alt obs["name"] = "test_{:02}".format(ob) # Add a focalplane dictionary with just the detector index focalplane = {} for idet, det in enumerate(detnames): focalplane[det] = {"index": idet} obs["focalplane"] = focalplane # Add the observation to the dataset self.data.obs.append(obs) nse = toast.tod.OpSimNoise(out="signal", realization=0) nse.exec(self.data) return
def main(): parser = argparse.ArgumentParser( description="This program measures the median offset of subset of " "detectors from boresight.", usage="get_wafer_offset [options] (use --help for details)") group = parser.add_mutually_exclusive_group(required=True) group.add_argument( "--tube_slots", help="Comma-separated list of optics tube slots: c1 (UHF), i5 (UHF), " " i6 (MF), i1 (MF), i3 (MF), i4 (MF), o6 (LF). ") group.add_argument("--wafer_slots", help="Comma-separated list of optics tube slots. ") parser.add_argument("--reverse", action="store_true", help="Reverse offsets") args = parser.parse_args() hw = hardware.get_example() # Which telescope? if args.wafer_slots is not None: wafer_slots = args.wafer_slots.split(",") wafer_map = hw.wafer_map() tube_slots = [wafer_map["tube_slots"][ws] for ws in wafer_slots] else: tube_slots = args.tube_slots.split(",") telescope = None for tube_slot in tube_slots: for telescope_name, telescope_data in hw.data["telescopes"].items(): if tube_slot in telescope_data["tube_slots"]: if telescope is None: telescope = telescope_name elif telescope != telescope.name: raise RuntimeError( f"Tubes '{tube_slots}' span more than one telescope") if telescope is None: raise RuntimeError( f"Failed to match tube_slot = '{tube_slot}' with a telescope") # Which detectors? hw.data["detectors"] = hardware.sim_telescope_detectors(hw, telescope) match = {} tube_slots = None if args.wafer_slots is not None: match["wafer_slot"] = args.wafer_slots.split(",") elif args.tube_slots is not None: tube_slots = args.tube_slots.split(",") hw = hw.select(tube_slots=tube_slots, match=match) ndet = len(hw.data["detectors"]) # print(f"tube_slots = {tube_slots}, match = {match} leaves {ndet} detectors") # Average detector offset vec_mean = np.zeros(3) zaxis = np.array([0, 0, 1]) for det_name, det_data in hw.data["detectors"].items(): quat = det_data["quat"] vec = qa.rotate(quat, zaxis) vec_mean += vec vec_mean /= ndet # Radius all_dist = [] for det_name, det_data in hw.data["detectors"].items(): quat = det_data["quat"] vec = qa.rotate(quat, zaxis) all_dist.append(np.degrees(np.arccos(np.dot(vec_mean, vec)))) dist_max = np.amax(all_dist) # Translate into Az/El offsets at el=0 rot = hp.Rotator(rot=[0, 90, 0]) vec_mean = rot(vec_mean) az_offset, el_offset = hp.vec2dir(vec_mean, lonlat=True) el_offset *= -1 if args.reverse: az_offset *= -1 el_offset *= -1 print(f"{az_offset:.3f} {el_offset:.3f} {dist_max:.3f}") return
def setUp(self): fixture_name = os.path.splitext(os.path.basename(__file__))[0] if not toast_available: print("toast cannot be imported- skipping unit tests", flush=True) return self.comm, self.procs, self.rank = get_world() self.outdir = create_outdir(fixture_name, comm=self.comm) toastcomm = toast.Comm() self.data = toast.Data(toastcomm) # Focalplane hwfull = get_example() dets = sim_telescope_detectors(hwfull, "SAT4") hwfull.data["detectors"] = dets hw = hwfull.select(match={ "wafer_slot": "w42", "band": "f030", "pixel": "00[01]" }) print(hw.data["detectors"], flush=True) detquats = {k: v["quat"] for k, v in hw.data["detectors"].items()} # Samples per observation self.totsamp = 10000 # Pixelization nside = 512 self.sim_nside = nside self.map_nside = nside # Scan properties self.site_lon = '-67:47:10' self.site_lat = '-22:57:30' self.site_alt = 5200. self.coord = 'C' self.azmin = 45 self.azmax = 55 self.el = 60 self.scanrate = 1.0 self.scan_accel = 0.1 self.CES_start = None # Noise properties self.rate = 100.0 self.NET = 5.0 self.epsilon = 0.0 self.fmin = 1.0e-5 self.alpha = 1.0 self.fknee = 0.05 tod = TODGround(self.data.comm.comm_group, detquats, self.totsamp, detranks=self.data.comm.group_size, firsttime=0.0, rate=self.rate, site_lon=self.site_lon, site_lat=self.site_lat, site_alt=self.site_alt, azmin=self.azmin, azmax=self.azmax, el=self.el, coord=self.coord, scanrate=self.scanrate, scan_accel=self.scan_accel, CES_start=self.CES_start) # Analytic noise model detnames = list(detquats.keys()) drate = {x: self.rate for x in detnames} dfmin = {x: self.fmin for x in detnames} dfknee = {x: self.fknee for x in detnames} dalpha = {x: self.alpha for x in detnames} dnet = {x: self.NET for x in detnames} nse = AnalyticNoise(rate=drate, fmin=dfmin, detectors=detnames, fknee=dfknee, alpha=dalpha, NET=dnet) # Single observation obs = dict() obs["tod"] = tod obs["noise"] = nse obs["id"] = 12345 obs["intervals"] = tod.subscans obs["site"] = "SimonsObs" obs["telescope"] = "SAT4" obs["site_id"] = 1 obs["telescope_id"] = 4 obs["fpradius"] = 5.0 obs["start_time"] = 0 obs["altitude"] = self.site_alt obs["name"] = "test" # Add the observation to the dataset self.data.obs.append(obs) return