HSM: measure PSF/star shapes directly in sky coords (use_sky_coords) - #812
HSM: measure PSF/star shapes directly in sky coords (use_sky_coords)#812cailmdaley wants to merge 6 commits into
Conversation
Attach the local (Jacobian) WCS at each object position to the PSF/star stamps and pass use_sky_coords=True to galsim FindAdaptiveMom, so PSFEx and MCCD HSM ellipticities and sizes come out already in world coordinates. This makes the downstream WCS-Jacobian shape rotation (convert_psf_pix2world) redundant. Threaded at every in-repo HSM PSF/star call site: - psfex_interp: multi-epoch (per-CCD WCS log), single-exposure validation and classic (WCS from the galcat FITS_LDAC image header via _galcat_wcs) - mccd_interpolation_script: multi-epoch (per-CCD WCS log) - shapepipe_auxiliary_mccd: interpolation (WCS from galcat LDAC header) local_wcs_list() builds the per-object local WCS: use_sky_coords evaluates the stamp WCS at true_center, so it must be the full WCS linearised at the object's image position, not at the stamp centre. SIGMA_*_HSM (hence HSM_T_* = 2 sigma^2) is now in sky units (arcsec) rather than pixels; this is the intended, physically correct size. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gao7Pi5QDBgnTuagV7HT2w
HSM ellipticities and sizes are measured directly in world coordinates upstream, so the WCS-Jacobian shape rotation (transform_shape, getDecomposition) is redundant. Remove it from both the PSFEx and MCCD branches; the script keeps its remaining job of collating positions (X/Y/ RA/DEC), assigning the MCCD focal-plane CCD id, and merging per-exposure catalogues into per-patch star catalogues. Drops the galsim dependency. Caveat documented in the module docstring: the MCCD PSF_MOM_LIST/STAR_MOM_LIST columns come from the external mccd fit-validation code, still measured in the pixel frame; they are now passed through unrotated. Update the CANFAR doc to describe the step as collation, not pix->world shape conversion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gao7Pi5QDBgnTuagV7HT2w
Equivalence test for use_sky_coords=True: draw an elliptical Gaussian on a stamp with a nontrivial local WCS (rotation + shear + 0.187 arcsec/pix scale, positive determinant), and assert that measuring in the pixel frame then applying the removed convert_psf_pix2world.transform_shape rotation (copied in verbatim as reference) agrees with measuring directly in sky coordinates, to numerical precision, for e1/e2 and sigma. A second test pins the deliberate unit change: the sky-frame sigma is the pixel sigma times the WCS scale. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gao7Pi5QDBgnTuagV7HT2w
…ranch The MCCD PSF_MOM_LIST/STAR_MOM_LIST columns come from the external mccd fit-validation code (mccd.auxiliary_fun.mccd_validation), which still measures HSM adaptive moments in the pixel frame. Stripping the WCS-Jacobian rotation there (71d502f) would have handed MergeStarCatMCCD pixel-frame ellipticities. Restore transform_shape + the per-CCD getDecomposition rotation for the MCCD MOM_LIST branch only (and the galsim import it needs); the in-repo PSFEx and MCCD-interpolation paths stay unrotated, as they now measure in world coordinates upstream. Update the module docstring caveat: this branch keeps the rotation until mccd itself adopts use_sky_coords. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gao7Pi5QDBgnTuagV7HT2w
local_wcs_list wraps galsim.AstropyWCS, which follows the 1-indexed FITS pixel convention, but the multi-epoch paths fed it positions from all_world2pix(..., 0) (origin 0) — evaluating the local Jacobian one pixel off. Compute a separate origin=1 position array (gal_pos_wcs) for local_wcs_list; the origin-0 gal_pos stays for the PSF-model interpolation (interpsfex / interp_MCCD), which is its only other use. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gao7Pi5QDBgnTuagV7HT2w
|
We should revisit |
| PSF/star ellipticities and sizes are now measured directly in sky coordinates | ||
| during PSF interpolation (galsim `FindAdaptiveMom(use_sky_coords=True)`), so | ||
| `convert_psf_pix2world.py` only collates and passes the shapes through. | ||
|
|
There was a problem hiding this comment.
Update to reflect removal of the patch concept in v2.0
Martin (PR #812 review): the patch concept is removed in v2.0. For -V v2.0 the handler reads summary/missing_job_32_all.txt and exp_numbers.txt relative to the run root instead of iterating P1..P9; -p restores an explicit P1..P<n> layout when needed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MqH9wjbJicVmaQdhZ4kBYr
…add patch-less v2.0 Re-scope the script to its actual remaining purpose: collating per-exposure PSF validation catalogues into star catalogues. The WCS-Jacobian shape rotation is gone (HSM moments are measured in sky coordinates upstream), so "convert" no longer describes it. The external-mccd PSF_MOM_LIST/STAR_MOM_LIST rotation branch stays until mccd adopts use_sky_coords. Add a -V/--version option mirroring get_ccds_with_psf. v1.x is unchanged (loop over -P patches, <base>/P<patch>/output, validation_psf_conv-<patch>-<idx>). v2.0 is patch-less: single <base>/output root, patch token dropped from the output filename (validation_psf_conv-<idx>). The downstream combine_runs.bash glob (validation_psf_conv-*) matches both. Path/filename logic extracted into pure collate_paths/output_filename helpers with unit tests; docs collate section updated with both invocations. The script command name follows the file (Dockerfile symlinks by basename). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WqNFhq9uGpDpprYeuGeb8k
79fafe0 to
baea03a
Compare
|
Thanks Martin — both points addressed.
— Fable on behalf of Cail |
Align with the collate_star_cat convention (PR #812): v2.0 (patch-less) is now the default catalogue version. Older, patched layouts are selected explicitly with -V. Help text and the pipeline_canfar.md invocations updated; the v2.0 call drops the flag, v1.x shows -V v1.6. Tests set the version explicitly, so none pinned the old default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WqNFhq9uGpDpprYeuGeb8k
|
Hello, |
|
Good point — agreed, and it turns out this was attempted before: #698 (fourth-order moments, PSFHOME-style) was closed unmerged and is now stale. It edits exactly the two functions this PR rewrites. We've reopened #697/#698 to track it and will implement as a follow-up on top of this PR: the spin-2 fourth-moment combinations measured in the sky frame (which removes the pixel→sky rotation the old code needed), plus galsim's spin-0 — Fable on behalf of Cail |
Closes #775.
ShapePipe measured PSF/star HSM adaptive moments in the pixel frame, then rotated the ellipticities into sky coordinates in a separate post-processing step (
scripts/python/convert_psf_pix2world.py, a WCS-Jacobian decomposition). galsim'sFindAdaptiveMomnow does this at the point of measurement viause_sky_coords=True(available since galsim 2.5; we pin ≥2.8) — per @aguinot's suggestion on #741. This PR moves the WCS knowledge into the HSM call and drops the redundant rotation.What changed
FindAdaptiveMomcall site — PSFEx single-exposure and multi-epoch (psfex_interp.py), MCCD interpolation (mccd_interpolation_script.py,shapepipe_auxiliary_mccd.py) — now attaches the local WCS (linearised at the object's image position) to the stamp and passesuse_sky_coords=True. Multi-epoch paths use the per-CCD WCS log already in scope; single-exposure paths read the WCS from the galcat'sLDAC_IMHEADheader.convert_psf_pix2world.pyno longer rotates the in-repoE1/E2/SIGMA_*_HSMshapes. Per review, it is renamed tocollate_star_cat.pyto reflect its remaining purpose: collate the per-exposure PSF validation catalogues into star catalogues (positions, MCCD CCD id, merge).v2.0support. The script takes-V(defaultv2.0), following theget_ccds_with_psfconvention from Coverage nexp masks #797. the patch-less default reads from the single run root and writesvalidation_psf_conv-<idx>.fits(no patch token; downstreamcombine_runs.bash/config_Ms_psfex_conv.iniglobs match both schemes).-V v1.6 -P …selects the unchanged v1.x behaviour. Invalid versions raise. The collate section ofpipeline_canfar.mdshows both invocations.PSF_MOM_LIST/STAR_MOM_LISTcolumns come from the externalmccdlibrary, which still measures in the pixel frame — that one branch keeps its rotation (with a docstring caveat) untilmccditself adoptsuse_sky_coords.tests/module/test_hsm_sky_coords.py: a synthetic Gaussian stamp under a nontrivial local WCS (0.187″/pix, 28° rotation, shear), measured pixel-frame + oldtransform_shapemath vsuse_sky_coords=True— g1/g2/sigma agree to rtol 1e-6. Plustest_collate_star_cat.pypinning the v1.x/v2.0 path and filename logic. All 14 tests pass in the develop container.Notes for review
moments_sigmanow comes back in world units (arcsec) rather than pixels, soHSM_T_* = 2σ²is arcsec² — which is what the old pipeline produced after the rotation step, so end-of-pipeline catalogues are unchanged. Downstream consumers (merge_starcat, ngmix T-guess) checked: no pixel-scale assumption.getDecompositionto the HSM ellipticities;merge_starcatpasses them through.f153ea28).An independent adversarial review of the full diff ran before opening this PR; both findings it raised (the external-mccd branch above, and the indexing fix) are addressed.
— Claude on behalf of Cail
🤖 Generated with Claude Code
https://claude.ai/code/session_01Gao7Pi5QDBgnTuagV7HT2w