curryer.correction¶
Correction module for iterative geolocation alignment.
Provides tools for Monte Carlo-style correction loops, image matching against ground control points, PSF modelling, and error statistics.
Sub-module layout¶
- config
Config models (
GeolocationSetup,Sweep,OutputConfig,ParameterConfig, etc.) and theParameterTypeenum.- io_config
NetCDF output configuration and standard attribute definitions (
NetCDFConfig,NetCDFParameterMetadata,DEFAULT_NETCDF_ATTRIBUTES).- parameters
Random parameter-set generation (
load_param_sets()).- kernel_ops
SPICE kernel creation and telemetry/time-offset application.
- results_io
NetCDF result file read/write and checkpoint support.
- pipeline
Main
loop()orchestration and all per-iteration helpers. Preferred-name aliases:run_correction(),run_image_matching(),compute_error_stats().run_correction()also acceptsCorrectionInputobjects.- grid_types
Pure grid data containers (
ImageGrid,PSFGrid, …).- dataio
Validation helpers and S3 data-access utilities. The S3 utilities (
S3Configuration,find_netcdf_objects,download_netcdf_objects) are optional convenience helpers for mission-specific data pipelines; the core correction API does not depend on them.- error_stats
Error statistics computation (
ErrorStatsProcessor).- image_match
Image-matching algorithm (
integrated_image_match).- io
Unified path resolution (
resolve_path). Transparently handles local paths and S3 URIs (s3://…) whenboto3is installed. Optional convenience — the public API contract is localPathobjects; S3 support is opt-in.- pairing
Ground-control-point pairing utilities.
- psf
Point-spread-function modelling.
- search
Image-search / correlation routines.
- verification
Standalone geolocation compliance check (
verify()).
Submodules¶
- curryer.correction.config
- curryer.correction.dataio
- curryer.correction.error_stats
- curryer.correction.grid_types
- curryer.correction.image_io
- curryer.correction.image_match
- curryer.correction.io
- curryer.correction.io_config
- curryer.correction.kernel_ops
- curryer.correction.pairing
- curryer.correction.parameters
- curryer.correction.pipeline
- curryer.correction.psf
- curryer.correction.regrid
- curryer.correction.results
- curryer.correction.results_io
- curryer.correction.search
- curryer.correction.verification
Classes¶
Direct paths to instrument calibration inputs. |
|
A single input set for the correction loop. |
|
Configuration for config-driven internal data loading. |
|
SPICE kernel paths and instrument settings for geolocation. |
|
Durable, mission-specific setup for geolocation correction/verification. |
|
Configuration for NetCDF output structure and metadata. |
|
NetCDF metadata for a single output parameter variable. |
|
Output settings for a correction run. |
|
A single parameter to vary during correction analysis. |
|
Typed sampling specification for a single correction parameter. |
|
Parameter types used in the correction configuration. |
|
Configuration for PSF sampling during image matching. |
|
Configuration for GCP chip regridding. |
|
Verification requirements / thresholds. |
|
Configuration for the image-matching correlation search grid. |
|
Strategy used to generate parameter sets during correction analysis. |
|
A parameter-variation experiment run against a |
|
Configuration for geolocation error statistics processing. |
|
Production-ready processor for geolocation error statistics. |
|
Container for image data sampled on a latitude/longitude grid. |
|
Point spread function sampled on a latitude/longitude grid. |
|
Structured result from |
|
Results for a single parameter set in a correction sweep. |
|
Per-measurement/GCP error detail. |
|
Structured result from a |
Functions¶
|
Load |
|
Load a |
|
Load a |
|
Compute the percentage of errors below a given threshold. |
Convert a geolocated |
|
|
Deprecated — use |
|
Load any supported image file as an |
|
Load line-of-sight unit vectors from a |
Load any supported image file as a |
|
Load one observation file and return |
|
|
Load optical PSF entries from a |
|
Save an |
|
Resolve a file path, downloading from S3 if necessary. |
|
Compute error statistics from image matching results. |
|
Correction loop for parameter sensitivity analysis. |
|
Run the correction parameter sweep. |
|
Run image matching against GCP reference. |
|
Generate a side-by-side comparison of two verification results. |
|
Run image matching between already-geolocated data and GCP reference files. |
|
Evaluate current alignment against mission requirements. |
Package Contents¶
- class curryer.correction.CalibrationFiles(/, **data: Any)¶
Bases:
pydantic.BaseModelDirect paths to instrument calibration inputs.
Both fields are optional and interim: real line-of-sight vectors and spacecraft geometry will be SPICE-derived from telemetry rather than loaded from files, so nothing in the pipeline requires these.
- los_vectors_file¶
Per-detector line-of-sight unit vectors (instrument frame).
- psf_file¶
Optical point-spread-function calibration.
- los_vectors_file: pathlib.Path | None = None¶
- psf_file: pathlib.Path | None = None¶
- class curryer.correction.CorrectionInput(/, **data: Any)¶
Bases:
pydantic.BaseModelA single input set for the correction loop.
Replaces the positional tuple
(telemetry_path, science_path, gcp_path)with named fields for clarity and IDE autocomplete.The reader for each file is chosen by
DataConfig.file_format, so the inputs are format-agnostic. The first-class real-data path is a NetCDF image observation (radiance as the science variable) carrying telemetry, metadata, and science times;.matfiles are interim test scaffolding.- Parameters:
telemetry_file (Path) – Telemetry observation file (NetCDF for real data; CSV/HDF5 also read).
science_file (Path) – Science/timing observation file (NetCDF for real data; CSV/HDF5 also read).
gcp_file (Path) – GCP reference-image file (NetCDF or
.mat).
Examples
>>> from curryer.correction import CorrectionInput >>> inputs = [ ... CorrectionInput( ... telemetry_file="data/obs_20240317.nc", ... science_file="data/obs_20240317.nc", ... gcp_file="gcps/landsat_chip_001.nc", ... ) ... ]
- telemetry_file: pathlib.Path¶
- science_file: pathlib.Path¶
- gcp_file: pathlib.Path¶
- class curryer.correction.DataConfig(/, **data: Any)¶
Bases:
pydantic.BaseModelConfiguration for config-driven internal data loading.
Replaces mission-specific loader callables with a declarative specification of how files should be read. The pipeline reads telemetry and science data directly from the provided file paths using pandas/xarray, applying the
time_scale_factorto convert the science time column to uGPS.- file_format¶
File format for both telemetry and science data files.
"csv"usespandas.read_csv();"netcdf"converts viaxarray.open_dataset();"hdf5"usespandas.read_hdf().
- time_scale_factor¶
Multiply science timestamps by this factor to obtain uGPS (microseconds since GPS epoch). For example,
1e6converts GPS seconds to uGPS;1.0means the file already contains uGPS. The time column name is taken fromGeolocationConfig.time_field(single source of truth).
- position_columns¶
Explicit column name mappings for telemetry spacecraft-position data, e.g.
["sc_pos_x", "sc_pos_y", "sc_pos_z"].Nonemeans use mission defaults from the geolocation configuration.
- file_format: Literal['csv', 'netcdf', 'hdf5'] = 'csv'¶
- time_scale_factor: float = 1.0¶
- position_columns: list[str] | None = None¶
- class curryer.correction.GeolocationConfig(/, **data: Any)¶
Bases:
pydantic.BaseModelSPICE kernel paths and instrument settings for geolocation.
- meta_kernel_file¶
Path to the mission meta-kernel JSON file.
- generic_kernel_dir¶
Directory containing generic/shared SPICE kernels.
- dynamic_kernels¶
Kernels regenerated from telemetry each run (SC-SPK, SC-CK, etc.) but not altered by parameter variations.
- instrument_name¶
SPICE instrument name (e.g.
"CPRS_HYSICS").
- time_field¶
Column name in the science DataFrame that holds uGPS timestamps.
- minimum_correlation¶
Optional image-matching quality filter threshold (0.0–1.0).
- meta_kernel_file: pathlib.Path¶
- generic_kernel_dir: pathlib.Path¶
- dynamic_kernels: list[pathlib.Path] = None¶
- instrument_name: str¶
- time_field: str¶
- minimum_correlation: float | None = None¶
- class curryer.correction.GeolocationSetup(/, **data: Any)¶
Bases:
pydantic.BaseModelDurable, mission-specific setup for geolocation correction/verification.
Built once per mission and reused across many
Sweepruns. Holds everything that does not change when you vary which parameters are swept: SPICE kernels and instrument identity (GeolocationConfig), the pass/failRequirementsConfig, how input data is read (DataConfig), static instrument calibration (CalibrationFiles), the science-Dataset variable names, and an optional custom image-matching implementation.- geo¶
SPICE kernels, instrument name, and science time field.
- requirements¶
Pass/fail thresholds used by verification and the correction verdict.
- data_config¶
How telemetry/science files are read.
Noneuses CSV defaults.
- calibration¶
Optional direct calibration file paths.
Nonewhen geometry is supplied another way (e.g. SPICE-derived).
- spacecraft_position_name, boresight_name, transformation_matrix_name
Variable names for the spacecraft-state fields in the image-matching
xr.Dataset(mission-configurable; generic defaults).
- image_matching_func¶
Optional custom image-matching callable.
Noneuses the built-inimage_matching(). Excluded from JSON serialisation because callables are not serialisable.
- model_config¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- geo: GeolocationConfig¶
- requirements: RequirementsConfig¶
- data_config: DataConfig | None = None¶
- calibration: CalibrationFiles | None = None¶
- spacecraft_position_name: str = 'sc_position'¶
- boresight_name: str = 'boresight'¶
- transformation_matrix_name: str = 't_inst2ref'¶
- image_matching_func: collections.abc.Callable | None = None¶
- class curryer.correction.NetCDFConfig(/, **data: Any)¶
Bases:
pydantic.BaseModelConfiguration for NetCDF output structure and metadata.
- performance_threshold_m¶
Accuracy threshold in meters used to derive threshold-specific variable names (e.g.
"percent_under_250m").
- title¶
Global title attribute for the output NetCDF file.
- description¶
Global description attribute for the output NetCDF file.
- parameter_metadata¶
Optional mapping of parameter key →
NetCDFParameterMetadata. Auto-generated from the sweep’sparameterswhenNone.
- standard_attributes¶
Optional mission-specific attribute overrides. Falls back to the module-level
DEFAULT_NETCDF_ATTRIBUTESwhenNone.
- performance_threshold_m: float¶
- title: str = 'Correction Geolocation Analysis Results'¶
- description: str = 'Parameter sensitivity analysis'¶
- parameter_metadata: dict[str, NetCDFParameterMetadata] | None = None¶
- standard_attributes: dict[str, dict[str, str]] | None = None¶
- property threshold_metric_name: str¶
Threshold-derived metric variable name, e.g.
"percent_under_250m".
- property standard_attributes_dict: dict[str, dict[str, str]]¶
Standard variable attributes, with optional mission-specific overrides.
Returns a shallow copy so callers may add derived entries (e.g. the threshold metric) without mutating the stored config.
- get_parameter_netcdf_metadata(param_config: curryer.correction.config.ParameterConfig, angle_type: str | None = None) NetCDFParameterMetadata¶
Get NetCDF metadata for a parameter.
- _auto_generate_metadata(param_config: curryer.correction.config.ParameterConfig, angle_type: str | None, base_key: str) NetCDFParameterMetadata¶
Auto-generate NetCDF metadata from parameter configuration.
- class curryer.correction.NetCDFParameterMetadata(/, **data: Any)¶
Bases:
pydantic.BaseModelNetCDF metadata for a single output parameter variable.
- variable_name: str¶
- units: str¶
- long_name: str¶
- class curryer.correction.OutputConfig(/, **data: Any)¶
Bases:
pydantic.BaseModelOutput settings for a correction run.
- netcdf¶
NetCDF structure/metadata config.
Noneis auto-populated byrun_correction()from the setup’s performance threshold.
- output_filename¶
Output NetCDF filename.
Nonefalls back to the default inget_output_filename().
- netcdf: curryer.correction.io_config.NetCDFConfig | None = None¶
- output_filename: str | None = None¶
- get_output_filename(default: str = 'correction_results.nc') str¶
Return
output_filenameif set, otherwise default.
- class curryer.correction.ParameterConfig(/, **data: Any)¶
Bases:
pydantic.BaseModelA single parameter to vary during correction analysis.
- ptype¶
How this parameter is applied (constant kernel, offset kernel, or time offset).
- config_file¶
Path to the SPICE kernel JSON template, or
Nonefor time offsets that require no kernel file.
- spec¶
Sampling specification. Accepts a plain
dictorNoneon construction (Pydantic coerces both toParameterSpecautomatically;Nonebecomes an emptyParameterSpec()).
- ptype: ParameterType¶
- config_file: pathlib.Path | None = None¶
- spec: ParameterSpec = None¶
- classmethod _coerce_none_spec(values: Any) Any¶
Convert
spec=Noneto an emptyParameterSpec(backward compat).
- class curryer.correction.ParameterSpec(/, **data: Any)¶
Bases:
pydantic.BaseModelTyped sampling specification for a single correction parameter.
Strict by design (
extra="forbid"): unknown fields raise aValidationErrorso typos surface immediately. Mission-specific extras that the pipeline does not interpret go inmetadata.- current_value¶
Baseline parameter value(s). A scalar for OFFSET_KERNEL/OFFSET_TIME and a 3-element list
[roll, pitch, yaw]for CONSTANT_KERNEL.
- bounds¶
[min, max]offset limits (same units assigma).
- sigma¶
Standard deviation for normal-distribution sampling.
Nonemeans the parameter is held fixed atcurrent_value.
- units¶
Physical units string, e.g.
"arcseconds"or"milliseconds".
- distribution¶
Sampling distribution name. Stored for documentation purposes; the current implementation always uses a normal distribution.
- field¶
Telemetry / science DataFrame column that this parameter modifies (required for
OFFSET_KERNELandOFFSET_TIME).
- transformation_type¶
Optional hint consumed by kernel-creation routines (e.g.
"dcm_rotation"or"angle_bias").
- coordinate_frames¶
Optional list of SPICE frame names affected by this parameter.
- metadata¶
Free-form mission-specific extras not interpreted by the pipeline (e.g. a display
"name", provenance, calibration date).
- model_config¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- current_value: float | list[float] = 0.0¶
- bounds: list[float] = None¶
- sigma: float | None = None¶
- units: str | None = None¶
- distribution: str = 'normal'¶
- field: str | None = None¶
- transformation_type: str | None = None¶
- coordinate_frames: list[str] | None = None¶
- metadata: dict[str, Any] = None¶
- class curryer.correction.ParameterType¶
Bases:
str,enum.EnumParameter types used in the correction configuration.
Specifies how a parameter is applied during geolocation analysis: whether as a constant kernel value, a kernel offset, or a time offset. String-valued so JSON configs use readable names (
"OFFSET_TIME").- CONSTANT_KERNEL¶
Set a specific kernel value (e.g., fixed rotation angles).
- OFFSET_KERNEL¶
Modify input kernel data by an offset.
- OFFSET_TIME¶
Modify input timetags by an offset.
- CONSTANT_KERNEL = 'CONSTANT_KERNEL'¶
- OFFSET_KERNEL = 'OFFSET_KERNEL'¶
- OFFSET_TIME = 'OFFSET_TIME'¶
- class curryer.correction.PSFSamplingConfig¶
Configuration for PSF sampling during image matching.
Default values are calibrated for Landsat 30 m GCPs, which are the standard reference for GCP-based geolocation verification. Override all fields for instruments with different ground resolution or motion characteristics.
- Parameters:
gcp_step_m (float, optional) – Ground control point step size in meters. Default is 30.0.
motion_convolution_step_m (float or None, optional) – Step size for spacecraft motion convolution in meters. If
None(default), derived asgcp_step_m / 20.0in__post_init__.psf_lat_sample_dist_deg (float, optional) – PSF sample distance in the latitude direction in degrees. Default approximately 2.7 m at the equator (Landsat calibration).
psf_lon_sample_dist_deg (float, optional) – PSF sample distance in the longitude direction in degrees. Default approximately 2.7 m at the equator (Landsat calibration).
- gcp_step_m: float = 30.0¶
- motion_convolution_step_m: float | None = None¶
- psf_lat_sample_dist_deg: float = 2.4397105613972e-05¶
- psf_lon_sample_dist_deg: float = 2.8737038710207e-05¶
- __post_init__() None¶
- class curryer.correction.RegridConfig(/, **data: Any)¶
Bases:
pydantic.BaseModelConfiguration for GCP chip regridding.
Specifies output grid parameters for transforming irregular geodetic grids to regular latitude/longitude grids. ECEF → geodetic conversion always uses the WGS84 ellipsoid, which is the only ellipsoid supported by
curryer.compute.spatial.ecef_to_geodetic.- Parameters:
output_grid_size (tuple[int, int], optional) – Desired output grid dimensions as (nrows, ncols). Mutually exclusive with
output_resolution_deg.output_resolution_deg (tuple[float, float], optional) – Desired output resolution as (dlat, dlon) in degrees. Mutually exclusive with
output_grid_size. Required whenoutput_boundsis set.output_bounds (tuple[float, float, float, float], optional) – Explicit output grid bounds as (minlon, maxlon, minlat, maxlat) in degrees. Requires
output_resolution_deg.conservative_bounds (bool, default=True) – If True, shrink bounds to ensure all output points lie within the input irregular grid (avoids edge extrapolation).
interpolation_method (str, default="bilinear") – Interpolation method; one of
"bilinear"or"nearest".fill_value (float, default=NaN) – Value assigned to output points that fall outside the input grid.
- output_grid_size: tuple[int, int] | None = None¶
- output_resolution_deg: tuple[float, float] | None = None¶
- output_bounds: tuple[float, float, float, float] | None = None¶
- conservative_bounds: bool = True¶
- interpolation_method: str = 'bilinear'¶
- fill_value: float¶
- classmethod validate_method(v: str) str¶
Validate interpolation method name.
- classmethod validate_grid_size(v: tuple[int, int] | None) tuple[int, int] | None¶
Validate that grid size has at least 2 rows and 2 columns.
- classmethod validate_resolution(v: tuple[float, float] | None) tuple[float, float] | None¶
Validate that resolution values are positive.
- classmethod validate_bounds(v: tuple[float, float, float, float] | None) tuple[float, float, float, float] | None¶
Validate that bounds are properly ordered.
- validate_grid_spec() RegridConfig¶
Validate that grid specification options are mutually consistent.
- class curryer.correction.RequirementsConfig(/, **data: Any)¶
Bases:
pydantic.BaseModelVerification requirements / thresholds.
Held as the required
requirementsfield onGeolocationSetupand consumed byverify()and the correction verdict.- performance_threshold_m¶
Per-measurement nadir-equivalent error limit in meters (must be > 0). A measurement passes when its error is below this value.
- Type:
float
- performance_spec_percent¶
Minimum fraction of measurements (0–100) that must pass for the overall verification to be considered successful.
- Type:
float
- performance_threshold_m: float = None¶
- performance_spec_percent: float = None¶
- class curryer.correction.SearchConfig¶
Configuration for the image-matching correlation search grid.
Default values are tuned for Landsat 30 m GCPs. Override all fields for instruments with different ground resolution.
- Parameters:
grid_size (int, optional) – Number of grid points per axis in the correlation search grid. Default 44 (Landsat-tuned).
grid_span_km (float, optional) – Half-width of the search grid in kilometers. Default 11.0.
reduction_factor (float, optional) – Multiplicative reduction applied to grid spacing each iteration. Default 0.8.
spacing_limit_m (float, optional) – Minimum grid spacing in meters; search stops when reached. Default 10.0 (Landsat-tuned).
- grid_size: int = 44¶
- grid_span_km: float = 11.0¶
- reduction_factor: float = 0.8¶
- spacing_limit_m: float = 10.0¶
- class curryer.correction.SearchStrategy¶
Bases:
str,enum.EnumStrategy used to generate parameter sets during correction analysis.
- RANDOM¶
Monte Carlo random walk (current default). Each iteration draws an independent sample from a normal distribution centered on the parameter’s
current_valuewith the specifiedsigma, clipped tobounds. Requiresseedandn_iterationsonSweep.
- GRID_SEARCH¶
Deterministic cartesian-product sweep. For every parameter,
grid_points_per_paramevenly-spaced values are generated across the fullboundsoffset range and the cartesian product of all per-parameter grids is enumerated.n_iterationsis ignored.
- SINGLE_OFFSET¶
Deterministic single-parameter sweep. Each parameter is varied independently across
n_iterationsevenly-spaced values (spanning itsboundsoffset range) while all other parameters are held at their nominalcurrent_value. Total parameter sets produced:len(parameters) × n_iterations.
- RANDOM = 'random'¶
- GRID_SEARCH = 'grid'¶
- SINGLE_OFFSET = 'single'¶
- class curryer.correction.Sweep(/, **data: Any)¶
Bases:
pydantic.BaseModelA parameter-variation experiment run against a
GeolocationSetup.Lightweight and cheap to copy, so a setup can be held fixed while rapidly trying parameter variations.
- parameters¶
The parameters to vary (at least one).
- search_strategy¶
How parameter sets are generated (RANDOM / GRID_SEARCH / SINGLE_OFFSET).
- n_iterations¶
Iterations for RANDOM and values-per-parameter for SINGLE_OFFSET; ignored by GRID_SEARCH.
- seed¶
Random seed for reproducible RANDOM sweeps.
- grid_points_per_param¶
Evenly-spaced points per parameter for GRID_SEARCH.
- max_grid_sets¶
Safety cap on total GRID_SEARCH parameter sets.
- parameters: list[ParameterConfig] = None¶
- search_strategy: SearchStrategy¶
- n_iterations: int = None¶
- seed: int | None = None¶
- grid_points_per_param: int = None¶
- max_grid_sets: int = None¶
- with_strategy(strategy: SearchStrategy | str, **sweep_changes: Any) Sweep¶
Return a copy of this sweep using a different search strategy.
Additional sweep-level fields (
n_iterations,seed,grid_points_per_param,max_grid_sets) may be overridden via keyword arguments. The result is re-validated, so typos and strategy-inconsistent settings fail eagerly.Examples
>>> grid = sweep.with_strategy("grid", grid_points_per_param=5) >>> repro = sweep.with_strategy(SearchStrategy.RANDOM, seed=7, n_iterations=200)
- update_param(selector: int | str, **spec_changes: Any) Sweep¶
Return a copy of this sweep with one parameter’s
ParameterSpecchanged.selector is either an integer index into
parameters, or a string matched against each parameter’sspec.fieldor itsconfig_filestem. The changed spec is re-validated againstParameterSpec(which isextra="forbid"), so out-of-spec values or unknown field names raise immediately rather than being silently swallowed.Examples
>>> wider = sweep.update_param("hps.az_ang_nonlin", bounds=[-100.0, 100.0]) >>> tighter = sweep.update_param(0, sigma=5.0)
- _resolve_param_index(selector: int | str) int¶
Resolve selector (index,
spec.field, orconfig_filestem) to an index.
- curryer.correction.load_config_files(config_path: pathlib.Path) tuple[GeolocationSetup, Sweep, OutputConfig]¶
Load
(GeolocationSetup, Sweep, OutputConfig)from one JSON file.The file has three top-level sections —
"setup","sweep", and an optional"output"— each validated directly against its model. The"sweep".parametersentries mirrorParameterConfig(ptype/config_file/spec); rotation frames are authored as a singleCONSTANT_KERNELparameter withspec.current_value = [roll, pitch, yaw].
- curryer.correction.load_setup_from_json(config_path: pathlib.Path) GeolocationSetup¶
Load a
GeolocationSetupfrom the"setup"section of a JSON file.
- curryer.correction.load_sweep_from_json(config_path: pathlib.Path) Sweep¶
Load a
Sweepfrom the"sweep"section of a JSON file.
- class curryer.correction.ErrorStatsConfig¶
Configuration for geolocation error statistics processing.
- Parameters:
minimum_correlation (float or None, optional) – Minimum correlation filter threshold (0.0–1.0). Measurements whose correlation score falls below this value are excluded before processing. Default is
None(no filtering).variable_names (dict of str to str or None, optional) – Mission-agnostic variable name mappings from semantic names to actual dataset variable names. If
None, generic defaults are used.
Notes
Pass/fail thresholds are not part of this config.
ErrorStatsProcessorcomputes statistics only; whether those numbers meet mission requirements is the caller’s responsibility.Earth radius is not a config field either.
_EARTH_RADIUS_M(derived fromcurryer.compute.constants.WGS84_SEMI_MAJOR_AXIS_KM) is used directly in all calculations.- minimum_correlation: float | None = None¶
- variable_names: dict[str, str] | None = None¶
- classmethod from_setup(setup) ErrorStatsConfig¶
Create an
ErrorStatsConfigfrom aGeolocationSetup.Extracts the science-Dataset variable names and
minimum_correlationfrom the setup, the single source of truth for those settings.- Parameters:
setup (GeolocationSetup) – The geolocation setup (variable names + geo settings).
- Return type:
- get_variable_name(semantic_name: str) str¶
Get actual variable name for a semantic concept.
- Parameters:
semantic_name (str) – Semantic name like ‘spacecraft_position’, ‘boresight’, etc.
- Returns:
Actual variable name in the dataset.
- Return type:
str
- Raises:
ValueError – If variable_names is None or semantic_name is not found.
- class curryer.correction.ErrorStatsProcessor(config: ErrorStatsConfig)¶
Production-ready processor for geolocation error statistics.
- config¶
- _filter_by_correlation(data: xarray.Dataset) xarray.Dataset¶
Filter measurements by correlation coefficient threshold.
- Parameters:
data – Input dataset with optional ‘correlation’ or ‘ccv’ variable
- Returns:
Filtered dataset with low-correlation measurements removed
- compute_nadir_equivalent_errors(input_data: xarray.Dataset) xarray.Dataset¶
Compute per-measurement nadir-equivalent errors WITHOUT aggregate statistics.
This is the method to call inside the correction loop — it requires observation geometry (spacecraft position, boresight, transformation matrix) that is only available during each iteration, and produces nadir-equivalent errors for each measurement. No aggregate statistics are computed (meaningless for a single GCP pair in isolation).
Use this inside the loop for checkpoint/resume support. Call
process_geolocation_errors()for the final aggregate pass (nadir-equivalent + comprehensive statistics).- Parameters:
input_data (xr.Dataset) – Dataset with required error measurement variables and a
measurementdimension.- Returns:
Dataset with
nadir_equiv_total_error_mand related intermediate variables. No statistical attributes are set on the output.- Return type:
xr.Dataset
- Raises:
ValueError – If required variables are missing or all measurements are filtered out by the correlation threshold.
- process_geolocation_errors(input_data: xarray.Dataset) xarray.Dataset¶
Full processing: nadir-equivalent errors + aggregate statistics.
Use this for final aggregation after the loop, or in
verify(). For per-iteration computation (single GCP pair), prefercompute_nadir_equivalent_errors()to avoid computing aggregate statistics on a small or single-measurement sample.- Parameters:
input_data (xr.Dataset) – Dataset with required error measurement variables.
- Returns:
Dataset with
nadir_equiv_total_error_mand related intermediate variables, plus comprehensive statistics as global attributes.- Return type:
xr.Dataset
- _validate_input_data(data: xarray.Dataset) None¶
Validate that input dataset contains all required variables.
- _transform_boresight_vectors(bhat_hs: numpy.ndarray, t_hs2ctrs: numpy.ndarray) numpy.ndarray¶
Transform boresight vectors from HS to CTRS coordinate system.
- _process_to_nadir_equivalent(ns_error_m: numpy.ndarray, ew_error_m: numpy.ndarray, riss_ctrs: numpy.ndarray, bhat_ctrs: numpy.ndarray, gcp_lat_rad: numpy.ndarray, gcp_lon_rad: numpy.ndarray, n_measurements: int) dict[str, numpy.ndarray]¶
Process error measurements to nadir-equivalent values.
- _create_ctrs_to_uen_transform(lat_rad: float, lon_rad: float) numpy.ndarray¶
Create transformation matrix from CTRS to Up-East-North coordinates.
- _calculate_view_plane_vectors(bhat_uen: numpy.ndarray) ViewPlaneVectors¶
Calculate view-plane and cross-view-plane unit vectors in UEN coordinates.
- _calculate_scaling_factors(riss_ctrs: numpy.ndarray, theta: float) ScalingFactors¶
Calculate scaling factors for nadir-equivalent transformation.
- _create_output_dataset(input_data: xarray.Dataset, results: dict[str, numpy.ndarray]) xarray.Dataset¶
Create output Xarray Dataset with processing results.
- _calculate_statistics(nadir_equiv_errors_m: numpy.ndarray) dict[str, float | int]¶
Calculate comprehensive, mission-agnostic performance statistics.
This method intentionally does NOT include any pass/fail evaluation. Whether these statistics meet mission requirements is the caller’s responsibility. Use
compute_percent_below()for custom threshold queries not covered by the standard table.- Parameters:
nadir_equiv_errors_m (np.ndarray) – Array of nadir-equivalent geolocation errors in meters.
- Returns:
Keys: central tendency (
mean_error_m,median_error_m,rms_error_m), spread (std_error_m,min_error_m,max_error_m), percentiles (p25_error_m…p99_error_m), count (total_measurements), and a threshold table at standard intervals (percent_below_100m…percent_below_1000m).- Return type:
dict[str, float | int]
- process_from_netcdf(filepath: str | pathlib.Path, minimum_correlation: float | None = None) xarray.Dataset¶
Load previous results from NetCDF and reprocess error statistics.
This enables iterative post-processing of Correction results without re-running expensive image matching operations.
- Parameters:
filepath – Path to NetCDF file from previous Correction run
minimum_correlation – Override correlation threshold (if provided)
- Returns:
Xarray Dataset with reprocessed error statistics
Example
>>> processor = ErrorStatsProcessor() >>> # Try different correlation thresholds >>> results_50 = processor.process_from_netcdf( ... "correction_results/run_001.nc", ... minimum_correlation=0.5 ... ) >>> results_70 = processor.process_from_netcdf( ... "correction_results/run_001.nc", ... minimum_correlation=0.7 ... )
- curryer.correction.compute_percent_below(errors: numpy.ndarray, threshold_m: float) float¶
Compute the percentage of errors below a given threshold.
Useful for evaluating custom thresholds not in the standard table produced by
ErrorStatsProcessor._calculate_statistics().- Parameters:
errors (np.ndarray) – Array of nadir-equivalent geolocation errors in meters.
threshold_m (float) – Threshold in meters.
- Returns:
Percentage (0–100) of errors strictly below threshold_m. Returns
0.0when errors is empty.- Return type:
float
- class curryer.correction.ImageGrid¶
Container for image data sampled on a latitude/longitude grid.
- data: numpy.ndarray¶
- lat: numpy.ndarray¶
- lon: numpy.ndarray¶
- h: numpy.ndarray | None = None¶
- __post_init__() None¶
- _validate_shapes() None¶
- property mid_indices: tuple[int, int]¶
Return the row/column indices of the central pixel.
- class curryer.correction.PSFGrid¶
Point spread function sampled on a latitude/longitude grid.
- data: numpy.ndarray¶
- lat: numpy.ndarray¶
- lon: numpy.ndarray¶
- __post_init__() None¶
- _validate_shapes() None¶
- curryer.correction.geolocated_to_image_grid(geo_dataset: xarray.Dataset) curryer.correction.grid_types.ImageGrid¶
Convert a geolocated
xr.Datasetto anImageGridfor image matching.This is the canonical adapter between SPICE geolocation output and the image-matching subsystem. It should be used wherever an
ImageGridis needed from an already-geolocated dataset, ensuring a single consistent implementation across the correction pipeline and the verification module.- Parameters:
geo_dataset (xr.Dataset) – Geolocated dataset with
latitudeandlongitudevariables (2-D arrays) and optionallyaltitude/height,radiance, orreflectance.- Returns:
Image grid with
lat,lon,hfrom the dataset anddataset to the first available ofradiance,reflectance, or an all-ones placeholder.- Return type:
Notes
Altitude/height defaults to an all-zeros array when absent. The placeholder
dataarray (all ones) is used only for geometric operations where actual radiance values are not yet required.
- curryer.correction.infer_spacecraft_state(grid: curryer.correction.grid_types.ImageGrid, r_spacecraft_m: numpy.ndarray | None, default_altitude_m: float = 400000.0) tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray]¶
Deprecated — use
resolve_spacecraft_eceffromcurryer.correction.psfinstead.
- curryer.correction.load_image_grid(filepath: pathlib.Path | str, mat_key: str = 'subimage') curryer.correction.grid_types.ImageGrid¶
Load any supported image file as an
ImageGrid.Dispatches on file extension — callers do not need to know the underlying format.
- Parameters:
filepath (path-like) – Path to the image file. Local paths and
s3://URIs supported (S3 requiresboto3).mat_key (str, optional) – MATLAB struct key. Defaults to
"subimage". Ignored for NetCDF.
- Return type:
- Raises:
ValueError – If the file extension is not recognised.
FileNotFoundError – If filepath does not exist.
Examples
>>> obs = load_image_grid(Path("subimage.mat"), mat_key="subimage") >>> gcp = load_image_grid(Path("GCP12055_regridded.nc"))
- curryer.correction.load_los_vectors(mat_file: str | pathlib.Path, key: str = 'b_HS') numpy.ndarray¶
Load line-of-sight unit vectors from a
.matcalibration file.- Parameters:
mat_file (str or Path) – Path to MATLAB file with LOS vectors (local path or
s3://URI).key (str, default="b_HS") – Primary key to try for LOS data.
- Returns:
LOS unit vectors in instrument frame, shape (n_pixels, 3).
- Return type:
np.ndarray
- Raises:
FileNotFoundError – If mat_file is a local path and doesn’t exist.
ImportError – If mat_file is an S3 URI and boto3 is not installed.
KeyError – If no LOS vectors found with common key names.
- curryer.correction.load_named_image_grid(filepath: pathlib.Path | str, mat_key: str = 'subimage') curryer.correction.grid_types.NamedImageGrid¶
Load any supported image file as a
NamedImageGrid.Dispatches on file extension so callers do not need to know the underlying format. The returned grid always carries the file path as its
name.Supported formats¶
.matMATLAB struct file. The struct accessed via mat_key must have
data,lat, andlonattributes (and optionallyh)..nc/.netcdf/.nc4NetCDF file written by
save_image_grid()or the regridding pipeline (expectsband_data,lat,lon).
- param filepath:
Path to the image file.
- type filepath:
path-like
- param mat_key:
MATLAB struct key to read. Defaults to
"subimage". Ignored for NetCDF files.- type mat_key:
str, optional
- returns:
Loaded image grid with
nameset to the string representation of filepath.- rtype:
NamedImageGrid
- raises ValueError:
If the file extension is not recognised.
- raises FileNotFoundError:
If filepath does not exist.
Examples
>>> obs = load_named_image_grid(Path("TestCase1a_subimage.mat"), mat_key="subimage") >>> gcp = load_named_image_grid(Path("GCP12055Dili_regridded.nc"))
- curryer.correction.load_observation_file(filepath: str | pathlib.Path, mat_key: str = 'subimage') tuple[curryer.correction.grid_types.ImageGrid, numpy.ndarray | None]¶
Load one observation file and return
(ImageGrid, spacecraft_position_m).Supports
.matand NetCDF (.nc,.nc4,.netcdf) formats. The spacecraft ECEF position is extracted when available in the file; when absent,Noneis returned and callers should fall back toinfer_spacecraft_state().- Parameters:
filepath (str or Path) – Local path or
s3://URI to a.mator.ncobservation file.mat_key (str, optional) – MATLAB struct key containing the image data. Defaults to
"subimage". Ignored for NetCDF files.
- Returns:
grid (ImageGrid) – Radiance data on a lat/lon grid.
r_spacecraft_m (ndarray of shape (3,) or None) – Spacecraft ECEF position in meters at the mid-frame, extracted from the file when available.
Nonewhen not present — caller should useinfer_spacecraft_state()to approximate.
- Raises:
ValueError – If the file extension is not recognised.
FileNotFoundError – If filepath is a local path that does not exist.
ImportError – If filepath is an S3 URI and
boto3is not installed.
- curryer.correction.load_optical_psf(mat_file: str | pathlib.Path, key: str = 'PSF_struct_675nm') list[curryer.correction.grid_types.OpticalPSFEntry]¶
Load optical PSF entries from a
.matcalibration file.- Parameters:
mat_file (str or Path) – Path to MATLAB file with PSF data (local path or
s3://URI).key (str, default="PSF_struct_675nm") – Primary key to try for PSF data.
- Returns:
Optical PSF samples with data, x, and field_angle arrays.
- Return type:
list[OpticalPSFEntry]
- Raises:
FileNotFoundError – If mat_file is a local path and doesn’t exist.
ImportError – If mat_file is an S3 URI and boto3 is not installed.
KeyError – If no PSF data found with common key names.
ValueError – If PSF entries missing field angle attribute.
- curryer.correction.save_image_grid(filepath: pathlib.Path, image_grid: curryer.correction.grid_types.ImageGrid, metadata: dict | None = None, compression: bool = True, band_units: str = 'DN', band_long_name: str = 'regridded_radiance') None¶
Save an
ImageGridto file.The output format is determined by the file extension:
.nc/.netcdf/.nc4→ CF-1.8 NetCDF (vianetCDF4).mat→ MATLAB struct (key"GCP").tif/.tiff→ GeoTIFF (requiresrasterio)
- Parameters:
filepath (Path) – Output file path. Extension controls the format.
image_grid (ImageGrid) – Image data with lat/lon coordinates.
metadata (dict, optional) – Additional metadata written as file-level attributes or tags.
compression (bool, optional) – Enable compression for NetCDF output (default
True). Ignored for other formats.band_units (str, optional) –
units/long_namefor the band data variable in NetCDF output (defaults describe a regridded Landsat GCP chip in digital numbers). Ignored for other formats.band_long_name (str, optional) –
units/long_namefor the band data variable in NetCDF output (defaults describe a regridded Landsat GCP chip in digital numbers). Ignored for other formats.
- Raises:
ValueError – If the file extension is not supported.
Examples
>>> save_image_grid(Path("chip.nc"), regridded, metadata={"band": "red"}) >>> save_image_grid(Path("chip.mat"), regridded)
- curryer.correction.resolve_path(path: str | pathlib.Path, *, s3_client=None) pathlib.Path¶
Resolve a file path, downloading from S3 if necessary.
- Parameters:
path (str or Path) – Local file path or S3 URI (
s3://bucket/key).s3_client (boto3 S3 client, optional) – Injected client for testing. If omitted and path is an S3 URI, a default client is created via boto3.
- Returns:
Local file path. For S3 URIs, a temporary local file that is cleaned up at process exit via
atexit().- Return type:
Path
- Raises:
ImportError – If path is an S3 URI and boto3 is not installed.
FileNotFoundError – If path is a local path that does not exist.
ValueError – If path is an S3 URI with no object key (e.g.
s3://bucket).
- curryer.correction.compute_error_stats(image_matching_results, setup: curryer.correction.config.GeolocationSetup)¶
Compute error statistics from image matching results.
This is the preferred name for
call_error_stats_module(). Seecall_error_stats_module()for full documentation.- Parameters:
image_matching_results (xr.Dataset or list of xr.Dataset) – Output from image matching, either a single dataset or a list.
setup (GeolocationSetup) – Geolocation setup used to initialise the error stats processor.
- Returns:
Aggregate error statistics dataset.
- Return type:
xr.Dataset
- curryer.correction.loop(setup: curryer.correction.config.GeolocationSetup, sweep: curryer.correction.config.Sweep, work_dir: pathlib.Path, tlm_sci_gcp_sets: list[tuple[str, str, str]], output: curryer.correction.config.OutputConfig | None = None, resume_from_checkpoint: bool = False)¶
Correction loop for parameter sensitivity analysis.
- Parameters:
setup (GeolocationSetup) – Durable mission setup: SPICE kernels/instrument (
geo), pass/failrequirements,data_config(file format + time scaling), optionalcalibrationfiles, mission variable names, and an optionalimage_matching_funcoverride.sweep (Sweep) – The parameter-variation experiment:
parameters,search_strategy,n_iterations,seed, and grid settings.work_dir (Path) – Working directory for temporary files.
tlm_sci_gcp_sets (list of (str, str, str)) – List of (telemetry_key, science_key, gcp_key) tuples. File paths are expected to be local. S3 URIs (
s3://…) are also accepted as a convenience whenboto3is installed; seeresolve_path().output (OutputConfig or None, optional) – Output settings (NetCDF metadata + filename).
Noneuses defaults derived fromsetup.requirements.resume_from_checkpoint (bool, optional) – If True, resume from an existing checkpoint.
- Returns:
results (list) – List of iteration results (order: pair_idx * N + param_idx).
netcdf_data (dict) – Dictionary of NetCDF variables indexed as [param_idx, pair_idx].
Notes
This implementation uses a pair-outer, parameter-inner loop order: - Outer loop: GCP pairs (load data once per image) - Inner loop: Parameter sets (reuse loaded data) This reduces file I/O and centralizes mission-specific behavior through the
setupobject.Examples
Correction mode (parameter optimization):
from curryer.correction.config import DataConfig results, netcdf_data = loop(setup, sweep, work_dir, tlm_sci_gcp_sets)
Where each element of
tlm_sci_gcp_setsis a tuple of file paths:tlm_sci_gcp_sets = [ ("telemetry.csv", "science.csv", "landsat_chip_001.mat"), ]
- curryer.correction.run_correction(setup: curryer.correction.config.GeolocationSetup, sweep: curryer.correction.config.Sweep, inputs: collections.abc.Sequence[curryer.correction.config.CorrectionInput | tuple[str, str, str]], work_dir: pathlib.Path, output: curryer.correction.config.OutputConfig | None = None, resume_from_checkpoint: bool = False) curryer.correction.results.CorrectionResult¶
Run the correction parameter sweep.
This is the preferred user-facing entry point (compared to
loop()). Returns a structuredCorrectionResultwith the best parameter set, pass/fail verdict, recommendation, and a human-readable summary table. The rawresultslist andnetcdf_datadict fromloop()are available asresult.resultsandresult.netcdf_datafor advanced use.- Parameters:
setup (GeolocationSetup) – Durable mission setup (kernels, requirements, calibration, names).
sweep (Sweep) – The parameter-variation experiment to run against setup.
inputs (list of CorrectionInput or list of (str, str, str)) – Each element is either a
CorrectionInput(named fields) or a legacy(telemetry_key, science_key, gcp_key)tuple. Both forms may be mixed in the same list. File paths are expected to be local. S3 URIs (s3://…) are also accepted as a convenience whenboto3is installed; seeresolve_path().work_dir (Path) – Working directory for temporary files.
output (OutputConfig or None, optional) – Output settings (NetCDF metadata + filename).
Noneuses defaults derived fromsetup.requirements.resume_from_checkpoint (bool, optional) – If True, resume from an existing checkpoint.
- Returns:
Structured result with best parameters, pass/fail verdict, recommendation, summary table, and raw NetCDF/intermediate data available on the returned object (for example,
result.netcdf_data).- Return type:
- curryer.correction.run_image_matching(geolocated_data: xarray.Dataset, gcp_reference_file: pathlib.Path, telemetry: pandas.DataFrame, params_info: list, setup: curryer.correction.config.GeolocationSetup, los_vectors_cached: numpy.ndarray | None = None, optical_psfs_cached: list | None = None) xarray.Dataset¶
Run image matching against GCP reference.
This is the preferred name for
image_matching(). Seeimage_matching()for full documentation.- Parameters:
geolocated_data (xr.Dataset) – Geolocated scene data with latitude/longitude.
gcp_reference_file (Path) – Path to the GCP reference image (.mat file).
telemetry (pd.DataFrame) – Telemetry DataFrame with spacecraft state.
params_info (list) – Parameter information for the current iteration.
setup (GeolocationSetup) – Geolocation setup (calibration paths, variable names, instrument name).
los_vectors_cached (np.ndarray or None, optional) – Pre-loaded LOS vectors; loaded from disk if None.
optical_psfs_cached (list or None, optional) – Pre-loaded optical PSFs; loaded from disk if None.
- Returns:
Image matching results dataset.
- Return type:
xr.Dataset
- class curryer.correction.CorrectionResult(/, **data: Any)¶
Bases:
pydantic.BaseModelStructured result from
run_correction().Provides the instrument engineer with a clear answer: what is the best parameter set, does it meet requirements, and what should they do next.
Serialisation¶
Most fields are JSON-serialisable via
model_dump()/model_dump_json(). Theresultsandnetcdf_datafields are excluded from serialisation by default because they contain non-JSON-serialisable types (xr.Dataset, numpy arrays). Access them directly on the object when raw data is needed:result = run_correction(setup, sweep, inputs, work_dir) result.best_parameter_set # dict[str, float] — use this result.results # raw per-iteration dicts — advanced use only result.netcdf_data # raw numpy arrays — advanced use only
- best_parameter_set¶
Parameter values that produced the lowest aggregate RMS.
- Type:
dict[str, float]
- best_rms_m¶
Best aggregate RMS achieved across all parameter sets (meters).
- Type:
float
- best_index¶
Index of the best parameter set (for cross-referencing with NetCDF output).
- Type:
int
- worst_rms_m¶
Worst aggregate RMS across all parameter sets (meters).
- Type:
float
- mean_rms_m¶
Mean of all aggregate RMS values (meters).
- Type:
float
- n_parameter_sets¶
Number of parameter sets tested in the sweep.
- Type:
int
- n_gcp_pairs¶
Number of GCP pairs used.
- Type:
int
- all_parameter_sets¶
All tested parameter sets sorted by mean RMS (ascending).
- Type:
list[ParameterSetResult]
- met_threshold¶
Whether the best parameter set met the mission performance requirements.
- Type:
bool
- recommendation¶
Human-readable next-step guidance for the instrument engineer.
- Type:
str
- summary_table¶
Human-readable ASCII table of the top results.
- Type:
str
- netcdf_path¶
Path to the saved NetCDF output file.
- Type:
Path or None
- config_snapshot¶
Key config values used, for reproducibility records.
- Type:
dict
- elapsed_time_s¶
Total wall-clock processing time in seconds.
- Type:
float
- timestamp¶
UTC time when the run completed.
- Type:
datetime
- model_config¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- best_parameter_set: dict[str, float]¶
- best_rms_m: float¶
- best_index: int¶
- worst_rms_m: float¶
- mean_rms_m: float¶
- n_parameter_sets: int¶
- n_gcp_pairs: int¶
- all_parameter_sets: list[ParameterSetResult]¶
- met_threshold: bool¶
- recommendation: str¶
- summary_table: str¶
- netcdf_path: pathlib.Path | None = None¶
- config_snapshot: dict = None¶
- elapsed_time_s: float = 0.0¶
- timestamp: datetime.datetime = None¶
- results: list = None¶
- netcdf_data: dict = None¶
- class curryer.correction.ParameterSetResult(/, **data: Any)¶
Bases:
pydantic.BaseModelResults for a single parameter set in a correction sweep.
- index¶
Zero-based index of this parameter set in the sweep.
- Type:
int
- parameter_values¶
Parameter name → sampled value for this set.
- Type:
dict[str, float]
- mean_rms_m¶
Mean RMS geolocation error across all GCP pairs (meters).
- Type:
float
- best_pair_rms_m¶
RMS error of the best-performing GCP pair (meters).
- Type:
float
- worst_pair_rms_m¶
RMS error of the worst-performing GCP pair (meters).
- Type:
float
- index: int¶
- parameter_values: dict[str, float]¶
- mean_rms_m: float¶
- best_pair_rms_m: float¶
- worst_pair_rms_m: float¶
- class curryer.correction.GCPError(/, **data: Any)¶
Bases:
pydantic.BaseModelPer-measurement/GCP error detail.
Each instance corresponds to one row in the aggregated image-matching output — typically one measurement from a single GCP pair.
- gcp_index¶
Zero-based measurement index in the aggregated dataset.
- Type:
int
- science_key¶
Identifier for the science data segment (dataset label or index).
- Type:
str
- gcp_key¶
Identifier for the ground-control-point source.
- Type:
str
- lat_error_deg¶
Latitude error in degrees (positive = northward shift).
- Type:
float
- lon_error_deg¶
Longitude error in degrees (positive = eastward shift).
- Type:
float
- nadir_equiv_error_m¶
Nadir-equivalent total geolocation error in meters, or
Nonewhen error-stats processing was not performed.- Type:
float or None
- correlation¶
Image-matching correlation score, or
Nonewhen not available.- Type:
float or None
- passed¶
Whether this measurement satisfies the per-measurement threshold.
- Type:
bool
- model_config¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- gcp_index: int¶
- science_key: str¶
- gcp_key: str¶
- lat_error_deg: float¶
- lon_error_deg: float¶
- nadir_equiv_error_m: float | None = None¶
- correlation: float | None = None¶
- passed: bool¶
- class curryer.correction.VerificationResult(/, **data: Any)¶
Bases:
pydantic.BaseModelStructured result from a
verify()call.Most fields are JSON-serialisable via Pydantic’s
model_dump()/model_dump_json(). Theaggregate_statsfield (anxr.Dataset) must be excluded when serialising to JSON — persist it separately (e.g. viaaggregate_stats.to_netcdf(path)):json_str = result.model_dump_json(exclude={"aggregate_stats"}) result.aggregate_stats.to_netcdf("verification_stats.nc")
- passed¶
Truewhenpercent_within_threshold≥requirements.performance_spec_percent.- Type:
bool
- aggregate_stats¶
Full output from
process_geolocation_errors().- Type:
xr.Dataset
- requirements¶
The thresholds used for this verification run.
- Type:
- summary_table¶
Human-readable ASCII table suitable for logging or reports.
- Type:
str
- percent_within_threshold¶
Percentage of measurements with nadir-equivalent error below
requirements.performance_threshold_m.- Type:
float
- files_processed¶
Science/GCP key pairs that were processed, as
"<sci_key>+<gcp_key>"strings. Empty when the source mapping is unavailable.- Type:
list[str]
- elapsed_time_s¶
Wall-clock time for the verify call in seconds, or
Nonewhen not measured.- Type:
float or None
- config_snapshot¶
Key config fields used for this run (threshold, spec percent, instrument name), for reproducibility records.
- Type:
dict or None
- model_config¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- passed: bool¶
- aggregate_stats: xarray.Dataset¶
- requirements: curryer.correction.config.RequirementsConfig¶
- summary_table: str¶
- percent_within_threshold: float¶
- warnings: list[str]¶
- timestamp: datetime.datetime¶
- files_processed: list[str] = None¶
- elapsed_time_s: float | None = None¶
- config_snapshot: dict | None = None¶
- curryer.correction.compare_results(before: VerificationResult, after: VerificationResult) str¶
Generate a side-by-side comparison of two verification results.
Useful for evaluating whether a correction run improved geolocation accuracy relative to a baseline.
- Parameters:
before (VerificationResult) – Baseline verification result (e.g., pre-correction).
after (VerificationResult) – Updated verification result (e.g., post-correction).
- Returns:
Human-readable side-by-side comparison table.
- Return type:
str
- curryer.correction.match_geolocated_to_gcp_files(geolocated_data: xarray.Dataset, gcp_files: list[pathlib.Path], setup: curryer.correction.config.GeolocationSetup, los_vectors_cached: numpy.ndarray | None = None, optical_psfs_cached: list | None = None) list[xarray.Dataset]¶
Run image matching between already-geolocated data and GCP reference files.
This is the reusable pipeline tail: both the correction loop (after kernel tweaking and geolocation) and standalone
verify()call this function. Given geolocated data and a list of GCP reference files it performs image matching against each file and returns the per-GCP error datasets ready for aggregation and error-stats processing.- Parameters:
geolocated_data (xr.Dataset) – Geolocated observation dataset with
latitude,longitude, and aframecoordinate (GPS seconds).gcp_files (list of Path) – GCP reference files to match against.
setup (GeolocationSetup) – Mission setup (calibration paths, variable names, instrument name).
los_vectors_cached (np.ndarray or None, optional) – Pre-loaded LOS vectors.
optical_psfs_cached (list or None, optional) – Pre-loaded optical PSF entries.
- Returns:
One error dataset per successfully matched GCP file. Failures are logged as warnings and skipped.
- Return type:
list of xr.Dataset
- curryer.correction.verify(setup: curryer.correction.config.GeolocationSetup, gcp_pairs: list[tuple[str | pathlib.Path, str | pathlib.Path]] | None = None, observation_paths: list[str | pathlib.Path] | None = None, gcp_directory: str | pathlib.Path | None = None, los_file: str | pathlib.Path | None = None, psf_file: str | pathlib.Path | None = None, max_distance_m: float = 0.0, gcp_pattern: str = '*_regridded.nc', default_altitude_m: float = 400000.0, image_matching_results: list[xarray.Dataset] | None = None, geolocated_data: xarray.Dataset | None = None, work_dir: pathlib.Path | None = None) VerificationResult¶
Evaluate current alignment against mission requirements.
No parameter variation, no kernel creation, no iteration loop. This function checks whether a given set of alignment parameters meets geolocation requirements.
Input priority (first match wins)¶
image_matching_results — pre-computed outputs from image matching; the most common entry point for weekly automated checks.
geolocated_data — raw geolocated data. Either set
setup.image_matching_funcfor a custom matcher, or supply gcp_directory, los_file, and psf_file to run built-in spatial pairing + image matching.gcp_pairs — explicit
(observation_path, gcp_path)file-path pairs. Requires los_file and psf_file.observation_paths + gcp_directory — auto-paired via spatial overlap. Requires los_file and psf_file.
None of the above provided — raises
ValueError.
- param setup:
Mission setup with all geolocation/calibration settings.
- type setup:
GeolocationSetup
- param gcp_pairs:
Explicit
(observation_path, gcp_path)pairs. Each path may be a local path or ans3://URI (requiresboto3).- type gcp_pairs:
list of (path, path) or None
- param observation_paths:
Observation file paths for automatic GCP pairing. Requires gcp_directory, los_file, and psf_file.
- type observation_paths:
list of path or None
- param gcp_directory:
Directory of GCP reference images for automatic pairing with observation_paths.
- type gcp_directory:
path or None
- param los_file:
Instrument line-of-sight vectors (
.matfile). Required when gcp_pairs or observation_paths is provided.- type los_file:
path or None
- param psf_file:
Optical PSF
.matfile. Required when gcp_pairs or observation_paths is provided.- type psf_file:
path or None
- param max_distance_m:
Spatial pairing margin for the auto-pair mode (default
0.0— GCP center must be inside the observation footprint).- type max_distance_m:
float, optional
- param gcp_pattern:
Glob pattern used to discover GCP chips when gcp_directory is provided. Defaults to
"*_regridded.nc".- type gcp_pattern:
str, optional
- param default_altitude_m:
Fallback spacecraft altitude (meters) used when observation files do not contain position data. Default
400_000.0(ISS nominal orbit). Override for other platforms (e.g.505_000.0for CTIM).- type default_altitude_m:
float, optional
- param image_matching_results:
Pre-computed image-matching datasets, one per GCP pair.
- type image_matching_results:
list[xr.Dataset] or None
- param geolocated_data:
Already-geolocated data. Matched either via
setup.image_matching_func(custom override) or, when gcp_directory, los_file, and psf_file are supplied, via built-in spatial pairing + image matching.- type geolocated_data:
xr.Dataset or None
- param work_dir:
Working directory for outputs. Created if absent.
- type work_dir:
Path or None, optional
- returns:
Structured pass/fail result with per-GCP detail and a human-readable
summary_table.- rtype:
VerificationResult
- raises ValueError:
When none of the input modes is provided; when geolocated_data is supplied without gcp_directory / los_file / psf_file and
setup.image_matching_funcis not set; when los_file or psf_file isNonefor a file-path mode (gcp_pairs or observation_paths + gcp_directory); when observation_paths and gcp_directory are not both supplied; or when image matching produces no results.- raises FileNotFoundError:
If any of the supplied file paths do not exist.