def read_detector(parameters: Dict[str, Any], imo: lbs.Imo): if "channel_obj" in parameters: detobj = lbs.FreqChannelInfo.from_imo( imo, parameters["channel_obj"]).get_boresight_detector() elif "detector_obj" in parameters: detobj = lbs.DetectorInfo.from_imo(imo, parameters["detector_obj"]) else: detobj = lbs.DetectorInfo() for param_name in ( "name", "wafer", "pixel", "pixtype", "channel", "sampling_rate_hz", "fwhm_arcmin", "ellipticity", "net_ukrts", "fknee_mhz", "fmin_hz", "alpha", "pol", "orient", "bandwidth_ghz", "bandcenter_ghz", ): if param_name in parameters: setattr(detobj, param_name, parameters[param_name]) return detobj
def test_make_bin_map_api_simulation(tmp_path): # We should add a more meaningful observation: # Currently this test just shows the interface sim = lbs.Simulation(base_path=tmp_path / "tut04", start_time=0.0, duration_s=86400.0) sim.generate_spin2ecl_quaternions( scanning_strategy=lbs.SpinningScanningStrategy( spin_sun_angle_rad=np.radians(30), # CORE-specific parameter spin_rate_hz=0.5 / 60, # Ditto # We use astropy to convert the period (4 days) in # minutes, the unit expected for the precession period precession_rate_hz=1 / (4 * u.day).to("s").value, )) instr = lbs.InstrumentInfo(name="core", spin_boresight_angle_rad=np.radians(65)) det = lbs.DetectorInfo(name="foo", sampling_rate_hz=10) obss = sim.create_observations(detectors=[det]) pointings = lbs.get_pointings( obss[0], sim.spin2ecliptic_quats, detector_quats=[det.quat], bore2spin_quat=instr.bore2spin_quat, ) nside = 64 obss[0].pixind = hp.ang2pix(nside, pointings[..., 0], pointings[..., 1]) obss[0].psi = pointings[..., 2] mapping.make_bin_map(obss, nside)
def __write_complex_observation(tmp_path, use_mjd: bool): start_time = AstroTime("2021-01-01") if use_mjd else 0 time_span_s = 60 sampling_hz = 10 sim = lbs.Simulation( base_path=tmp_path, start_time=start_time, duration_s=time_span_s, ) scanning = lbs.SpinningScanningStrategy( spin_sun_angle_rad=0.785_398_163_397_448_3, precession_rate_hz=8.664_850_513_998_931e-05, spin_rate_hz=0.000_833_333_333_333_333_4, start_time=start_time, ) spin2ecliptic_quats = scanning.generate_spin2ecl_quaternions( start_time, time_span_s, delta_time_s=1.0) instr = lbs.InstrumentInfo( boresight_rotangle_rad=0.0, spin_boresight_angle_rad=0.872_664_625_997_164_8, spin_rotangle_rad=3.141_592_653_589_793, ) det = lbs.DetectorInfo( name="Dummy detector", sampling_rate_hz=sampling_hz, bandcenter_ghz=100.0, quat=[0.0, 0.0, 0.0, 1.0], ) sim.create_observations(detectors=[det]) obs = sim.observations[0] obs.tod = np.random.random(obs.tod.shape) obs.pointings = lbs.scanning.get_pointings( obs, spin2ecliptic_quats=spin2ecliptic_quats, detector_quats=[det.quat], bore2spin_quat=instr.bore2spin_quat, ) obs.local_flags = np.zeros(obs.tod.shape, dtype="uint16") obs.local_flags[0, 12:15] = 1 obs.global_flags = np.zeros(obs.tod.shape[1], dtype="uint32") obs.global_flags[12:15] = 15 return obs, det, lbs.write_observations(sim=sim, subdir_name="")
def test_distribute_observation_astropy(tmp_path): sim = lbs.Simulation( base_path=tmp_path / "simulation_dir", start_time=astropy.time.Time("2020-01-01T00:00:00"), duration_s=11.0, ) det = lbs.DetectorInfo("dummy", sampling_rate_hz=15) obs_list = sim.create_observations(detectors=[det], num_of_obs_per_detector=5) assert len(obs_list) == 5 assert int(obs_list[-1].get_times()[-1] - obs_list[0].get_times()[0]) == 10 assert sum([o.n_samples for o in obs_list]) == sim.duration_s * det.sampling_rate_hz
def test_distribute_observation(tmp_path): for dtype in (np.float16, np.float32, np.float64, np.float128): sim = lbs.Simulation(base_path=tmp_path / "simulation_dir", start_time=1.0, duration_s=11.0) det = lbs.DetectorInfo("dummy", sampling_rate_hz=15) obs_list = sim.create_observations(detectors=[det], num_of_obs_per_detector=5, dtype_tod=dtype) assert len(obs_list) == 5 assert int(obs_list[-1].get_times()[-1] - obs_list[0].get_times()[0]) == 10 assert (sum([o.n_samples for o in obs_list ]) == sim.duration_s * det.sampling_rate_hz)
def test_write_hdf5_mpi(tmp_path): start_time = 0 time_span_s = 60 sampling_hz = 10 sim = lbs.Simulation( base_path=tmp_path, start_time=start_time, duration_s=time_span_s, ) det = lbs.DetectorInfo( name="Dummy detector", sampling_rate_hz=sampling_hz, bandcenter_ghz=100.0, quat=[0.0, 0.0, 0.0, 1.0], ) num_of_obs = 12 sim.create_observations(detectors=[det], num_of_obs_per_detector=num_of_obs) file_names = lbs.write_observations( sim, subdir_name="tod", file_name_mask="litebird_tod{global_index:04d}.h5") assert len(file_names) == len(sim.observations) if lbs.MPI_ENABLED: # Wait that all the processes have completed writing the files lbs.MPI_COMM_WORLD.barrier() tod_path = sim.base_path / "tod" files_found = list(tod_path.glob("litebird_tod*.h5")) assert len(files_found) == num_of_obs, ( f"{len(files_found)} files found in {tod_path} instead of " + f"{num_of_obs}: {files_found}") for idx in range(num_of_obs): cur_tod = tod_path / f"litebird_tod{idx:04d}.h5" assert cur_tod.is_file(), f"File {cur_tod} was expected but not found"
sim.generate_spin2ecl_quaternions( scanning_strategy=lbs.SpinningScanningStrategy( spin_sun_angle_rad=np.deg2rad(30), # CORE-specific parameter spin_rate_hz=0.5 / 60, # Ditto # We use astropy to convert the period (4 days) in # seconds precession_rate_hz=1.0 / (4 * u.day).to("s").value, )) instr = lbs.InstrumentInfo(name="core", spin_boresight_angle_rad=np.deg2rad(65)) # We create two detectors, whose polarization angles are separated by π/2 sim.create_observations( detectors=[ lbs.DetectorInfo(name="0A", sampling_rate_hz=10), lbs.DetectorInfo(name="0B", sampling_rate_hz=10, quat=lbs.quat_rotation_z(np.pi / 2)), ], dtype_tod=np.float64, n_blocks_time=lbs.MPI_COMM_WORLD.size, split_list_over_processes=False, ) # Generate some white noise rs = RandomState(MT19937(SeedSequence(123456789))) for curobs in sim.observations: curobs.tod *= 0.0 curobs.tod += rs.randn(*curobs.tod.shape)
def test_solar_dipole_fit(tmpdir): tmpdir = Path(tmpdir) test = unittest.TestCase() # The purpose of this test is to simulate the motion of the spacecraft # for one year (see `time_span_s`) and produce *two* timelines: the first # is associated with variables `*_s_o` and refers to the case of a nonzero # velocity of the Solar System, and the second is associated with variables # `*_o` and assumes that the reference frame of the Solar System is the # same as the CMB's (so that there is no dipole). start_time = Time("2022-01-01") time_span_s = 365 * 24 * 3600 nside = 256 sampling_hz = 1 sim = lbs.Simulation(start_time=start_time, duration_s=time_span_s) scanning = lbs.SpinningScanningStrategy( spin_sun_angle_rad=0.785_398_163_397_448_3, precession_rate_hz=8.664_850_513_998_931e-05, spin_rate_hz=0.000_833_333_333_333_333_4, start_time=start_time, ) spin2ecliptic_quats = scanning.generate_spin2ecl_quaternions( start_time, time_span_s, delta_time_s=7200 ) instr = lbs.InstrumentInfo( boresight_rotangle_rad=0.0, spin_boresight_angle_rad=0.872_664_625_997_164_8, spin_rotangle_rad=3.141_592_653_589_793, ) det = lbs.DetectorInfo( name="Boresight_detector", sampling_rate_hz=sampling_hz, bandcenter_ghz=100.0, quat=[0.0, 0.0, 0.0, 1.0], ) (obs_s_o,) = sim.create_observations(detectors=[det]) (obs_o,) = sim.create_observations(detectors=[det]) pointings = lbs.scanning.get_pointings( obs_s_o, spin2ecliptic_quats=spin2ecliptic_quats, detector_quats=[det.quat], bore2spin_quat=instr.bore2spin_quat, ) orbit_s_o = lbs.SpacecraftOrbit(obs_s_o.start_time) orbit_o = lbs.SpacecraftOrbit(obs_o.start_time, solar_velocity_km_s=0.0) assert orbit_s_o.solar_velocity_km_s == 369.8160 assert orbit_o.solar_velocity_km_s == 0.0 pos_vel_s_o = lbs.spacecraft_pos_and_vel(orbit_s_o, obs_s_o, delta_time_s=86400.0) pos_vel_o = lbs.spacecraft_pos_and_vel(orbit_o, obs_o, delta_time_s=86400.0) assert pos_vel_s_o.velocities_km_s.shape == (366, 3) assert pos_vel_o.velocities_km_s.shape == (366, 3) lbs.add_dipole_to_observations( obs_s_o, pointings, pos_vel_s_o, dipole_type=lbs.DipoleType.LINEAR ) lbs.add_dipole_to_observations( obs_o, pointings, pos_vel_o, dipole_type=lbs.DipoleType.LINEAR ) npix = hp.nside2npix(nside) pix_indexes = hp.ang2pix(nside, pointings[0, :, 0], pointings[0, :, 1]) h = np.zeros(npix) m = np.zeros(npix) map_s_o = np.zeros(npix) map_o = np.zeros(npix) bin_map( tod=obs_s_o.tod, pixel_indexes=pix_indexes, binned_map=map_s_o, accum_map=m, hit_map=h, ) import healpy healpy.write_map(tmpdir / "map_s_o.fits.gz", map_s_o, overwrite=True) bin_map( tod=obs_o.tod, pixel_indexes=pix_indexes, binned_map=map_o, accum_map=m, hit_map=h, ) healpy.write_map(tmpdir / "map_o.fits.gz", map_o, overwrite=True) dip_map = map_s_o - map_o assert np.abs(np.nanmean(map_s_o) * 1e6) < 1 assert np.abs(np.nanmean(map_o) * 1e6) < 1 assert np.abs(np.nanmean(dip_map) * 1e6) < 1 dip_map[np.isnan(dip_map)] = healpy.UNSEEN mono, dip = hp.fit_dipole(dip_map) r = hp.Rotator(coord=["E", "G"]) l, b = hp.vec2ang(r(dip), lonlat=True) # Amplitude, longitude and latitude test.assertAlmostEqual(np.sqrt(np.sum(dip ** 2)) * 1e6, 3362.08, 1) test.assertAlmostEqual(l[0], 264.021, 1) test.assertAlmostEqual(b[0], 48.253, 1)
def test_destriper(tmp_path): sim = lbs.Simulation(base_path=tmp_path / "destriper_output", start_time=0, duration_s=86400.0) sim.generate_spin2ecl_quaternions( scanning_strategy=lbs.SpinningScanningStrategy( spin_sun_angle_rad=np.deg2rad(30), # CORE-specific parameter spin_rate_hz=0.5 / 60, # Ditto # We use astropy to convert the period (4 days) in # seconds precession_rate_hz=1.0 / (4 * u.day).to("s").value, )) instr = lbs.InstrumentInfo(name="core", spin_boresight_angle_rad=np.deg2rad(65)) sim.create_observations( detectors=[ lbs.DetectorInfo(name="0A", sampling_rate_hz=10), lbs.DetectorInfo(name="0B", sampling_rate_hz=10, quat=lbs.quat_rotation_z(np.pi / 2)), ], # num_of_obs_per_detector=lbs.MPI_COMM_WORLD.size, dtype_tod=np.float64, n_blocks_time=lbs.MPI_COMM_WORLD.size, split_list_over_processes=False, ) # Generate some white noise rs = RandomState(MT19937(SeedSequence(123456789))) for curobs in sim.observations: curobs.tod *= 0.0 curobs.tod += rs.randn(*curobs.tod.shape) params = lbs.DestriperParameters( nside=16, nnz=3, baseline_length=100, iter_max=10, return_hit_map=True, return_binned_map=True, return_destriped_map=True, return_npp=True, return_invnpp=True, return_rcond=True, ) results = lbs.destripe(sim, instr, params=params) ref_map_path = Path(__file__).parent / "destriper_reference" hit_map_filename = ref_map_path / "destriper_hit_map.fits.gz" # healpy.write_map(hit_map_filename, results.hit_map, dtype="int32", overwrite=True) np.testing.assert_allclose( results.hit_map, healpy.read_map(hit_map_filename, field=None, dtype=np.int32)) binned_map_filename = ref_map_path / "destriper_binned_map.fits.gz" # healpy.write_map( # binned_map_filename, # results.binned_map, # dtype=list((np.float32 for i in range(3))), # overwrite=True, # ) ref_binned = healpy.read_map(binned_map_filename, field=None, dtype=list((np.float32 for i in range(3)))) assert results.binned_map.shape == ref_binned.shape np.testing.assert_allclose(results.binned_map, ref_binned, rtol=1e-2, atol=1e-3) destriped_map_filename = ref_map_path / "destriper_destriped_map.fits.gz" # healpy.write_map( # destriped_map_filename, # results.destriped_map, # dtype=list((np.float32 for i in range(3))), # overwrite=True, # ) ref_destriped = healpy.read_map(destriped_map_filename, field=None, dtype=list((np.float32 for i in range(3)))) assert results.destriped_map.shape == ref_destriped.shape np.testing.assert_allclose(results.destriped_map, ref_destriped, rtol=1e-2, atol=1e-3) npp_filename = ref_map_path / "destriper_npp.fits.gz" # healpy.write_map( # npp_filename, # results.npp, # dtype=list((np.float32 for i in range(6))), # overwrite=True, # ) ref_npp = healpy.read_map(npp_filename, field=None, dtype=list((np.float32 for i in range(6)))) assert results.npp.shape == ref_npp.shape np.testing.assert_allclose(results.npp, ref_npp, rtol=1e-2, atol=1e-3) invnpp_filename = ref_map_path / "destriper_invnpp.fits.gz" # healpy.write_map( # invnpp_filename, # results.invnpp, # dtype=list((np.float32 for i in range(6))), # overwrite=True, # ) ref_invnpp = healpy.read_map(invnpp_filename, field=None, dtype=list((np.float32 for i in range(6)))) assert results.invnpp.shape == ref_invnpp.shape np.testing.assert_allclose(results.invnpp, ref_invnpp, rtol=1e-2, atol=1e-3) rcond_filename = ref_map_path / "destriper_rcond.fits.gz" # healpy.write_map( # rcond_filename, # results.rcond, # dtype=np.float32, # overwrite=True, # ) assert np.allclose( results.rcond, healpy.read_map(rcond_filename, field=None, dtype=np.float32))
def test_scan_map(): # The purpose of this test is to simulate the motion of the spacecraft # for one year (see `time_span_s`) and produce *two* maps: the first # is associated with the Observation `obs1` and is built using # `scan_map_in_observations` and `make_bin_map`, the second is associated # the Observation `obs2` and is built directly filling in the test # `tod`, `psi` and `pixind` and then using `make_bin_map` # In the final test `out_map1` is compared with both `out_map2` and the # input map. Both simulations use two orthogonal detectors at the boresight # and input maps generated with `np.random.normal`. start_time = 0 time_span_s = 365 * 24 * 3600 nside = 16 sampling_hz = 1 hwp_radpsec = 4.084_070_449_666_731 npix = hp.nside2npix(nside) sim = lbs.Simulation(start_time=start_time, duration_s=time_span_s) scanning = lbs.SpinningScanningStrategy( spin_sun_angle_rad=0.785_398_163_397_448_3, precession_rate_hz=8.664_850_513_998_931e-05, spin_rate_hz=0.000_833_333_333_333_333_4, start_time=start_time, ) spin2ecliptic_quats = scanning.generate_spin2ecl_quaternions( start_time, time_span_s, delta_time_s=7200) instr = lbs.InstrumentInfo( boresight_rotangle_rad=0.0, spin_boresight_angle_rad=0.872_664_625_997_164_8, spin_rotangle_rad=3.141_592_653_589_793, ) detT = lbs.DetectorInfo( name="Boresight_detector_T", sampling_rate_hz=sampling_hz, bandcenter_ghz=100.0, quat=[0.0, 0.0, 0.0, 1.0], ) detB = lbs.DetectorInfo( name="Boresight_detector_B", sampling_rate_hz=sampling_hz, bandcenter_ghz=100.0, quat=[0.0, 0.0, 1.0 / np.sqrt(2.0), 1.0 / np.sqrt(2.0)], ) np.random.seed(seed=123_456_789) maps = np.random.normal(0, 1, (3, npix)) in_map = {"Boresight_detector_T": maps, "Boresight_detector_B": maps} (obs1, ) = sim.create_observations(detectors=[detT, detB]) (obs2, ) = sim.create_observations(detectors=[detT, detB]) pointings = lbs.scanning.get_pointings( obs1, spin2ecliptic_quats=spin2ecliptic_quats, detector_quats=[detT.quat, detB.quat], bore2spin_quat=instr.bore2spin_quat, ) lbs.scan_map_in_observations(obs1, pointings, hwp_radpsec, in_map, fill_psi_and_pixind_in_obs=True) out_map1 = lbs.make_bin_map(obs1, nside).T times = obs2.get_times() obs2.pixind = np.empty(obs2.tod.shape, dtype=np.int32) obs2.psi = np.empty(obs2.tod.shape) for idet in range(obs2.n_detectors): obs2.pixind[idet, :] = hp.ang2pix(nside, pointings[idet, :, 0], pointings[idet, :, 1]) obs2.psi[idet, :] = np.mod( pointings[idet, :, 2] + 2 * times * hwp_radpsec, 2 * np.pi) for idet in range(obs2.n_detectors): obs2.tod[idet, :] = ( maps[0, obs2.pixind[idet, :]] + np.cos(2 * obs2.psi[idet, :]) * maps[1, obs2.pixind[idet, :]] + np.sin(2 * obs2.psi[idet, :]) * maps[2, obs2.pixind[idet, :]]) out_map2 = lbs.make_bin_map(obs2, nside).T np.testing.assert_allclose(out_map1, in_map["Boresight_detector_T"], rtol=1e-6, atol=1e-6) np.testing.assert_allclose(out_map1, out_map2, rtol=1e-6, atol=1e-6)
def main(): warnings.filterwarnings("ignore", category=ErfaWarning) sim = lbs.Simulation( parameter_file=sys.argv[1], name="Observation of planets", description=""" This report contains the result of a simulation of the observation of the sky, particularly with respect to the observation of planets. """, ) params = load_parameters(sim) if lbs.MPI_ENABLED: log.info("Using MPI with %d processes", lbs.MPI_COMM_WORLD.size) else: log.info("Not using MPI, serial execution") log.info("Generating the quaternions") scanning_strategy = read_scanning_strategy( sim.parameters["scanning_strategy"], sim.imo, sim.start_time) sim.generate_spin2ecl_quaternions( scanning_strategy=scanning_strategy, delta_time_s=params.spin2ecl_delta_time_s) log.info("Creating the observations") instr = lbs.InstrumentInfo( name="instrum", spin_boresight_angle_rad=params.spin_boresight_angle_rad) detector = lbs.DetectorInfo( sampling_rate_hz=params.detector_sampling_rate_hz) conversions = [ ("years", astropy.units.year), ("year", astropy.units.year), ("days", astropy.units.day), ("day", astropy.units.day), ("hours", astropy.units.hour), ("hour", astropy.units.hour), ("minutes", astropy.units.minute), ("min", astropy.units.minute), ("sec", astropy.units.second), ("s", astropy.units.second), ("km", astropy.units.kilometer), ("Km", astropy.units.kilometer), ("au", astropy.units.au), ("AU", astropy.units.au), ("deg", astropy.units.deg), ("rad", astropy.units.rad), ] def conversion(x, new_unit): if isinstance(x, str): for conv_str, conv_unit in conversions: if x.endswith(" " + conv_str): value = float(x.replace(conv_str, "")) return (value * conv_unit).to(new_unit).value break else: return float(x) sim_params = sim.parameters["simulation"] durations = ["duration_s", "duration_of_obs_s"] for dur in durations: sim_params[dur] = conversion(sim_params[dur], "s") delta_t_s = sim_params["duration_of_obs_s"] sim.create_observations( detectors=[detector], num_of_obs_per_detector=int(sim_params["duration_s"] / sim_params["duration_of_obs_s"]), ) ################################################################# # Here begins the juicy part log.info("The loop starts on %d processes", lbs.MPI_COMM_WORLD.size) sky_hitmap = np.zeros(healpy.nside2npix(params.output_nside), dtype=np.int32) detector_hitmap = np.zeros(healpy.nside2npix(params.output_nside), dtype=np.int32) dist_map_m2 = np.zeros(len(detector_hitmap)) iterator = tqdm if lbs.MPI_ENABLED and lbs.MPI_COMM_WORLD.rank != 0: iterator = lambda x: x # Time variable inizialized at the beginning of the simulation t = 0.0 for obs in iterator(sim.observations): solar_system_ephemeris.set("builtin") times = obs.get_times(astropy_times=True) # We only compute the planet's position for the first sample in # the observation and then assume that it does not move # significantly. (In Ecliptic coordinates, Jupiter moves by # fractions of an arcmin over a time span of one hour) time0 = times[0] icrs_pos = get_ecliptic_vec( get_body_barycentric(params.planet_name, time0)) earth_pos = get_ecliptic_vec(get_body_barycentric("earth", time0)) # Move the spacecraft to L2 L2_pos = earth_pos * ( 1.0 + params.earth_L2_distance_km / norm(earth_pos).to("km").value) # Creating a Lissajous orbit R1 = conversion(params.radius_au[0], "au") R2 = conversion(params.radius_au[1], "au") phi1_t = params.L2_orbital_velocity_rad_s[0] * t phi2_t = params.L2_orbital_velocity_rad_s[1] * t phase = conversion(params.phase_rad, "rad") orbit_pos = np.array([ -R1 * np.sin(np.arctan(L2_pos[1] / L2_pos[0])) * np.cos(phi1_t), R1 * np.cos(np.arctan(L2_pos[1] / L2_pos[0])) * np.cos(phi1_t), R2 * np.sin(phi2_t + phase), ]) orbit_pos = astropy.units.Quantity(orbit_pos, unit="AU") # Move the spacecraft to a Lissajous orbit around L2 sat_pos = orbit_pos + L2_pos # Compute the distance between the spacecraft and the planet distance_m = norm(sat_pos - icrs_pos).to("m").value # This is the direction of the solar system body with respect # to the spacecraft, in Ecliptic coordinates ecl_vec = (icrs_pos - sat_pos).value # The variable ecl_vec is a 3-element vector. We normalize it so # that it has length one (using the L_2 norm, hence ord=2) ecl_vec /= np.linalg.norm(ecl_vec, axis=0, ord=2) # Convert the matrix to a N×3 shape by repeating the vector: # planets move slowly, so we assume that the planet stays fixed # during this observation. ecl_vec = np.repeat(ecl_vec.reshape(1, 3), len(times), axis=0) # Calculate the quaternions that convert the Ecliptic # reference system into the detector's reference system quats = lbs.get_ecl2det_quaternions( obs, sim.spin2ecliptic_quats, detector_quats=[detector.quat], bore2spin_quat=instr.bore2spin_quat, ) # Make room for the xyz vectors in the detector's reference frame det_vec = np.empty_like(ecl_vec) # Do the rotation! lbs.all_rotate_vectors(det_vec, quats[0], ecl_vec) pixidx = healpy.vec2pix(params.output_nside, det_vec[:, 0], det_vec[:, 1], det_vec[:, 2]) bincount = np.bincount(pixidx, minlength=len(detector_hitmap)) detector_hitmap += bincount dist_map_m2 += bincount / ((4 * np.pi * (distance_m**2))**2) pointings = lbs.get_pointings(obs, sim.spin2ecliptic_quats, [detector.quat], instr.bore2spin_quat)[0] pixidx = healpy.ang2pix(params.output_nside, pointings[:, 0], pointings[:, 1]) bincount = np.bincount(pixidx, minlength=len(sky_hitmap)) sky_hitmap += bincount # updating the time variable t += delta_t_s if lbs.MPI_ENABLED: sky_hitmap = lbs.MPI_COMM_WORLD.allreduce(sky_hitmap) detector_hitmap = lbs.MPI_COMM_WORLD.allreduce(detector_hitmap) dist_map_m2 = lbs.MPI_COMM_WORLD.allreduce(dist_map_m2) time_map_s = detector_hitmap / params.detector_sampling_rate_hz dist_map_m2[dist_map_m2 > 0] = np.power(dist_map_m2[dist_map_m2 > 0], -0.5) obs_time_per_radius_s = [ time_per_radius(time_map_s, angular_radius_rad=np.deg2rad(radius_deg)) for radius_deg in params.radii_deg ] if lbs.MPI_COMM_WORLD.rank == 0: # Create a plot of the observation time of the planet as a # function of the angular radius fig, ax = plt.subplots() ax.loglog(params.radii_deg, obs_time_per_radius_s) ax.set_xlabel("Radius [deg]") ax.set_ylabel("Observation time [s]") # Create a map showing how the observation time is distributed on # the sphere (in the reference frame of the detector) healpy.orthview(time_map_s, title="Time spent observing the source", unit="s") if scanning_strategy.spin_rate_hz != 0: spin_period_min = 1.0 / (60.0 * scanning_strategy.spin_rate_hz) else: spin_period_min = 0.0 if scanning_strategy.precession_rate_hz != 0: precession_period_min = 1.0 / ( 60.0 * scanning_strategy.precession_rate_hz) else: precession_period_min = 0.0 sim.append_to_report( """ ## Scanning strategy parameters Parameter | Value --------- | -------------- Angle between the spin axis and the Sun-Earth axis | {{ sun_earth_angle_deg }} deg Angle between the spin axis and the boresight | {{ spin_boresight_angle_deg }} deg Precession period | {{ precession_period_min }} min Spin period | {{ spin_period_min }} min ## Observation of {{ params.planet_name | capitalize }} ![](detector_hitmap.png) The overall time spent in the map is {{ overall_time_s }} seconds. The time resolution of the simulation was {{ delta_time_s }} seconds. Angular radius [deg] | Time spent [s] -------------------- | ------------------------ {% for row in radius_vs_time_s -%} {{ "%.1f"|format(row[0]) }} | {{ "%.1f"|format(row[1]) }} {% endfor -%} ![](radius_vs_time.svg) """, figures=[(plt.gcf(), "detector_hitmap.png"), (fig, "radius_vs_time.svg")], params=params, overall_time_s=np.sum(detector_hitmap) / params.detector_sampling_rate_hz, radius_vs_time_s=list(zip(params.radii_deg, obs_time_per_radius_s)), delta_time_s=1.0 / params.detector_sampling_rate_hz, sun_earth_angle_deg=np.rad2deg( scanning_strategy.spin_sun_angle_rad), spin_boresight_angle_deg=np.rad2deg( params.spin_boresight_angle_rad), precession_period_min=precession_period_min, spin_period_min=spin_period_min, det=detector, ) healpy.write_map( params.output_map_file_name, (detector_hitmap, time_map_s, dist_map_m2, sky_hitmap), coord="DETECTOR", column_names=["HITS", "OBSTIME", "SQDIST", "SKYHITS"], column_units=["", "s", "m^2", ""], dtype=[np.int32, np.float32, np.float64, np.int32], overwrite=True, ) np.savetxt( params.output_table_file_name, np.array(list(zip(params.radii_deg, obs_time_per_radius_s))), fmt=["%.2f", "%.5e"], ) with (sim.base_path / "parameters.json").open("wt") as outf: time_value = scanning_strategy.start_time if not isinstance(time_value, (int, float)): time_value = str(time_value) json.dump( { "scanning_strategy": { "spin_sun_angle_rad": scanning_strategy.spin_sun_angle_rad, "precession_rate_hz": scanning_strategy.precession_rate_hz, "spin_rate_hz": scanning_strategy.spin_rate_hz, "start_time": time_value, }, "detector": { "sampling_rate_hz": params.detector_sampling_rate_hz }, "planet": { "name": params.planet_name }, }, outf, indent=2, ) sim.flush()
#Imo work imo = lbs.Imo() sim_params = sim.parameters["simulation"] scanning_params = sim.parameters["scanning_strategy"] planet_params = sim.parameters["planet_scanning"] scan_params = imo.query(scanning_params["scanning_strategy_obj"]) #Instrumental variables metadata = scan_params.metadata strat = ss.LBScanningStrategy(metadata) instr = lbs.Instrument( name="LiteBIRD", spin_boresight_angle_deg=sim.parameters["scanning_strategy"] ["spin_boresight_angle_deg"]) det = lbs.DetectorInfo( name="Boresight", sampling_rate_hz=sim.parameters["planet_scanning"]["sampling_rate_hz"]) obs, = sim.create_observations(detectors=[det]) utils.print_inputs(simulation=sim, detector=det, instrument=instr, strategy=strat) sim.generate_spin2ecl_quaternions( scanning_strategy=ss.LBScanningStrategy(metadata=metadata) ) #Get quaternions responsible for rotation from spin-axis to ecliptic plane planet = planet_params["planet_name"] solar_system_ephemeris.set("builtin") start = time.time()
def create_fake_detector(sampling_rate_hz=1, quat=np.array([0.0, 0.0, 0.0, 1.0])): return lbs.DetectorInfo(name="dummy", sampling_rate_hz=sampling_rate_hz, quat=quat)
spin2ecliptic_quats = scanning.generate_spin2ecl_quaternions(start_time, time_span_s, delta_time_s=5.0) # We simulate an instrument whose boresight is perpendicular to # the spin axis. instr = lbs.InstrumentInfo( boresight_rotangle_rad=0.0, spin_boresight_angle_rad=np.deg2rad(90), spin_rotangle_rad=np.deg2rad(75), ) # A simple detector looking along the boresight direction det = lbs.DetectorInfo( name="Boresight_detector", sampling_rate_hz=sampling_hz, bandcenter_ghz=100.0, ) (obs, ) = sim.create_observations(detectors=[det]) pointings = lbs.scanning.get_pointings( obs, spin2ecliptic_quats=spin2ecliptic_quats, detector_quats=[det.quat], bore2spin_quat=instr.bore2spin_quat, ) # Simulate the orbit of the spacecraft and compute positions and # velocities orbit = lbs.SpacecraftOrbit(obs.start_time) pos_vel = lbs.spacecraft_pos_and_vel(orbit, obs, delta_time_s=60.0)