Skip to content

torchsky.map.field.chromatic

Experimental surface

These APIs are under active development. Names, defaults, and result objects may change between minor releases; pin a version if you depend on them in production.

Chromatic PSF fields and continuous-wavelength sky fields integrated over band transmission curves.

Guides: fields, coadds


This reference is generated from the package source. Names are grouped by the module that defines them; import every name from the public namespace torchsky.map.field.chromatic unless the group text says otherwise.

Top-level namespace

Chromatic PSF fields and continuous-wavelength sky fields for multiband forward models.

These are the building blocks of a forward model in which a single sky s(x, y, lambda) is observed through each band's transmission curve and a PSF that varies smoothly with wavelength and detector position:

m_b(p) = sum_q w_bq sum_k u_k(p; lambda_b) [K_k(.; lambda_bq) * s(., lambda_bq)](T(p))

  • :class:ChromaticPSFField -- one network for every band: kernel coordinates are expressed in diffraction units dx * pixel / (lambda / D) so the Airy-like structure scales with wavelength by construction, plus pixel-unit coordinates for pixel response and jitter. Kernel 0 is a normalised, non-negative core; kernels 1.. are zero-sum perturbations mixed with weights that vary smoothly over the detector.
  • :class:LogLambdaRBFBasis -- a partition-of-unity spectral basis uniform in log lambda, optionally with a learned smooth correction.
  • :class:SpectralSkyField -- s(x, y, lambda) = sum_k a_k(x, y) phi_k(lambda) with any coefficient provider (pixel grid or neural field) and band quadrature nodes from :func:torchsky.filter_profiles.photon_quadrature.

Everything is plain torch and runs on CPU, CUDA and MPS.

ChromaticPSFField

ChromaticPSFField(
    *,
    num_channels: int,
    num_detectors: int,
    pixel_scale_arcsec: float,
    aperture_m: float = 6.5,
    num_kernels: int = 4,
    size: int = 31,
    hidden: int = 96,
    max_diffraction_radius: float = 24.0,
    lambda_ref_um: float = 2.0,
)

Bases: Module

PSF basis field smooth in wavelength and detector position.

Parameters

num_channels: Number of optical channels sharing the field (e.g. 2 for NIRCam SW/LW); a channel embedding conditions the kernel network. num_detectors: Detectors with their own (learned) embedding for the spatial weights. pixel_scale_arcsec: Pixel scale of the grid the kernels are sampled on. aperture_m: Telescope diameter, used for lambda / D. num_kernels: Kernel 0 is the normalised core, the others zero-sum perturbations. size: Odd kernel side in grid pixels. max_diffraction_radius: Normaliser of the diffraction-unit coordinates (in lambda / D).

_offsets instance-attribute

_offsets: Tensor

aperture_m instance-attribute

aperture_m = float(aperture_m)

detector_embedding instance-attribute

detector_embedding = Embedding(num_detectors, 4)

kernel_net instance-attribute

kernel_net = Sequential(
    Linear(2 * 2 * 6 + 2 * 2 * 4 + cond, hidden),
    SiLU(),
    Linear(hidden, hidden),
    SiLU(),
    Linear(hidden, hidden),
    SiLU(),
    Linear(hidden, num_kernels),
)

lambda_ref_um instance-attribute

lambda_ref_um = float(lambda_ref_um)

max_diffraction_radius instance-attribute

max_diffraction_radius = float(max_diffraction_radius)

pixel_scale_arcsec instance-attribute

pixel_scale_arcsec = float(pixel_scale_arcsec)

weight_net instance-attribute

weight_net = Sequential(
    Linear(2 * 2 * 3 + cond + 4, 48),
    SiLU(),
    Linear(48, 48),
    SiLU(),
    Linear(48, max(num_kernels - 1, 1)),
)

_condition

_condition(lam_um: Tensor, channel: Tensor) -> Tensor

basis

basis(lam_um: Tensor, channel: Tensor) -> Tensor

Kernels at wavelengths lam_um (M,) and channels (M,): (M, num_kernels, size, size).

centring_penalty

centring_penalty(lam_um: Tensor, channel: Tensor) -> Tensor

Sum of squared first moments of every kernel: pins the PSF centroid, which is otherwise degenerate with the astrometric solution.

weights

weights(
    lam_um: Tensor,
    channel: Tensor,
    detector: Tensor,
    u: Tensor,
    v: Tensor,
) -> Tensor

Mixing weights (N, num_kernels) at detector coordinates u, v in [-1, 1].

lam_um, channel and detector broadcast against u.

LogLambdaRBFBasis

LogLambdaRBFBasis(
    num_basis: int,
    lam_min_um: float,
    lam_max_um: float,
    *,
    learned: bool = False,
)

Bases: Module

phi_k(lambda): K normalised Gaussian bumps uniform in log lambda on [lam_min, lam_max] (a partition of unity), optionally plus a learned smooth correction initialised at zero.

centres instance-attribute

centres: Tensor

correction instance-attribute

correction: Sequential | None = None

num_basis instance-attribute

num_basis = int(num_basis)

width instance-attribute

width = 1.0 / (num_basis - 1)

forward

forward(lam_um: Tensor) -> Tensor

unit

unit(lam_um: Tensor) -> Tensor

SpectralSkyField

SpectralSkyField(
    coefficients: Module,
    basis: LogLambdaRBFBasis,
    nodes_um: Tensor,
    node_weights: Tensor,
    *,
    spectral_smoothness: float = 0.0,
    scale: float = 1.0,
    smoothness_mode: str = "relative",
    floor: float = 3.0,
)

Bases: Module

Continuous sky s(x, y, lambda) = sum_k a_k(x, y) phi_k(lambda).

coefficients is any module returning (K, H, W) (a pixel grid or a neural field); nodes_um / node_weights are (B, Q) band quadrature nodes, e.g. from :func:torchsky.filter_profiles.photon_quadrature.

The spectral prior penalises the second difference of a_k across k. smoothness_mode="relative" (the default) divides it by each pixel's own spectral level (mean_k |a_k| + floor * scale), so a colour gradient costs the same for a faint galaxy as for a bright one; "absolute" divides by scale only and flattens the spectra of bright sources.

node_weights instance-attribute

node_weights: Tensor

nodes_um instance-attribute

nodes_um: Tensor

at_nodes

at_nodes() -> tuple[Tensor, Tensor]

(B, Q, H, W) sky at every quadrature node and (B, H, W) band averages.

forward

forward() -> Tensor

penalty

penalty() -> Tensor

spectral_cube

spectral_cube(lam_um: Tensor) -> Tensor

spectral_coefficients_from_bands

spectral_coefficients_from_bands(
    band_images: Tensor,
    nodes_um: Tensor,
    node_weights: Tensor,
    basis: LogLambdaRBFBasis,
    *,
    smoothness: float = 1e-05,
) -> Tensor

Initial a_k that reproduce band_images (B, H, W) through the band quadrature: ridge least squares with a second-difference prior across k.