diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3fb1bd..ae2715a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,9 +32,21 @@ jobs: needs: linting runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: - os: [ubuntu-latest] - python-version: ["3.10", "3.11", "3.12", "3.13"] + include: + - os: ubuntu-latest + python-version: "3.10" + tox-env: py310 + - os: ubuntu-latest + python-version: "3.11" + tox-env: py311 + - os: ubuntu-latest + python-version: "3.12" + tox-env: py312 + - os: ubuntu-latest + python-version: "3.13" + tox-env: py313 steps: - uses: actions/checkout@v4 @@ -49,7 +61,7 @@ jobs: run: uv sync --extra dev - name: Run tests - run: uv run tox -m test + run: uv run tox -e ${{ matrix.tox-env }} finalise: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 6d94321..1b5caca 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,10 @@ __pycache__/ .pytest_cache/ .ruff_cache/ .mypy_cache/ +.pyre/ .cache/ .coverage +.coverage.* coverage.xml htmlcov/ @@ -14,6 +16,7 @@ htmlcov/ .venv/ venv/ env/ +ENV/ .tox/ .nox/ @@ -42,6 +45,14 @@ Thumbs.db # IDE files .vscode/ .idea/ +*.iml + +# PyCharm +.idea/ +*.iws +*.ipr +*.iml +.idea_modules/ # Local env files .env diff --git a/docs/_build/html/index.html b/docs/_build/html/index.html deleted file mode 100644 index 35cea5a..0000000 --- a/docs/_build/html/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - -
- -Redirecting to main.
- - \ No newline at end of file diff --git a/src/plima/backends/ccl/__pycache__/__init__.cpython-312.pyc b/src/plima/backends/ccl/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 0a5b408..0000000 Binary files a/src/plima/backends/ccl/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/src/plima/backends/ccl/__pycache__/builder.cpython-312.pyc b/src/plima/backends/ccl/__pycache__/builder.cpython-312.pyc deleted file mode 100644 index 99c7902..0000000 Binary files a/src/plima/backends/ccl/__pycache__/builder.cpython-312.pyc and /dev/null differ diff --git a/src/plima/backends/ccl/__pycache__/halo_model.cpython-312.pyc b/src/plima/backends/ccl/__pycache__/halo_model.cpython-312.pyc deleted file mode 100644 index ec70126..0000000 Binary files a/src/plima/backends/ccl/__pycache__/halo_model.cpython-312.pyc and /dev/null differ diff --git a/src/plima/backends/ccl/__pycache__/la.cpython-312.pyc b/src/plima/backends/ccl/__pycache__/la.cpython-312.pyc deleted file mode 100644 index 7f68537..0000000 Binary files a/src/plima/backends/ccl/__pycache__/la.cpython-312.pyc and /dev/null differ diff --git a/src/plima/backends/ccl/__pycache__/nla.cpython-312.pyc b/src/plima/backends/ccl/__pycache__/nla.cpython-312.pyc deleted file mode 100644 index 2327a20..0000000 Binary files a/src/plima/backends/ccl/__pycache__/nla.cpython-312.pyc and /dev/null differ diff --git a/src/plima/backends/ccl/__pycache__/tatt.cpython-312.pyc b/src/plima/backends/ccl/__pycache__/tatt.cpython-312.pyc deleted file mode 100644 index 19f4fe0..0000000 Binary files a/src/plima/backends/ccl/__pycache__/tatt.cpython-312.pyc and /dev/null differ diff --git a/src/plima/backends/ccl/la.py b/src/plima/backends/ccl/la.py index 59ddf14..dec34af 100644 --- a/src/plima/backends/ccl/la.py +++ b/src/plima/backends/ccl/la.py @@ -50,12 +50,15 @@ def make_ccl_la_ia_bias( validate_greater_than(z_array, threshold=-1.0, name="z") if amplitude is None: - ia_bias = la_amplitude(z_array, a_ia=a_ia) + physical_amplitude = la_amplitude(z_array, a_ia=a_ia) else: amplitude_array = as_finite_float_array(amplitude, name="amplitude") try: - ia_bias = np.broadcast_to(amplitude_array, z_array.shape).astype( + physical_amplitude = np.broadcast_to( + amplitude_array, + z_array.shape, + ).astype( np.float64, copy=True, ) @@ -66,4 +69,8 @@ def make_ccl_la_ia_bias( ) raise ValueError(msg) from error - return z_array.astype(np.float64, copy=True), ia_bias.astype(np.float64, copy=True) + ia_bias = -physical_amplitude + + return z_array.astype(np.float64, copy=True), ia_bias.astype( + np.float64, copy=True + ) diff --git a/src/plima/backends/ccl/nla.py b/src/plima/backends/ccl/nla.py index 79d3b4a..17a73b3 100644 --- a/src/plima/backends/ccl/nla.py +++ b/src/plima/backends/ccl/nla.py @@ -3,8 +3,10 @@ This module connects PLIMA NLA amplitude models to the IA bias tuple expected by CCL weak lensing tracers. -The NLA amplitude model lives in ``plima.models.nla``. This file only prepares -the ``(z, ia_bias)`` tuple used by CCL. +The backend independent NLA model uses a positive physical ``A_IA`` and applies +the physical NLA response sign internally. CCL weak lensing tracers use the +opposite sign convention for the IA bias tuple, so this backend flips the sign +before returning ``(z, ia_bias)``. """ from __future__ import annotations @@ -29,14 +31,22 @@ def make_ccl_nla_ia_bias( ) -> tuple[FloatArray, FloatArray]: """Return a CCL IA bias tuple for NLA. + This backend follows the PLIMA user-facing convention that positive + ``A_IA`` corresponds to a positive physical NLA amplitude. The sign needed + by CCL weak lensing tracers is applied internally, so the returned + ``ia_bias`` is ``-amplitude``. + Args: z: Redshift values where the IA bias should be sampled. - amplitude: Optional precomputed NLA amplitude evaluated at ``z``. If - ``None``, the amplitude is computed from ``nla_amplitude``. - a_ia: NLA amplitude normalization used when ``amplitude`` is ``None``. + amplitude: Optional precomputed positive physical NLA amplitude + evaluated at ``z``. If ``None``, the amplitude is computed from + ``nla_amplitude``. + a_ia: Positive physical NLA amplitude normalization used when + ``amplitude`` is ``None``. Returns: - Redshift values and IA bias values sampled on the same grid. + Redshift values and CCL sign convention IA bias values sampled on the + same grid. Raises: ValueError: If redshifts are not finite, redshifts are outside the @@ -50,12 +60,15 @@ def make_ccl_nla_ia_bias( validate_greater_than(z_array, threshold=-1.0, name="z") if amplitude is None: - ia_bias = nla_amplitude(z_array, a_ia=a_ia) + physical_amplitude = nla_amplitude(z_array, a_ia=a_ia) else: amplitude_array = as_finite_float_array(amplitude, name="amplitude") try: - ia_bias = np.broadcast_to(amplitude_array, z_array.shape).astype( + physical_amplitude = np.broadcast_to( + amplitude_array, + z_array.shape, + ).astype( np.float64, copy=True, ) @@ -66,4 +79,8 @@ def make_ccl_nla_ia_bias( ) raise ValueError(msg) from error - return z_array.astype(np.float64, copy=True), ia_bias.astype(np.float64, copy=True) + ia_bias = -physical_amplitude + + return z_array.astype(np.float64, copy=True), ia_bias.astype( + np.float64, copy=True + ) diff --git a/tests/__pycache__/test_backends_ccl_builder.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_backends_ccl_builder.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index 66faa5b..0000000 Binary files a/tests/__pycache__/test_backends_ccl_builder.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_backends_ccl_halo_model.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_backends_ccl_halo_model.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index b9bad77..0000000 Binary files a/tests/__pycache__/test_backends_ccl_halo_model.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_backends_ccl_la.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_backends_ccl_la.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index 3e2578b..0000000 Binary files a/tests/__pycache__/test_backends_ccl_la.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_backends_ccl_nla.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_backends_ccl_nla.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index 6a9e719..0000000 Binary files a/tests/__pycache__/test_backends_ccl_nla.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_backends_ccl_tatt.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_backends_ccl_tatt.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index 93426f4..0000000 Binary files a/tests/__pycache__/test_backends_ccl_tatt.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_import.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_import.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index a8fe144..0000000 Binary files a/tests/__pycache__/test_import.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_models_discovery.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_models_discovery.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index 3dfde29..0000000 Binary files a/tests/__pycache__/test_models_discovery.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_models_halo_model.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_models_halo_model.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index 30c5cba..0000000 Binary files a/tests/__pycache__/test_models_halo_model.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_models_hybrid.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_models_hybrid.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index 22225c8..0000000 Binary files a/tests/__pycache__/test_models_hybrid.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_models_la.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_models_la.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index 8ac1035..0000000 Binary files a/tests/__pycache__/test_models_la.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_models_model_registry.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_models_model_registry.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index c2ad8dd..0000000 Binary files a/tests/__pycache__/test_models_model_registry.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_models_nla.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_models_nla.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index d049c26..0000000 Binary files a/tests/__pycache__/test_models_nla.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_models_tatt.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_models_tatt.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index 20e0ecf..0000000 Binary files a/tests/__pycache__/test_models_tatt.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_utils_constants.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_utils_constants.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index 1186ba8..0000000 Binary files a/tests/__pycache__/test_utils_constants.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_utils_converters.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_utils_converters.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index 7f0a8f1..0000000 Binary files a/tests/__pycache__/test_utils_converters.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_utils_types.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_utils_types.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index 1d6cd2b..0000000 Binary files a/tests/__pycache__/test_utils_types.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/__pycache__/test_utils_validators.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/test_utils_validators.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index c4a5213..0000000 Binary files a/tests/__pycache__/test_utils_validators.cpython-312-pytest-8.4.2.pyc and /dev/null differ diff --git a/tests/test_backends_ccl_builder.py b/tests/test_backends_ccl_builder.py index 8f233e9..c3c3e76 100644 --- a/tests/test_backends_ccl_builder.py +++ b/tests/test_backends_ccl_builder.py @@ -52,7 +52,9 @@ def test_canonical_model_name_resolves_alias(monkeypatch) -> None: def test_canonical_model_name_returns_unknown_name(monkeypatch) -> None: """Tests that unknown names are returned normalized.""" - monkeypatch.setattr(builder, "list_model_aliases", lambda: {"nla": ("nla_lf",)}) + monkeypatch.setattr( + builder, "list_model_aliases", lambda: {"nla": ("nla_lf",)} + ) assert builder._canonical_model_name("missing") == "missing" @@ -78,7 +80,9 @@ def test_evaluate_amplitude_model_passes_z_when_supported() -> None: """Tests that amplitude models with z receive redshift values.""" z = np.array([0.0, 0.5, 1.0]) - amplitude = builder._evaluate_amplitude_model(_amplitude_with_z, z, a_ia=3.0) + amplitude = builder._evaluate_amplitude_model( + _amplitude_with_z, z, a_ia=3.0 + ) np.testing.assert_allclose(amplitude, np.full_like(z, 3.0)) @@ -156,7 +160,9 @@ def fake_make_ccl_la_ia_bias(z_arg, *, amplitude): np.testing.assert_allclose(amplitude, np.full_like(z, 5.0)) return ("la_z", "la_bias") - monkeypatch.setattr(builder, "make_ccl_la_ia_bias", fake_make_ccl_la_ia_bias) + monkeypatch.setattr( + builder, "make_ccl_la_ia_bias", fake_make_ccl_la_ia_bias + ) result = builder._build_la_model( cosmo=object(), @@ -170,7 +176,9 @@ def fake_make_ccl_la_ia_bias(z_arg, *, amplitude): assert result["family"] == "la" assert result["mode"] == "native_bias" assert result["ia_bias"] == ("la_z", "la_bias") - np.testing.assert_allclose(result["metadata"]["amplitude"], np.full_like(z, 5.0)) + np.testing.assert_allclose( + result["metadata"]["amplitude"], np.full_like(z, 5.0) + ) def test_build_nla_model_delegates_to_nla_bias_builder(monkeypatch) -> None: @@ -183,7 +191,9 @@ def fake_make_ccl_nla_ia_bias(z_arg, *, amplitude): np.testing.assert_allclose(amplitude, np.full_like(z, 6.0)) return ("nla_z", "nla_bias") - monkeypatch.setattr(builder, "make_ccl_nla_ia_bias", fake_make_ccl_nla_ia_bias) + monkeypatch.setattr( + builder, "make_ccl_nla_ia_bias", fake_make_ccl_nla_ia_bias + ) result = builder._build_nla_model( cosmo=object(), @@ -197,10 +207,14 @@ def fake_make_ccl_nla_ia_bias(z_arg, *, amplitude): assert result["family"] == "nla" assert result["mode"] == "native_bias" assert result["ia_bias"] == ("nla_z", "nla_bias") - np.testing.assert_allclose(result["metadata"]["amplitude"], np.full_like(z, 6.0)) + np.testing.assert_allclose( + result["metadata"]["amplitude"], np.full_like(z, 6.0) + ) -def test_build_tatt_model_delegates_to_tatt_spectra_builder(monkeypatch) -> None: +def test_build_tatt_model_delegates_to_tatt_spectra_builder( + monkeypatch, +) -> None: """Tests that TATT models delegate to the TATT spectra builder.""" cosmo = object() z = np.array([0.0, 0.5]) @@ -235,7 +249,9 @@ def fake_make_ccl_tatt_power_spectra(cosmo_arg, z_arg, **kwargs): assert result["metadata"]["raw_backend_result"] == raw_result -def test_build_halo_model_delegates_to_halo_spectra_builder(monkeypatch) -> None: +def test_build_halo_model_delegates_to_halo_spectra_builder( + monkeypatch, +) -> None: """Tests that halo model IA delegates to the halo spectra builder.""" cosmo = object() z = np.array([0.0, 0.5]) @@ -258,7 +274,9 @@ def fake_make_ccl_halo_model_power_spectra(cosmo_arg, z_arg, **kwargs): cosmo=cosmo, model_name="halo_model", canonical_model_name="halo_model", - model_function=_set_module(_amplitude_with_z, "plima.models.halo_model"), + model_function=_set_module( + _amplitude_with_z, "plima.models.halo_model" + ), z=z, a1h=0.01, ) @@ -338,7 +356,9 @@ def fake_family_builder(**kwargs): assert calls[0]["amplitude"] == 1.0 -def test_build_ccl_ia_model_resolves_alias_to_canonical_name(monkeypatch) -> None: +def test_build_ccl_ia_model_resolves_alias_to_canonical_name( + monkeypatch, +) -> None: """Tests that aliases are recorded with their canonical model name.""" z = np.array([0.0, 0.5]) model_function = _set_module(_amplitude_with_z, "plima.models.nla") @@ -356,8 +376,12 @@ def fake_family_builder(**kwargs): } monkeypatch.setattr(builder, "get_model", lambda name: model_function) - monkeypatch.setattr(builder, "list_model_aliases", lambda: {"nla": ("nla_lf",)}) - monkeypatch.setitem(builder._CCL_FAMILY_BUILDERS, "nla", fake_family_builder) + monkeypatch.setattr( + builder, "list_model_aliases", lambda: {"nla": ("nla_lf",)} + ) + monkeypatch.setitem( + builder._CCL_FAMILY_BUILDERS, "nla", fake_family_builder + ) result = builder.build_ccl_ia_model(object(), "NLA_LF", z) @@ -371,11 +395,15 @@ def test_build_ccl_ia_model_raises_for_unknown_family(monkeypatch) -> None: monkeypatch.setattr(builder, "get_model", lambda name: model_function) monkeypatch.setattr(builder, "list_model_aliases", lambda: {"unknown": ()}) - with pytest.raises(ValueError, match="Model family 'unknown' has no CCL builder."): + with pytest.raises( + ValueError, match="Model family 'unknown' has no CCL builder." + ): builder.build_ccl_ia_model(object(), "unknown", np.array([0.0, 0.5])) -def test_build_ccl_ia_model_propagates_missing_model_error(monkeypatch) -> None: +def test_build_ccl_ia_model_propagates_missing_model_error( + monkeypatch, +) -> None: """Tests that missing registry entries keep the registry KeyError.""" def fake_get_model(name: str): @@ -396,14 +424,18 @@ def test_normalize_model_name_rejects_non_string() -> None: def test_canonical_model_name_strips_and_lowers_alias(monkeypatch) -> None: """Tests that canonical model lookup normalizes aliases.""" - monkeypatch.setattr(builder, "list_model_aliases", lambda: {"nla": ("nla_lf",)}) + monkeypatch.setattr( + builder, "list_model_aliases", lambda: {"nla": ("nla_lf",)} + ) assert builder._canonical_model_name(" NLA_LF ") == "nla" def test_model_family_handles_nested_module_family() -> None: """Tests that model family uses the final module component.""" - model_function = _set_module(_amplitude_with_z, "some.package.plima.models.nla") + model_function = _set_module( + _amplitude_with_z, "some.package.plima.models.nla" + ) assert builder._model_family(model_function) == "nla" @@ -433,7 +465,9 @@ def test_evaluate_amplitude_model_forwards_kwargs_when_z_supported() -> None: def model(z, *, scale: float, offset: float): return scale * np.asarray(z) + offset - amplitude = builder._evaluate_amplitude_model(model, z, scale=2.0, offset=1.0) + amplitude = builder._evaluate_amplitude_model( + model, z, scale=2.0, offset=1.0 + ) np.testing.assert_allclose(amplitude, np.array([1.0, 2.0])) @@ -444,7 +478,9 @@ def test_evaluate_amplitude_model_forwards_kwargs_when_z_unsupported() -> None: def model(*, scale: float, offset: float): return scale + offset - amplitude = builder._evaluate_amplitude_model(model, np.array([0.0]), scale=2.0, offset=1.0) + amplitude = builder._evaluate_amplitude_model( + model, np.array([0.0]), scale=2.0, offset=1.0 + ) assert amplitude == 3.0 @@ -480,7 +516,9 @@ def test_pk2d_model_preserves_raw_backend_result_identity() -> None: assert result["metadata"]["raw_backend_result"] is raw_backend_result -def test_build_la_model_omits_cosmo_for_native_bias_builder(monkeypatch) -> None: +def test_build_la_model_omits_cosmo_for_native_bias_builder( + monkeypatch, +) -> None: """Tests that LA native bias construction does not pass cosmology.""" z = np.array([0.0, 0.5]) model_function = _set_module(_amplitude_with_z, "plima.models.la") @@ -491,7 +529,9 @@ def fake_make_ccl_la_ia_bias(*args, **kwargs): assert set(kwargs) == {"amplitude"} return ("z", "bias") - monkeypatch.setattr(builder, "make_ccl_la_ia_bias", fake_make_ccl_la_ia_bias) + monkeypatch.setattr( + builder, "make_ccl_la_ia_bias", fake_make_ccl_la_ia_bias + ) result = builder._build_la_model( cosmo=object(), @@ -504,7 +544,9 @@ def fake_make_ccl_la_ia_bias(*args, **kwargs): assert result["mode"] == "native_bias" -def test_build_nla_model_omits_cosmo_for_native_bias_builder(monkeypatch) -> None: +def test_build_nla_model_omits_cosmo_for_native_bias_builder( + monkeypatch, +) -> None: """Tests that NLA native bias construction does not pass cosmology.""" z = np.array([0.0, 0.5]) model_function = _set_module(_amplitude_with_z, "plima.models.nla") @@ -515,7 +557,9 @@ def fake_make_ccl_nla_ia_bias(*args, **kwargs): assert set(kwargs) == {"amplitude"} return ("z", "bias") - monkeypatch.setattr(builder, "make_ccl_nla_ia_bias", fake_make_ccl_nla_ia_bias) + monkeypatch.setattr( + builder, "make_ccl_nla_ia_bias", fake_make_ccl_nla_ia_bias + ) result = builder._build_nla_model( cosmo=object(), @@ -569,14 +613,18 @@ def test_build_halo_model_ignores_model_function(monkeypatch) -> None: cosmo=cosmo, model_name="halo_model", canonical_model_name="halo_model", - model_function=_set_module(_amplitude_without_z, "plima.models.halo_model"), + model_function=_set_module( + _amplitude_without_z, "plima.models.halo_model" + ), z=z, ) assert result["spectra"] == spectra -def test_build_ccl_ia_model_uses_family_not_canonical_name(monkeypatch) -> None: +def test_build_ccl_ia_model_uses_family_not_canonical_name( + monkeypatch, +) -> None: """Tests that dispatch follows the model function family.""" z = np.array([0.0, 0.5]) model_function = _set_module(_amplitude_with_z, "plima.models.nla") @@ -594,8 +642,12 @@ def fake_family_builder(**kwargs): } monkeypatch.setattr(builder, "get_model", lambda name: model_function) - monkeypatch.setattr(builder, "list_model_aliases", lambda: {"some_alias": ()}) - monkeypatch.setitem(builder._CCL_FAMILY_BUILDERS, "nla", fake_family_builder) + monkeypatch.setattr( + builder, "list_model_aliases", lambda: {"some_alias": ()} + ) + monkeypatch.setitem( + builder._CCL_FAMILY_BUILDERS, "nla", fake_family_builder + ) result = builder.build_ccl_ia_model(object(), "some_alias", z) @@ -623,7 +675,9 @@ def fake_family_builder(**kwargs): monkeypatch.setattr(builder, "get_model", lambda name: model_function) monkeypatch.setattr(builder, "list_model_aliases", lambda: {"la": ()}) - monkeypatch.setitem(builder._CCL_FAMILY_BUILDERS, "la", fake_family_builder) + monkeypatch.setitem( + builder._CCL_FAMILY_BUILDERS, "la", fake_family_builder + ) builder.build_ccl_ia_model( object(), diff --git a/tests/test_backends_ccl_halo_model.py b/tests/test_backends_ccl_halo_model.py index da59e09..6f1075b 100644 --- a/tests/test_backends_ccl_halo_model.py +++ b/tests/test_backends_ccl_halo_model.py @@ -85,10 +85,7 @@ def test_halo_model_nla_prefactor_matches_expected_formula( ) expected = ( - a_ia - * c1_rho_critical - * cosmo["Omega_m"] - / cosmo.growth_factor(a) + a_ia * c1_rho_critical * cosmo["Omega_m"] / cosmo.growth_factor(a) ) np.testing.assert_allclose(prefactor, expected) @@ -150,7 +147,9 @@ def test_power_grid_accepts_transposed_shape( a: np.ndarray, ) -> None: """Tests that power grid validation transposes CCL style grids.""" - values = np.arange(k.size * a.size, dtype=np.float64).reshape(k.size, a.size) + values = np.arange(k.size * a.size, dtype=np.float64).reshape( + k.size, a.size + ) grid = _power_grid(values, k=k, a=a, name="values") @@ -358,7 +357,9 @@ def test_evaluate_pk2d_grid_rejects_nonfinite_values( """Tests that Pk2D grid evaluation rejects nonfinite values.""" class BadPk2D: - def __call__(self, k_eval: np.ndarray, a_eval: np.ndarray) -> np.ndarray: + def __call__( + self, k_eval: np.ndarray, a_eval: np.ndarray + ) -> np.ndarray: values = np.ones((a_eval.size, k_eval.size)) values[0, 0] = np.nan return values diff --git a/tests/test_backends_ccl_la.py b/tests/test_backends_ccl_la.py index 2f78803..939cece 100644 --- a/tests/test_backends_ccl_la.py +++ b/tests/test_backends_ccl_la.py @@ -15,7 +15,7 @@ def test_make_ccl_la_ia_bias_uses_default_amplitude() -> None: z_out, ia_bias = make_ccl_la_ia_bias(z, a_ia=2.5) np.testing.assert_allclose(z_out, z) - np.testing.assert_allclose(ia_bias, np.full_like(z, 2.5)) + np.testing.assert_allclose(ia_bias, np.full_like(z, -2.5)) assert z_out.dtype == np.float64 assert ia_bias.dtype == np.float64 @@ -28,7 +28,7 @@ def test_make_ccl_la_ia_bias_uses_precomputed_amplitude() -> None: z_out, ia_bias = make_ccl_la_ia_bias(z, amplitude=amplitude) np.testing.assert_allclose(z_out, z) - np.testing.assert_allclose(ia_bias, amplitude) + np.testing.assert_allclose(ia_bias, -amplitude) def test_make_ccl_la_ia_bias_accepts_scalar_amplitude_for_scalar_z() -> None: @@ -36,7 +36,7 @@ def test_make_ccl_la_ia_bias_accepts_scalar_amplitude_for_scalar_z() -> None: z_out, ia_bias = make_ccl_la_ia_bias(0.5, amplitude=2.0) np.testing.assert_allclose(z_out, np.array([0.5])) - np.testing.assert_allclose(ia_bias, np.array([2.0])) + np.testing.assert_allclose(ia_bias, np.array([-2.0])) assert z_out.shape == (1,) assert ia_bias.shape == (1,) @@ -48,7 +48,7 @@ def test_make_ccl_la_ia_bias_accepts_scalar_amplitude_for_array_z() -> None: z_out, ia_bias = make_ccl_la_ia_bias(z, amplitude=2.0) np.testing.assert_allclose(z_out, z) - np.testing.assert_allclose(ia_bias, np.array([2.0, 2.0, 2.0])) + np.testing.assert_allclose(ia_bias, np.array([-2.0, -2.0, -2.0])) def test_make_ccl_la_ia_bias_rejects_amplitude_shape_mismatch() -> None: @@ -91,7 +91,9 @@ def test_make_ccl_la_ia_bias_rejects_nonfinite_amplitude( """Tests that LA IA bias rejects nonfinite amplitude values.""" z = np.array([0.0, 0.5]) - with pytest.raises(ValueError, match="amplitude must contain only finite values."): + with pytest.raises( + ValueError, match="amplitude must contain only finite values." + ): make_ccl_la_ia_bias(z, amplitude=amplitude) @@ -103,7 +105,9 @@ def test_make_ccl_la_ia_bias_rejects_nonfinite_amplitude( np.array([0.0, -1.0]), ], ) -def test_make_ccl_la_ia_bias_rejects_invalid_redshift_domain(z: np.ndarray) -> None: +def test_make_ccl_la_ia_bias_rejects_invalid_redshift_domain( + z: np.ndarray, +) -> None: """Tests that LA IA bias rejects redshift values less than or equal to minus one.""" with pytest.raises( ValueError, @@ -120,7 +124,7 @@ def test_make_ccl_la_ia_bias_preserves_redshift_and_amplitude_order() -> None: z_out, ia_bias = make_ccl_la_ia_bias(z, amplitude=amplitude) np.testing.assert_allclose(z_out, z) - np.testing.assert_allclose(ia_bias, amplitude) + np.testing.assert_allclose(ia_bias, -amplitude) def test_make_ccl_la_ia_bias_returns_copies_as_float_arrays() -> None: @@ -131,7 +135,7 @@ def test_make_ccl_la_ia_bias_returns_copies_as_float_arrays() -> None: z_out, ia_bias = make_ccl_la_ia_bias(z, amplitude=amplitude) np.testing.assert_allclose(z_out, np.array([1.0, 0.0])) - np.testing.assert_allclose(ia_bias, np.array([2.0, 1.0])) + np.testing.assert_allclose(ia_bias, np.array([-2.0, -1.0])) assert z_out.dtype == np.float64 assert ia_bias.dtype == np.float64 @@ -144,7 +148,7 @@ def test_make_ccl_la_ia_bias_accepts_list_redshift_and_amplitude() -> None: z_out, ia_bias = make_ccl_la_ia_bias(z, amplitude=amplitude) np.testing.assert_allclose(z_out, np.array(z)) - np.testing.assert_allclose(ia_bias, np.array(amplitude)) + np.testing.assert_allclose(ia_bias, -np.array(amplitude)) assert z_out.dtype == np.float64 assert ia_bias.dtype == np.float64 @@ -180,7 +184,7 @@ def test_make_ccl_la_ia_bias_returns_independent_arrays() -> None: amplitude[0] = 99.0 np.testing.assert_allclose(z_out, np.array([0.0, 0.5, 1.0])) - np.testing.assert_allclose(ia_bias, np.array([1.0, 2.0, 3.0])) + np.testing.assert_allclose(ia_bias, np.array([-1.0, -2.0, -3.0])) def test_make_ccl_la_ia_bias_rejects_empty_redshift() -> None: @@ -189,7 +193,9 @@ def test_make_ccl_la_ia_bias_rejects_empty_redshift() -> None: make_ccl_la_ia_bias(np.array([])) -def test_make_ccl_la_ia_bias_rejects_empty_amplitude_for_nonempty_redshift() -> None: +def test_make_ccl_la_ia_bias_rejects_empty_amplitude_for_nonempty_redshift() -> ( + None +): """Tests that LA IA bias rejects empty amplitudes for nonempty redshift arrays.""" z = np.array([0.0, 0.5]) @@ -208,4 +214,4 @@ def test_make_ccl_la_ia_bias_accepts_length_one_amplitude_array() -> None: z_out, ia_bias = make_ccl_la_ia_bias(z, amplitude=amplitude) np.testing.assert_allclose(z_out, z) - np.testing.assert_allclose(ia_bias, np.full_like(z, 2.0)) + np.testing.assert_allclose(ia_bias, np.full_like(z, -2.0)) diff --git a/tests/test_backends_ccl_nla.py b/tests/test_backends_ccl_nla.py index 26afee5..fc0fca3 100644 --- a/tests/test_backends_ccl_nla.py +++ b/tests/test_backends_ccl_nla.py @@ -15,7 +15,7 @@ def test_make_ccl_nla_ia_bias_uses_default_amplitude() -> None: z_out, ia_bias = make_ccl_nla_ia_bias(z, a_ia=2.5) np.testing.assert_allclose(z_out, z) - np.testing.assert_allclose(ia_bias, np.full_like(z, 2.5)) + np.testing.assert_allclose(ia_bias, np.full_like(z, -2.5)) assert z_out.dtype == np.float64 assert ia_bias.dtype == np.float64 @@ -28,7 +28,7 @@ def test_make_ccl_nla_ia_bias_uses_precomputed_amplitude() -> None: z_out, ia_bias = make_ccl_nla_ia_bias(z, amplitude=amplitude) np.testing.assert_allclose(z_out, z) - np.testing.assert_allclose(ia_bias, amplitude) + np.testing.assert_allclose(ia_bias, -amplitude) def test_make_ccl_nla_ia_bias_accepts_scalar_amplitude_for_scalar_z() -> None: @@ -36,7 +36,7 @@ def test_make_ccl_nla_ia_bias_accepts_scalar_amplitude_for_scalar_z() -> None: z_out, ia_bias = make_ccl_nla_ia_bias(0.5, amplitude=2.0) np.testing.assert_allclose(z_out, np.array([0.5])) - np.testing.assert_allclose(ia_bias, np.array([2.0])) + np.testing.assert_allclose(ia_bias, np.array([-2.0])) assert z_out.shape == (1,) assert ia_bias.shape == (1,) @@ -48,7 +48,7 @@ def test_make_ccl_nla_ia_bias_accepts_scalar_amplitude_for_array_z() -> None: z_out, ia_bias = make_ccl_nla_ia_bias(z, amplitude=2.0) np.testing.assert_allclose(z_out, z) - np.testing.assert_allclose(ia_bias, np.array([2.0, 2.0, 2.0])) + np.testing.assert_allclose(ia_bias, np.array([-2.0, -2.0, -2.0])) def test_make_ccl_nla_ia_bias_rejects_amplitude_shape_mismatch() -> None: @@ -71,7 +71,9 @@ def test_make_ccl_nla_ia_bias_rejects_amplitude_shape_mismatch() -> None: np.array([0.0, -np.inf]), ], ) -def test_make_ccl_nla_ia_bias_rejects_nonfinite_redshift(z: np.ndarray) -> None: +def test_make_ccl_nla_ia_bias_rejects_nonfinite_redshift( + z: np.ndarray, +) -> None: """Tests that NLA IA bias rejects nonfinite redshift values.""" with pytest.raises(ValueError, match="z must contain only finite values."): make_ccl_nla_ia_bias(z) @@ -91,7 +93,9 @@ def test_make_ccl_nla_ia_bias_rejects_nonfinite_amplitude( """Tests that NLA IA bias rejects nonfinite amplitude values.""" z = np.array([0.0, 0.5]) - with pytest.raises(ValueError, match="amplitude must contain only finite values."): + with pytest.raises( + ValueError, match="amplitude must contain only finite values." + ): make_ccl_nla_ia_bias(z, amplitude=amplitude) @@ -103,7 +107,9 @@ def test_make_ccl_nla_ia_bias_rejects_nonfinite_amplitude( np.array([0.0, -1.0]), ], ) -def test_make_ccl_nla_ia_bias_rejects_invalid_redshift_domain(z: np.ndarray) -> None: +def test_make_ccl_nla_ia_bias_rejects_invalid_redshift_domain( + z: np.ndarray, +) -> None: """Tests that NLA IA bias rejects redshift values less than or equal to minus one.""" with pytest.raises( ValueError, @@ -120,7 +126,7 @@ def test_make_ccl_nla_ia_bias_preserves_redshift_and_amplitude_order() -> None: z_out, ia_bias = make_ccl_nla_ia_bias(z, amplitude=amplitude) np.testing.assert_allclose(z_out, z) - np.testing.assert_allclose(ia_bias, amplitude) + np.testing.assert_allclose(ia_bias, -amplitude) def test_make_ccl_nla_ia_bias_returns_copies_as_float_arrays() -> None: @@ -131,7 +137,7 @@ def test_make_ccl_nla_ia_bias_returns_copies_as_float_arrays() -> None: z_out, ia_bias = make_ccl_nla_ia_bias(z, amplitude=amplitude) np.testing.assert_allclose(z_out, np.array([1.0, 0.0])) - np.testing.assert_allclose(ia_bias, np.array([2.0, 1.0])) + np.testing.assert_allclose(ia_bias, np.array([-2.0, -1.0])) assert z_out.dtype == np.float64 assert ia_bias.dtype == np.float64 @@ -144,7 +150,7 @@ def test_make_ccl_nla_ia_bias_accepts_list_redshift_and_amplitude() -> None: z_out, ia_bias = make_ccl_nla_ia_bias(z, amplitude=amplitude) np.testing.assert_allclose(z_out, np.array(z)) - np.testing.assert_allclose(ia_bias, np.array(amplitude)) + np.testing.assert_allclose(ia_bias, -np.array(amplitude)) assert z_out.dtype == np.float64 assert ia_bias.dtype == np.float64 @@ -180,7 +186,7 @@ def test_make_ccl_nla_ia_bias_returns_independent_arrays() -> None: amplitude[0] = 99.0 np.testing.assert_allclose(z_out, np.array([0.0, 0.5, 1.0])) - np.testing.assert_allclose(ia_bias, np.array([1.0, 2.0, 3.0])) + np.testing.assert_allclose(ia_bias, np.array([-1.0, -2.0, -3.0])) def test_make_ccl_nla_ia_bias_rejects_empty_redshift() -> None: @@ -189,7 +195,9 @@ def test_make_ccl_nla_ia_bias_rejects_empty_redshift() -> None: make_ccl_nla_ia_bias(np.array([])) -def test_make_ccl_nla_ia_bias_rejects_empty_amplitude_for_nonempty_redshift() -> None: +def test_make_ccl_nla_ia_bias_rejects_empty_amplitude_for_nonempty_redshift() -> ( + None +): """Tests that NLA IA bias rejects empty amplitudes for nonempty redshift arrays.""" z = np.array([0.0, 0.5]) @@ -208,4 +216,4 @@ def test_make_ccl_nla_ia_bias_accepts_length_one_amplitude_array() -> None: z_out, ia_bias = make_ccl_nla_ia_bias(z, amplitude=amplitude) np.testing.assert_allclose(z_out, z) - np.testing.assert_allclose(ia_bias, np.full_like(z, 2.0)) + np.testing.assert_allclose(ia_bias, np.full_like(z, -2.0)) diff --git a/tests/test_models_discovery.py b/tests/test_models_discovery.py index 53066ad..2247611 100644 --- a/tests/test_models_discovery.py +++ b/tests/test_models_discovery.py @@ -31,13 +31,18 @@ def fake_import_module(module_name: str): return SimpleNamespace() monkeypatch.setattr(_discovery.pkgutil, "iter_modules", fake_iter_modules) - monkeypatch.setattr(_discovery.importlib, "import_module", fake_import_module) + monkeypatch.setattr( + _discovery.importlib, "import_module", fake_import_module + ) _discovery.import_model_modules() assert imported_modules == [] -def test_import_model_modules_skips_registry_and_helper_modules(monkeypatch) -> None: + +def test_import_model_modules_skips_registry_and_helper_modules( + monkeypatch, +) -> None: """Tests that registry and helper modules are not imported.""" module_names = [ "_discovery", @@ -54,7 +59,9 @@ def fake_import_module(module_name: str): return SimpleNamespace() monkeypatch.setattr(_discovery.pkgutil, "iter_modules", fake_iter_modules) - monkeypatch.setattr(_discovery.importlib, "import_module", fake_import_module) + monkeypatch.setattr( + _discovery.importlib, "import_module", fake_import_module + ) _discovery.import_model_modules() @@ -166,4 +173,3 @@ def test_real_discovery_retrieves_halo_model() -> None: np.testing.assert_allclose(parameters["b"], [-2.0, -2.0, -2.0]) np.testing.assert_allclose(parameters["k_1h"], [1.5, 1.5, 1.5]) np.testing.assert_allclose(parameters["k_2h"], [0.2, 0.2, 0.2]) - diff --git a/tests/test_models_halo_model.py b/tests/test_models_halo_model.py index c52593b..b72a8dd 100644 --- a/tests/test_models_halo_model.py +++ b/tests/test_models_halo_model.py @@ -219,7 +219,9 @@ def test_halo_model_ia_parameters_accepts_negative_amplitudes() -> None: np.testing.assert_allclose(parameters["b"], np.full_like(z, -1.7)) -def test_halo_model_ia_parameters_transition_scales_follow_input_shape() -> None: +def test_halo_model_ia_parameters_transition_scales_follow_input_shape() -> ( + None +): """Tests that halo model IA transition scales follow the redshift shape.""" z = np.array( [ diff --git a/tests/test_models_la.py b/tests/test_models_la.py index 9acfebd..b9c3715 100644 --- a/tests/test_models_la.py +++ b/tests/test_models_la.py @@ -91,7 +91,9 @@ def test_la_mass_amplitude_matches_mass_scaling() -> None: beta=beta, ) - expected = a_ia * red_fraction * (halo_mass / DEFAULT_PIVOT_HALO_MASS) ** beta + expected = ( + a_ia * red_fraction * (halo_mass / DEFAULT_PIVOT_HALO_MASS) ** beta + ) np.testing.assert_allclose(amplitude, expected) assert amplitude.dtype == np.float64 @@ -100,7 +102,9 @@ def test_la_mass_amplitude_matches_mass_scaling() -> None: def test_la_mass_amplitude_accepts_broadcastable_inputs() -> None: """Tests that mass dependent LA amplitude accepts broadcastable inputs.""" - halo_mass = np.array([DEFAULT_PIVOT_HALO_MASS, 2.0 * DEFAULT_PIVOT_HALO_MASS]) + halo_mass = np.array( + [DEFAULT_PIVOT_HALO_MASS, 2.0 * DEFAULT_PIVOT_HALO_MASS] + ) amplitude = la_mass_amplitude( a_ia=2.0, @@ -307,7 +311,9 @@ def red_fraction( return 1.2 -def test_red_fraction_from_luminosity_functions_rejects_invalid_fraction() -> None: +def test_red_fraction_from_luminosity_functions_rejects_invalid_fraction() -> ( + None +): """Tests that red fraction helper rejects invalid returned fractions.""" red_lf = SimpleNamespace(fractions=InvalidFakeFractions()) @@ -322,7 +328,9 @@ def test_red_fraction_from_luminosity_functions_rejects_invalid_fraction() -> No ) -def test_red_fraction_from_luminosity_functions_rejects_invalid_limits() -> None: +def test_red_fraction_from_luminosity_functions_rejects_invalid_limits() -> ( + None +): """Tests that red fraction helper rejects invalid magnitude limits.""" red_lf = SimpleNamespace(fractions=FakeFractions()) @@ -411,7 +419,9 @@ def test_lf_la_amplitude_rejects_invalid_redshift() -> None: def test_lf_la_amplitude_rejects_invalid_red_fraction() -> None: """Tests that LF weighted LA amplitude rejects invalid red fractions.""" with pytest.raises(ValueError): - lf_la_amplitude([0.0, 0.5], [1.0, 1.0], a_ia=1.0, red_fraction=[0.5, -0.1]) + lf_la_amplitude( + [0.0, 0.5], [1.0, 1.0], a_ia=1.0, red_fraction=[0.5, -0.1] + ) def test_lf_la_amplitude_rejects_invalid_low_z_pivot() -> None: diff --git a/tests/test_models_nla.py b/tests/test_models_nla.py index bc3b993..4975228 100644 --- a/tests/test_models_nla.py +++ b/tests/test_models_nla.py @@ -130,8 +130,18 @@ def test_nla_mass_scalar() -> None: @pytest.mark.parametrize( ("red_fraction", "halo_mass", "pivot_halo_mass", "match"), [ - ([-0.1, 0.5], [1.0e13, 2.0e13], DEFAULT_PIVOT_HALO_MASS, "red_fraction"), - ([0.1, 1.2], [1.0e13, 2.0e13], DEFAULT_PIVOT_HALO_MASS, "red_fraction"), + ( + [-0.1, 0.5], + [1.0e13, 2.0e13], + DEFAULT_PIVOT_HALO_MASS, + "red_fraction", + ), + ( + [0.1, 1.2], + [1.0e13, 2.0e13], + DEFAULT_PIVOT_HALO_MASS, + "red_fraction", + ), ([0.1, 0.5], [0.0, 2.0e13], DEFAULT_PIVOT_HALO_MASS, "halo_mass"), ([0.1, 0.5], [1.0e13, 2.0e13], 0.0, "pivot_halo_mass"), ], @@ -490,7 +500,12 @@ def test_registry_aliases() -> None: assert aliases["nla"] == ("constant_nla", "nla_constant") assert aliases["nla_z"] == ("z_nla", "redshift_nla", "nla_redshift") - assert aliases["nla_m"] == ("m_nla", "mass_nla", "nla_mass", "halo_mass_nla") + assert aliases["nla_m"] == ( + "m_nla", + "mass_nla", + "nla_mass", + "halo_mass_nla", + ) assert aliases["nla_lf"] == ( "lf_nla", "luminosity_nla", diff --git a/tests/test_models_tatt.py b/tests/test_models_tatt.py index 42c31fd..d0df1c8 100644 --- a/tests/test_models_tatt.py +++ b/tests/test_models_tatt.py @@ -150,9 +150,7 @@ def test_tatt_normalized_coefficients_applies_amplitudes() -> None: expected_c1 = -a1_z * c1_rho_critical * omega_m / growth_factor expected_c2 = a2_z * 5.0 * c1_rho_critical * omega_m / growth_factor**2 - expected_cdelta = ( - -a1delta_z * c1_rho_critical * omega_m / growth_factor - ) + expected_cdelta = -a1delta_z * c1_rho_critical * omega_m / growth_factor np.testing.assert_allclose(coefficients["c1"], expected_c1) np.testing.assert_allclose(coefficients["c2"], expected_c2) @@ -189,7 +187,9 @@ def test_tatt_normalized_coefficients_supports_omega_m_squared_c2() -> None: np.testing.assert_allclose(coefficients["c2"], expected_c2) -def test_tatt_normalized_coefficients_rejects_growth_factor_shape_mismatch() -> None: +def test_tatt_normalized_coefficients_rejects_growth_factor_shape_mismatch() -> ( + None +): """Tests that normalized TATT coefficients reject growth factor shape mismatch.""" z = np.array([0.0, 0.5]) growth_factor = np.array([1.0, 0.8, 0.6])