예제 #1
0
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,
        )
예제 #2
0
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
예제 #3
0
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)
예제 #4
0
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()
예제 #5
0
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)
예제 #6
0
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()
예제 #7
0
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="")
예제 #8
0
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,
    )
예제 #9
0
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)
예제 #10
0
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)
예제 #11
0
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()
예제 #12
0
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,
예제 #13
0
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)
예제 #14
0
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))
예제 #15
0
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)
예제 #16
0
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),