Add DES_PSFEx (PSFEx model reader) to jax_galsim.des - #261
Conversation
Port galsim.des.DES_PSFEx so an empirical PSFEx model (*_psfcat.psf) can be read and evaluated entirely within JAX-GalSim, removing the need to fall back to reference GalSim just to build the PSF. The PSFEx file read (read()) is host-side FITS I/O, unchanged from galsim. getPSFArray -- the per-position evaluation of the interpolated PSF -- is reimplemented in JAX (the [1, x, x^2, ...] powers are built with a cumulative product instead of galsim's in-place np.empty loop, which JAX forbids), so it can be jitted, vmapped over image positions, and differentiated with respect to the image position. getPSF wraps the array in an InterpolatedImage exactly as galsim does (Lanczos(3), scale = PSF_SAMP), and applies the WCS if given. The GalSim config framework registration (des_psfex input type / DES_PSFEx object type) is intentionally not ported, since JAX-GalSim has no config system; this is noted in the lax_description. Tests compare getPSFArray and the drawn effective-PSF image against reference GalSim (to single-precision, since PSFEx bases are float32) using the existing DECam_00154912_12_psfcat.psf test file, and check that getPSFArray is jittable, vmappable, and differentiable in the image position.
beckermr
left a comment
There was a problem hiding this comment.
This class needs to be registered as a pytree and we need think about what kinds of autodiff we'd allow.
|
I'll register it as a pytree. My idea of the split: basis, the polynomial zero/scale constants, and wcs as traced children (keeping it consistent with how other jax_galsim objects treat numeric params), with fit_order/fit_size as static aux_data since they set the loop unrolling and array shapes. tree_unflatten will rebuild via On autodiff scope: I think the physically meaningful gradient is w.r.t. image_pos (where on the focal plane the PSF is evaluated), which already works and comes through the method argument rather than the pytree. Differentiating w.r.t. basis/wcs/calibration constants falls out structurally once they're leaves, but I don't see a concrete use case for those. I'd be happy to lock any of them into aux_data if you'd rather keep the differentiable surface narrow. What's your preference? |
Add
DES_PSFExtojax_galsim.desHi! Nice to meet you, this is my first PR ever, happy to adjust anything to match your conventions.
This ports
galsim.des.DES_PSFExso a PSFEx model (*_psfcat.psf) can be read and evaluated entirely within JAX-GalSim. Right now, if you want an empirical PSF you have to drop back to reference GalSim just to build it; this closes that gap. I hit it while benchmarking a weak lensing pipeline's dataset generation before and after porting to jax-galsim.DES_PSFExwas the last thing keeping regular GalSim as a dependency.What it does
read()is host-side FITS I/O, unchanged from GalSim (parses the PSFEx header + PCA basis cube).getPSFArray()is the per-position evaluation of the interpolated PSF. It's reimplemented in JAX so it'sjit-able,vmap-able over image positions, and differentiable w.r.t. the image position. The one non-obvious change: GalSim builds the[1, x, x^2, ...]powers with an in-placenp.emptyloop, which tracing forbids, so I use a cumulative product with the same recurrence.getPSF()wraps the array in anInterpolatedImageexactly as GalSim does (Lanczos(3),scale = PSF_SAMP) and applies the WCS if one was provided.Scope (intentionally narrow)
Just
DES_PSFEx, notDES_Shapelet, and not the config-framework registration (des_psfexinput type /DES_PSFExobject type), since JAX-GalSim doesn't have a config system. That's noted in thelax_description. Happy to follow up with more in a separate PR if you'd like it.Testing
tests/jax/test_des_psfex_jax.pycompares against reference GalSim using the existingDECam_00154912_12_psfcat.psfin thetests/GalSimsubmodule:getPSFArrayand the drawn effective-PSF image match GalSim to ~single precision (the PSFEx bases arefloat32). Drawn withmethod='no_pixel', since PSFEx PSFs already include the pixel.getPSFArrayis verifiedjit-able,vmap-able across a batch of positions, and differentiable in position (finite gradient).ruff checkandruff formatare clean.Open questions
DES_Shapeletalongside it.