def test_simulation_pointings_mjd(tmp_path): sim = lbs.Simulation( base_path=tmp_path / "simulation_dir", start_time=Time("2020-01-01T00:00:00"), duration_s=130.0, ) fakedet = create_fake_detector() sim.create_observations( detectors=[fakedet], num_of_obs_per_detector=2, distribute=False, ) sstr = lbs.SpinningScanningStrategy( spin_sun_angle_deg=10.0, precession_period_min=10.0, spin_rate_rpm=0.1, ) sim.generate_spin2ecl_quaternions(scanning_strategy=sstr, delta_time_s=60.0) instr = lbs.Instrument(spin_boresight_angle_deg=20.0) for obs in sim.observations: pointings_and_polangle = obs.get_pointings( spin2ecliptic_quats=sim.spin2ecliptic_quats, detector_quats=np.array([[0.0, 0.0, 0.0, 1.0]]), bore2spin_quat=instr.bore2spin_quat, )
def read_scanning_strategy(parameters: Dict[str, Any], imo: lbs.Imo, start_time): if "scanning_strategy_obj" in parameters: sstr = lbs.SpinningScanningStrategy.from_imo( imo, parameters["scanning_strategy_obj"]) else: sstr = lbs.SpinningScanningStrategy( spin_sun_angle_rad=0.0, precession_rate_hz=0.0, spin_rate_hz=1.0 / 60, start_time=start_time, ) if "spin_sun_angle_rad" in parameters: sstr.spin_sun_angle_rad = parameters["spin_sun_angle_rad"] if "precession_period_min" in parameters: precession_period_min = parameters["precession_period_min"] if precession_period_min != 0: sstr.precession_rate_hz = 1.0 / ( 60.0 * parameters["precession_period_min"]) else: sstr.precession_rate_hz = 0.0 if "spin_rate_rpm" in parameters: sstr.spin_rate_hz = parameters["spin_rate_rpm"] / 60.0 return sstr
def test_simulation_pointings_mjd(tmp_path): sim = lbs.Simulation( base_path=tmp_path / "simulation_dir", start_time=Time("2020-01-01T00:00:00"), duration_s=130.0, ) fakedet = create_fake_detector() sim.create_observations(detectors=[fakedet], num_of_obs_per_detector=2, split_list_over_processes=False) sstr = lbs.SpinningScanningStrategy(spin_sun_angle_rad=10.0, precession_rate_hz=10.0, spin_rate_hz=0.1) sim.generate_spin2ecl_quaternions(scanning_strategy=sstr, delta_time_s=60.0) instr = lbs.InstrumentInfo(spin_boresight_angle_rad=np.deg2rad(20.0)) for idx, obs in enumerate(sim.observations): pointings_and_polangle = lbs.get_pointings( obs, spin2ecliptic_quats=sim.spin2ecliptic_quats, detector_quats=np.array([[0.0, 0.0, 0.0, 1.0]]), bore2spin_quat=instr.bore2spin_quat, ) filename = Path( __file__).parent / f"reference_obs_pointings{idx:03d}.npy" reference = np.load(filename, allow_pickle=False) assert np.allclose(pointings_and_polangle, reference)
def test_simulation_pointings_polangle(tmp_path): sim = lbs.Simulation(base_path=tmp_path / "simulation_dir", start_time=0.0, duration_s=61.0) fakedet = create_fake_detector(sampling_rate_hz=50.0) sim.create_observations(detectors=[fakedet], num_of_obs_per_detector=1, split_list_over_processes=False) assert len(sim.observations) == 1 obs = sim.observations[0] sstr = lbs.SpinningScanningStrategy(spin_sun_angle_rad=0.0, precession_rate_hz=0.0, spin_rate_hz=1.0 / 60) sim.generate_spin2ecl_quaternions(scanning_strategy=sstr, delta_time_s=0.5) instr = lbs.InstrumentInfo(spin_boresight_angle_rad=0.0) pointings_and_polangle = lbs.get_pointings( obs, spin2ecliptic_quats=sim.spin2ecliptic_quats, detector_quats=np.array([[0.0, 0.0, 0.0, 1.0]]), bore2spin_quat=instr.bore2spin_quat, ) polangle = pointings_and_polangle[..., 2] # Check that the polarization angle scans every value between -π # and +π assert np.allclose(np.max(polangle), np.pi, atol=0.01) assert np.allclose(np.min(polangle), -np.pi, atol=0.01) # Simulate the generation of a report sim.flush()
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 test_simulation_pointings_spinning(tmp_path): sim = lbs.Simulation( base_path=tmp_path / "simulation_dir", start_time=0.0, duration_s=61.0, ) fakedet = create_fake_detector(sampling_rate_hz=50.0) sim.create_observations( detectors=[fakedet], num_of_obs_per_detector=1, distribute=False, ) assert len(sim.observations) == 1 obs = sim.observations[0] sstr = lbs.SpinningScanningStrategy( spin_sun_angle_deg=0.0, precession_period_min=0.0, spin_rate_rpm=1.0, ) sim.generate_spin2ecl_quaternions(scanning_strategy=sstr, delta_time_s=0.5) instr = lbs.Instrument(spin_boresight_angle_deg=15.0) pointings_and_polangle = obs.get_pointings( spin2ecliptic_quats=sim.spin2ecliptic_quats, detector_quats=np.array([[0.0, 0.0, 0.0, 1.0]]), bore2spin_quat=instr.bore2spin_quat, ) colatitude = pointings_and_polangle[..., 0] with open("spin2ecliptic_quats.txt", "wt") as outf: for i in range(sim.spin2ecliptic_quats.quats.shape[0]): print(*sim.spin2ecliptic_quats.quats[i, :], file=outf) with open("pointings.txt", "wt") as outf: import healpy for i in range(pointings_and_polangle.shape[1]): print( *healpy.ang2vec(pointings_and_polangle[0, i, 0], pointings_and_polangle[0, i, 1]), file=outf, ) # Check that the colatitude does not depart more than ±15° from # the Ecliptic assert np.allclose(np.rad2deg(np.max(colatitude)), 90 + 15, atol=0.01) assert np.allclose(np.rad2deg(np.min(colatitude)), 90 - 15, atol=0.01) sim.flush()
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_simulation_two_detectors(): sim = lbs.Simulation(start_time=0.0, duration_s=86400.0) # Two detectors, the second rotated by 45° quaternions = [ np.array([0.0, 0.0, 0.0, 1.0]), np.array([0.0, 0.0, 1.0, 1.0]) / np.sqrt(2), ] fakedet1 = create_fake_detector(sampling_rate_hz=1 / 3600, quat=quaternions[0]) fakedet2 = create_fake_detector(sampling_rate_hz=1 / 3600, quat=quaternions[1]) sim.create_observations( detectors=[fakedet1, fakedet2], num_of_obs_per_detector=1, split_list_over_processes=False, ) assert len(sim.observations) == 1 obs = sim.observations[0] # The spacecraft stands still in L2, with no spinning nor precession sstr = lbs.SpinningScanningStrategy(spin_sun_angle_rad=0.0, precession_rate_hz=0.0, spin_rate_hz=0.0) sim.generate_spin2ecl_quaternions(sstr, delta_time_s=60.0) assert sim.spin2ecliptic_quats.quats.shape == (24 * 60 + 1, 4) instr = lbs.InstrumentInfo(spin_boresight_angle_rad=0.0) pointings_and_polangle = lbs.get_pointings( obs, spin2ecliptic_quats=sim.spin2ecliptic_quats, detector_quats=quaternions, bore2spin_quat=instr.bore2spin_quat, ) assert pointings_and_polangle.shape == (2, 24, 3) assert np.allclose(pointings_and_polangle[0, :, 0], pointings_and_polangle[1, :, 0]) assert np.allclose(pointings_and_polangle[0, :, 1], pointings_and_polangle[1, :, 1]) # The ψ angle should differ by 45° assert np.allclose( np.abs(pointings_and_polangle[0, :, 2] - pointings_and_polangle[1, :, 2]), np.pi / 2, )
def test_simulation_pointings_still(): sim = lbs.Simulation(start_time=0.0, duration_s=86400.0) fakedet = create_fake_detector(sampling_rate_hz=1 / 3600) sim.create_observations( detectors=[fakedet], num_of_obs_per_detector=1, distribute=False, ) assert len(sim.observations) == 1 obs = sim.observations[0] # The spacecraft stands still in L2, with no spinning nor precession sstr = lbs.SpinningScanningStrategy( spin_sun_angle_deg=0.0, precession_period_min=0.0, spin_rate_rpm=0.0, ) sim.generate_spin2ecl_quaternions(sstr, delta_time_s=60.0) assert sim.spin2ecliptic_quats.quats.shape == (24 * 60 + 1, 4) instr = lbs.Instrument(spin_boresight_angle_deg=0.0) # Move the Z vector manually using the last quaternion and check # that it's rotated by 1/365.25 of a complete circle boresight = np.empty(3) lbs.rotate_z_vector(boresight, *sim.spin2ecliptic_quats.quats[-1, :]) assert np.allclose(np.arctan2(boresight[1], boresight[0]), 2 * np.pi / 365.25) # Now redo the calculation using Observation.get_pointings pointings_and_polangle = obs.get_pointings( spin2ecliptic_quats=sim.spin2ecliptic_quats, detector_quats=np.array([[0.0, 0.0, 0.0, 1.0]]), bore2spin_quat=instr.bore2spin_quat, ) colatitude = pointings_and_polangle[..., 0] longitude = pointings_and_polangle[..., 1] polangle = pointings_and_polangle[..., 2] assert np.allclose(colatitude, np.pi / 2), colatitude assert np.allclose(np.abs(polangle), np.pi / 2), polangle # The longitude should have changed by a fraction 23 hours / # 365.25 days of a complete circle (we have 24 samples, from t = 0 # to t = 23 hr) assert np.allclose(np.abs(longitude[..., -1] - longitude[..., 0]), 2 * np.pi * 23 / 365.25 / 24)
def test_scanning_quaternions(tmp_path): sim = lbs.Simulation( base_path=tmp_path / "simulation_dir", start_time=0.0, duration_s=61.0, ) fakedet = create_fake_detector(sampling_rate_hz=50.0) sim.create_observations( detectors=[fakedet], num_of_obs_per_detector=1, distribute=False, ) assert len(sim.observations) == 1 obs = sim.observations[0] sstr = lbs.SpinningScanningStrategy( spin_sun_angle_deg=0.0, precession_period_min=0.0, spin_rate_rpm=1.0, ) sim.generate_spin2ecl_quaternions(scanning_strategy=sstr, delta_time_s=0.5) instr = lbs.Instrument(spin_boresight_angle_deg=15.0) detector_quat = np.array([[0.0, 0.0, 0.0, 1.0]]) det2ecl_quats = obs.get_det2ecl_quaternions( spin2ecliptic_quats=sim.spin2ecliptic_quats, detector_quats=detector_quat, bore2spin_quat=instr.bore2spin_quat, ) ecl2det_quats = obs.get_ecl2det_quaternions( spin2ecliptic_quats=sim.spin2ecliptic_quats, detector_quats=detector_quat, bore2spin_quat=instr.bore2spin_quat, ) identity = np.array([0, 0, 0, 1]) det2ecl_quats = det2ecl_quats.reshape(-1, 4) ecl2det_quats = ecl2det_quats.reshape(-1, 4) for i in range(det2ecl_quats.shape[0]): # Check that the two quaternions (ecl2det and det2ecl) are # actually one the inverse of the other quat = np.copy(det2ecl_quats[i, :]) lbs.quat_right_multiply(quat, *ecl2det_quats[i, :]) assert np.allclose(quat, identity)
def test_simulation_pointings_spinning(tmp_path): sim = lbs.Simulation(base_path=tmp_path / "simulation_dir", start_time=0.0, duration_s=61.0) fakedet = create_fake_detector(sampling_rate_hz=50.0) sim.create_observations(detectors=[fakedet], num_of_obs_per_detector=1, split_list_over_processes=False) assert len(sim.observations) == 1 obs = sim.observations[0] sstr = lbs.SpinningScanningStrategy(spin_sun_angle_rad=0.0, precession_rate_hz=0.0, spin_rate_hz=1.0) sim.generate_spin2ecl_quaternions(scanning_strategy=sstr, delta_time_s=0.5) instr = lbs.InstrumentInfo(spin_boresight_angle_rad=np.deg2rad(15.0)) pointings_and_polangle = lbs.get_pointings( obs, spin2ecliptic_quats=sim.spin2ecliptic_quats, detector_quats=np.array([[0.0, 0.0, 0.0, 1.0]]), bore2spin_quat=instr.bore2spin_quat, ) colatitude = pointings_and_polangle[..., 0] reference_spin2ecliptic_file = Path( __file__).parent / "reference_spin2ecl.txt.gz" reference = np.loadtxt(reference_spin2ecliptic_file) assert np.allclose(sim.spin2ecliptic_quats.quats, reference) reference_pointings_file = Path( __file__).parent / "reference_pointings.txt.gz" reference = np.loadtxt(reference_pointings_file) assert np.allclose(pointings_and_polangle[0, :, :], reference) # Check that the colatitude does not depart more than ±15° from # the Ecliptic assert np.allclose(np.rad2deg(np.max(colatitude)), 90 + 15, atol=0.01) assert np.allclose(np.rad2deg(np.min(colatitude)), 90 - 15, atol=0.01) sim.flush()
import numpy as np import astropy.units as u from numpy.random import MT19937, RandomState, SeedSequence import litebird_sim as lbs sim = lbs.Simulation(base_path="/tmp/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)) # 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,
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)
from astropy.time import Time import numpy as np import litebird_sim as lbs import matplotlib.pylab as plt start_time = Time("2022-01-01") time_span_s = 120.0 # Two minutes sampling_hz = 20 sim = lbs.Simulation(start_time=start_time, duration_s=time_span_s) # We pick a simple scanning strategy where the spin axis is aligned # with the Sun-Earth axis, and the spacecraft spins once every minute scanning = lbs.SpinningScanningStrategy( spin_sun_angle_rad=np.deg2rad(0), precession_rate_hz=0, spin_rate_hz=1 / 60, start_time=start_time, ) # The spacecraft spins pretty fast (once per minute!), so we # need to pick delta_time_s ≪ 1/spin_rate_hz 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),