Skip to content

feat: Lenstool-native dPIE parameterization (from_lenstool + dPIEMassLenstool) and analytic potential#487

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/dpie-lenstool-param
Jul 9, 2026
Merged

feat: Lenstool-native dPIE parameterization (from_lenstool + dPIEMassLenstool) and analytic potential#487
Jammy2211 merged 1 commit into
mainfrom
feature/dpie-lenstool-param

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

Adds a Lenstool-native parameterization of the dPIE mass profile, so Lenstool users can construct and fit PyAutoGalaxy models directly in the parameters they read out of .par files and Lenstool-based papers: fiducial velocity dispersion sigma (v_disp), ellipticity (ellipticite), angle_pos, r_core, r_cut. Every conversion convention was verified against the Lenstool C source (set_potfile.c, set_lens.c, e_grad.c, e_pcpx.c) — see #485 for the research trail.

Two correctness fixes surfaced during parity validation:

  1. dPIEMass.potential_2d_from was an MGE approximation whose gradient disagreed with the ci05f deflections by up to 15% for elliptical profiles (the MGE reconstructs a different elliptical geometry than the Kassiola & Kovner pseudo-elliptical mass model). It is replaced by the analytic KK93 I0.5 potential ported from Lenstool's pi05; finite-difference grad(psi) now matches deflections to 1.7e-8.
  2. _ellip() now min-clamps at 1e-5 (identical to Lenstool's set_lens.c clamp): the ci05 integral is degenerate at exactly zero ellipticity, so ell_comps=(0.0, 0.0) elliptical dPIE profiles previously returned NaN deflections.

API Changes

Added Lenstool-parameterized construction and fitting for the dPIE family: from_lenstool(...) classmethods on dPIEMass / dPIEMassSph, and new model-fittable wrapper profiles dPIEMassLenstool / dPIEMassLenstoolSph (with prior configs). dPIEMass.potential_2d_from values change (MGE approximation → exact analytic potential); dPIE deflections at |ell_comps| < 1e-5 change from NaN to the tiny-ellipticity limit. No removals or renames.
See full details below.

Test Plan

  • test_dual_pseudo_isothermal_mass.py — 15 pass (10 new: conversion math, sqrt(3/2) sigma cross-check, emass→epot vs Lenstool's own formula, angle/radii mapping, sph↔elliptical parity, isothermal-limit b0=theta_E, potential-gradient consistency ×2, wrapper parity, af.Model composition)
  • Full PyAutoGalaxy suite — 956 pass
  • Downstream PyAutoLens suite against this branch — pass (count in issue)
  • autolens_workspace_test/scripts/cluster/lenstool_parity.py — 6 legs, agreement 1e-7 to 1e-10 (companion PR)

Validation checklist (--auto run — in-session directives, no separate plan pre-approval)

  • Effective level: supervised (header: supervised, cap: feature → supervised); ship + wrapper-class rework directed in-session by the user ("use wrapper class's so it support modeling", "one shot")
  • Plan: on the issue (feat: LensTool-native dPIE parameterization (from_lenstool) + parity validation #485), written at start; one scope addition (wrapper classes) explicitly user-directed
  • Gate: tests 956 pass (PyAutoGalaxy) + downstream PyAutoLens pass · smoke cluster start_here/modeling (result in issue) · review surface prepared · Heart YELLOW acked in-session (TEST RUN stale-parked scripts / VERSION SKEW autolens_assistant / worktree drift from other parked tasks)
  • Human: plan sound in hindsight?
  • Human: diff matches plan (no scope creep)?
  • Human: merge, amend, or reject — then log the outcome
Full API Changes (for automation & release notes)

Added

  • ag.mp.dPIEMass.from_lenstool(centre, ellipticity, angle_pos, sigma, r_core, r_cut, redshift_object, redshift_source, cosmology=) — construct a dPIEMass from Lenstool .par parameters; converts sigma_LT → b0 via 6·648000·(sigma/c)²·(D_LS/D_S), emass → ell_comps, radii one-to-one.
  • ag.mp.dPIEMassSph.from_lenstool(centre, sigma, r_core, r_cut, redshift_object, redshift_source, cosmology=) — spherical variant.
  • ag.mp.dPIEMassLenstool(centre, ellipticity, angle_pos, sigma, r_core, r_cut, redshift_object, redshift_source) — model-fittable wrapper (subclass of dPIEMass) whose free parameters are the Lenstool ones; Planck15 cosmology fixed internally (NFWMCRLudlow convention). Prior config added.
  • ag.mp.dPIEMassLenstoolSph(centre, sigma, r_core, r_cut, redshift_object, redshift_source) — spherical wrapper (subclass of dPIEMassSph). Prior config added.

Changed Behaviour

  • dPIEMass.potential_2d_from — now the analytic Kassiola & Kovner I0.5 potential (Lenstool pi05 port, psi = b0·rs/(rs−ra)·(pi05(ra) − pi05(rs))) instead of a 30-Gaussian MGE approximation. Elliptical-profile potentials change by up to ~15%; the new values are consistent with the deflection field to 1e-8. Any consumer of dPIE potentials (e.g. time delays) gets corrected numbers.
  • PIEMass._ellip / dPIEMass._ellip — ellipticity clamped to [1e-5, 0.99999] (was max-clamp only). Deflections/convergence/potential of profiles with |ell_comps| < 1e-5 change from NaN (deflections) / unclamped to the Lenstool-identical tiny-ellipticity limit.

Migration

  • No action required. To construct from a Lenstool model: ag.mp.dPIEMass.from_lenstool(sigma=v_disp, ellipticity=ellipticite, angle_pos=angle_pos, r_core=core_radius, r_cut=cut_radius, redshift_object=z_l, redshift_source=z_s). Note sigma is Lenstool's fiducial sigma_LT, not the central dispersion (sigma_0 = sqrt(3/2)·sigma_LT).

🤖 Generated with Claude Code

- dPIEMass.from_lenstool / dPIEMassSph.from_lenstool convert Lenstool .par
  parameters (v_disp sigma_LT, ellipticite, angle_pos, core_radius, cut_radius)
  to (b0, ell_comps, ra, rs); conventions verified against the Lenstool C
  source (set_potfile.c, set_lens.c, e_grad.c).
- dPIEMassLenstool / dPIEMassLenstoolSph wrapper profiles support model-fitting
  with priors directly on the Lenstool parameters; prior configs added.
- dPIEMass.potential_2d_from: replace the MGE approximation (up to 15% off vs
  deflections for elliptical profiles) with the analytic KK93 I0.5 potential
  ported from Lenstool pi05 (e_pcpx.c); grad(psi) matches deflections to 1e-8.
- _ellip() min-clamps at 1e-5 (Lenstool set_lens.c identical), fixing NaN
  deflections at ell_comps=(0,0).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PUuWXiS23FvmfQPLvMNjeM
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label Jul 8, 2026
@Jammy2211 Jammy2211 merged commit c1e9a1f into main Jul 9, 2026
4 checks passed
@Jammy2211 Jammy2211 deleted the feature/dpie-lenstool-param branch July 9, 2026 08:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pending-release PR queued for the next release build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant