torchsky.wcs¶
Stability: core. Names on this page follow the deprecation policy in contributing.
Tensor-native FITS WCS: analytic and distorted projections, SIP/TPV and lookup-table distortions, spectral and time axes, tabular and coupled axes, celestial frames, sampled GWCS detector tables, and astrometric calibration. Every transform accepts and returns torch.Tensor and dispatches on the axes present in the header.
Guides: coordinates, frames, psf-conventions
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.wcs unless the group text says otherwise.
Header parse¶
WCSHeaderWarning ¶
Bases: UserWarning
A header was read under a documented compatibility rule its CTYPE does not state.
The one rule today is the pre-2012 SCAMP spelling: CTYPE = RA---TAN /
DEC--TAN with PVi_m cards where some m >= 5. WCSLIB and Astropy
read that as TPV, and so does torchsky, rewriting CTYPE to -TPV and
emitting this warning. Turn it into an error with
warnings.simplefilter("error", WCSHeaderWarning).
Alignment¶
AffineFitResult
dataclass
¶
AffineFitResult(
matrix: Tensor,
offset: Tensor,
residuals: Tensor,
rms: Tensor,
geometry: str,
inlier_mask: Tensor,
iterations: int,
)
Weighted 2D affine correction fit.
SkyAffineFitResult
dataclass
¶
SkyAffineFitResult(
frame: TangentPlaneFrame, affine: AffineFitResult
)
Affine correction fitted in a local tangent plane.
TangentPlaneFrame
dataclass
¶
TangentPlaneFrame(ra0: float, dec0: float)
Gnomonic tangent plane centered on a sky position.
fit_affine_2d ¶
fit_affine_2d(
source: Any,
target: Any,
*,
weights: Any | None = None,
geometry: AffineGeometry = "general",
sigma_clip: float | None = None,
max_iter: int = 3,
) -> AffineFitResult
Fit a weighted 2D correction from source to target points.
Geometry modes mirror common tweakwcs alignment families:
shift (translation), rshift (rotation + translation),
rscale (uniform scale + rotation + translation), and general
(full affine + translation).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Any
|
Input points with shape |
required |
target
|
Any
|
Corresponding target points with shape |
required |
weights
|
Any | None
|
Optional nonnegative per-point weights. |
None
|
geometry
|
AffineGeometry
|
Constrained affine transformation family. |
'general'
|
sigma_clip
|
float | None
|
Optional residual clipping threshold in robust sigmas. |
None
|
max_iter
|
int
|
Maximum clipping-and-refit iterations. |
3
|
Returns:
| Type | Description |
|---|---|
AffineFitResult
|
Fitted matrix, offset, residuals, mask, and fit diagnostics. |
Examples:
>>> import torch
>>> from torchsky.wcs import fit_affine_2d
>>> fit = fit_affine_2d(torch.tensor([[0.0, 0.0]]), torch.tensor([[1.0, 2.0]]), geometry="shift")
>>> fit.offset.tolist()
[1.0, 2.0]
fit_sky_affine ¶
fit_sky_affine(
source_ra: Any,
source_dec: Any,
target_ra: Any,
target_dec: Any,
*,
frame: TangentPlaneFrame | None = None,
weights: Any | None = None,
geometry: AffineGeometry = "general",
sigma_clip: float | None = None,
max_iter: int = 3,
) -> SkyAffineFitResult
Fit a local sky-coordinate affine correction in a gnomonic plane.
Astrometric calibration¶
ApproximateMatchResult
dataclass
¶
ApproximateMatchResult(
reference_indices: Tensor, separation_arcsec: Tensor
)
AstrometricMatchGraph ¶
AstrometricMatchGraph(
observations: Sequence[AstrometricObservation],
*,
reference_source_ids: Any | None = None,
reference_positions: Any | None = None,
reference_covariance: Any | None = None,
reference_proper_motion_mas_per_year: Any | None = None,
reference_proper_motion_covariance: Any | None = None,
reference_parallax_mas: Any | None = None,
reference_parallax_variance: Any | None = None,
tangent_frame: TangentPlaneFrame | None = None,
)
Bipartite exposure/source graph for supplied matches and reference priors.
reference_motion_precision
instance-attribute
¶
reference_motion_precision = reference_motion_precision
reference_parallax_precision
instance-attribute
¶
reference_parallax_precision = reference_parallax_precision
_components
staticmethod
¶
_components(
n_exposure: int,
n_source: int,
row_exposure: Tensor,
row_source: Tensor,
reference_mask: Tensor,
) -> tuple[
tuple[tuple[int, ...], ...],
tuple[tuple[int, ...], ...],
tuple[bool, ...],
]
_plane_covariance
staticmethod
¶
_plane_covariance(
observations: tuple[AstrometricObservation, ...],
frame: TangentPlaneFrame,
) -> Tensor
solve ¶
solve(
config: AstrometryConfig | None = None,
*,
source_colors: Tensor | None = None,
fit_mask: Tensor | None = None,
) -> AstrometrySolution
AstrometricObservation
dataclass
¶
AstrometricObservation(
exposure_id: Hashable,
detector_xy: Tensor,
source_ids: Tensor | None,
centroid_covariance: Tensor,
approximate_wcs: Any | None = None,
sky_position: Tensor | None = None,
epoch: Epoch | Tensor | float | None = None,
detector_id: Hashable = "detector",
covariance_space: CovarianceSpace = "detector",
world_jacobian: Tensor | None = None,
color: Tensor | None = None,
dcr_basis: Tensor | None = None,
lateral_color_basis: Tensor | None = None,
zenith_angle_deg: Tensor | float | None = None,
parallactic_angle_deg: Tensor | float | None = None,
parallax_factor: Tensor | None = None,
)
One exposure's supplied centroid catalog and match identifiers.
sky_position is the approximate sky position in degrees. When omitted,
it is evaluated from detector_xy through approximate_wcs. A tangent
covariance is in square arcseconds; a detector covariance is in square
pixels and is propagated with a local approximate-WCS Jacobian.
approximate_wcs
class-attribute
instance-attribute
¶
approximate_wcs: Any | None = field(
default=None, repr=False, compare=False
)
covariance_space
class-attribute
instance-attribute
¶
covariance_space: CovarianceSpace = 'detector'
parallactic_angle_deg
class-attribute
instance-attribute
¶
parallactic_angle_deg: Tensor | float | None = None
zenith_angle_deg
class-attribute
instance-attribute
¶
zenith_angle_deg: Tensor | float | None = None
AstrometryConfig
dataclass
¶
AstrometryConfig(
pose_model: PoseModel = "rscale",
max_iterations: int = 15,
convergence_tolerance: float = 1e-08,
huber_delta: float = 3.0,
cg_max_iterations: int = 200,
cg_rtol: float = 1e-10,
cg_atol: float = 0.0,
damping: float = 1e-12,
fit_detector_grid: bool = False,
detector_grid_shape: tuple[int, int] = (4, 4),
detector_grid_regularization: float = 1e-08,
fit_dcr: bool = False,
fit_lateral_color: bool = False,
color_pivot: float = 0.0,
missing_color: MissingPolicy = "error",
fit_proper_motion: bool = False,
fit_parallax: bool = False,
reference_epoch: float = 2000.0,
epoch_format: Literal[
"jd", "mjd", "jyear", "byear", "unix"
] = "jyear",
epoch_scale: Literal[
"utc", "tai", "tt", "gps", "ut1", "tcb", "tdb"
] = "tcb",
missing_epoch: Literal["error", "reference"] = "error",
rank_policy: RankPolicy = "error",
rank_rtol: float = 1e-10,
covariance_max_parameters: int = 256,
covariance_jacobian_step: float = 0.001,
)
covariance_jacobian_step
class-attribute
instance-attribute
¶
covariance_jacobian_step: float = 0.001
detector_grid_regularization
class-attribute
instance-attribute
¶
detector_grid_regularization: float = 1e-08
detector_grid_shape
class-attribute
instance-attribute
¶
detector_grid_shape: tuple[int, int] = (4, 4)
epoch_format
class-attribute
instance-attribute
¶
epoch_format: Literal[
"jd", "mjd", "jyear", "byear", "unix"
] = "jyear"
epoch_scale
class-attribute
instance-attribute
¶
epoch_scale: Literal[
"utc", "tai", "tt", "gps", "ut1", "tcb", "tdb"
] = "tcb"
missing_epoch
class-attribute
instance-attribute
¶
missing_epoch: Literal['error', 'reference'] = 'error'
AstrometryDiagnostics
dataclass
¶
AstrometryDiagnostics(
converged: bool,
iterations: int,
objective_history: tuple[float, ...],
step_history: tuple[float, ...],
cg_iterations: tuple[int, ...],
reduced_rank: int | None,
reduced_dimension: int,
condition_number: float | None,
connected_components: tuple[tuple[Hashable, ...], ...],
gauge_exposures: tuple[Hashable, ...],
kinematic_gauge_sources: tuple[int, ...],
reference_anchored_components: tuple[bool, ...],
dropped_source_blocks: tuple[int, ...],
dropped_dcr_exposures: tuple[Hashable, ...],
dropped_lateral_color_detectors: tuple[Hashable, ...],
matrix_free_reduced: bool = True,
assembled_observation_matrix: bool = False,
)
AstrometrySolution
dataclass
¶
AstrometrySolution(
exposure_ids: tuple[Hashable, ...],
source_ids: Tensor,
pose_model: str,
pose_parameters: Tensor,
source_positions: Tensor,
source_tangent_positions: Tensor,
proper_motion_mas_per_year: Tensor | None,
parallax_mas: Tensor | None,
dcr_coefficients: Tensor | None,
lateral_color_coefficients: Tensor | None,
detector_ids: tuple[Hashable, ...],
detector_residual_control: Tensor | None,
residuals_arcsec: Tensor,
robust_weights: Tensor,
exposure_covariance: dict[Hashable, Tensor],
diagnostics: AstrometryDiagnostics,
fit_mask: Tensor,
)
match_approximate_wcs ¶
match_approximate_wcs(
observation: AstrometricObservation,
reference_sky: Any,
*,
radius_arcsec: float,
index: HealpixIndex | None = None,
) -> ApproximateMatchResult
Nearest supplied-reference matching, using only HealpixIndex candidates.
solve_astrometry ¶
solve_astrometry(
graph: AstrometricMatchGraph,
config: AstrometryConfig | None = None,
) -> AstrometrySolution
Solve an astrometric match graph for exposure and source parameters.
tangent_plane_block_residuals ¶
tangent_plane_block_residuals(
observed: Any,
predicted: Any,
centroid_covariance: Any,
reference_covariance: Any | None = None,
*,
robust_weights: Any | None = None,
whiten: bool = True,
) -> Tensor
Return differentiable two-coordinate residual blocks with full covariance.
Astrometry.net bootstrap¶
AstrometryNetBootstrapResult
dataclass
¶
AstrometryNetBootstrapResult(
hypothesis: AstrometryNetHypothesis,
verification: AstrometryNetVerification,
bundle_solution: AstrometrySolution,
provenance: AstrometryNetProvenance,
)
AstrometryNetConfig
dataclass
¶
AstrometryNetConfig(
executable: str | Path,
executable_sha256: str,
executable_version: str,
index_manifest: str | Path,
index_manifest_sha256: str,
timeout_seconds: float = 60.0,
version_args: tuple[str, ...] = ("--version",),
)
AstrometryNetError ¶
Bases: RuntimeError
AstrometryNetExecutionError ¶
Bases: AstrometryNetError
AstrometryNetHypothesis
dataclass
¶
AstrometryNetHypothesis(
header: Mapping[str, Any],
center_ra_deg: float,
center_dec_deg: float,
pixel_scale_arcsec: tuple[float, float],
orientation_deg: float,
determinant_deg2_per_pixel2: float,
handedness: Literal["right", "left"],
parity: Literal["normal", "flipped"],
index_id: int,
index_healpix: int,
index_hpnside: int,
log_odds: float,
matched_sources: int,
)
AstrometryNetHypothesisRejected ¶
Bases: AstrometryNetError
AstrometryNetIdentityError ¶
Bases: AstrometryNetError
AstrometryNetIndexIdentity
dataclass
¶
AstrometryNetIndexIdentity(
index_id: str,
version: str,
manifest_path: str,
manifest_sha256: str,
backend_config_path: str,
backend_config_sha256: str,
astrometry_index_ids: tuple[int, ...],
files: tuple[tuple[str, str], ...],
)
AstrometryNetProvenance
dataclass
¶
AstrometryNetProvenance(
executable_path: str,
executable_sha256: str,
executable_version: str,
index: AstrometryNetIndexIdentity,
bootstrap_arguments: tuple[str, ...],
verification_arguments: tuple[str, ...],
bootstrap_input_count: int,
verification_input_count: int,
runtime_downloads: bool = False,
)
AstrometryNetUnavailableError ¶
Bases: AstrometryNetError
AstrometryNetVerification
dataclass
¶
AstrometryNetVerification(
supplied_count: int,
matched_count: int,
residuals_pixels: Tensor,
rms_pixels: float,
max_pixels: float,
)
AstrometryNetVerificationConfig
dataclass
¶
AstrometryNetVerificationConfig(
min_matches: int,
max_rms_pixels: float,
max_residual_pixels: float,
reference_sigma_arcsec: float = 0.01,
)
solve_with_astrometry_net ¶
solve_with_astrometry_net(
x: Any,
y: Any,
*,
image_width: int,
image_height: int,
scale_arcsec_per_pixel: tuple[float, float],
verification_mask: Any,
external: AstrometryNetConfig,
verification: AstrometryNetVerificationConfig,
flux: Any | None = None,
covariance: Any | None = None,
pixel_origin: Literal[0, 1] = 0,
bundle_config: AstrometryConfig | None = None,
) -> AstrometryNetBootstrapResult
Bootstrap a supplied centroid list and refine accepted correspondences.
Coupled calibration¶
CoupledCalibrationConfig
dataclass
¶
CoupledCalibrationConfig(
astrometry: AstrometryConfig = AstrometryConfig(),
max_iterations: int = 6,
photometry_max_iterations: int = 20,
convergence_tolerance: float = 1e-07,
photometry_convergence_tolerance: float = 1e-08,
huber_delta: float = 3.0,
fit_extinction: bool = True,
fit_cloud: bool = True,
fit_star_flat: bool = True,
fit_color_terms: bool = True,
color_bands: tuple[Hashable, Hashable] | None = None,
color_pivot: float = 0.0,
color_scale: float = -2.5 / log(10.0),
missing_color: MissingColorPolicy = "drop",
fit_variability: bool = False,
variable_source_ids: tuple[int, ...] = (),
holdout_source_ids: tuple[int, ...] = (),
holdout_exposure_ids: tuple[Hashable, ...] = (),
damping: float = 1e-10,
rank_rtol: float = 1e-10,
cg_max_iterations: int = 500,
cg_rtol: float = 1e-10,
covariance_max_parameters: int = 256,
)
astrometry
class-attribute
instance-attribute
¶
astrometry: AstrometryConfig = field(
default_factory=AstrometryConfig
)
color_bands
class-attribute
instance-attribute
¶
color_bands: tuple[Hashable, Hashable] | None = None
holdout_exposure_ids
class-attribute
instance-attribute
¶
holdout_exposure_ids: tuple[Hashable, ...] = ()
photometry_convergence_tolerance
class-attribute
instance-attribute
¶
photometry_convergence_tolerance: float = 1e-08
CoupledCalibrationDiagnostics
dataclass
¶
CoupledCalibrationDiagnostics(
converged: bool,
iterations: int,
stage_history: tuple[str, ...],
astrometric_step_history: tuple[float, ...],
photometric_step_history: tuple[float, ...],
color_step_history: tuple[float, ...],
source_holdout_count: int,
exposure_holdout_count: int,
)
CoupledCalibrationGraph ¶
CoupledCalibrationGraph(
astrometry_graph: AstrometricMatchGraph,
photometric_blocks: Sequence[
PhotometricMeasurementBlock
],
*,
reference: PhotometricReference | None = None,
sed_basis: Tensor | None = None,
)
Fixed-association exposure-source graph with astrometric and flux blocks.
base_fit_mask
instance-attribute
¶
base_fit_mask = cat(
[_normalized(fit_mask) for block in blocks]
)
cloud_basis
instance-attribute
¶
cloud_basis = cat(
[_normalized(cloud_basis) for block in blocks]
)
extinction_basis
instance-attribute
¶
extinction_basis = cat(
[_normalized(extinction_basis) for block in blocks]
)
log_covariance
instance-attribute
¶
log_covariance = tuple(
flux_covariance / (flux[:, None] * flux[None, :])
for block in blocks
)
CoupledCalibrationSolution
dataclass
¶
CoupledCalibrationSolution(
astrometry: AstrometrySolution,
photometry: PhotometricCalibrationSolution,
diagnostics: CoupledCalibrationDiagnostics,
covariance: dict[str, object],
provenance: dict[str, object],
)
PhotometricCalibrationDiagnostics
dataclass
¶
PhotometricCalibrationDiagnostics(
converged: bool,
iterations: int,
objective_history: tuple[float, ...],
step_history: tuple[float, ...],
cg_iterations: tuple[int, ...],
connected_components: tuple[tuple[Hashable, ...], ...],
gauge_exposures: tuple[Hashable, ...],
reference_anchored_components: tuple[bool, ...],
dropped_extinction_exposures: tuple[Hashable, ...],
dropped_cloud_exposures: tuple[Hashable, ...],
dropped_star_flat_parameters: tuple[
tuple[Hashable, int], ...
],
dropped_color_bands: tuple[Hashable, ...],
information_rank: int | None,
information_dimension: int,
condition_number: float | None,
matrix_free: bool = True,
assembled_measurement_matrix: bool = False,
)
assembled_measurement_matrix
class-attribute
instance-attribute
¶
assembled_measurement_matrix: bool = False
dropped_extinction_exposures
instance-attribute
¶
dropped_extinction_exposures: tuple[Hashable, ...]
dropped_star_flat_parameters
instance-attribute
¶
dropped_star_flat_parameters: tuple[
tuple[Hashable, int], ...
]
PhotometricCalibrationSolution
dataclass
¶
PhotometricCalibrationSolution(
source_ids: Tensor,
bands: tuple[Hashable, ...],
source_band_flux: Tensor,
source_band_log_flux: Tensor,
source_coefficient_variance: Tensor,
colors: Tensor,
exposure_ids: tuple[Hashable, ...],
exposure_log_zeropoint: Tensor,
exposure_extinction: Tensor,
exposure_cloud: Tensor,
detector_ids: tuple[Hashable, ...],
star_flat_coefficients: Tensor,
band_color_terms: Tensor,
predicted_log_flux: Tensor,
residual_log_flux: Tensor,
robust_weights: Tensor,
variability_offsets: Tensor,
fit_mask: Tensor,
global_covariance: Tensor | None,
diagnostics: PhotometricCalibrationDiagnostics,
provenance: dict[str, object],
)
PhotometricMeasurementBlock
dataclass
¶
PhotometricMeasurementBlock(
exposure_id: Hashable,
source_ids: Tensor,
band: Hashable,
flux: Tensor,
flux_covariance: Tensor,
detector_id: Hashable = "detector",
extinction_basis: Tensor | float | None = None,
cloud_basis: Tensor | float | None = None,
star_flat_basis: Tensor | None = None,
weights: Tensor | None = None,
fit_mask: Tensor | None = None,
epoch: Tensor | float | None = None,
)
extinction_basis
class-attribute
instance-attribute
¶
extinction_basis: Tensor | float | None = None
PhotometricReference
dataclass
¶
PhotometricReference(
source_ids: Tensor,
bands: tuple[Hashable, ...],
flux: Tensor,
flux_variance: Tensor,
)
photometric_log_residuals ¶
photometric_log_residuals(
measured_flux: Any,
predicted_flux: Any,
flux_covariance: Any,
*,
weights: Any | None = None,
whiten: bool = True,
) -> Tensor
Compute optionally whitened log-flux residuals for calibration.
solve_coupled_calibration ¶
solve_coupled_calibration(
graph: CoupledCalibrationGraph,
config: CoupledCalibrationConfig | None = None,
) -> CoupledCalibrationSolution
Solve the coupled astrometric and photometric calibration graph.
Catalog state¶
CatalogState
dataclass
¶
CatalogState(
lon: Tensor,
lat: Tensor,
frame: str = "ICRS",
epoch: Tensor | float | Epoch = 2000.0,
epoch_scale: TimeScale | None = None,
epoch_format: TimeFormat | None = None,
pm_lon_coslat_mas_yr: Tensor | None = None,
pm_lat_mas_yr: Tensor | None = None,
parallax_mas: Tensor | None = None,
radial_velocity_km_s: Tensor | None = None,
valid: Tensor | None = None,
)
Batched sky state with explicit missing components.
Missing proper motion, parallax, or radial velocity stay None. They
are never filled from a default distance or a pmsafe override.
valid is an optional boolean mask; it is never used to impute values.
Coords¶
transform ¶
transform(
lon: Any,
lat: Any,
*,
from_frame: str,
to_frame: str,
obstime_mjd_utc: Any | None = None,
site: Site | None = None,
eop: EarthOrientation | None = None,
pn: PNModel | None = None,
aberration: bool = False,
refraction: bool = False,
refraction_model: RefractionModel = "refco",
) -> tuple[Tensor, Tensor]
Rotate or observe (lon, lat) tensors. Returns (lon_out, lat_out).
Geometric frames use CatalogState.to_frame. ALTAZ, ITRS,
GCRS, CIRS, and TETE require obstime_mjd_utc and eop.
ECLIPTIC_OF_DATE uses TT MJD (obstime_mjd_utc is treated as TT
unless you pass a TT value through CatalogState.to_frame).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lon
|
Any
|
Longitude values in degrees. |
required |
lat
|
Any
|
Latitude values in degrees. |
required |
from_frame
|
str
|
Input coordinate-frame name. |
required |
to_frame
|
str
|
Output coordinate-frame name. |
required |
obstime_mjd_utc
|
Any | None
|
Observation time in UTC MJD, or TT MJD for ecliptic-of-date. |
None
|
site
|
Site | None
|
Observing site required for altitude-azimuth output. |
None
|
eop
|
EarthOrientation | None
|
Earth-orientation parameters required for observed frames. |
None
|
pn
|
PNModel | None
|
Precession-nutation model. |
None
|
aberration
|
bool
|
Apply annual aberration for supported observed frames. |
False
|
refraction
|
bool
|
Apply atmospheric refraction to altitude-azimuth output. |
False
|
refraction_model
|
RefractionModel
|
|
'refco'
|
Returns:
| Type | Description |
|---|---|
tuple[Tensor, Tensor]
|
Output longitude and latitude tensors in degrees. |
Examples:
>>> import torch
>>> from torchsky.coords import transform
>>> lon, lat = transform(torch.tensor([0.0]), torch.tensor([0.0]), from_frame="ICRS", to_frame="GALACTIC")
>>> lon.shape == lat.shape
True
Core¶
DistortionLookupTable ¶
DistortionLookupTable(
data: Any,
crpix: tuple[float, float] = (1.0, 1.0),
crval: tuple[float, float] = (1.0, 1.0),
cdelt: tuple[float, float] = (1.0, 1.0),
)
FITS WCS Paper IV 2D distortion lookup table (CPDIS / DET2IM).
Matches astropy.wcs.DistortionLookupTable semantics:
1-based FITS pixel coordinates (x, y) map to 0-based table indices
tx = (x - crval1) / cdelt1 + crpix1 - 1, ty = (y - crval2) / cdelt2 + crpix2 - 1
and are bilinearly interpolated on data (shape (H, W) = (NAXIS2, NAXIS1)),
with clamping at table boundaries.
PrecisionWarning ¶
Bases: UserWarning
A WCS runs in float32 (MPS) with an expected error of half a pixel or more.
MPS has no float64. The warning is emitted once per WCS when the expected
float32 position error, (ulp32(world) / pixel scale) + ulp32(pixel extent)
in pixels, reaches 0.5 pixel: beyond that the nearest pixel can no longer be
identified reliably. Use CPU or CUDA (float64) for such grids.
WCS ¶
WCS(
header: Optional[Dict[str, Any]] = None,
key: str = "",
tabular_axes: Mapping[int, TabularAxis] | None = None,
coupled_tabular: CoupledTabularLookupWCS | None = None,
coupled_tabular_axes: Sequence[int] | None = None,
coupled_tabular_pixel_axes: Sequence[int] | None = None,
tables: Any = None,
cpdis1: DistortionLookupTable | Any | None = None,
cpdis2: DistortionLookupTable | Any | None = None,
det2im1: DistortionLookupTable | Any | None = None,
det2im2: DistortionLookupTable | Any | None = None,
**kwargs: Any,
)
Bases: _RotationMixin, _GeometryMixin, _HeaderIOMixin, _HeaderParseMixin, _WCSStateMixin, _SetupTensorsMixin, _PixelWorldCoreMixin, _AxesFramesMixin, _MixedMixin, _DifferentiableMixin
PyTorch-native world coordinate system parsed from FITS-style metadata.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
header
|
Optional[Dict[str, Any]]
|
FITS-style header mapping. An empty mapping creates a default WCS. |
None
|
key
|
str
|
Alternate-WCS suffix without the leading keyword letter. |
''
|
tabular_axes
|
Mapping[int, TabularAxis] | None
|
Explicit one-dimensional lookup axes keyed by world axis. |
None
|
coupled_tabular
|
CoupledTabularLookupWCS | None
|
Optional coupled multi-axis lookup transform. |
None
|
tables
|
Any
|
Table resolver used by |
None
|
cpdis1
|
DistortionLookupTable | Any | None
|
First prior-distortion lookup table. |
None
|
cpdis2
|
DistortionLookupTable | Any | None
|
Second prior-distortion lookup table. |
None
|
det2im1
|
DistortionLookupTable | Any | None
|
First detector-to-image lookup table. |
None
|
det2im2
|
DistortionLookupTable | Any | None
|
Second detector-to-image lookup table. |
None
|
Examples:
>>> from torchsky.wcs import WCS
>>> wcs = WCS({"NAXIS": 2, "CTYPE1": "RA---TAN", "CTYPE2": "DEC--TAN"})
>>> wcs.pixel_n_dim
2
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
header
|
Optional[Dict[str, Any]]
|
FITS header dictionary (or similar object behaving like dict) |
None
|
**kwargs
|
Any
|
Manual override for WCS keywords (CRVAL, CRPIX, CD, etc.) |
{}
|
ALLSKY_CODES
class-attribute
instance-attribute
¶
ALLSKY_CODES = ('AIT', 'MOL', 'HPX', 'SFL', 'XPH')
CYLINDRICAL_CODES
class-attribute
instance-attribute
¶
CYLINDRICAL_CODES = ('CEA', 'MER', 'CYP', 'CAR')
SPECIAL_CODES
class-attribute
instance-attribute
¶
SPECIAL_CODES = ('ZPX', 'TNX', 'TPV', 'NCP', 'GLS')
ZENITHAL_CODES
class-attribute
instance-attribute
¶
ZENITHAL_CODES = (
"TAN",
"SIN",
"ARC",
"ZPN",
"STG",
"ZEA",
"AZP",
"SZP",
"AIR",
)
_compiled_stack_pixel_to_world
instance-attribute
¶
_compiled_stack_pixel_to_world: (
dict[float, Callable[[Tensor], Tensor]] | None
) = None
_compiled_stack_world_to_pixel
instance-attribute
¶
_compiled_stack_world_to_pixel: (
dict[float, Callable[[Tensor], Tensor]] | None
) = None
_enable_cpp_dispatcher
instance-attribute
¶
_enable_cpp_dispatcher = (
get("TORCHSKY_CPP_DISPATCHER", "1") == "1"
)
cpdis1
instance-attribute
¶
cpdis1: DistortionLookupTable | None = (
_coerce_distortion_lookup_table(cpdis1)
)
cpdis2
instance-attribute
¶
cpdis2: DistortionLookupTable | None = (
_coerce_distortion_lookup_table(cpdis2)
)
det2im1
instance-attribute
¶
det2im1: DistortionLookupTable | None = (
_coerce_distortion_lookup_table(det2im1)
)
det2im2
instance-attribute
¶
det2im2: DistortionLookupTable | None = (
_coerce_distortion_lookup_table(det2im2)
)
_dropaxis_fixed_at_zero ¶
_dropaxis_fixed_at_zero(axis: int) -> 'WCS'
Drop an axis fixed by slicing at zero-based pixel coordinate 0.
_mps_float32_error_pixels ¶
_mps_float32_error_pixels() -> float
Expected float32 (MPS) round-trip position error in pixels.
One float32 ulp of the largest world value on each celestial axis
(longitude up to 360 degrees, scaled by cos(dec_0); latitude up to 90)
divided by the smallest pixel scale (norm of a CD column, degrees per
pixel), plus one ulp of the largest pixel coordinate (NAXISn or
2 CRPIXn). Zero without a celestial pair.
_normalize_axis_index
staticmethod
¶
_normalize_axis_index(
axis_index: int, axis_len: int | None
) -> int
_normalize_axis_slice
staticmethod
¶
_normalize_axis_slice(
axis_slice: slice, axis_len: int | None
) -> tuple[int, int | None, int]
_normalize_wcs_slice ¶
_normalize_wcs_slice(
view: "slice | int | tuple[slice | int | EllipsisType, ...]",
*,
numpy_order: bool,
) -> "tuple[slice | int, ...]"
_pixel_to_world_2d_fast ¶
_pixel_to_world_2d_fast(
x: Tensor, y: Tensor, origin: float = 0
) -> Tuple[Tensor, Tensor]
Fast path for common 2D separate-argument pixel->world calls.
_rebase_sip_header_for_diagonal_pixel_map ¶
_rebase_sip_header_for_diagonal_pixel_map(
header: dict[str, Any], steps: tuple[int, int]
) -> None
_require_wcs_device ¶
_require_wcs_device(value: Tensor, name: str) -> Tensor
Differentiable forms need the WCS on the coordinates' device.
The plain forms follow accelerator inputs; the differentiable forms keep WCS parameters in the graph (WCS fitting), so a device mismatch is reported here instead of moving parameters or failing inside torch.
_stacked_pixels_to_world_flat ¶
_stacked_pixels_to_world_flat(
pixels_flat: Tensor,
origin: float,
*,
allow_cpp_sphere: bool = True,
) -> Tensor
Fused pixels (internal) -> rel -> world for torch.compile (2D spatial).
_sub_wcs ¶
_sub_wcs(
keep_axes: list[int],
*,
fixed_rel_by_axis: dict[int, Tensor | float]
| None = None,
) -> "WCS"
_transform_optimized ¶
_transform_optimized(
rel: Tensor, *, allow_cpp_sphere: bool = True
) -> Tensor
The hot path for coordinate transformation. Input: (N, NAXIS) relative pixels (pix - crpix [internal]) Output: (N, NAXIS) world
When allow_cpp_sphere is False, pole spherical rotation stays in Torch so
torch.compile can fuse the full forward graph (stacked pixel API).
_warn_mps_precision ¶
_warn_mps_precision() -> None
Emit :class:PrecisionWarning once per WCS when MPS float32 is too coarse.
_world_to_pixel_2d_fast ¶
_world_to_pixel_2d_fast(
ra: Tensor,
dec: Tensor,
iterative: bool = True,
origin: float = 0,
) -> Tuple[Tensor, Tensor]
Fast path for common 2D separate-argument world->pixel calls.
compile ¶
compile(**kwargs: Any) -> 'WCS'
Wrap the pure-Python 2D spatial cores in torch.compile.
After compile(), use a stacked pixel tensor pixel_to_world(pixels)
with pixels.shape == (..., 2) for 2D spatial WCS. That path prefers a
dedicated compiled graph that fuses pixels + (1-origin) - CRPIX with the
transform and uses pure Torch pole rotation (no C++ sphere op inside the
graph) so torch.compile can optimize end-to-end. The inverse
world_to_pixel(world) with world.shape == (..., 2) uses an analogous
fused graph with pure Torch inverse pole rotation for origin in
{0, 1}. Other origin values and naxis > 2 still use
_compiled_transform_fn / the general inverse path on intermediate coords.
The two-argument pixel_to_world(x, y) shortcut may still use native C++
fast paths. Run benchmarks/bench_wcs_small_n_paths.py from the
torchsky-harness checkout for timings against Astropy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Any
|
Arguments passed to torch.compile (e.g., mode, options). |
{}
|
dropaxis ¶
dropaxis(axis: int) -> 'WCS'
Return a WCS with one pixel/world axis removed.
The axis is 0-based in FITS pixel-axis order. Coupled linear and celestial
axes are baked at CRPIX (fixed_rel=0) so the retained transform matches
the parent WCS on that slice.
pixel_to_world ¶
pixel_to_world(
*args, **kwargs
) -> Union[Tensor, Tuple[Tensor, ...]]
Convert pixel coordinates to world coordinates. Args: origin: FITS origin (default 0). Set to 1 for FITS 1-based indexing.
slice ¶
slice(
view: "slice | int | tuple[slice | int | EllipsisType, ...]",
*,
numpy_order: bool = True,
) -> "WCS"
Return a WCS adjusted for an array slice/cutout.
By default view is in NumPy array order, so a 2D image slice is
(rows, columns) while FITS pixel axes are updated as (x, y).
Positive-step and negative-step slice objects preserve dimensionality. Integer indices
fix one pixel coordinate and drop the corresponding uncoupled WCS axis.
sub ¶
sub(axes: Sequence[int]) -> 'WCS'
Return a WCS containing selected pixel/world axes in the requested order.
Axes are 0-based in FITS pixel-axis order. Dropped axes must be linearly uncoupled from retained axes. Spatial WCS instances keep both celestial projection axes; retained axes may be reordered in FITS/API order.
to ¶
to(device: Union[str, device])
Move WCS parameters to specified device.
CUDA and CPU keep float64 cached parameters. MPS is float32-only, so cached tensors are cast to float32 there (arcsecond-class error vs float64 is expected). C++ fused kernels stay CPU.
with_affine ¶
with_affine(
matrix_or_fit: Any,
offset: Any | None = None,
*,
metadata_prefix: str = "TSKYAF",
) -> "WCS"
Return a WCS corrected by an AffineFitResult or (matrix, offset).
with_affine_fit_correction ¶
with_affine_fit_correction(
fit: Any, *, metadata_prefix: str = "TSKYAF"
) -> "WCS"
Return a WCS corrected by an AffineFitResult pixel fit.
with_pixel_affine_correction ¶
with_pixel_affine_correction(
matrix: Any,
offset: Any,
*,
metadata_prefix: str = "TSKYAF",
) -> "WCS"
Return a WCS corrected by a fitted 2D pixel affine transform.
matrix and offset map old/source zero-based pixel coordinates to
corrected zero-based pixel coordinates: p_new = matrix @ p_old +
offset. The returned WCS maps corrected pixels to the same world
coordinates as the original WCS at the corresponding source pixels.
The transform acts on the two pixel axes associated with the celestial CTYPE pair. Distorted WCS store the affine and apply it in pixel space before SIP/TPV/TNX/ZPX distortion.
world_to_pixel ¶
world_to_pixel(
*args, **kwargs
) -> Union[Tensor, Tuple[Tensor, ...]]
World -> Pixel.
Detector astrometry¶
AffineFreeResidualGrid2D ¶
AffineFreeResidualGrid2D(
control: Any,
*,
origin: Any = (0.0, 0.0),
spacing: Any = (1.0, 1.0),
mode: InterpolationMode = "bicubic",
)
Bases: Module
Smooth detector-coordinate residual with constant/affine modes removed.
bending_energy ¶
bending_energy() -> Tensor
Mean squared second difference of the projected control grid.
DetectorToSkyTransform ¶
DetectorToSkyTransform(
detector_to_tangent: DetectorToTangentTransform,
attitude: Any,
)
Bases: Module
Forward-only detector-to-sky composition with a frozen attitude.
The attitude callable receives tangent-plane (..., 2) points and may
return either an (..., 2) tensor or an (longitude, latitude) tuple.
Its parameters are frozen while derivatives with respect to coordinates
remain available. Invertibility diagnostics intentionally apply only to the
detector-to-tangent transform, before any spherical longitude wrapping.
detector_to_tangent
instance-attribute
¶
detector_to_tangent: DetectorToTangentTransform = (
detector_to_tangent
)
assert_invertible ¶
assert_invertible(
*,
subdivisions: int | None = None,
determinant_floor: float = 0.0,
) -> Tensor
jacobian_determinant ¶
jacobian_determinant(points: Any) -> Tensor
Return the detector-to-tangent determinant, not a sky-chart value.
DetectorToTangentTransform ¶
DetectorToTangentTransform(
table: RegularGridTransform2D,
affine: TangentPlaneAffine,
residual: AffineFreeResidualGrid2D | None = None,
)
Bases: Module
Compose a fixed table, exposure affine, and optional detector residual.
RegularGridTransform2D ¶
RegularGridTransform2D(
table: Any,
*,
origin: Any = (0.0, 0.0),
spacing: Any = (1.0, 1.0),
mode: InterpolationMode = "bilinear",
validation_subdivisions: int = 4,
determinant_floor: float = 0.0,
)
Bases: Module
Frozen regular-grid detector transform with consistent sampled parity.
table has shape (height, width, 2) and samples detector coordinates
origin + spacing * (x_index, y_index). Bicubic mode uses local
four-point Lagrange interpolation, which reproduces affine maps exactly,
including at the detector boundary.
Sampled Jacobians may be consistently positive or consistently negative;
a reflected coordinate frame is preserved without changing its values.
The determinant floor applies to their absolute magnitude. These sampled
diagnostics do not prove global injectivity between validation points.
assert_invertible ¶
assert_invertible(
*,
subdivisions: int | None = None,
determinant_floor: float | None = None,
) -> Tensor
Return sampled determinants or reject a non-finite/folded table.
inverse ¶
inverse(
values: Any,
*,
max_iter: int = 25,
atol: float | None = None,
rtol: float = 0.0,
fail_closed: bool = True,
) -> Tensor
Newton inverse with output-unit atol and dimensionless rtol.
SampledTransformValidation
dataclass
¶
SampledTransformValidation(
errors_mas: Tensor,
p99_mas: float,
max_mas: float,
p99_limit_mas: float,
max_limit_mas: float,
)
Angular residual summary for independent transform samples.
TangentPlaneAffine ¶
TangentPlaneAffine(matrix: Any, offset: Any)
Bases: Module
Learnable full affine correction in a two-dimensional tangent plane.
identity
classmethod
¶
identity(
*,
dtype: dtype = float32,
device: device | str | None = None,
) -> TangentPlaneAffine
validate_sampled_transform ¶
validate_sampled_transform(
transform: Any,
reference: Any,
points: Any,
*,
coordinates: AngularCoordinates = "sky_degrees",
p99_limit_mas: float = 0.01,
max_limit_mas: float = 0.05,
raise_on_failure: bool = False,
) -> SampledTransformValidation
Compare a torch transform with an independent sampled reference.
Celestial frames¶
CelestialFrameBiasWarning ¶
Bases: UserWarning
A resampling path converted between FK5 (J2000) and ICRS.
The conversion is the 23-mas-scale FK5 frame bias, correct when the input
metadata are right. It is emitted because many survey headers keep a legacy
RADESYS/RADECSYS = 'FK5' (or EQUINOX = 2000 alone) while their
astrometric solution was fitted to Gaia, i.e. is ICRS.
convert_celestial ¶
convert_celestial(
lon_deg: Any,
lat_deg: Any,
*,
from_frame: str = "ICRS",
to_frame: str = "ICRS",
from_equinox: float | None = None,
to_equinox: float | None = None,
tt_mjd: Any | None = None,
) -> tuple[Tensor, Tensor]
Convert between the currently supported celestial frames.
ecliptic_of_date_to_icrs ¶
ecliptic_of_date_to_icrs(
lon_deg: Any, lat_deg: Any, tt_mjd: Any
) -> tuple[Tensor, Tensor]
Rotate mean ecliptic of date to ICRS via IAU 2006 NPB.
ecliptic_to_icrs ¶
ecliptic_to_icrs(
lon_deg: Any, lat_deg: Any
) -> tuple[Tensor, Tensor]
Rotate mean ecliptic of J2000 coordinates to ICRS equatorial.
galactic_to_icrs ¶
galactic_to_icrs(
l_deg: Any, b_deg: Any
) -> tuple[Tensor, Tensor]
Convert Galactic lon/lat to ICRS equatorial coordinates.
galactocentric_to_icrs ¶
galactocentric_to_icrs(
xyz_kpc: Any,
*,
galcen_distance_kpc: float = _GALCEN_DISTANCE_KPC,
galcen_ra_deg: float = _GALCEN_RA_DEG,
galcen_dec_deg: float = _GALCEN_DEC_DEG,
z_sun_pc: float = _Z_SUN_PC,
) -> tuple[Tensor, Tensor, Tensor]
Galactocentric Cartesian (kpc) → ICRS spherical plus distance (kpc).
heliocentric_rv_to_lsr ¶
heliocentric_rv_to_lsr(
ra_deg: Any,
dec_deg: Any,
rv_kms: Any,
*,
solar_u_kms: float = _SOLAR_U_KMS,
solar_v_kms: float = _SOLAR_V_KMS,
solar_w_kms: float = _SOLAR_W_KMS,
) -> Tensor
Heliocentric radial velocity → LSR (km/s) with explicit solar UVW.
icrs_to_ecliptic ¶
icrs_to_ecliptic(
ra_deg: Any, dec_deg: Any
) -> tuple[Tensor, Tensor]
Rotate ICRS equatorial coordinates to mean ecliptic of J2000.
icrs_to_ecliptic_of_date ¶
icrs_to_ecliptic_of_date(
ra_deg: Any, dec_deg: Any, tt_mjd: Any
) -> tuple[Tensor, Tensor]
Rotate ICRS to the mean ecliptic of date via IAU 2006 NPB.
tt_mjd is TT MJD. This is a geometric frame, not observed place:
no aberration, refraction, or site.
icrs_to_galactic ¶
icrs_to_galactic(
ra_deg: Any, dec_deg: Any
) -> tuple[Tensor, Tensor]
Convert ICRS equatorial coordinates to Galactic lon/lat.
icrs_to_galactocentric ¶
icrs_to_galactocentric(
ra_deg: Any,
dec_deg: Any,
distance_kpc: Any,
*,
galcen_distance_kpc: float = _GALCEN_DISTANCE_KPC,
galcen_ra_deg: float = _GALCEN_RA_DEG,
galcen_dec_deg: float = _GALCEN_DEC_DEG,
z_sun_pc: float = _Z_SUN_PC,
) -> Tensor
Heliocentric ICRS spherical → Galactocentric Cartesian (kpc).
Origin at the Galactic Centre (galcen_ra_deg / galcen_dec_deg).
+x toward the anticenter (Sun at x ≈ -R0), +y in rotation, +z toward
the NGP. z_sun_pc tilts the midplane so the Sun sits at z = z_sun.
Solar peculiar velocity is not applied.
lsr_line_of_sight_kms ¶
lsr_line_of_sight_kms(
ra_deg: Any,
dec_deg: Any,
*,
solar_u_kms: float = _SOLAR_U_KMS,
solar_v_kms: float = _SOLAR_V_KMS,
solar_w_kms: float = _SOLAR_W_KMS,
) -> Tensor
Solar peculiar velocity projected onto the ICRS line of sight (km/s).
UVW are Galactic: U toward the GC, V in rotation, W toward the NGP.
precess_fk5 ¶
precess_fk5(
ra_deg: Any,
dec_deg: Any,
*,
from_equinox: float = 2000.0,
to_equinox: float = 2000.0,
) -> tuple[Tensor, Tensor]
Precess FK5 equatorial coordinates between Julian equinoxes.
Uses the IAU 1976 precession angles for FK5-style mean places. This is a
compact torch-native parity target for common WCS RADESYS=FK5 / EQUINOX
headers; higher-precision nutation and full FK4 E-term behavior are separate
roadmap items.
propagate_proper_motion ¶
propagate_proper_motion(
lon_deg: Any,
lat_deg: Any,
pm_lon_coslat_mas_yr: Any,
pm_lat_mas_yr: Any,
*,
source_epoch_jyear: Any,
target_epoch_jyear: Any,
) -> tuple[Tensor, Tensor]
Propagate angular coordinates with proper motion.
pm_lon_coslat_mas_yr is the conventional longitude proper motion with
the cosine-of-latitude factor already applied (for ICRS, pm_ra_cosdec).
Epochs are Julian years. Inputs broadcast and outputs are longitude and
latitude in degrees, with longitude wrapped to [0, 360).
This follows the same unit-distance Cartesian propagation used by
SkyCoord.apply_space_motion when distance and radial velocity are not
supplied. It stays well behaved at the poles, unlike dividing a longitude
increment by cos(latitude).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lon_deg
|
Any
|
Initial longitude in degrees. |
required |
lat_deg
|
Any
|
Initial latitude in degrees. |
required |
pm_lon_coslat_mas_yr
|
Any
|
Cosine-weighted longitude proper motion in mas/yr. |
required |
pm_lat_mas_yr
|
Any
|
Latitude proper motion in mas/yr. |
required |
source_epoch_jyear
|
Any
|
Initial Julian epoch. |
required |
target_epoch_jyear
|
Any
|
Destination Julian epoch. |
required |
Returns:
| Type | Description |
|---|---|
tuple[Tensor, Tensor]
|
Propagated longitude and latitude tensors in degrees. |
Examples:
>>> from torchsky.wcs import propagate_proper_motion
>>> lon, lat = propagate_proper_motion(10.0, 20.0, 0.0, 0.0, source_epoch_jyear=2000.0, target_epoch_jyear=2010.0)
>>> round(float(lon), 6), round(float(lat), 6)
(10.0, 20.0)
propagate_proper_motion_with_jacobian ¶
propagate_proper_motion_with_jacobian(
lon_deg: Any,
lat_deg: Any,
pm_lon_coslat_mas_yr: Any,
pm_lat_mas_yr: Any,
*,
source_epoch_jyear: Any,
target_epoch_jyear: Any,
) -> tuple[tuple[Tensor, Tensor], Tensor]
Propagate angular motion and return its batched local Jacobian.
The Jacobian has trailing dimensions (2, 4). Its input order is
(position_east, position_north, pm_lon_coslat, pm_lat) and its output
rows are local east/north position at the propagated coordinate. Position
units are mas and proper-motion units are mas/yr.
This is the unit-distance angular-motion model used by
:func:propagate_proper_motion; it does not invent a distance or radial
velocity and therefore does not model perspective acceleration.
propagate_space_motion ¶
propagate_space_motion(
lon_deg: Any,
lat_deg: Any,
pm_lon_coslat_mas_yr: Any,
pm_lat_mas_yr: Any,
parallax_mas: Any,
radial_velocity_km_s: Any,
*,
source_epoch_jyear: Any,
target_epoch_jyear: Any,
) -> tuple[Tensor, Tensor, Tensor, Tensor, Tensor, Tensor]
Propagate a complete barycentric astrometric state in ICRS.
Inputs and outputs are longitude/latitude in degrees, cosine-weighted longitude and latitude proper motions in mas/yr, parallax in mas, and radial velocity in km/s. Epochs are TCB Julian years. Inputs broadcast.
The implementation follows the ERFA/SOFA starpv to rectilinear motion
with changing light time to pvstar model, including the special-
relativistic conversion between catalogue observables and inertial
velocity. A complete state is required: use
:func:propagate_proper_motion when distance or radial velocity is
unavailable.
Returns:
| Type | Description |
|---|---|
tuple[Tensor, Tensor, Tensor, Tensor, Tensor, Tensor]
|
|
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lon_deg
|
Any
|
Initial ICRS longitude in degrees. |
required |
lat_deg
|
Any
|
Initial ICRS latitude in degrees. |
required |
pm_lon_coslat_mas_yr
|
Any
|
Cosine-weighted longitude proper motion in mas/yr. |
required |
pm_lat_mas_yr
|
Any
|
Latitude proper motion in mas/yr. |
required |
parallax_mas
|
Any
|
Parallax in milliarcseconds. |
required |
radial_velocity_km_s
|
Any
|
Radial velocity in km/s. |
required |
source_epoch_jyear
|
Any
|
Initial TCB Julian epoch. |
required |
target_epoch_jyear
|
Any
|
Destination TCB Julian epoch. |
required |
Examples:
>>> from torchsky.wcs import propagate_space_motion
>>> result = propagate_space_motion(10.0, 20.0, 0.0, 0.0, 10.0, 0.0, source_epoch_jyear=2000.0, target_epoch_jyear=2000.0)
>>> len(result)
6
propagate_space_motion_with_jacobian ¶
propagate_space_motion_with_jacobian(
lon_deg: Any,
lat_deg: Any,
pm_lon_coslat_mas_yr: Any,
pm_lat_mas_yr: Any,
parallax_mas: Any,
radial_velocity_km_s: Any,
*,
source_epoch_jyear: Any,
target_epoch_jyear: Any,
) -> tuple[
tuple[Tensor, Tensor, Tensor, Tensor, Tensor, Tensor],
Tensor,
]
Propagate space motion and return its batched local 6D Jacobian.
The Jacobian's trailing dimensions are (6, 6). Its input and output
order is (position_east, position_north, pm_lon_coslat, pm_lat,
parallax, radial_velocity). Position perturbations are in mas, proper
motions in mas/yr, parallax in mas, and radial velocity in km/s.
The positional rows use local tangent bases at the source and propagated
positions. This stays continuous across longitude wrap and avoids the
singular raw-longitude derivative near the poles. A covariance in these
local catalogue units can therefore be propagated with J @ C @ J.mT.
Inputs broadcast and are validated by :func:propagate_space_motion.
Returns:
| Type | Description |
|---|---|
tuple[tuple[Tensor, Tensor, Tensor, Tensor, Tensor, Tensor], Tensor]
|
|
Graph¶
AmbiguousPathError ¶
Bases: RuntimeError
GeneralizedWCS ¶
GeneralizedWCS(
graph: TransformGraph,
input_frame: str,
output_frame: str,
*,
path: Sequence[str] | None = None,
)
Bases: Module
from_state
classmethod
¶
from_state(
metadata: Mapping[str, Any],
tensors: Mapping[str, Tensor],
) -> GeneralizedWCS
get_transform ¶
get_transform(
source: str,
target: str,
*,
path: Sequence[str] | None = None,
) -> Mapping
TransformEdge
dataclass
¶
TransformEdge(source: str, target: str, mapping: Mapping)
TransformGraph ¶
TransformGraph(
frames: Sequence[FrameSpec] = (),
transforms: Sequence[TransformEdge] = (),
)
Bases: Module
find_path ¶
find_path(
source: str,
target: str,
*,
path: Sequence[str] | None = None,
) -> tuple[str, ...]
from_state
classmethod
¶
from_state(
metadata: Mapping[str, Any],
tensors: Mapping[str, Tensor],
) -> TransformGraph
get_mapping ¶
get_mapping(
source: str,
target: str,
*,
path: Sequence[str] | None = None,
) -> Mapping
UnsupportedPathError ¶
Bases: RuntimeError
Gwcs sampling¶
FrozenDetectorEpochTables
dataclass
¶
FrozenDetectorEpochTables(
epochs: tuple[float, ...],
samples: tuple[GWCSGridSamplingResult, ...],
)
Time-dependent detector tables as frozen samples, not a live GWCS graph.
evaluate ¶
evaluate(detector_xy: Any, epoch: float) -> Tensor
Device-native table eval. Runtime does not import gwcs.
inverse ¶
inverse(sky_xy: Any, epoch: float, **kwargs: Any) -> Tensor
Newton inverse of the frozen table at the nearest epoch.
to ¶
to(device: Any) -> 'FrozenDetectorEpochTables'
Move frozen tables to device. Sampling still happened on host.
GWCSGridSamplingResult
dataclass
¶
GWCSGridSamplingResult(
transform: RegularGridTransform2D,
validation: Mapping[str, SampledTransformValidation],
grid_shape: tuple[int, int],
detector_bounds: tuple[
tuple[float, float], tuple[float, float]
],
reference_name: str,
calibration_provenance: Mapping[str, str],
)
Frozen torch table, validation groups, and calibration provenance.
detector_bounds
instance-attribute
¶
detector_bounds: tuple[
tuple[float, float], tuple[float, float]
]
IFUSliceWCS
dataclass
¶
IFUSliceWCS(
ra_map: Tensor,
dec_map: Tensor,
wavelength_map: Tensor,
slice_id_map: Tensor,
)
Piecewise-disjoint 2D detector -> 3D (ra_deg, dec_deg, wavelength) IFU slice WCS.
Prevents cross-slice interpolation bleed at IFU slice boundaries by restricting
sub-pixel bilinear interpolation strictly to neighbors sharing the same slice_id >= 0.
from_callable
classmethod
¶
from_callable(
reference: Callable[..., Any],
detector_shape: tuple[int, int],
*,
slice_id_map: Tensor | None = None,
device: Any = "cpu",
) -> "IFUSliceWCS"
Sample a 2D -> 3D (ra, dec, wavelength) callable across the detector grid.
from_slices
classmethod
¶
from_slices(
detector_shape_or_slices: Any,
slices: list[Any] | tuple[Any, ...] | None = None,
*,
device: Any = "cpu",
) -> "IFUSliceWCS"
Build an :class:IFUSliceWCS from (slice_mask, callable_or_tuple) pairs or slice dicts.
pixel_to_world ¶
pixel_to_world(
x: Tensor | float, y: Tensor | float
) -> tuple[Tensor, Tensor, Tensor]
Evaluate (ra_deg, dec_deg, wavelength) at sub-pixel (x, y) without cross-slice bleed.
sample_gwcs_detector_epochs ¶
sample_gwcs_detector_epochs(
references: Mapping[float, Callable[..., Any]],
*,
detector_bounds: tuple[
tuple[float, float], tuple[float, float]
],
initial_grid_shape: tuple[int, int] = (9, 9),
maximum_grid_shape: tuple[int, int] = (257, 257),
interpolation: Literal[
"bilinear", "bicubic"
] = "bicubic",
coordinates: AngularCoordinates = "plane_arcsec",
random_validation_points: int = 4096,
seed: int = 0,
p99_limit_mas: float = 0.01,
max_limit_mas: float = 0.05,
chip_boundaries_x: tuple[float, ...] = (),
reference_name: str = "gwcs_detector_to_v2v3",
calibration_provenance: Mapping[str, str] | None = None,
dtype: dtype = float64,
) -> FrozenDetectorEpochTables
Sample one frozen table per epoch. Runtime never imports gwcs.
sample_gwcs_detector_to_tangent ¶
sample_gwcs_detector_to_tangent(
reference: Callable[..., Any],
*,
detector_bounds: tuple[
tuple[float, float], tuple[float, float]
],
initial_grid_shape: tuple[int, int] = (9, 9),
maximum_grid_shape: tuple[int, int] = (257, 257),
interpolation: Literal[
"bilinear", "bicubic"
] = "bicubic",
coordinates: AngularCoordinates = "plane_arcsec",
random_validation_points: int = 4096,
seed: int = 0,
p99_limit_mas: float = 0.01,
max_limit_mas: float = 0.05,
chip_boundaries_x: tuple[float, ...] = (),
reference_name: str = "gwcs_detector_to_v2v3",
calibration_provenance: Mapping[str, str] | None = None,
dtype: dtype = float64,
) -> GWCSGridSamplingResult
Refine a detector table until independent points satisfy mas gates.
Iau2006¶
apply_dcr ¶
apply_dcr(
ra_deg: Tensor,
dec_deg: Tensor,
wavelength_angstrom: Tensor | float,
zenith_deg: Tensor | float,
parallactic_deg: Tensor | float = 0.0,
*,
ref_wavelength_angstrom: float = 5000.0,
pressure_mbar: float = 780.0,
temperature_c: float = 10.0,
inverse: bool = False,
) -> tuple[Tensor, Tensor]
Apply or remove Differential Chromatic Refraction on (ra_deg, dec_deg).
apply_ephemeris_offset ¶
apply_ephemeris_offset(
ra_deg: Tensor,
dec_deg: Tensor,
*,
mjd_obs: float,
reference_mjd: float,
tracking_rate: tuple[float, float] | None = None,
dra_cosdec_arcsec_per_hr: float = 0.0,
ddec_arcsec_per_hr: float = 0.0,
inverse: bool = False,
) -> tuple[Tensor, Tensor]
Shift sky coordinates into (or out of) a moving target's comoving frame.
Parameters¶
tracking_rate
(dra_cosdec_arcsec_per_hr, ddec_arcsec_per_hr) non-sidereal rate.
inverse
If False (default), maps sidereal sky coordinates at mjd_obs into
the comoving target frame at reference_mjd (subtracting target motion).
If True, maps comoving coordinates back to sidereal coordinates at mjd_obs.
apply_refraction ¶
apply_refraction(
alt_deg: Tensor,
*,
pressure_mbar: Tensor | float,
temperature_c: Tensor | float,
) -> Tensor
Apply atmospheric refraction to altitude in degrees.
apply_stellar_aberration ¶
apply_stellar_aberration(
unit_xyz: Tensor, velocity_m_s: Tensor
) -> Tensor
Classical stellar aberration: normalize(p + v/c).
dcr_offset ¶
dcr_offset(
wavelength_angstrom: Tensor | float,
zenith_deg: Tensor | float,
parallactic_deg: Tensor | float = 0.0,
*,
ref_wavelength_angstrom: float = 5000.0,
pressure_mbar: float = 780.0,
temperature_c: float = 10.0,
) -> tuple[Tensor, Tensor]
Compute Differential Chromatic Refraction (DCR) tangent-plane offset (d_east_deg, d_north_deg).
Returns the apparent chromatic shift toward zenith at wavelength_angstrom
relative to ref_wavelength_angstrom in degrees along local East and North.
Mapping¶
AffineMapping ¶
AffineMapping(
matrix: Tensor,
offset: Tensor,
input_axes: Sequence[AxisSpec],
output_axes: Sequence[AxisSpec],
*,
domain: DomainSpec | None = None,
)
CallableMapping ¶
CallableMapping(
function: Callable[[Tensor], Tensor],
input_axes: Sequence[AxisSpec],
output_axes: Sequence[AxisSpec],
*,
inverse_function: Callable[[Tensor], Tensor]
| None = None,
domain: DomainSpec | None = None,
)
NumericalInverseMapping ¶
NumericalInverseMapping(
mapping: Mapping,
*,
initial: Tensor,
bounds: DomainSpec,
max_iterations: int = 16,
residual_tolerance: float = 1e-10,
relative_tolerance: float = 1e-10,
damping: float = 1e-08,
)
Bases: Mapping
NumericalInverseResult
dataclass
¶
NumericalInverseResult(
values: Tensor,
converged: Tensor,
residual_norm: Tensor,
iterations: int,
)
ParallelMapping ¶
ParallelMapping(mappings: Sequence[Mapping])
PortRoute
dataclass
¶
PortRoute(
mapping: Mapping,
inputs: Sequence[int],
outputs: Sequence[int],
)
PortRoutingMapping ¶
PortRoutingMapping(
input_axes: Sequence[AxisSpec],
output_axes: Sequence[AxisSpec],
routes: Sequence[PortRoute],
*,
domain: DomainSpec | None = None,
)
SerialMapping ¶
SerialMapping(mappings: Sequence[Mapping])
UnitConversionMapping ¶
UnsupportedInverseError ¶
Bases: RuntimeError
Observed¶
EarthOrientation
dataclass
¶
EarthOrientation(
dut1_s: Tensor,
xp_arcsec: Tensor | None = None,
yp_arcsec: Tensor | None = None,
tt_minus_utc_s: Tensor | None = None,
)
IERS Earth orientation. dut1_s is required.
Polar motion xp_arcsec / yp_arcsec is optional. If either is set,
both are applied (missing member treated as 0) via SOFA pom00 with
TIO locator s' = 0. tt_minus_utc_s overrides TT−UTC; when it is
None, TT−UTC is 32.184 s + TAI−UTC from torchsky's leap-second
table, and epochs outside that table (before 1972 or after its expiry)
raise ValueError.
Site
dataclass
¶
Site(
lon_deg: Tensor,
lat_deg: Tensor,
height_m: Tensor | float = 0.0,
pressure_mbar: Tensor | float | None = None,
temperature_c: Tensor | float | None = None,
relative_humidity: Tensor | float = 0.0,
wavelength_um: Tensor | float = 0.55,
)
Geodetic site. Height is WGS84 ellipsoidal height (metres) on the ITRS path.
relative_humidity (0..1) and wavelength_um (> 100 selects the radio
formula) only enter the ERFA refco refraction model.
observed_altaz ¶
observed_altaz(
state: CatalogState,
*,
obstime_mjd_utc: Any,
site: Site,
eop: EarthOrientation,
pn: PNModel | None = None,
aberration: bool = False,
refraction: bool = False,
refraction_model: RefractionModel = "refco",
) -> tuple[Tensor, Tensor]
Return (az_deg, alt_deg) from north toward east.
obstime_mjd_utc is UTC MJD. UT1 = UTC + DUT1. Polar motion is applied
when xp/yp are set.
pn=None (default) and pn='iau2006' apply Fukushima-Williams
bias-precession and IAU 2000A nutation via the CIRS matrix; with
aberration=True this matches astropy AltAz to about 1 arcsec.
TT−UTC is eop.tt_minus_utc_s when set, otherwise 32.184 s + TAI−UTC
from torchsky's leap-second table; an epoch outside that table (before
1972, or after its expiry) raises ValueError rather than guessing.
pn='none' is an explicit opt-in that omits precession-nutation and uses
GMST; it is approximate (~0.3 deg off) and is continuous in xp/yp
(zero polar motion equals no polar motion).
aberration=True converts the astrometric ICRS direction to the apparent
place as ERFA atciq does: solar light deflection plus annual and diurnal
aberration (the observer's Earth-rotation velocity), with the epv00 Earth
ephemeris. Without refraction the result agrees with erfa.atco13 to
< 1 mas (residual: TIO locator s' = 0, observer offset in the solar
deflection, TT used for TDB).
refraction=True applies the ERFA refco model (A tan z + B tan^3 z,
honouring site.relative_humidity and site.wavelength_um) to the
topocentric direction as atioq does; refraction_model="saemundsson"
selects the Saemundsson/Meeus altitude formula instead. Both are off unless
requested and need site.pressure_mbar and site.temperature_c.
Time-only quantities are evaluated in float64 on CPU on every device; only the final rotation matrices move to the coordinate device (CUDA float64, MPS float32). Gradients flow through the coordinates. The kernels are ATen, not fused C++.
Residuals¶
AstrometricResidualFeatures
dataclass
¶
AstrometricResidualFeatures(
focal_xy: Tensor,
ccd_xy: Tensor,
band_encoding: Tensor,
color: Tensor,
time: Tensor,
airmass: Tensor,
parallactic_angle: Tensor,
telemetry: Tensor,
)
Continuous and explicitly encoded features; identifiers are never embedded.
AstrometricResidualLadder ¶
AstrometricResidualLadder(
gauge: TangentPlaneGauge, envelope: CorrectionEnvelope
)
Compose global, local, and sparse astrometric residual corrections.
BayesianModePrediction
dataclass
¶
BayesianModePrediction(
stable: Tensor,
drift: Tensor,
local: Tensor,
mean: Tensor,
covariance: Tensor,
)
BayesianModeState
dataclass
¶
BayesianModeState(
mean: Tensor,
covariance: Tensor,
widths: tuple[int, int, int],
version: int = 1,
)
ConditionalResidualPrediction
dataclass
¶
ConditionalResidualPrediction(
mean: Tensor,
covariance: Tensor,
supported: Tensor,
context_count: Tensor,
)
CorrectionEnvelope
dataclass
¶
CorrectionEnvelope(
max_correction: float,
max_jacobian: float,
max_covariance_eigenvalue: float,
gauge_tolerance: float = 1e-08,
)
ResidualComponentInput
dataclass
¶
ResidualComponentInput(
name: str,
mean: Tensor,
covariance: Tensor,
supported: Tensor,
jacobian: Tensor | None = None,
)
ResidualComponentResult
dataclass
¶
ResidualComponentResult(
name: str,
mean: Tensor,
covariance: Tensor,
full_covariance: Tensor,
trusted: Tensor,
fallback_reason: str | None,
)
ResidualLadderPrediction
dataclass
¶
ResidualLadderPrediction(
mean: Tensor,
covariance: Tensor,
full_covariance: Tensor,
components: tuple[ResidualComponentResult, ...],
)
ResidualModeDesign
dataclass
¶
ResidualModeDesign(
stable: Tensor,
drift: Tensor,
local: Tensor,
stable_names: tuple[str, ...] = (),
drift_names: tuple[str, ...] = (),
local_names: tuple[str, ...] = (),
)
ResidualSupport
dataclass
¶
ResidualSupport(
lower: Tensor,
upper: Tensor,
max_inducing_distance: float,
)
SparseGPResidual
dataclass
¶
SparseGPResidual(
inducing_features: Tensor,
length_scale: Tensor,
amplitude: Tensor,
output_covariance: Tensor,
posterior_mean: Tensor,
posterior_covariance: Tensor,
inducing_covariance: Tensor,
support: ResidualSupport,
covariance_scale: float = 1.0,
jitter: float = 1e-08,
)
calibrate_covariance ¶
calibrate_covariance(
features: Tensor,
residual: Tensor,
*,
min_scale: float = 1.0,
) -> SparseGPResidual
SparseGPResidualPrediction
dataclass
¶
SparseGPResidualPrediction(
mean: Tensor, covariance: Tensor, supported: Tensor
)
TangentPlaneGauge
dataclass
¶
TangentPlaneGauge(
design: Tensor,
precision: Tensor,
rank_rtol: float = 1e-10,
)
Exact weighted projection and null-space coordinates for vector residuals.
project_covariance ¶
project_covariance(
covariance: Tensor, active: Tensor | None = None
) -> Tensor
VersionedResidualState
dataclass
¶
VersionedResidualState(
version: int,
parent_version: int | None,
feature_version: str,
gauge_version: str,
coefficients: BayesianModeState,
replay_features: Tensor,
replay_residuals: Tensor,
replay_covariance: Tensor,
anchor_features: Tensor,
anchor_residuals: Tensor,
anchor_covariance: Tensor,
)
append_replay ¶
append_replay(
features: Tensor,
residuals: Tensor,
covariance: Tensor,
*,
capacity: int,
) -> VersionedResidualState
fit_bayesian_modes ¶
fit_bayesian_modes(
design: ResidualModeDesign,
residual: Tensor,
noise_covariance: Tensor,
*,
prior_scale: tuple[float, float, float] = (
0.1,
0.05,
0.1,
),
gauge: TangentPlaneGauge | None = None,
) -> BayesianModeState
Fit residual modes with Gaussian priors and correlated noise.
fit_sparse_gp_residual ¶
fit_sparse_gp_residual(
features: Tensor,
residual: Tensor,
noise_covariance: Tensor,
inducing_features: Tensor,
*,
length_scale: Tensor,
amplitude: float = 1.0,
output_covariance: Tensor | None = None,
support: ResidualSupport | None = None,
gauge: TangentPlaneGauge | None = None,
jitter: float = 1e-08,
) -> SparseGPResidual
Fit a sparse Gaussian-process model to tangent-plane residuals.
interpretable_residual_modes ¶
interpretable_residual_modes(
features: AstrometricResidualFeatures,
) -> ResidualModeDesign
Build named affine, color, and detector residual-mode columns.
predict_bayesian_modes ¶
predict_bayesian_modes(
state: BayesianModeState, design: ResidualModeDesign
) -> BayesianModePrediction
Predict residual-mode means and covariance from a fitted state.
update_bayesian_modes ¶
update_bayesian_modes(
state: BayesianModeState,
design: ResidualModeDesign,
residual: Tensor,
noise_covariance: Tensor,
*,
component: ResidualComponent = "local",
) -> BayesianModeState
Update one residual component while preserving the other components.
Semantics¶
AxisSpec
dataclass
¶
AxisSpec(
name: str,
unit: UnitSpec | str = UnitSpec(),
physical_type: str | None = None,
domain: DomainSpec | None = None,
wrap: float | None = None,
)
DomainSpec
dataclass
¶
DomainSpec(
bounds: tuple[tuple[float | None, float | None], ...],
closed: tuple[tuple[bool, bool], ...] = (),
)
Epoch
dataclass
¶
Epoch(value: Any, spec: TimeSpec | None = None)
FrameSpec
dataclass
¶
FrameSpec(
name: str,
axes: Sequence[AxisSpec],
representation: str = "cartesian",
equinox: Epoch | None = None,
obstime: Epoch | None = None,
observer: Sequence[float] | None = None,
reference_position: str | None = None,
)
TimeSpec
dataclass
¶
TimeSpec(
format: TimeFormat = "jyear",
scale: TimeScale = "tcb",
reference_position: str | None = None,
)
Spectral axes¶
air_wavelength_to_vacuum ¶
air_wavelength_to_vacuum(
wavelength_air: Any, unit: str | None = None
) -> Tensor
Convert standard-air wavelength to vacuum wavelength.
Uses the WCSLIB awavwave refractive index (FITS-WCS Paper III / Edlén
form), matching astropy.wcs. Inputs and outputs use unit when provided;
FITS default is meters.
convert_spectral ¶
convert_spectral(
value: Any,
from_type: str,
to_type: str,
*,
from_unit: str | None = None,
to_unit: str | None = None,
rest_frequency: float | Tensor | None = None,
rest_wavelength: float | Tensor | None = None,
) -> Tensor
Convert between supported spectral coordinate types through frequency.
frequency_to_spectral ¶
frequency_to_spectral(
frequency: Any,
spectral_type: str,
*,
unit: str | None = None,
rest_frequency: float | Tensor | None = None,
rest_wavelength: float | Tensor | None = None,
) -> Tensor
Convert frequency in Hz to a requested spectral coordinate.
rest_frequency_from_header ¶
rest_frequency_from_header(
header: dict[str, Any],
) -> float | None
Return rest frequency in Hz from FITS RESTFRQ/FREQ or RESTWAV.
spectral_to_frequency ¶
spectral_to_frequency(
value: Any,
spectral_type: str,
*,
unit: str | None = None,
rest_frequency: float | Tensor | None = None,
rest_wavelength: float | Tensor | None = None,
) -> Tensor
Convert a spectral coordinate to frequency in Hz.
vacuum_wavelength_to_air ¶
vacuum_wavelength_to_air(
wavelength_vacuum: Any, unit: str | None = None
) -> Tensor
Convert vacuum wavelength to standard-air wavelength.
Uses WCSLIB waveawav (four refractive-index iterations).
Tabular WCS axes¶
CoupledTabularLookupWCS
dataclass
¶
CoupledTabularLookupWCS(
pixel_axes: Any,
world: Any,
*,
names: Any = None,
units: Any = None,
bounds: TabularBoundsMode = "nan",
)
Coupled multidimensional table lookup with multilinear interpolation.
pixel_axes define the table-grid coordinates for each pixel dimension.
world has shape (*grid_shape, world_n_dim). The forward transform is
differentiable with respect to query coordinates inside each grid cell.
Inverse lookup is unique only when world_n_dim >= pixel_n_dim and the
query lies on the interpolated manifold. Underdetermined tables
(world_n_dim < pixel_n_dim) return a nearest-seed Gauss–Newton
particular solution (minimum-norm step); it is not the unique inverse.
pixel_to_world ¶
pixel_to_world(
pixels: Any, *, bounds: TabularBoundsMode | None = None
) -> Tensor
to ¶
to(
*,
device: device | str | None = None,
dtype: dtype | None = None,
) -> "CoupledTabularLookupWCS"
world_to_pixel ¶
world_to_pixel(
world: Any,
*,
bounds: TabularBoundsMode | None = None,
max_iter: int = 20,
tol: float = 1e-10,
) -> Tensor
TabularAxis
dataclass
¶
TabularAxis(
pixel: Any,
world: Any,
name: str | None = None,
unit: str | None = None,
bounds: TabularBoundsMode = "nan",
)
One-dimensional table-driven coordinate transform.
The forward direction maps pixel/index coordinates to world coordinates by piecewise-linear interpolation. The inverse maps monotonic world coordinates back to pixel/index coordinates with the same interpolation rule.
world_direction
property
¶
world_direction: int
Return 1 for increasing world values, -1 for decreasing.
pixel_to_world ¶
pixel_to_world(
pixel: Any, *, bounds: TabularBoundsMode | None = None
) -> Tensor
Interpolate world coordinates from pixel/index coordinates.
to ¶
to(
*,
device: device | str | None = None,
dtype: dtype | None = None,
) -> "TabularAxis"
Return a copy with tables moved to device and/or dtype.
world_to_pixel ¶
world_to_pixel(
world: Any, *, bounds: TabularBoundsMode | None = None
) -> Tensor
Interpolate pixel/index coordinates from monotonic world coordinates.
TabularLookupWCS
dataclass
¶
TabularLookupWCS(axes: Any)
Separable multi-axis table-driven WCS transform.
This is the torch-native execution primitive for independent lookup axes and
separable multidimensional FITS -TAB coordinate arrays. Arbitrary coupled
table-coordinate interpolation needs a separate multi-axis substrate.
pixel_to_world ¶
pixel_to_world(
pixels: Any, *, bounds: TabularBoundsMode | None = None
) -> Tensor
coupled_tabular_wcs_from_fits ¶
coupled_tabular_wcs_from_fits(
header: Mapping[str, Any], tables: Any, *, key: str = ""
) -> CoupledTabularLookupWCS
Build a forward coupled table-lookup WCS from FITS -TAB metadata.
tabular_axes_from_fits ¶
tabular_axes_from_fits(
header: Mapping[str, Any], tables: Any, *, key: str = ""
) -> dict[int, TabularAxis]
Build explicit WCS(..., tabular_axes=...) axes from FITS -TAB metadata.
This implements independent one-dimensional FITS table lookup WCS plus the
exact separable subset of multidimensional coordinate arrays selected by
PVi_3. For each CTYPEi ending in -TAB, PSi_0 selects a table
by EXTNAME when tables is a mapping, PSi_1 names the
coordinate-array column, and optional PSi_2 names the indexing-vector
column. If no indexing vector is present, samples are indexed by 0..N-1.
Multidimensional coordinate arrays must be invariant along non-selected
dimensions; truly coupled arrays fail explicitly.
Temporal¶
TemporalWCS ¶
TemporalWCS(header: dict[str, Any])
FITS Temporal WCS implementation (Paper IV).
Supports vectorized transformations between relative time and MJD plus leap-second-aware UTC/TAI/TT/GPS scale conversion.
Main keywords: - MJDREF: Reference MJD - TIMESYS: Time scale (UTC, TT, TAI, TDB, GPS) - TIMEUNIT: 's', 'd', 'a', 'cy' - TREFPOS: TOPOCENTER, GEOCENTER, BARYCENTER, HELIOCENTER, EMBARYCENTER, MOON, CUSTOM, BASECENTER, GALACTIC, LOCALGROUP, and Keplerian planets.
duration_days
property
¶
duration_days: float | None
Observation duration in days from MJD-BEG/END, TELAPSE, or EXPOSURE.
midpoint_mjd
property
¶
midpoint_mjd: float | None
Observation midpoint MJD when enough metadata is available.
observatory_lon_lat_height_deg_m
property
¶
observatory_lon_lat_height_deg_m: (
tuple[float, float, float] | None
)
obsgeo_lon_lat_height
instance-attribute
¶
obsgeo_lon_lat_height: tuple[float, float, float] | None = (
None
)
apply_corrections ¶
apply_corrections(
mjd: Tensor, ra: Tensor, dec: Tensor
) -> Tensor
Apply Roemer light-time to the header TREFPOS.
BARYCENTER/HELIOCENTER use a Keplerian Earth (Sun ≈ SSB). Planetary
TREFPOS uses the same JPL approximate Keplerian elements, not DE.
EMBARYCENTER and MOON are treated as GEOCENTER (~0.01 s and ~1.3 s).
GALACTIC/LOCALGROUP use the barycentric delay (no Galactic motion).
from_mjd ¶
from_mjd(mjd: Tensor) -> Tensor
Convert absolute MJD in the header TIMESYS to relative time.
from_mjd_scale ¶
from_mjd_scale(mjd: Tensor, scale: str) -> Tensor
Convert absolute MJD in scale to relative header time values.
jd_to_mjd
staticmethod
¶
jd_to_mjd(jd: float | Tensor) -> float | Tensor
JD to MJD: MJD = JD - 2400000.5
mjd_to_jd
staticmethod
¶
mjd_to_jd(mjd: float | Tensor) -> float | Tensor
MJD to JD: JD = MJD + 2400000.5
to_iso8601 ¶
to_iso8601(mjd: Tensor) -> str | list[Any]
Convert MJD to ISO-8601 strings (UTC). Note: This is not vectorized as strings are involved, but useful for parity.
to_mjd ¶
to_mjd(time_val: Tensor) -> Tensor
Convert relative time to absolute MJD in the header TIMESYS.
to_mjd_scale ¶
to_mjd_scale(time_val: Tensor, scale: str) -> Tensor
Convert relative time to absolute MJD in another supported scale.
Typing¶
TabularBoundsMode
typing.Literal['nan', 'clamp']