Skip to content

refactor(core): consistent call conventions in the mass-definition modules - #445

Merged
steven-murray merged 3 commits into
mainfrom
refactor/core-mass-definition-conventions
Nov 8, 2026
Merged

steven-murray merged 3 commits into
mainfrom
refactor/core-mass-definition-conventions

Conversation

@steven-murray

@steven-murray steven-murray commented Nov 8, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Makes the mass-definition, concentration, conversion and profile modules of hmf.core call the same way as MassFunction and LinearPower: keyword-only arguments, one name per operation, one calibration-domain API. These modules are unreleased and experimental, so there are no deprecation aliases. Results are bit-identical.

Renames and signature changes (old → new)

hmf.core.mass_definitions.MassDefinition

Old New
m_to_r(m, *, omega_m_z, rho_mean0) radius_from_m(*, m, omega_m_z, rho_mean0)
r_to_m(r, *, omega_m_z, rho_mean0) m_from_radius(*, r, omega_m_z, rho_mean0)
m_to_r_kernel(m, *, omega_m_z, rho_mean0) radius_from_m_kernel(*, m, omega_m_z, rho_mean0)
r_to_m_kernel(r, *, omega_m_z, rho_mean0) m_from_radius_kernel(*, r, omega_m_z, rho_mean0)
delta_halo_mean(omega_m_z) delta_halo_mean(*, omega_m_z)
delta_halo_mean_kernel(omega_m_z) delta_halo_mean_kernel(*, omega_m_z)

hmf.core.concentration.ConcentrationModel

Old New
concentration(m, *, z) concentration(*, m, z)
ln_concentration_and_slope_kernel(m, *, z) ln_concentration_and_slope_kernel(*, m, z)
in_calibration_domain_kernel(m, *, z) in_calibration_domain_kernel(*, m, z)

hmf.core.mass_conversion.MassConversion

Old New
convert(m, *, z, omega_m_z, source, target) convert(*, m, z, omega_m_z, source, target)
convert_kernel(m, *, z, omega_m_z, source, target) convert_kernel(*, m, z, omega_m_z, source, target)

hmf.core.profiles.DensityProfile

Old New
mu(x) mu(*, x)
ln_mu_and_slope_kernel(x) ln_mu_and_slope_kernel(*, x)
convert_concentration_kernel(c, *, slope, ln_q) convert_concentration_kernel(*, c, slope, ln_q)

hmf.core.fits.FittingFunction

Old New
in_calibration_domain(x) in_calibration_domain_kernel(x). It now checks x against valid_domain (raising DomainError), like every other *_kernel. evaluate_fsigma doesn't repeat that check, because fsigma_kernel has already done it.

x stays positional here, to match fsigma_kernel(x): it's a FitInputs bundle, not an array.

The calibration-domain API

hmf.core.domain.Calibrated is a mixin with empty __slots__. Every model kind with calibration ranges now uses it: FittingFunction, ConcentrationModel, DensityProfile, Filter, and TransferModel / GrowthModel (through _CosmologyModel).

  • model.calibration (instance property) is the API. It gives where this instance was calibrated, or None if it wasn't.
  • cls.calibration_domain (class variable) is the calibration of the class's default parameters, and calibration returns it unless the model overrides it.
  • Duffy08.calibration gives z = 0 for redshifts="0", while Duffy08.calibration_domain stays the z = 0–2 default.
  • FittingFunction.in_calibration_domain_kernel, evaluate_fsigma, ConcentrationModel.in_calibration_domain_kernel and ProfileConversion all read calibration. A fit whose calibration depends on its parameters is masked by its own range (tested).
  • The concentration, fits and domain module docs, docs/core.rst (one sentence in "Domains") and the model-class doc template now point to calibration.

Removed kernels

hmf.core._kernels.mass_conversion: nfw_ln_mu, nfw_ln_mu_slope, nfw_concentration_ratio_solve, nfw_convert. The library didn't use them. Their physical tests (closed form and series, ψ against a numerical derivative, round-off residual of the solve over 1e-3 < c < 1e4 and 1e-4 < q < 1e4, batch independence, the exact identity at q = 1, agreement with the v3 brentq solve, the Hu & Kravtsov accuracy, the Jacobian against a finite difference) now run through NFW().ln_mu_and_slope_kernel and NFW().convert_concentration_kernel. nfw_ln_mean_density and hu_kravtsov_inverse stay, because nfw_start uses them.

SOGeneric names round-trip

  • MassDefinition.from_name parses "so(preferred <name>)".
  • It raises ValueError when the preferred definition isn't an SOMean, SOCritical or SOVirial.
  • Names now write a number in full when :g would round it. Before, SOMean(18 pi^2).name was "177.653m", which read back as a different definition. Names that were already exact ("200m", "500c", "fof(b=0.2)", …) don't change.
  • A parametrised test round-trips every definition type, including those numbers.

Call sites

  • mass_function.py: four one-line changes (m=m, omega_m_z=omega_m_z, and two in_calibration_domain_kernel calls).
  • tests/regression/v4_providers.py: one keyword.

Checks

  • uv run pytest tests/core tests/regression: 2319 passed, 11 skipped. Every touched hmf.core file is at 100% coverage. The global 95% gate counts v3 code, so it needs the full suite.
  • uv run pytest benchmarks/test_gates.py: 25 passed.
  • uv run mypy: clean.
  • uv run prek run --files …: clean.
  • sphinx-build -W --keep-going: succeeded.

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Maintenance (refactoring, CI, dependencies, etc.)

Checklist

I have

  • Added or updated tests covering this change.
  • Updated docstrings and/or docs where relevant.

Generated by Claude Code

Summary by Sourcery

Standardize experimental core model interfaces and calibration-domain handling while consolidating profile kernels and preserving existing numerical results.

New Features:

  • Add round-trip parsing and formatting for SOGeneric and spherical-overdensity mass-definition names.

Bug Fixes:

  • Ensure mass-definition names preserve enough numeric precision to reconstruct equivalent definitions.

Enhancements:

  • Standardize core model APIs around keyword-only arguments and consistent operation names.
  • Introduce a shared instance-level calibration-domain API across calibrated model kinds.
  • Route NFW profile calculations and conversion tests through DensityProfile kernels.

Documentation:

  • Update core and model documentation to describe instance calibration domains and the standardized APIs.

Tests:

  • Expand core tests for keyword-only interfaces, instance-dependent calibration domains, mass-definition name round trips, and profile-kernel behavior.

Chores:

  • Remove unused mass-conversion kernels and their direct test usage while preserving bit-identical results.

…dules

- Keyword-only m, r, z, x, c and omega_m_z in the public and *_kernel methods
  of mass_definitions, concentration, mass_conversion and profiles.
- Rename MassDefinition.m_to_r / r_to_m (and their kernels) to
  radius_from_m / m_from_radius, as in MassVariance and MassFunction.
- One calibration-domain API: the Calibrated mixin in hmf.core.domain gives
  every kind with calibration ranges (fits, concentration, profiles, filters,
  transfer and growth models) an instance property `calibration`, defaulting
  to the class's calibration_domain. Duffy08 overrides it per redshift range;
  evaluate_fsigma and the fits use it.
- Rename FittingFunction.in_calibration_domain to
  in_calibration_domain_kernel; it checks the valid domain, like every kernel.
- Remove the NFW kernels only the tests used (nfw_ln_mu, nfw_ln_mu_slope,
  nfw_concentration_ratio_solve, nfw_convert); the tests go through NFW().
- MassDefinition.from_name parses SOGeneric names, and names write numbers
  that :g would round in full, so every name round-trips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019U8u424ZT3yjRFWgUZTC2n
@steven-murray steven-murray added API Breaking Breaking Changes type: maint: refactoring Refactoring labels Nov 8, 2026 — with Claude
@sourcery-ai

sourcery-ai Bot commented Nov 8, 2026

Copy link
Copy Markdown

Sorry @steven-murray, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 4 days and 5 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Nov 8, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Data structures

Introduce the Calibrated mixin as the shared instance-level calibration interface, defaulting to each model kind’s class calibration domain.

  • src/hmf/core/_cosmology_models.py L6-7, L22-25, L41 (removed lines)
  • src/hmf/core/domain.py L3-18, L413-436 (+2 small edits)

Make concentration, fits, filters and density profiles calibrated model kinds, and route instance calibration checks and fit evaluation through calibration.

  • src/hmf/core/concentration.py L13-256 (10 small edits)
  • src/hmf/core/filters.py L30, L68
  • src/hmf/core/fits.py L87-92, L711-714, L731-735 (+5 small edits)
  • src/hmf/core/profiles.py L41, L53

Make mass-definition names round-trip precisely, including parsing valid SOGeneric preferred definitions.

  • src/hmf/core/mass_definitions.py L155-158, L176-184, L417-422 (+5 small edits)

API

Standardize public and kernel call signatures on keyword-only operation inputs, and rename mass-radius operations for clarity.

  • src/hmf/core/mass_conversion.py L153, L189
  • src/hmf/core/mass_definitions.py L266-270, L389-393 (+8 small edits)
  • src/hmf/core/profiles.py L79-160 (4 small edits)

Rename the fit calibration check to its kernel API, validate inputs against the valid domain, and remove unused low-level NFW conversion entry points.

  • src/hmf/core/_kernels/mass_conversion.py L49-295 (4 small edits)

Uses of the API

Update internal consumers to pass renamed operation arguments by keyword and to use the profile conversion API and instance calibration checks.

  • src/hmf/core/mass_conversion.py L284-287, L292-300, L355-359 (+3 small edits)
  • src/hmf/core/mass_function.py L525, L649, L972-976

Update the regression provider to call the mass-definition kernel with its keyword-only argument.

  • tests/regression/v4_providers.py L166

Implementation

Implement the shared NFW profile calculations through combined log-mass-and-slope evaluation and adjust their kernel documentation and exports.

  • src/hmf/core/_kernels/mass_conversion.py L79-83 (+5 small edits)

Documentation

Revise core and model documentation to describe instance calibration and the renamed mass-radius and profile conversion APIs.

  • docs/core.rst L131-135
  • docs/templates/core-model-class.rst L11
  • src/hmf/core/mass_definitions.py L31

Tests

Exercise calibration inheritance and instance-specific behavior, keyword-only APIs, name round-trips, and profile-backed conversion behavior.

  • tests/core/test_core_concentration.py L62-69, L85-92, L102-126 (+4 small edits)
  • tests/core/test_core_domain.py L423-489
  • tests/core/test_core_fits.py L872, L1021
  • tests/core/test_core_kernel_safety.py L397-402, L418-443 (+4 small edits)
  • tests/core/test_core_mass_conversion.py L49-74, L80-89, L274-282 (+25 small edits)
  • tests/core/test_core_mass_definitions.py L92-107, L119-130, L278-301 (+10 small edits)
  • tests/core/test_core_profiles.py L49-79, L107-115 (+5 small edits)

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions github-actions Bot added the type: maint: documentation Improvements or additions to documentation label Nov 8, 2026
@codecov

codecov Bot commented Nov 8, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.70%. Comparing base (a76c553) to head (26052ee).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #445      +/-   ##
==========================================
- Coverage   99.70%   99.70%   -0.01%     
==========================================
  Files          69       69              
  Lines        9537     9536       -1     
==========================================
- Hits         9509     9508       -1     
  Misses         28       28              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@steven-murray
steven-murray merged commit a0bc5b7 into main Nov 8, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

API Breaking Breaking Changes type: maint: documentation Improvements or additions to documentation type: maint: refactoring Refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants