Skip to content

PSF fourth-order moments in the sky frame (spin-2 + rho4)#859

Open
cailmdaley wants to merge 4 commits into
feat/hsm-sky-coordsfrom
feat/psf-fourth-moments
Open

PSF fourth-order moments in the sky frame (spin-2 + rho4)#859
cailmdaley wants to merge 4 commits into
feat/hsm-sky-coordsfrom
feat/psf-fourth-moments

Conversation

@cailmdaley

Copy link
Copy Markdown
Contributor

Closes #697. Supersedes #698. Follow-up to #812; based on its branch so the diff shows only the fourth-moment work — retarget to develop after #812 merges.

What this does

Adds fourth-order moment columns to the PSF/star measurement chain: HSM_M4_1/2_{PSF,STAR} (spin-2 combinations M40 − M04, 2(M13 + M31), PSFHOME-style) and HSM_RHO4_{PSF,STAR} (galsim's spin-0 kurtosis, previously computed and discarded).

How

All computation happens in the world frame. The pixel grid maps to sky offsets through the local WCS Jacobian. The whitening matrix comes from the sky-frame second moments returned by use_sky_coords=True. This makes the spin-2 columns frame-invariant; the pixel-frame computation in #698 was not (verified numerically — it rotates with the CCD orientation).

Columns flow through all write paths: single-epoch, validation, multi-epoch, and merge_starcat into the merged star catalogue.

Two latent #698 issues do not carry over: the residual imaginary part from scipy.linalg.sqrtm is dropped, and the merge_starcat copy-paste bug (M_4_PSF_2 reading the _1 column) is avoided.

Tests

23 pass (13 new + masked-pixel and centroid coverage from review, plus the #812 suite — no regression). Analytic guards: round Gaussian → spin-2 ≈ 0, rho4 ≈ 2; frame invariance across four WCS orientations at rtol=1e-5 (actual agreement ~1e-8); -1e30 mask sentinels; off-center sources. A physics note encoded in the tests: whitening circularises any sheared circular profile, so a single elliptical Moffat also gives spin-2 ≈ 0 — the spin-2 signal traces radial ellipticity gradients. The non-trivial fixture is a two-component coaxial Gaussian.

Known follow-up

sp_validation's residual-star plot reads the old M_4_STAR_1-style names; it needs 4 one-line renames to the HSM_M4_* grammar (separate repo, separate PR).

🤖 Generated with Claude Code

https://claude.ai/code/session_01K98geWHTuT62whqjKocfCm

cailmdaley and others added 4 commits July 21, 2026 14:37
Extend the sky-coordinate HSM measurement (PR #812) to also store
fourth-order moments for PSF and star:

- spin-2 combinations HSM_M4_1_* = M40 - M04 and HSM_M4_2_* = 2*(M13 + M31),
  ported from the PSFHOME/moment4 math, and
- galsim's spin-0 HSM_RHO4_* (moments_rho4).

Frame handling is the key change over the moment4 port. Whitening with the
symmetric sqrt(inv(M)) leaves the whitened axes aligned with the frame in
which M and the pixel grid are built, so the spin-2 combinations are defined
relative to those axes. Building them in the pixel frame ties them to the CCD
orientation. Instead _fourth_moments builds everything in the world frame: M
from the use_sky_coords world ellipticity/size, and the grid via the local WCS
Jacobian mapping pixel offsets to world offsets about the world centroid
(moments_centroid is relative to the stamp true_center). The result is
invariant to a re-orientation of the pixel frame viewing the same sky object.

HSM failures fill the spin-2 terms with 0 and pass rho4 through (-1); the FLAG
column stays the source of truth. Masked star pixels are zeroed before the
moment sum. Columns are added to the single-epoch, validation and multi-epoch
output paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K98geWHTuT62whqjKocfCm
…ments

Drive the real _get_psfshapes / _get_starshapes on galsim stamps rendered
through a nontrivial local WCS (scale + rotation + shear):

- round and elliptical Gaussians: whitened spin-2 fourth moments ~ 0 and
  rho4 ~ 2 (whitening circularises any single sheared circular profile, so an
  elliptical Moffat would also vanish -- a two-Gaussian composite is used to
  get a genuine non-zero spin-2 signal),
- frame invariance: one sky object rendered under WCS orientations of
  0/28/63/-45/90 deg gives the same world-frame fourth moments, on both the
  PSF and star paths,
- PSF/star agreement on a clean stamp, and HSM-failure sentinel handling.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K98geWHTuT62whqjKocfCm
MergeStarCatPSFEX read and wrote only HSM_G1/G2/T/FLAG for PSF and STAR,
so the spin-2 fourth moments and rho4 written per-tile by psfex_interp
were dropped at the merge step. The merged full_starcat is the catalogue
PSF validation consumes, so the feature was inert past the per-tile stage.

Read and write HSM_M4_1/HSM_M4_2/HSM_RHO4 for both PSF and STAR, matching
the per-tile column grammar. Avoids the moment4 reference's copy-paste bug
(m4_2_psf now reads the _2 column) and adds RHO4, which the reference omitted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K98geWHTuT62whqjKocfCm
Two paths the summary claimed but the suite left unexercised:

- Bad-pixel masking: every star fixture had an all-zero mask, so zeroing
  masked pixels before the fourth-moment sum was a no-op in the suite.
  Add a test that plants the -1e30 sentinel in outskirt pixels, asserts the
  masked vignet reproduces the clean result, and asserts the same sentinels
  fed through un-zeroed blow the fourth moments up by ~5 orders (mutation:
  removing the zeroing makes M4_1 go -0.03 -> -4278).

- Centroid transform: every fixture was drawn centered, so moments_centroid
  ~ 0 and the sky-frame recentering was dead. Add a world-frame-shift case;
  the fourth moments stay invariant only because the transformed centroid is
  subtracted (mutation: dropping the subtraction fails both angles).

Also tighten the frame-invariance tolerances from rtol=1e-3/atol=1e-5 to
rtol=1e-5/atol=1e-6 (measured cross-orientation agreement is ~1e-8), so a
subtle partial-frame error at the 1e-4 level now bites.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K98geWHTuT62whqjKocfCm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant