torchsky.field¶
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.
Continuous sky models: domains, field model kinds and presets, observation encoding, fitting, rendering, residual diagnostics, and portable artifacts. The formulation behind these APIs is in the field formulation guide.
Guides: fields, formulation, encoders
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.field unless the group text says otherwise.
Top-level namespace¶
FIELD_MODEL_KINDS
module-attribute
¶
FIELD_MODEL_KINDS: tuple[str, ...] = tuple(
get_args(FieldModelKind)
)
RECOMMENDED_FIELD_MODEL_KINDS
module-attribute
¶
RECOMMENDED_FIELD_MODEL_KINDS: tuple[str, ...] = (
"sky_lambda_feature_field",
"sky_encoder_resmlp",
"hashgrid_spectral_field",
)
distribution ¶
distribution(
field_model: Module,
observation: FieldObservation,
*,
target: Literal[
"observation", "samples"
] = "observation",
**kwargs: Any,
) -> tuple[Tensor, Tensor]
Render predictive mean and log-variance.
preset ¶
preset(
name: str, domain: FieldDomain, **overrides: Any
) -> Module
Build a recommended field model by preset name.
render ¶
render(
field_model: Module,
observation: FieldObservation,
*,
target: Literal["observation"] = "observation",
**kwargs: Any,
) -> Tensor
render(
field_model: Module,
observation: FieldObservation,
*,
target: Literal["samples"],
ra_deg: Tensor,
dec_deg: Tensor,
**kwargs: Any,
) -> Tensor
render(
field_model: Module,
observation: FieldObservation | None = None,
*,
target: Literal["cube", "healpix", "cube_via_healpix"],
**kwargs: Any,
) -> Tensor
render(
field_model: Module,
observation: FieldObservation | None = None,
*,
target: RenderTarget = "observation",
**kwargs: Any,
) -> Tensor
Render a field to an observation, coordinate samples, cube, or HEALPix map.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
field_model
|
Module
|
Trained or initialized field module. |
required |
observation
|
FieldObservation | None
|
Observation metadata required by observation and sample targets. |
None
|
target
|
RenderTarget
|
Output geometry selector. |
'observation'
|
**kwargs
|
Any
|
Target-specific coordinates, shape, WCS, or HEALPix options. |
{}
|
Returns:
| Type | Description |
|---|---|
Tensor
|
Rendered tensor on the model's execution device. |
Examples:
>>> from torchsky.field import render
>>> callable(render)
True
sample ¶
sample(
field_model: Module,
observation: FieldObservation,
*,
ra_deg: Tensor,
dec_deg: Tensor,
**kwargs: Any,
) -> Tensor
Evaluate a field on explicit sky-coordinate samples for one observation.
Core helpers¶
estimate_domain ¶
estimate_domain(
observations: Sequence[FieldObservation],
*,
coord_mode: FieldCoordinateMode = "local_tangent",
) -> FieldDomain
Estimate a normalized spatial-spectral domain covering observations.
Adaptive¶
ResidualTileBasisSpec
dataclass
¶
ResidualTileBasisSpec(
centers: Tensor,
scales: Tensor,
amplitudes: Tensor,
tiles: tuple[FieldResidualTile, ...],
)
Encoded centers, scales, and amplitudes for residual-tile basis atoms.
residual_tile_basis ¶
residual_tile_basis(
base_model: _BaseFieldModel,
observation: FieldObservation,
*,
residual_product: FieldResidualProduct,
tile_hw: tuple[int, int],
max_tiles: int,
min_support_fraction: float = 0.0,
spectral_scale_encoded: float = 1.0,
learn_scales: bool = False,
) -> ResidualTileBasisField
Build an adaptive residual-tile field from rendered residual evidence.
residual_tile_basis_spec ¶
residual_tile_basis_spec(
base_model: _BaseFieldModel,
observation: FieldObservation,
tiles: Sequence[FieldResidualTile],
*,
residual_product: FieldResidualProduct | None = None,
spectral_scale_encoded: float = 1.0,
) -> ResidualTileBasisSpec
Convert residual-image tiles into encoded basis-atom parameters.
Artifacts¶
ArtifactManifest
dataclass
¶
ArtifactManifest(payload: Mapping[str, Any])
LoadedArtifact
dataclass
¶
LoadedArtifact(
manifest: FieldArtifactManifest,
model: Module,
optimizer_state: dict[str, Any] | None,
amp_scaler_state: dict[str, Any] | None,
rng_state: dict[str, Any] | None,
sampling_rng_state: Tensor | None,
completed_steps: int,
)
load_artifact ¶
load_artifact(
path: str | Path,
*,
device: device | str | None = None,
verify_inputs: bool = True,
) -> LoadedFieldArtifact
Load and validate a saved field model artifact.
save_artifact ¶
save_artifact(
path: str | Path,
*,
model: Module,
model_kind: FieldModelKind,
model_kwargs: Mapping[str, Any] | None = None,
domain: FieldDomain | None = None,
operator_manifest: Mapping[str, Any] | None = None,
calibration_manifest: Mapping[str, Any] | None = None,
fit_config: Mapping[str, Any] | None = None,
input_identities: list[Mapping[str, Any]] | None = None,
fit_result: FieldFitResult | None = None,
overwrite: bool = False,
) -> FieldArtifactManifest
Save a field model, manifest, and optional training state.
Core¶
component_decomposition ¶
component_decomposition(
*,
component_roles: Sequence[str],
domain: FieldDomain | None = None,
component_models: Sequence[Module] | None = None,
component_model_kind: FieldModelKind = "sine_implicit",
component_model_kwargs: dict[str, object] | None = None,
surveys: Sequence[str] | None = None,
instruments: Sequence[str] | None = None,
observation_forward_contexts: Sequence[
ForwardContext | None
]
| None = None,
dtype: dtype = float32,
device: device | None = None,
) -> FieldComponentDecomposition
Build an explicit field decomposition model from component specs or modules.
model ¶
model(
kind: FieldModelKind, domain: FieldDomain, **kwargs: Any
) -> Module
Construct a field model of the requested kind on a fixed domain.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kind
|
FieldModelKind
|
Registered field-model kind. |
required |
domain
|
FieldDomain
|
Spatial and spectral normalization domain. |
required |
**kwargs
|
Any
|
Model-specific constructor options. |
{}
|
Returns:
| Type | Description |
|---|---|
Module
|
An untrained PyTorch field module. |
Examples:
>>> from torchsky.field import Domain, model
>>> domain = Domain(0.0, 0.0, 1.0, 5000.0, 1000.0)
>>> field = model("sine_implicit", domain)
>>> field.domain is domain
True
Models component¶
FieldComponentDecomposition ¶
FieldComponentDecomposition(
component_models: Sequence[Module],
*,
component_roles: Sequence[str],
surveys: Sequence[str] = (),
instruments: Sequence[str] = (),
dtype: dtype = float32,
device: device | None = None,
)
Bases: _BaseFieldModel
Explicit shared/private decomposition over multiple field models.
component_gains
instance-attribute
¶
component_gains = Parameter(
ones(len(component_roles), dtype=dtype, device=device)
)
mixer
instance-attribute
¶
mixer = SurveyInstrumentComponentMixer(
component_roles=component_roles,
surveys=surveys,
instruments=instruments,
dtype=dtype,
device=device,
)
_context_labels ¶
_context_labels(
forward_context: ForwardContext | None,
) -> tuple[str | None, str | None]
component_prediction ¶
component_prediction(
ra_deg: Tensor,
dec_deg: Tensor,
wavelength_angstrom: Tensor | float,
*,
roles: str | Sequence[str],
forward_context: ForwardContext | None = None,
aggregate: bool = True,
) -> Tensor
decomposition_diagnostics ¶
decomposition_diagnostics(
observations: Sequence[FieldObservation],
truth_model: "FieldComponentDecomposition",
*,
observation_forward_contexts: Sequence[
ForwardContext | None
]
| None = None,
num_spectral_samples: int = 9,
spectral_sampling: FieldSpectralSampling = "deterministic_quadrature",
spectral_sampling_grid_size: int | None = None,
generator: Generator | None = None,
calibration_anchor_model: Module | None = None,
calibration_anchor_roles: str
| Sequence[str] = "shared",
) -> ComponentDecompositionDiagnostics
fix_component_scale_gauge_ ¶
fix_component_scale_gauge_(
*, target_gain: float = 1.0, min_gain: float = 1e-12
) -> Tensor
Canonicalize explicit component gains without changing rendered predictions.
forward ¶
forward(
ra_deg: Tensor,
dec_deg: Tensor,
wavelength_angstrom: Tensor | float,
*,
forward_context: ForwardContext | None = None,
) -> Tensor
render_component_observation ¶
render_component_observation(
observation: FieldObservation,
*,
roles: str | Sequence[str],
num_spectral_samples: int = 9,
spectral_sampling: FieldSpectralSampling = "deterministic_quadrature",
spectral_sampling_grid_size: int | None = None,
generator: Generator | None = None,
override_wavelengths: Tensor | None = None,
override_weights: Tensor | None = None,
forward_context: ForwardContext | None = None,
aggregate: bool = True,
) -> Tensor
render_component_samples ¶
render_component_samples(
observation: FieldObservation,
*,
ra_deg: Tensor,
dec_deg: Tensor,
roles: str | Sequence[str],
num_spectral_samples: int = 9,
spectral_sampling: FieldSpectralSampling = "deterministic_quadrature",
spectral_sampling_grid_size: int | None = None,
generator: Generator | None = None,
override_wavelengths: Tensor | None = None,
override_weights: Tensor | None = None,
forward_context: ForwardContext | None = None,
aggregate: bool = True,
) -> Tensor
Observation builders¶
field_observations_from_bin_centers ¶
field_observations_from_bin_centers(
bin_centers: Tensor | Sequence[float],
full_widths: Tensor | float,
values: Tensor,
*,
spatial_header: dict[str, Any] | None = None,
weight: Tensor | None = None,
mask: Tensor | None = None,
spectral_quantity: FieldSpectralQuantity = "wavelength",
band_name_prefix: str = "bin",
transmission_sigma: Tensor
| Sequence[float | None]
| float
| None = None,
psf_sigma_pix: float = 0.0,
sky_background: Tensor | None = None,
instrument_background: Tensor | None = None,
detector_background: Tensor | None = None,
) -> list[FieldObservation]
Top-hat bins [center - width/2, center + width/2] (e.g. PHA summaries).
Bins may be non-contiguous or overlap in axis space; each row is still one
independent [lo, hi] interval (unlike :func:field_observations_from_bin_edges,
which assumes a single contiguous edge chain).
full_widths may be a scalar broadcast to every bin or a 1D tensor matching
bin_centers.
field_observations_from_bin_edges ¶
field_observations_from_bin_edges(
bin_edges: Tensor | Sequence[float],
values: Tensor,
*,
spatial_header: dict[str, Any] | None = None,
weight: Tensor | None = None,
mask: Tensor | None = None,
spectral_quantity: FieldSpectralQuantity = "wavelength",
band_name_prefix: str = "bin",
transmission_sigma: Tensor
| Sequence[float | None]
| float
| None = None,
psf_sigma_pix: float = 0.0,
sky_background: Tensor | None = None,
instrument_background: Tensor | None = None,
detector_background: Tensor | None = None,
) -> list[FieldObservation]
One :class:FieldObservation per bin from native bin_edges and binned values.
Parameters¶
bin_edges
Length n_bin + 1, strictly increasing (same units as the spectral axis).
values
Shape (n_bin,) for a 1D spectrum (stored as 1×1 images) or
(n_bin, H, W) for an IFU-style stack of channel maps (one map per bin).
spatial_header
WCS header for the 2D slice. Required when values is 3D (IFU). If omitted
for 1D data, :func:make_tangent_plane_header is used with shape 1×1.
weight, mask
Optional maps matching each per-bin image (same shape as values after
the leading spectral dimension is dropped per observation), or broadcastable
spatial maps (H, W) shared across bins.
spectral_quantity
"energy" for X-ray channel edges in keV (or eV if you use that consistently),
"wavelength" for optical/IR, etc.
band_name_prefix
Band names are f"{prefix}_{i:06d}".
transmission_sigma
Per-bin effective Gaussian width in the same units as bin_edges, or a
scalar broadcast. Invalid or non-positive values are treated as unknown (None).
field_observations_from_ifu_cube ¶
field_observations_from_ifu_cube(
datacube: Tensor,
bin_edges: Tensor | Sequence[float],
spatial_header: dict[str, Any],
*,
spectral_axis: int = 0,
weight: Tensor | None = None,
mask: Tensor | None = None,
spectral_quantity: FieldSpectralQuantity = "wavelength",
band_name_prefix: str = "ifu",
transmission_sigma: Tensor
| Sequence[float | None]
| float
| None = None,
psf_sigma_pix: float = 0.0,
sky_background: Tensor | None = None,
instrument_background: Tensor | None = None,
detector_background: Tensor | None = None,
) -> list[FieldObservation]
IFU / image-spectral cube: (..., L, ...) with spectral axis at spectral_axis.
After moving that axis to the front, the array must be exactly (L, H, W).
For a batch of cubes, slice to one field before calling.
make_tangent_plane_header ¶
make_tangent_plane_header(
height: int,
width: int,
*,
crval_ra_deg: float = 180.0,
crval_dec_deg: float = 0.0,
cd11: float = -0.001,
cd12: float = 0.0,
cd21: float = 0.0,
cd22: float = 0.001,
) -> dict[str, float | str | int]
Minimal RA---TAN / DEC--TAN header for height × width pixels.
Presets¶
FieldModelPreset
dataclass
¶
FieldModelPreset(
name: str,
kind: FieldModelKind,
description: str,
kwargs: Mapping[str, Any],
)
Named field-model recipe for users who do not need class-level details.
make ¶
make(domain: FieldDomain, **overrides: Any) -> Module
Build this preset for domain, with explicit keyword overrides.
get_field_model_preset ¶
get_field_model_preset(name: str) -> FieldModelPreset
Return a named field-model preset.
Quality¶
ResidualProduct
dataclass
¶
ResidualProduct(
prediction: Tensor,
target: Tensor,
residual: Tensor,
weight: Tensor,
support: Tensor,
metrics: dict[str, float],
band_name: str | None = None,
)
Rendered prediction, residual map, support mask, and scalar metrics.
ResidualTile
dataclass
¶
ResidualTile(
y0: int,
y1: int,
x0: int,
x1: int,
residual_energy: float,
residual_rmse: float,
support_fraction: float,
effective_weight_sum: float,
band_name: str | None = None,
)
Support-aware residual energy summary for one image tile.
metrics ¶
metrics(
prediction: Tensor,
target: Tensor,
*,
weight: Tensor | None = None,
mask: Tensor | None = None,
residual_scales: Sequence[int] = (1, 2, 4),
) -> dict[str, float]
Compute weighted residual, SNR, sharpness, and multiscale residual metrics.
Metrics that require effective support are NaN when the nonnegative finite weight sum is zero. Support counts and fractions remain defined.
quality ¶
quality(
model: Module,
observations: Sequence[FieldObservation],
*,
num_spectral_samples: int = 9,
observation_forward_contexts: Sequence[
ForwardContext | None
]
| None = None,
observation_exposure_poses: Sequence[
ExposurePose | None
]
| None = None,
observation_operator_bundles: Sequence[
ObservationOperatorBundle | None
]
| None = None,
residual_scales: Sequence[int] = (1, 2, 4),
include_scorecard: bool = False,
include_residual_products: bool = False,
**render_kwargs: Any,
) -> dict[str, Any]
Render observations and summarize residual/SNR/sharpness metrics.
render_residual_product ¶
render_residual_product(
model: Module,
observation: FieldObservation,
*,
num_spectral_samples: int = 9,
forward_context: ForwardContext | None = None,
exposure_pose: ExposurePose | None = None,
operator_bundle: ObservationOperatorBundle
| None = None,
residual_scales: Sequence[int] = (1, 2, 4),
**render_kwargs: Any,
) -> FieldResidualProduct
Render a field observation and return a structured residual product.
residual ¶
residual(
model: Module,
observation: FieldObservation,
*,
num_spectral_samples: int = 9,
forward_context: ForwardContext | None = None,
exposure_pose: ExposurePose | None = None,
operator_bundle: ObservationOperatorBundle
| None = None,
masked: bool = True,
**render_kwargs: Any,
) -> Tensor
Render model into observation and return prediction minus image.
residual_product ¶
residual_product(
prediction: Tensor,
target: Tensor,
*,
weight: Tensor | None = None,
mask: Tensor | None = None,
psf_spec: object | None = None,
residual_scales: Sequence[int] = (1, 2, 4),
band_name: str | None = None,
) -> FieldResidualProduct
Build a residual product for one predicted image and target image.
residual_tiles ¶
residual_tiles(
product: FieldResidualProduct,
*,
tile_hw: tuple[int, int],
max_tiles: int | None = None,
min_support_fraction: float = 0.0,
) -> tuple[FieldResidualTile, ...]
Rank fixed image tiles by exact weighted residual energy.
Registry¶
is_recommended_field_model ¶
is_recommended_field_model(kind: str) -> bool
Return whether a field model kind is in the recommended subset.
Spectral budget¶
spectral_data_budget ¶
spectral_data_budget(
observations: Sequence[FieldObservation],
) -> SpectralDataBudget
Summarize wavelength coverage and variation scales in observations.
suggest_num_spectral_samples ¶
suggest_num_spectral_samples(
budget: SpectralDataBudget,
*,
spacing_to_scale_ratio: float = 0.35,
floor: int = 3,
cap: int = 256,
) -> int
Suggest a single num_spectral_samples for :func:fit_field_model / rendering.
For each observation with box span S and variation scale L (Gaussian σ
capped by S, or S for uniform-in-box), require trapezoid node spacing
h ≲ spacing_to_scale_ratio * L across the integration interval, i.e.
n ≳ ceil(S / h) + 1 when S > 0.
Default spacing_to_scale_ratio=0.35 targets on the order of three nodes per
correlation scale (documented tradeoff, not a hard error bound).
Delta-band observations contribute floor (minimum meaningful count).
suggest_spectral_model_capacity ¶
suggest_spectral_model_capacity(
budget: SpectralDataBudget,
) -> SpectralModelCapacityHints
Map global span vs finest scale to encoder width and model-family hints.
spectroscopicity = wavelength_span / min_variation_scale grows when many
narrow bands or small σ sit inside a wide global λ range.
Training¶
fit ¶
fit(
observations: Sequence[FieldObservation],
model: Module,
*,
steps: int = 200,
lr: float = 0.005,
weight_decay: float = 0.0,
ema_decay: float = 0.0,
num_spectral_samples: int = 9,
loss_kind: FieldLossKind = "mse",
charbonnier_eps: float = 0.001,
huber_delta: float = 0.05,
loss_reduction: FieldLossReduction = "per_observation",
lr_schedule: FieldLRSchedule = "constant",
grad_clip_norm: float | None = None,
curriculum: FieldCurriculum = "none",
training_spectral_sampling: FieldSpectralSampling = "deterministic_quadrature",
training_spectral_sampling_grid_size: int | None = None,
spatial_sampling: FieldSpatialSampling = "center",
spectral_anchor_observations_per_step: int = 0,
spectral_anchor_num_samples: int | None = None,
spectral_anchor_loss_weight: float = 0.0,
component_anchor_terms: Sequence[
FieldComponentAnchorTerm
]
| None = None,
component_anchor_num_spectral_samples: int
| None = None,
component_anchor_loss_kind: FieldLossKind | None = None,
component_centroid_anchor_terms: Sequence[
FieldCentroidAnchorTerm
]
| None = None,
lr_warmup_steps: int = 0,
spatial_smoothness_weight: float = 0.0,
spatial_smoothness_grid_size: int = 8,
gradient_residual_weight: float = 0.0,
observations_per_step: int | None = None,
observation_sampling: FieldObservationSampling = "uniform",
training_patch_size: int | None = None,
training_patches_per_observation: int = 1,
pixel_samples_per_observation: int | None = None,
shared_sky_patch_sampling: bool = False,
streaming_accumulation: bool = False,
full_observations_per_step: int = 0,
context_observations_per_step: int = 0,
context_downsample_factor: int = 1,
context_loss_weight: float = 0.0,
spectral_observability_weight: float = 0.0,
spectral_observability_probe_grid_size: int = 8,
residual_head_penalty_weight: float = 0.0,
hybrid_foam_sparsity_weight: float = 0.0,
hybrid_correlation_weight: float = 0.0,
hybrid_probe_grid_size: int = 8,
operator_scale_gate_weight: float = 0.0,
operator_scale_shift_weight: float = 0.0,
noise_pretrain_kind: FieldNoisePretrainKind = "none",
noise_pretrain_steps: int = 0,
noise_pretrain_lr: float | None = None,
noise_pretrain_observations_per_step: int | None = None,
noise_pretrain_pixel_samples_per_observation: int = 1024,
noise_pretrain_num_terms: int = 48,
noise_pretrain_max_frequency: float = 8.0,
freeze_field_encoder: bool = False,
freeze_field_body: bool = False,
amp_dtype: FieldAMPDtype = "none",
amp_scaler_state: Mapping[str, Any] | None = None,
device: device | str | None = None,
observation_forward_contexts: Sequence[
ForwardContext | None
]
| None = None,
observation_operator_bundles: Sequence[
ObservationOperatorBundle
]
| None = None,
operator_calibration_terms: Sequence[
OperatorCalibrationTerm
]
| None = None,
observation_exposure_poses: Sequence[
ExposurePose | None
]
| None = None,
refine_poses: bool = False,
anchor_first_pose: bool = True,
render_spatial_tile_hw: tuple[int, int] | None = None,
diagnostic_spatial_tile_hw: tuple[int, int]
| None = None,
optimizer_state: Mapping[str, Any] | None = None,
sampling_rng_state: Tensor | None = None,
_progress_callback: Callable[[int, float], None]
| None = None,
) -> FieldFitResult
Fit observations, optionally recomputing tiled structured-noise renders.
With streaming_accumulation and render_spatial_tile_hw, structured
noise uses one full-exposure likelihood and replays each renderer tile for
its gradient. Renderer activations are bounded by tile size; prediction,
residual, and noise-model storage still scale with exposure size. As with
activation checkpointing, rendering must not mutate model state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
observations
|
Sequence[FieldObservation]
|
Non-empty sequence of field observations to fit. |
required |
model
|
Module
|
Field module whose parameters are optimized in place. |
required |
steps
|
int
|
Number of optimizer steps. |
200
|
lr
|
float
|
Initial learning rate. |
0.005
|
device
|
device | str | None
|
Optional training device. |
None
|
loss_kind
|
FieldLossKind
|
Per-pixel fitting loss. |
'mse'
|
num_spectral_samples
|
int
|
Spectral quadrature samples per observation. |
9
|
render_spatial_tile_hw
|
tuple[int, int] | None
|
Optional renderer tile height and width. |
None
|
Returns:
| Type | Description |
|---|---|
FieldFitResult
|
Fit diagnostics, optimizer state, and reproducibility state. |
Examples:
>>> from torchsky.field import fit
>>> callable(fit)
True
fit_component_decomposition ¶
fit_component_decomposition(
observations: Sequence[FieldObservation],
*,
component_roles: Sequence[str],
model: FieldComponentDecomposition | None = None,
domain: FieldDomain | None = None,
component_models: Sequence[Module] | None = None,
component_model_kind: FieldModelKind = "sine_implicit",
component_model_kwargs: dict[str, object] | None = None,
surveys: Sequence[str] | None = None,
instruments: Sequence[str] | None = None,
observation_forward_contexts: Sequence[
ForwardContext | None
]
| None = None,
dtype: dtype = float32,
device: device | str | None = None,
**fit_kwargs: Any,
) -> FieldFitResult
Construct and fit a field decomposition model on context-labeled observations.
fit_hybrid ¶
fit_hybrid(
observations: Sequence[FieldObservation],
model: DiffuseFoamHybridField,
*,
diffuse_steps: int,
foam_steps: int,
joint_steps: int,
joint_foam_sparsity_weight: float = 0.0,
joint_correlation_weight: float = 0.0,
**fit_kwargs: Any,
) -> FieldFitResult
Fit diffuse, localized, then joint hybrid stages on one operator path.
fit_noise_crossfit ¶
fit_noise_crossfit(
observations: Sequence[FieldObservation],
cross_fitted_predictions: Sequence[Tensor],
*,
models: Sequence[StructuredDetectorNoise] | None = None,
steps: int = 100,
lr: float = 0.01,
device: device | str | None = None,
) -> tuple[
tuple[StructuredDetectorNoise, ...], tuple[float, ...]
]
Calibrate exposure noise only from leave-one-exposure-out predictions.
cross_fitted_predictions[e] must come from a scene fit that excluded
observation e. The function cannot verify that provenance, so callers
should record the exclusion split alongside the returned parameters.
Models are frozen before return for the subsequent scene fit.
Types¶
ComponentAnchorTerm
dataclass
¶
ComponentAnchorTerm(
observation: FieldObservation,
target_image: Tensor | None = None,
target_values: Tensor | None = None,
reference_model: Module | None = None,
roles: str | tuple[str, ...] = "shared",
sample_ra_deg: Tensor | None = None,
sample_dec_deg: Tensor | None = None,
sample_x_pix: Tensor | None = None,
sample_y_pix: Tensor | None = None,
sample_weight: Tensor | None = None,
override_wavelengths: Tensor | None = None,
override_bandpass_weights: Tensor | None = None,
forward_context: ForwardContext | None = None,
loss_weight: float = 1.0,
)
Domain
dataclass
¶
Domain(
center_ra_deg: float,
center_dec_deg: float,
spatial_scale_deg: float,
wavelength_center: float,
wavelength_scale: float,
coord_mode: FieldCoordinateMode = "local_tangent",
)
Sky + wavelength normalization box for continuous field models.
spatial_scale_deg is a footprint scale in degrees (from WCS pixel scale × extent).
Sky-encoder fields use it when scale_fourier_to_domain=True to choose spherical
Fourier min_frequency so bands resolve structure inside the patch.
FieldObservation
dataclass
¶
FieldObservation(
image: Tensor,
header: dict,
weight: Tensor | None = None,
mask: Tensor | None = None,
err: Tensor | None = None,
var_poisson: Tensor | None = None,
var_rnoise: Tensor | None = None,
var_flat: Tensor | None = None,
contamination_prior: Tensor | None = None,
amplifier_index: Tensor | None = None,
wavelength: float | None = None,
spectral_min: float | None = None,
spectral_max: float | None = None,
transmission_center: float | None = None,
transmission_sigma: float | None = None,
transmission_wavelength: Tensor | None = None,
transmission_throughput: Tensor | None = None,
psf_sigma_pix: float = 0.0,
psf_spec: PSFSpec | None = None,
sky_background: Tensor | None = None,
instrument_background: Tensor | None = None,
detector_background: Tensor | None = None,
background_offset: float = 0.0,
band_name: str | None = None,
spectral_quantity: FieldSpectralQuantity | None = None,
detector_x0_pix: float = 0.0,
detector_y0_pix: float = 0.0,
detector_to_sky: DetectorToSkyTransform | None = None,
passband: Passband | None = None,
value_unit: str | None = None,
value_semantics: str | None = None,
spectral_unit: str | None = None,
detector_law: DetectorLaw | None = None,
gain_electrons_per_adu: Tensor | float | None = None,
gain_provenance_id: str | None = None,
exposure_time_s: float | None = None,
collecting_area_m2: float | None = None,
additive_components: tuple[AdditiveComponent, ...] = (),
processing_state: AdditiveProcessingState | None = None,
)
One band-limited 2D map plus spectral metadata for field fitting.
Use :mod:torchsky.map.field.observation_builders to turn binned 1D spectra,
IFU channel cubes, or X-ray-style center/width summaries into observation lists.
Set spectral_quantity when the axis is energy (e.g. keV) rather than wavelength.
Optional transmission_wavelength / transmission_throughput give a tabulated
throughput curve (same units as the spectral axis, dimensionless throughput).
When both are set, bandpass quadrature integrates against this curve (trapezoid
rule on the quadrature grid, with linear interpolation of throughput) instead of
the uniform-in-band or Gaussian fallbacks from transmission_sigma.
_cached_coordinate_signature
class-attribute
instance-attribute
¶
_cached_coordinate_signature: tuple[Any, ...] | None = (
field(default=None, init=False, repr=False)
)
_cached_dec_deg
class-attribute
instance-attribute
¶
_cached_dec_deg: Tensor | None = field(
default=None, init=False, repr=False
)
_cached_ra_deg
class-attribute
instance-attribute
¶
_cached_ra_deg: Tensor | None = field(
default=None, init=False, repr=False
)
additive_components
class-attribute
instance-attribute
¶
additive_components: tuple[AdditiveComponent, ...] = ()
detector_to_sky
class-attribute
instance-attribute
¶
detector_to_sky: DetectorToSkyTransform | None = None
gain_electrons_per_adu
class-attribute
instance-attribute
¶
gain_electrons_per_adu: Tensor | float | None = None
instrument_background
class-attribute
instance-attribute
¶
instrument_background: Tensor | None = None
processing_state
class-attribute
instance-attribute
¶
processing_state: AdditiveProcessingState | None = None
spectral_quantity
class-attribute
instance-attribute
¶
spectral_quantity: FieldSpectralQuantity | None = None
transmission_throughput
class-attribute
instance-attribute
¶
transmission_throughput: Tensor | None = None
transmission_wavelength
class-attribute
instance-attribute
¶
transmission_wavelength: Tensor | None = None
clear_coordinate_cache ¶
clear_coordinate_cache() -> None
Drop cached WCS coordinate grids after mutating image shape or header.
coordinate_cache_signature ¶
coordinate_cache_signature(
shape: tuple[int, int],
) -> tuple[Any, ...]
Return a lightweight signature for cached WCS coordinate grids.
to ¶
to(
device: device | str | None = None,
dtype: dtype | None = None,
) -> "FieldObservation"
Return an independently moved observation with semantic dtypes preserved.
Floating detector planes follow dtype. Boolean masks and integer
amplifier indices retain their semantic dtype. Nested modules are copied
before moving, so the source observation is not mutated. Coordinate caches
are intentionally dropped by :func:dataclasses.replace.
validate_certified ¶
validate_certified(
forward_context: ForwardContext,
) -> "FieldObservation"
Validate the strict native-observation contract used for claims.
Legacy and exploratory observations remain valid without these fields; production adapters opt into this fail-closed check explicitly.
FitResult
dataclass
¶
FitResult(
model: Module,
loss_history: tuple[float, ...],
final_loss: float,
diagnostics: dict[str, Any] | None = None,
exposure_poses: tuple[ExposurePose | None, ...]
| None = None,
operator_bundle: ObservationOperatorBundle
| None = None,
observation_operator_bundles: tuple[
ObservationOperatorBundle, ...
]
| None = None,
optimizer_state: dict[str, Any] | None = None,
amp_scaler_state: dict[str, Any] | None = None,
sampling_rng_state: Tensor | None = None,
completed_steps: int = 0,
_pre_train_loss: float | None = None,
)
amp_scaler_state
class-attribute
instance-attribute
¶
amp_scaler_state: dict[str, Any] | None = None
exposure_poses
class-attribute
instance-attribute
¶
exposure_poses: tuple[ExposurePose | None, ...] | None = (
None
)
initial_loss
property
¶
initial_loss: float
Loss on full observations before any training (when available),
otherwise loss_history[0] (loss after the first optimizer step).
observation_operator_bundles
class-attribute
instance-attribute
¶
observation_operator_bundles: (
tuple[ObservationOperatorBundle, ...] | None
) = None
operator_bundle
class-attribute
instance-attribute
¶
operator_bundle: ObservationOperatorBundle | None = None
training_loss_after_step ¶
training_loss_after_step(step: int) -> float
Training loss after optimizer step step (1-based, matches loss_history index + 1).
ForwardContext
dataclass
¶
ForwardContext(
survey: str | None = None,
instrument: str | None = None,
detector: str | None = None,
exposure_id: str | None = None,
time_mjd: float | None = None,
extra: dict[str, Any] = dict(),
time_scale: TimeScale | None = None,
calibration_id: str | None = None,
provenance_id: str | None = None,
)
Exposure / instrument context c (see docs/models/fields.md).
Rendering passes this to nn.Module.forward or render_bandpass only when
the model declares a forward_context keyword parameter. Otherwise it is ignored
so existing field models stay valid without changes.
validate_certified ¶
validate_certified() -> 'ForwardContext'
Fail closed unless the context identifies one calibrated exposure.
PSFSpec
dataclass
¶
PSFSpec(
mode: FieldPSFMode = "none",
sigma_pix: float = 0.0,
kernel2d: Tensor | None = None,
model: Module | None = None,
cell_u_pix: Tensor | None = None,
cell_lam_norm: float = 0.5,
frozen: bool = True,
pixel_response_included: bool | None = None,
)
Public PSF description for field observations and target products.
kernel2d is an odd-sized, image-shaped unit-source response: its center
indexes zero displacement and increasing columns/rows are positive detector
x/y offsets. Rendering normalizes its sum and retains zero-padding losses
at detector boundaries. It is not a PyTorch cross-correlation weight array.
Learned PSFs are calibration products and are frozen while rendering a sky
scene. frozen=False is reserved for a future calibration-only execution
path; the scene renderer rejects it instead of silently dropping gradients.
pixel_response_included
class-attribute
instance-attribute
¶
pixel_response_included: bool | None = None
Whether the calibrated kernel already includes detector pixel response.
True requires center sampling; another pixel quadrature would integrate twice. False records an optical-only kernel; None leaves legacy calibration unknown. This metadata does not certify the accuracy of discrete detector-grid convolution.
learned
classmethod
¶
learned(
model: Module,
*,
base_sigma_pix: float,
cell_u_pix: Tensor | None = None,
cell_lam_norm: float = 0.5,
frozen: bool = True,
) -> "PSFSpec"
to ¶
to(
device: device | str | None = None,
dtype: dtype | None = None,
) -> "PSFSpec"
Return an independently moved PSF without mutating the source model.
SpectralDataBudget
dataclass
¶
SpectralDataBudget(
observations: tuple[ObservationSpectralSummary, ...],
wavelength_min: float,
wavelength_max: float,
wavelength_span: float,
min_variation_scale: float,
max_variation_scale: float,
n_distinct_band_specs: int,
)
Aggregated spectral complexity from a list of :class:FieldObservation.
SpectralModelCapacityHints
dataclass
¶
SpectralModelCapacityHints(
spectroscopicity: float,
profile: SpectralCapacityProfile,
spectral_frequencies: int,
num_spectral_frequencies_basis: int,
recommended_model_kinds: tuple[str, ...],
rationale: str,
)
Suggested encoder / model capacity from a :class:SpectralDataBudget.
num_spectral_frequencies_basis
instance-attribute
¶
num_spectral_frequencies_basis: int
Suggested num_spatial_frequencies-style order for spectral-basis families.
spectral_frequencies
instance-attribute
¶
spectral_frequencies: int
Suggested spectral_frequencies for :class:SkyCoordinateEncoder / sky MLP fields.
spectroscopicity
instance-attribute
¶
spectroscopicity: float
wavelength_span / min_variation_scale (large ⇒ finer λ structure).
Typing¶
FieldModelKind
typing.Literal['sine_implicit', 'wire_implicit', 'sasnet', 'bacon', 'flair_bla', 'explicit_spectral_grid_field', 'gaussian_basis', 'fourier_mlp', 'spectral_power_foam', 'foam_initialized_inr', 'diffuse_foam_hybrid', 'spectral_basis_field', 'learned_spectral_basis_field', 'sky_encoder_bandpass_field', 'sky_lambda_planes_field', 'sky_lambda_kplanes_field', 'sky_lambda_feature_field', 'operator_constrained_feature_field', 'sky_lambda_feature_field_hetero', 'sky_lambda_feature_atlas_field', 'sky_lambda_atlas_field', 'bandpass_conditioned_field', 'conditioned_spectral_field', 'hashgrid_conditioned_field', 'sky_encoder_mlp', 'strainer_sky_encoder_mlp', 'sky_encoder_resmlp', 'hashgrid_mlp', 'hashgrid_resmlp', 'hashgrid_spectral_field']
PresetName
typing.Literal['fast', 'balanced', 'spectral', 'operator_constrained']
RenderTarget
typing.Literal['observation', 'samples', 'cube', 'healpix', 'cube_via_healpix']
SpectralCapacityProfile
typing.Literal['photometric_wide', 'multiband', 'narrowband_sweep', 'spectroscopic']