Observing the CMB¶
[1]:
import maria
from maria.band import get_band
f090 = get_band("act/pa5/f090")
f150 = get_band("act/pa5/f150")
f090.NET_RJ = 20e-6
f150.NET_RJ = 20e-6
f090.knee = 1e1
f150.knee = 1e1
array = {"field_of_view": 0.25,
"primary_size": 10,
"n": 80,
"packing": "sunflower",
"shape": "circle",
"polarized": True,
"bands": [f090, f150]}
instrument = maria.get_instrument(array=array)
print(instrument)
instrument.plot()
Instrument(1 array)
├ arrays:
│ n field_of_view max_baseline bands polarized primary_size
│ array1 320 15’ 0 m [act/pa5/f090,act/pa5/f150] True 10 m
│
└ bands:
name center width η NEP NET_RJ NET_CMB FWHM
0 act/pa5/f090 90 GHz 20 GHz 0.5 2.938 aW√s 20 uK_RJ√s 24.58 uK_CMB√s 1.458’
1 act/pa5/f150 150 GHz 30 GHz 0.5 4.407 aW√s 20 uK_RJ√s 34.67 uK_CMB√s 52.49”
[2]:
from maria import Plan
plan1 = Plan.generate(duration=1200,
sample_rate=25,
start_time="2026-08-05T06:00:00",
scan_type="back-and-forth",
scan_parameters={"az_center": 90,
"el_center": 45,
"az_throw": 4,
},
site="cerro_toco")
plan1.plot(frames=["az/el", "ra/dec", "glon/glat"])
plan2 = Plan.generate(duration=1200,
sample_rate=25,
start_time="2026-08-05T12:18:00",
scan_type="back-and-forth",
scan_parameters={"az_center": -90,
"el_center": 45,
"az_throw": 4,
},
site="cerro_toco")
plan2.plot(frames=["az/el", "ra/dec", "glon/glat"])
[3]:
sim = maria.Simulation(
instrument=instrument,
plans=[plan1, plan2],
site="cerro_toco",
cmb="generate",
cmb_kwargs={"nside": 1024},
)
print(sim)
Initializing observations: 100%|██████████| 2/2 [00:00<00:00, 2.49it/s]
Generating CMB (nside=1024): 0%| | 0/1 [00:00<?, ?it/s]2026-07-06 17:14:39.686 INFO: Fetching https://github.com/thomaswmorris/maria-data/raw/master/cmb/spectra/lensed.csv
Downloading: | | 3.72M/? [00:00<00:00, 92.9MB/s]
Generating CMB (nside=1024): 100%|██████████| 1/1 [00:09<00:00, 9.88s/it]
Simulation
├ Instrument(1 array)
│ ├ arrays:
│ │ n field_of_view max_baseline bands polarized primary_size
│ │ array1 320 15’ 0 m [act/pa5/f090,act/pa5/f150] True 10 m
│ │
│ └ bands:
│ name center width η NEP NET_RJ NET_CMB FWHM
│ 0 act/pa5/f090 90 GHz 20 GHz 0.5 2.938 aW√s 20 uK_RJ√s 24.58 uK_CMB√s 1.458’
│ 1 act/pa5/f150 150 GHz 30 GHz 0.5 4.407 aW√s 20 uK_RJ√s 34.67 uK_CMB√s 52.49”
├ Site:
│ region: chajnantor
│ timezone: America/Santiago
│ location:
│ longitude: 67°47’16.08” W
│ latitude: 22°57’30.96” S
│ altitude: 5.19 km
│ seasonal: True
│ diurnal: True
├ PlanList(2 plans, 2400 s):
│ start_time duration sample_rate target(az,el)
│ chunk
│ 0 2026-08-05 06:00:00.000 +00:00 1200 s 25 Hz (90°, 45.03°)
│ 1 2026-08-05 12:18:00.000 +00:00 1200 s 25 Hz (270°, 45.03°)
└ HEALPixMap:
data(3, 1, 12582912):
min: -5.602e-04
max: 5.685e-04
units: K_CMB
quantity: cmb_temperature_anisotropy
stokes(3):
components: ['I' 'Q' 'U']
z(1):
values: [1089.92]
pixels(12582912):
nside: 1024
resolution: 3.435’
frame: ra/dec
beam(maj, min, rot): (0 rad, 0 rad, 0 rad)
memory: 302 MB
[4]:
tods = sim.run()
tods[0].plot()
2026-07-06 17:14:49.296 INFO: Simulating observation 1 of 2
Sampling source 'cmb': 100%|██████████| 2/2 [00:10<00:00, 5.39s/it, band=act/pa5/f150, message=Sampling channel (105 GHz, 195 GHz)]
Generating noise: 100%|██████████| 2/2 [00:01<00:00, 1.70it/s, band=act/pa5/f150]
2026-07-06 17:15:01.592 INFO: Simulated observation 1 of 2 in 12.29 s
2026-07-06 17:15:01.593 INFO: Simulating observation 2 of 2
Sampling source 'cmb': 100%|██████████| 2/2 [00:09<00:00, 4.97s/it, band=act/pa5/f150, message=Sampling channel (105 GHz, 195 GHz)]
Generating noise: 100%|██████████| 2/2 [00:00<00:00, 2.70it/s, band=act/pa5/f150]
2026-07-06 17:15:12.571 INFO: Simulated observation 2 of 2 in 10.97 s
Binning the data gives us a
[5]:
from maria.mappers import *
plot_kwargs = {"slices": dict(stokes=["I", "Q", "U"], nu=[[0], [1]]), "contrast": 1e-2}
bin_mapper = BinMapper(tods=tods,
units="uK_CMB",
resolution=2 / 60,
frame="ra/dec",
tod_preprocessing={
"remove_polynomial": {"time": 3, "elevation": 3},
},
)
bin_mapper.run()
bin_mapper.map.plot(**plot_kwargs)
2026-07-06 17:15:20.430 INFO: Inferring center {'ra': '01ʰ42ᵐ20.18ˢ', 'dec': '-16°09’33.98”'} for mapper
2026-07-06 17:15:20.442 INFO: Inferring mapper width 7.059° for mapper from observation patch
2026-07-06 17:15:20.442 INFO: Inferring mapper height 7.059° to match supplied width
2026-07-06 17:15:20.988 INFO: Inferring stokes parameters 'IQU' for mapper from detector sensitivities
Preprocessing TODs: 100%|██████████| 2/2 [00:01<00:00, 1.79it/s]
Mapping: 100%|██████████| 2/2 [00:02<00:00, 1.38s/it, tod=1/2]
[6]:
from maria.mapping.ml_mapper import *
ml_mapper = MaximumLikelihoodMapper(tods=tods,
units="uK_CMB",
resolution=1 / 60,
frame="ra/dec",
tod_preprocessing={
"remove_polynomial": {"time": 3, "elevation": 3},
},
)
2026-07-06 17:15:29.087 INFO: Inferring center {'ra': '01ʰ42ᵐ20.18ˢ', 'dec': '-16°09’33.98”'} for mapper
2026-07-06 17:15:29.099 INFO: Inferring mapper width 7.066° for mapper from observation patch
2026-07-06 17:15:29.100 INFO: Inferring mapper height 7.066° to match supplied width
2026-07-06 17:15:29.624 INFO: Inferring stokes parameters 'IQU' for mapper from detector sensitivities
Preprocessing TODs: 100%|██████████| 2/2 [00:00<00:00, 3.06it/s]
Computing pointing matrices: 100%|██████████| 2/2 [00:10<00:00, 5.04s/it]
[7]:
print(ml_mapper.map)
ml_mapper.map.plot(**plot_kwargs)
ProjectionMap:
data(3, 2, 423, 423):
min: -2.146e+03
max: 1.890e+03
units: uK_CMB
quantity: cmb_temperature_anisotropy
stokes(3):
components: ['I' 'Q' 'U']
nu(2):
values: [ 90. 150.] GHz
eta(423):
height: 7.033°
res: -60”
xi(423):
width: 7.033°
res: 60”
frame: ra/dec
center:
ra: 01ʰ42ᵐ20.18ˢ
dec: -16°09’33.98”
beam(maj, min, psi): ragged
memory: 8.589 MB
[8]:
ml_mapper.fit(epochs=1,
max_steps_per_epoch=50,
plot=True,
plot_kwargs=plot_kwargs)
Updating noise model: 100%|██████████| 2/2 [00:13<00:00, 6.54s/it, tod=2/2]
Fitting map (epoch 1/1): 50it [06:57, 8.35s/it, alpha=4.47e+8]