Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 21 additions & 19 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
# HEAD

- **Breaking change**: Stop supporting NumPy 1.x and move to NumPy 2.x. Add support for Python 3.14 [#519](https://github.com/litebird/litebird_sim/pull/519)

- **Breaking change**: Major reworking of the interfaces and handling of inputs across the framework [#479](https://github.com/litebird/litebird_sim/pull/479), in detail:

1. Rework the handling of spherical harmonics by integrating ducc0 as the primary engine for SHT operations, including interpolation.
2. New container for healpix maps called HealpixMap and further improvement of the class SphericalHarmonics. All the simulation modules are now only compatible with these new classes.
3. MBs replaced by a more flexible and simple module called input_sky.
4. Expansion of the class Units with several new functionalities. Integration with astropy and pysm3 improved.

- Refactor `input_sky.SkyGenerator` to reduce duplicated logic between channel/detector mode and frequency mode by using shared component-generation helpers for CMB, foregrounds, and dipole [#501](https://github.com/litebird/litebird_sim/pull/501)

- Simple pair differencing map-maker [#509](https://github.com/litebird/litebird_sim/pull/509)

- Update dependency on Ducc and Numba [#502](https://github.com/litebird/litebird_sim/pull/502)

- Add multi-frequency support to HealpixMap and SphericalHarmonics. New option for generation of multi-frequency maps in input_sky [#496](https://github.com/litebird/litebird_sim/pull/496)
- Add multi-frequency support to HealpixMap and SphericalHarmonics. New option for generation of multi-frequency maps in `input_sky` [#496](https://github.com/litebird/litebird_sim/pull/496)

- Fix normalization in the generation of gaussian beam alms [#494](https://github.com/litebird/litebird_sim/pull/494)

- Ducc0 1/f noise generation module included [#490](https://github.com/litebird/litebird_sim/pull/490)

- Small optimizations in beam convolver [#492](https://github.com/litebird/litebird_sim/pull/492)

- Fixed a TypeError in Observation when allocate_tod=False in MPI jobs [#491](https://github.com/litebird/litebird_sim/pull/491)
- Fixed a TypeError in Observation when `allocate_tod=False` in MPI jobs [#491](https://github.com/litebird/litebird_sim/pull/491)

- Save memory in pointing generation [#488](https://github.com/litebird/litebird_sim/pull/488)

- **Breaking change**: Major reworking of the interfaces and handling of inputs across the framework [#479](https://github.com/litebird/litebird_sim/pull/479), in detail:

1. Rework the handling of spherical harmonics by integrating ducc0 as the primary engine for SHT operations, including interpolation.
2. New container for healpix maps called HealpixMap and further improvement of the class SphericalHarmonics. All the simulation modules are now only compatible with these new classes.
3. MBs replaced by a more flexible and simple module called input_sky.
4. Expansion of the class Units with several new functionalities. Integration with astropy and pysm3 improved.

- Add automatic type-checking with ty [#481](https://github.com/litebird/litebird_sim/pull/481)

- Stop using sphinxcontrib-asciinema [#478](https://github.com/litebird/litebird_sim/pull/478)
Expand All @@ -39,18 +41,18 @@

- Refurbish HWP handling [#463](https://github.com/litebird/litebird_sim/pull/463), in detail:

1. Create NonIdealHWP class.
2. Remove HwpSys class.
3. Rename hwp_sys.py to hwp_harmonics.py.
4. Unify map scanning methods by making hwp_harmonics.fill_tod() a low-level method which is now executed by the high-level scan_map_in_observations.py.
1. Create `NonIdealHWP` class.
2. Remove `HwpSys class`.
3. Rename `hwp_sys.py` to `hwp_harmonics.py`.
4. Unify map scanning methods by making `hwp_harmonics.fill_tod()` a low-level method which is now executed by the high-level scan_map_in_observations.py.

- Fix angle in hwp differential emission [#452](https://github.com/litebird/litebird_sim/pull/452)

- New method `Imo.open_data_file` [#449](https://github.com/litebird/litebird_sim/pull/449)

- Improved `SphericalHarmonics` class, algebra and I/O implemented [#448](https://github.com/litebird/litebird_sim/pull/448)

- Change hwp_angle calculation to the complex domain [#433](https://github.com/litebird/litebird_sim/pull/433)
- Change `hwp_angle` calculation to the complex domain [#433](https://github.com/litebird/litebird_sim/pull/433)

# Version 0.16.0

Expand All @@ -72,7 +74,7 @@

- Add low-level interface to `BrahMap` [#440](https://github.com/litebird/litebird_sim/pull/440)

- Set Mueller matrix phases in Hwp_sys module as class attributes, instead of being hardcoded [#442](https://github.com/litebird/litebird_sim/pull/442)
- Set Mueller matrix phases in `Hwp_sys` module as class attributes, instead of being hardcoded [#442](https://github.com/litebird/litebird_sim/pull/442)

# Version 0.15.2

Expand All @@ -84,9 +86,9 @@

- Make sure that the PTEP IMo, the Madam templates, and the static files required to create the HTML reports are installed properly by `pip` and enable Binder/Google Colab [#436](https://github.com/litebird/litebird_sim/pull/436)

- Make the HWP_sys module able to deal with missing pixels, let the output maps to use a different NSIDE than the one of the inputs [#432](https://github.com/litebird/litebird_sim/pull/432)
- Make the `HWP_sys` module able to deal with missing pixels, let the output maps to use a different NSIDE than the one of the inputs [#432](https://github.com/litebird/litebird_sim/pull/432)

- Fix bug in the computation of pointings for the HWP_sys module [#429](https://github.com/litebird/litebird_sim/pull/429)
- Fix bug in the computation of pointings for the `HWP_sys` module [#429](https://github.com/litebird/litebird_sim/pull/429)

- Upgrade PySM to 3.4.2 [#431](https://github.com/litebird/litebird_sim/pull/431)

Expand Down Expand Up @@ -373,7 +375,7 @@

- Create a script that fetches information about the latest release and produce a release announcement [PR#156](https://github.com/litebird/litebird_sim/pull/156)

- Option for rotating the pointing from ecliptic to galactic coordinates in scan_map [#164](https://github.com/litebird/litebird_sim/pull/164)
- Option for rotating the pointing from ecliptic to galactic coordinates in `scan_map` [#164](https://github.com/litebird/litebird_sim/pull/164)

- Fix issue [#148](https://github.com/litebird/litebird_sim/issues/148)

Expand Down Expand Up @@ -435,7 +437,7 @@

- Make tests run faster by using ducc0 0.8.0 [PR#92](https://github.com/litebird/litebird_sim/pull/92)

- Misc minor changes: gitignore .DS_Store; losslessly compress some assets [PR#88](https://github.com/litebird/litebird_sim/pull/88)
- Misc minor changes: `gitignore`, `.DS_Store`; losslessly compress some assets [PR#88](https://github.com/litebird/litebird_sim/pull/88)

- Improve the `Observation` API. Deprecate the pointing-related methods (moved to `scanning`), quantities are local by default [PR#84](https://github.com/litebird/litebird_sim/pull/84)

Expand Down
14 changes: 7 additions & 7 deletions litebird_sim/bandpasses.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import logging
from dataclasses import dataclass, fields
from uuid import UUID

import numpy as np
import scipy as sp
import logging
from uuid import UUID

from .imo import Imo

Expand Down Expand Up @@ -166,7 +166,7 @@ def normalize_band(self):
Normalize the band transmission coefficients

"""
A = np.trapz(self.weights, self.freqs_ghz)
A = np.trapezoid(self.weights, self.freqs_ghz)
self.weights /= A
self.isnormalized = True

Expand Down Expand Up @@ -225,18 +225,18 @@ def get_normalization(self):
"""
Estimate the integral over the frequency band
"""
return np.trapz(self.weights, self.freqs_ghz)
return np.trapezoid(self.weights, self.freqs_ghz)

# Find effective central frequency of a bandpass profile
def find_central_frequency(self):
"""Find the effective central frequency of
a bandpass profile as defined in https://arxiv.org/abs/1303.5070
"""
if self.isnormalized:
return np.trapz(self.freqs_ghz * self.weights, self.freqs_ghz)
return np.trapezoid(self.freqs_ghz * self.weights, self.freqs_ghz)
else:
return (
np.trapz(self.freqs_ghz * self.weights, self.freqs_ghz)
np.trapezoid(self.freqs_ghz * self.weights, self.freqs_ghz)
/ self.get_normalization()
)

Expand Down Expand Up @@ -342,6 +342,6 @@ def bandpass_resampling(self, bstrap_size=1000, nresample=54, model=None):
)(self.freqs_ghz)
)
if self.isnormalized:
return resampled_bpass / np.trapz(resampled_bpass, self.freqs_ghz)
return resampled_bpass / np.trapezoid(resampled_bpass, self.freqs_ghz)
else:
return resampled_bpass
9 changes: 6 additions & 3 deletions litebird_sim/grasp2alm.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ def __init__(self, healpix_map):
def _check_reason(
self, reason: int, iter_count: int, residual_norm: float, quality: float
) -> None:
assert reason in (1, 2), (
assert reason in (
1,
2,
), (
f"pseudo_analysis failed, reason: {REASON_DESCRIPTION[reason]}, {iter_count=}, {residual_norm=}, {quality=}"
)

Expand Down Expand Up @@ -95,7 +98,7 @@ def to_alm(
(3, SphericalHarmonics.num_of_alm_from_lmax(lmax, mmax)),
dtype=np.complex128,
)
(_, reason, iter_count, residual_norm, quality) = ducc0.sht.pseudo_analysis(
_, reason, iter_count, residual_norm, quality = ducc0.sht.pseudo_analysis(
map=self.map[0].reshape(1, -1), # Make this a 2D matrix
alm=alm[0, :].reshape(1, -1),
lmax=lmax,
Expand Down Expand Up @@ -190,7 +193,7 @@ def beam_mapmaker(
if hit_map[i] > 0:
output_map[i] /= hit_map[i]
else:
output_map[i] = np.NaN
output_map[i] = np.nan


@dataclass
Expand Down
2 changes: 1 addition & 1 deletion litebird_sim/hwp_diff_emiss.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def compute_2f_for_one_sample(angle_rad, offset_rad, amplitude_k):
def add_2f_for_one_detector(
tod_det, angle_det_rad, offset_angle_rad: float, amplitude_k
):
for i, cur_angle in enumerate(angle_det_rad): # type: ignore[not-iterable]
for i, cur_angle in enumerate(angle_det_rad):
tod_det[i] += compute_2f_for_one_sample(
angle_rad=cur_angle, offset_rad=offset_angle_rad, amplitude_k=amplitude_k
)
Expand Down
9 changes: 3 additions & 6 deletions litebird_sim/pointings_in_obs.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
from collections.abc import Callable

import astropy.time
import numpy as np
import numpy.typing as npt
import astropy.time

from deprecated import deprecated

from ducc0.healpix import Healpix_Base

from .coordinates import CoordinateSystem, rotate_coordinates_e2g
from .detectors import InstrumentInfo
from .hwp import HWP
from .observations import Observation
from .scanning import RotQuaternion

from .coordinates import CoordinateSystem, rotate_coordinates_e2g


def prepare_pointings(
observations: Observation | list[Observation],
Expand Down Expand Up @@ -169,7 +166,7 @@ def _get_hwp_angle(
return obs.get_hwp_angle(pointings_dtype=pointing_dtype)
else:
if hasattr(obs, "mueller_hwp"):
if any(m is not None for m in obs.mueller_hwp): # type: ignore[not-iterable]
if any(m is not None for m in obs.mueller_hwp):
raise AssertionError(
"Detectors have been initialized with a mueller_hwp, "
"but no HWP is either passed or initialized in the pointing."
Expand Down
15 changes: 7 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,22 @@ authors = [
]
readme = "README.md"
license = {text = "GPL-3.0"}
requires-python = ">=3.10,<3.14"
requires-python = ">=3.10,<3.15"
dependencies = [
"numba>=0.63.0",
"numpy>=1.26.4",
"numba>=0.65.0",
"numpy>=2.2.6",
"astropy>=6.1.7",
"tomlkit>=0.12.1",
"jinja2>=3.1",
"matplotlib>=3.10.3",
"matplotlib>=3.10.8",
"healpy>=1.18.1",
"pyyaml>=6.0",
"jplephem>=2.22",
"requests>=2.32.0",
"rich>=14.0.0",
"ducc0>=0.40.0",
"pysm3>=3.4.2",
"ducc0>=0.41.0",
"pysm3>=3.4.4",
"h5py>=3.9",
"deprecation>=2.1.0",
"deprecated>=1.2.18",
"scipy>=1.14.0",
"libinsdb>=0.9.0",
Expand All @@ -72,7 +71,7 @@ dev = [
"ruff>=0.11.11",
"pytest>=8.4.1",
"pytest-cov>=7.0.0",
"ty>=0.0.9",
"ty==0.0.13",
]

[tool.setuptools.package-data]
Expand Down
6 changes: 5 additions & 1 deletion test/test_binner.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ def test_accumulate_map_and_info():
assert np.allclose(res_info, info)

rhs = mapping._extract_map_and_fill_info(info)
assert np.allclose(np.linalg.solve(info, rhs), res_map)
# Starting from NumPy 2, we must reshape `rhs`
# so that it matches the shape of the `info` tensor.
# Plus, we add `.squeeze(1)` to remove the (new)
# dimension at the end of the result
assert np.allclose(np.linalg.solve(info, rhs[..., np.newaxis]).squeeze(-1), res_map)


def test_make_binned_map_api_simulation(tmp_path):
Expand Down
20 changes: 8 additions & 12 deletions test/test_coordinates.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# -*- encoding: utf-8 -*-

import litebird_sim as lbs
import numpy as np
import healpy as hp

import litebird_sim as lbs
from utils import astropy_ecl_to_gal


def test_coordinates():
Expand Down Expand Up @@ -47,26 +48,21 @@ def test_coordinates():

pointings, _ = obs.get_pointings(0, pointings_dtype=np.float64)

r = hp.Rotator(coord=["E", "G"])

pointings_gal_hp = np.empty_like(pointings)

pointings_gal_hp[:, 0:2] = r(pointings[:, 0], pointings[:, 1]).T
pointings_gal_hp[:, 2] = pointings[:, 2] + r.angle_ref(
pointings[:, 0], pointings[:, 1]
pointings_gal_ref = astropy_ecl_to_gal(
pointings[:, 0],
pointings[:, 1],
pointings[:, 2],
)

pointings_gal_lbs = lbs.coordinates.rotate_coordinates_e2g(pointings)

# Calculate the raw difference
diff = pointings_gal_hp - pointings_gal_lbs
diff = pointings_gal_ref - pointings_gal_lbs

# Normalize the angular difference to handle periodicity (wrap-around).
# This maps any difference 'd' to the range [-pi, pi].
# Example: If the difference is ~2pi (e.g., 0.0 vs 6.28), the result becomes ~0.0.
angular_diff = np.arctan2(np.sin(diff), np.cos(diff))

print("\nMax angular error (wrapped):", np.max(np.abs(angular_diff)))

# Verify that the angular distance is effectively zero
np.testing.assert_allclose(angular_diff, 0.0, rtol=1e-6, atol=1e-6)
Loading
Loading