nav.reproj

Body reprojection and mosaicing utilities.

This module provides the BodyMosaic class for reprojecting planetary body images onto latitude/longitude grids and accumulating them into mosaics.

Bases: object

Reprojects and mosaics body images in latitude/longitude space.

Combines reprojected body images into a single mosaic, resolving conflicts using a configurable merge strategy.

The coordinate grid uses the specified resolution in both latitude and longitude. All angular values are in radians.

Internal storage uses a shifted circular buffer to handle longitude wraparound (data spanning the 0/2*pi boundary) without allocating the full 0..2*pi range.

Thread safety: reproject() uses oops backplane computation which is not safe for concurrent use on the same observation. Do not call reproject() from multiple threads on the same observation.

Example usage:

mosaic = BodyMosaic(body_name='MIMAS')
for obs in observations:
    result = mosaic.reproject(obs, data=obs.data)
    mosaic.add(result)
data = mosaic.to_bounded()

The name of the body.

Add a reprojected image to the mosaic.

For each valid pixel in repro, it is incorporated into the mosaic according to the merge strategy.

Parameters:
  • repro – Result from reproject().

  • resolution_threshold – Factor by which repro’s effective resolution must exceed the mosaic’s to trigger replacement. Should be >= 1.0 (higher = stricter).

  • copy_slop – Number of additional pixels around each copied pixel to also copy, reducing isolated-pixel artifacts.

  • max_incidence – Maximum incidence angle (rad) for pixels that may be written. USE_MOSAIC_LIMITS (default) uses the mosaic’s constructor value; an explicit float overrides for this call only; None disables the incidence cutoff for this call.

  • max_emission – Same pattern for emission angle (rad).

  • max_resolution – Same pattern for center resolution in km/pixel (compared to repro.resolution, as in reproject()).

Raises:
  • OverflowError – If the number of images added would exceed the uint16 maximum of 65 535.

  • ValueError – If repro’s resolution, coordinate system, or photometric model name does not match the mosaic’s configuration.

Current data extent as ((lat_min, lat_max), (lon_min, lon_max)).

Returns the bounding box of all valid data currently in the mosaic. Longitude bounds are in the contiguous arc order (min may be greater than max if the data wraps around the 0/2*pi boundary).

Returns:

((lat_min, lat_max), (lon_min, lon_max)) in radians, or None if no data has been added yet.

Generate a list of latitudes on resolution boundaries.

The returned latitudes are on lat_resolution grid boundaries and lie within [latitude_start, latitude_end].

Parameters:
  • latitude_start – Minimum latitude (rad). Defaults to -pi/2.

  • latitude_end – Maximum latitude (rad). Defaults to pi/2 minus slop.

  • lat_resolution – Latitude resolution (rad/pixel).

Returns:

1-D array of latitudes (rad).

Generate a list of longitudes on resolution boundaries.

Parameters:
  • longitude_start – Minimum longitude (rad). Defaults to 0.

  • longitude_end – Maximum longitude (rad). Defaults to 2*pi minus slop.

  • lon_resolution – Longitude resolution (rad/pixel).

Returns:

1-D array of longitudes (rad).

Convert latitude/longitude arrays to (U, V) image pixel coordinates.

Parameters:
  • obs – The Observation.

  • latitude – Latitude values (rad).

  • longitude – Longitude values (rad).

Returns:

UV pairs as a polymath UV object.

Reproject the body into a rectangular latitude/longitude space.

Parameters:
  • obs – The Observation (with its FOV already configured as needed).

  • data – Image data to reproject. Defaults to obs.data.

  • navigation_uncertainty – Maximum uncertainty in pixel pointing (pixels), used to compute eff_resolution.

  • mask_only – If True, return only the valid-pixel boolean mask. Other result fields will be empty masked arrays.

  • override_backplane – A Backplane to use instead of creating a new one from obs.

  • subimage_edges – (u_min, u_max, v_min, v_max) describing the subimage extent if override_backplane covers only a subimage.

  • mask_bad_areas – If True, expand bad-pixel regions before masking to handle images with transmission errors.

  • image_name – Optional label stored on the result (e.g. source image stem).

Returns:

BodyReprojResult with the reprojected data.

When the body has no valid latitude/longitude on the detector (fully outside the field of view or not projected onto the image), this returns immediately with an empty result without building the lat/lon grid or sampling image pixels.

Note

The image data is taken from the zoomed, interpolated image, while the incidence, emission, phase, and resolution are taken from the original non-interpolated data and thus will be slightly more coarse-grained. Backplane masks and limit tests are folded into ok_body_mask (see below); scatter uses that same mask so img is never valid where phase, emission, incidence, or resolution would be masked or beyond configured limits.

Raises:
  • TypeError – If navigation_uncertainty is not a real number (bool is not accepted).

  • ValueError – If navigation_uncertainty is not finite or is < 0.

Return the mosaic clipped to the given lat/lon range.

Parameters:
  • lat_range – (min_lat, max_lat) in radians. Defaults to current data bounds.

  • lon_range – (min_lon, max_lon) in radians. May wrap around 0/2*pi (e.g., (5.9, 0.3) means from 5.9 rad through 2*pi to 0.3 rad). Defaults to current data bounds.

Returns:

BodyMosaicData with the clipped mosaic.

Raises:

ValueError – If no data has been added yet and no range is specified.

Return the mosaic as a full latitude x longitude grid.

Returns:

BodyMosaicData covering the full -pi/2 to pi/2 x 0 to 2*pi grid. Pixels with no data are masked.

Bases: object

Mosaic data returned by BodyMosaic retrieval methods.

This is a dataclasses.dataclass(); each field is documented on its own member entry below.

Load a BodyMosaicData from a file.

Parameters:
  • path – Input path (str, pathlib.Path, or filecache.FCPath).

  • format – Explicit format ('npz' or 'fits'). If None, inferred from the file extension.

Returns:

A new BodyMosaicData with the loaded data.

Raises:

ValueError – If the file’s kind does not match, or if any array dtype does not match the declared image_dtype / metadata_dtype, or if image_number is not uint16, or if time is not float64.

Example:

data = BodyMosaicData.load('mimas.npz')

Save this BodyMosaicData to a file.

Parameters:
  • path – Output path (str, pathlib.Path, or filecache.FCPath). The format is inferred from the extension (.npz for NumPy archive, .fits/.fit for FITS) unless format_ is given.

  • format – Explicit format: 'npz' or 'fits'. Overrides extension-based inference.

  • compress – If True (default), use compressed npz. Ignored for FITS.

Raises:

ValueError – If the format cannot be inferred or is not supported.

Example:

data = mosaic.to_bounded()
data.save('mimas.npz')
data.save('mimas.fits', format_='fits')
data.save('mimas.npz', compress=False)
reloaded = BodyMosaicData.load('mimas.npz')

Bases: Enum

Strategy for resolving per-pixel conflicts when adding data to a BodyMosaic.

Members:
BEST_RESOLUTION: Replace an existing pixel only when the new data has

strictly better effective resolution, or if the existing pixel is empty (masked).

Bases: object

Data returned by BodyMosaic.reproject().

This is a dataclasses.dataclass(); each field is documented on its own member entry below.

Load a BodyReprojResult from a file.

Parameters:
  • path – Input path (str, pathlib.Path, or filecache.FCPath).

  • format – Explicit format ('npz' or 'fits'). If None, inferred from the file extension.

Returns:

A new BodyReprojResult with the loaded data.

Raises:

ValueError – If the file’s kind does not match, or if any array dtype does not match the declared image_dtype / metadata_dtype.

Example:

result = BodyReprojResult.load('reprojection.npz')

Save this BodyReprojResult to a file.

Parameters:
  • path – Output path (str, pathlib.Path, or filecache.FCPath). The format is inferred from the extension (.npz for NumPy archive, .fits/.fit for FITS) unless format_ is given.

  • format – Explicit format: 'npz' or 'fits'. Overrides extension-based inference.

  • compress – If True (default), use compressed npz. Ignored for FITS.

Raises:

ValueError – If the format cannot be inferred or is not supported.

Example:

result = mosaic.reproject(obs)
result.save('reprojection.npz')
result.save('reprojection.fits', format_='fits')
reloaded = BodyReprojResult.load('reprojection.npz')

Pass to BodyMosaic.add() for max_incidence / max_emission / max_resolution.

Uses the BodyMosaic constructor limits instead of per-call overrides.

Ring reprojection and mosaicing utilities.

This module provides the RingMosaic class for reprojecting planetary ring images onto radius/longitude grids and accumulating them into sparse mosaics.

Thread safety: RingMosaic.reproject() is not thread-safe because it may temporarily mutate obs.fov and oops global precision settings. Concurrent calls from separate threads will interfere.

Bases: object

Sparse ring mosaic accumulator.

Reprojects ring images onto a radius/longitude grid and accumulates them into a mosaic using true sparse longitude storage. Only longitude columns that actually contain reprojected data are stored; new columns are inserted in sorted order using batched np.insert calls.

The interpretation of radius_inner / radius_outer and longitudes depends on orbit_model:

  • orbit_model is None (default): longitudes are inertial J2000 ring longitudes; radius_inner and radius_outer are absolute ring radii in km.

  • orbit_model is not None: longitudes are co-rotating in the model’s frame; radius_inner and radius_outer are signed offsets in km from the orbital radius at each (longitude, time). For an eccentric orbit, that radial position varies between a (1 - e) and a (1 + e). The offset semantics make an eccentric ring appear as a straight line in the reprojection. A typical 2000 km wide window centred on the orbit uses radius_inner = -1000 and radius_outer = +1000.

Parameters:
  • body_name – The planet name (e.g. ‘SATURN’). Used to derive the oops ring body name and shadow body name for backplane calls.

  • radius_inner – Inner radius (km, absolute) when orbit_model is None; signed offset (km) from the orbital radius at each (longitude, time) otherwise.

  • radius_outer – Outer radius (km, absolute) when orbit_model is None; signed offset (km) from the orbital radius at each (longitude, time) otherwise. Must be greater than radius_inner.

  • longitude_resolution – Longitude bin width (rad/pixel).

  • radius_resolution – Radius bin height (km/pixel).

  • merge_strategy – How to resolve conflicts when the same longitude column appears in multiple reprojections.

  • orbit_model – Default RingOrbitModel for co-rotating frame reprojections; selects the offset-radius semantics described above. Can be overridden per-call in reproject(); the override must agree with this default.

  • image_dtype – NumPy dtype for the reprojected brightness img array. Defaults to np.float64.

  • metadata_dtype – NumPy dtype for geometry arrays (mean_radial_resolution, mean_angular_resolution, mean_phase, mean_emission). Defaults to np.float32.

  • photometric_model – Optional photometric correction applied to img in reproject() before accumulation. None means raw brightness.

Notes

reproject() is not thread-safe because it mutates obs.fov and oops global precision settings.

time is always stored as float64 regardless of metadata_dtype. image_number is always stored as uint16; _image_count is stored as the image_number before incrementing, so valid image_number values span 0..65535 (a total of 65,536 images). add() raises OverflowError after the 65,536th image is added.

Add a reprojected image to the mosaic.

New longitude columns are inserted into the sparse arrays using a single batched np.insert call. Existing columns are updated according to the merge strategy.

The reprojection’s orbit model and photometric model must match the mosaic’s. orbit_model must be the same instance (or both None); photometric_model_name must equal the mosaic’s photometric model name (or both None). Mixing different settings would silently corrupt the mosaic because radii and longitudes have different meanings under different orbit models.

Parameters:

repro – Sparse reprojection result from reproject().

Raises:
  • OverflowError – If the number of images added would exceed the uint16 maximum of 65 535.

  • ValueError – If the reprojection’s body name, grid resolution, radius bounds, dtypes, sparse shapes, longitude_antimask true count vs. sparse column count, orbit model, or photometric model does not match the mosaic’s.

The planet name supplied at construction.

Longitude extent of current mosaic data as (min, max) in radians.

Returns None if no data has been added yet.

Generate a longitude array aligned to grid boundaries.

Parameters:
  • longitude_start – Start of the range (rad). Defaults to 0.

  • longitude_end – End of the range (rad). Defaults to just under 2*pi.

  • longitude_resolution – Step size (rad/pixel).

Returns:

1-D array of longitudes (rad) on resolution boundaries, with no value less than longitude_start or greater than longitude_end.

Generate a radius array from inner to outer.

Parameters:
  • radius_inner – Inner radius (km).

  • radius_outer – Outer radius (km).

  • radius_resolution – Step size (km/pixel).

Returns:

1-D array of radii (km) starting at radius_inner with step radius_resolution, ending at or just before radius_outer.

Convert longitude/radius pairs to image pixel coordinates.

If orbit_model is given, the longitude values are treated as co-rotating and are converted to inertial before the coordinate lookup.

Parameters:
  • obs – The Observation whose FOV is used.

  • longitude – Longitude array (rad).

  • radius – Radius array (km).

  • orbit_model – RingOrbitModel for co-rotating frame conversion, or None for inertial longitude.

  • ring_body_name – oops ring body name for the surface lookup.

Returns:

Tuple of (u, v) floating-point pixel coordinate arrays.

Return (u, v) pixel pairs for an orbit model feature in an image.

Computes the full 0..2pi longitude range, converts each to image coordinates, and filters to those inside the FOV.

Parameters:
  • obs – The Observation (with its FOV already configured as needed).

  • orbit_model – The ring orbit model to trace.

  • ring_body_name – oops ring body name.

  • longitude_step – Longitude step for sampling (rad).

Returns:

Tuple of (u_pixels, v_pixels) integer pixel coordinate arrays.

Reproject the ring in an image to a sparse radius/longitude grid.

Always returns a sparse RingReprojResult: only longitude columns with valid data are stored in the result. The returned longitude_antimask indicates which of the n_full_lon bins are present.

Parameters:
  • obs – The Observation (with its FOV already configured as needed).

  • data – Image data to reproject. If None, uses obs.data.

  • longitude_range – (start, end) longitude limits (rad). Defaults to the full 0..2pi range.

  • radius_range – (inner, outer) radius limits (km). Defaults to the mosaic’s own radius_inner/outer.

  • margin – Number of edge pixels to exclude. Must be >= 1.

  • zoom_amt – Positive integer or (radial, longitude) tuple giving the zoom factor for sub-pixel interpolation. Negative values select spline interpolation order (not yet supported).

  • orbit_model – RingOrbitModel for co-rotating frame conversion. Overrides the default set at construction. None uses inertial longitude.

  • uv_range – (start_u, end_u, start_v, end_v) to restrict the image region reprojected.

  • omit_shadow – If True, mask pixels inside the planet’s shadow.

  • image_name – Optional label stored on the result (e.g. source image stem).

Returns:

RingReprojResult with sparse image and metadata arrays.

Raises:
  • NotImplementedError – If negative zoom_amt (spline order) is requested.

  • TypeError – If longitude_range or radius_range is not a tuple/list of numeric endpoints, or an endpoint has the wrong type.

  • ValueError – If longitude_range or radius_range has wrong length, non-finite values, longitudes outside [0, _MAX_LONGITUDE], start > end, radius_inner >= radius_outer, if zoom_amt is a sequence with length other than 2, if n_longitude_bins_zoom is not a multiple of l_zoom_amt, or for other argument errors.

  • TypeError – If zoom_amt is not an int (excluding bool) or a length-2 tuple/list of ints, or an element is not int-like.

ring’).

Type:

oops body name for the ring plane (e.g. ‘saturn

oops body name for the shadow-casting planet (e.g. ‘saturn’).

Return the mosaic restricted to the given longitude range.

The returned img has shape [n_radius, n_bins_in_range] where every bin from the start to end of the range is included. Bins without data are fully masked.

Parameters:

longitude_range – (start, end) in radians.

Returns:

RingMosaicData covering exactly the requested longitude range.

Raises:
  • TypeError – If longitude_range is not a tuple/list of two numbers, or an endpoint has the wrong type (same rules as reproject()).

  • ValueError – If endpoints are non-finite, outside [0, _MAX_LONGITUDE], or start > end (same rules as reproject()).

Return the mosaic as a dense full-circle array.

The returned img has shape [n_radius, n_full_lon]. Longitude columns with no data are fully masked.

Returns:

RingMosaicData with a full-circle dense array.

Return the mosaic in its native sparse representation.

The returned img has shape [n_radius, n_valid_longitudes] and the longitude_antimask has length n_full_lon with True at each stored column.

Returns:

RingMosaicData with the sparse internal arrays.

Bases: object

Mosaic data returned by RingMosaic retrieval methods.

The meaning of radius_inner / radius_outer and longitudes depends on whether orbit_model_name is None:

  • orbit_model_name is None: longitudes are inertial J2000 ring longitudes; radius_inner and radius_outer are absolute ring radii in km.

  • orbit_model_name is not None: longitudes are co-rotating in the named orbit model’s frame; radius_inner and radius_outer are signed offsets in km from the orbital radius at each (longitude, time) — i.e. from orbit_model.radius_at_longitude(inertial_lon, et).

This is a dataclasses.dataclass(); each field is documented on its own member entry below.

Load a RingMosaicData from a file.

Parameters:
  • path – Input path (str, pathlib.Path, or filecache.FCPath).

  • format – Explicit format ('npz' or 'fits'). If None, inferred from the file extension.

Returns:

A new RingMosaicData with the loaded data.

Raises:

ValueError – If the file’s kind does not match, or if any array dtype does not match the declared image_dtype / metadata_dtype, or if image_number is not uint16, or if time is not float64.

Example:

data = RingMosaicData.load('saturn_rings.npz')

Save this RingMosaicData to a file.

Parameters:
  • path – Output path (str, pathlib.Path, or filecache.FCPath). The format is inferred from the extension (.npz for NumPy archive, .fits/.fit for FITS) unless format_ is given.

  • format – Explicit format: 'npz' or 'fits'.

  • compress – If True (default), use compressed npz. Ignored for FITS.

Raises:

ValueError – If the format cannot be inferred or is not supported.

Example:

data = ring_mosaic.to_bounded(longitude_range=(0.0, math.pi))
data.save('saturn_rings.npz')
data.save('saturn_rings.fits', format_='fits')
reloaded = RingMosaicData.load('saturn_rings.npz')

Bases: Enum

Strategy for resolving per-longitude-column conflicts when adding data to a RingMosaic.

Members:
BEST_RESOLUTION: Replace an existing longitude column only when the new

data has strictly better mean radial resolution for that column.

MOST_COVERAGE_THEN_RESOLUTION: Fill empty (missing) longitude columns

first; for already-present columns, replace only when the new data has better mean radial resolution.

Bases: object

Data returned by RingMosaic.reproject().

The image and per-longitude metadata arrays are always sparse: only longitude columns with valid data are included. Use longitude_antimask to reconstruct the actual longitude values.

The interpretation of radius_inner / radius_outer and longitudes depends on whether orbit_model is None:

  • orbit_model is None: longitudes are inertial J2000 ring longitudes; radius_inner and radius_outer are absolute ring radii in km.

  • orbit_model is not None: longitudes are co-rotating; radius_inner and radius_outer are signed offsets in km from the orbit’s actual radial position at each (longitude, time). For an eccentric orbit, that radial position varies between a (1 - e) and a (1 + e); the offset semantics make an eccentric ring appear as a straight line in the reprojection.

This is a dataclasses.dataclass(); each field is documented on its own member entry below.

Load a RingReprojResult from a file.

Parameters:
  • path – Input path (str, pathlib.Path, or filecache.FCPath).

  • format – Explicit format ('npz' or 'fits'). If None, inferred from the file extension.

Returns:

A new RingReprojResult with the loaded data.

Raises:

ValueError – If the file’s kind does not match, or if any array dtype does not match the declared image_dtype / metadata_dtype.

Example:

result = RingReprojResult.load('ring_reproj.npz')

Save this RingReprojResult to a file.

Parameters:
  • path – Output path (str, pathlib.Path, or filecache.FCPath). The format is inferred from the extension (.npz for NumPy archive, .fits/.fit for FITS) unless format_ is given.

  • format – Explicit format: 'npz' or 'fits'.

  • compress – If True (default), use compressed npz. Ignored for FITS.

Raises:

ValueError – If the format cannot be inferred or is not supported.

Example:

result = ring_mosaic.reproject(obs)
result.save('ring_reproj.npz')
reloaded = RingReprojResult.load('ring_reproj.npz')

Cartographic model creation for planetary bodies.

Creates navigation model images by projecting a lat/lon body mosaic back onto the image coordinate system for use in navigation correlation.

Thread safety: create_cartographic_model() creates a Backplane from the provided observation and is not thread-safe. Do not call it from multiple threads with the same observation.

Bases: object

Result returned by create_cartographic_model().

This is a dataclasses.dataclass(); model_img is the model image in observation pixel coordinates [v, u] (0.0 outside mosaic coverage or where the body is not visible), and resolution_ratio is the ratio of the median mosaic effective resolution to the image-center resolution (both km/pixel; 1.0 means equal, greater than 1.0 means the mosaic is coarser).

Create a navigation model by projecting a body mosaic onto image coordinates.

For each pixel in the observation image, the corresponding latitude and longitude on the body surface is computed using the observation geometry. The mosaic is sampled at those coordinates via bilinear interpolation to produce a model image suitable for correlation with the actual image.

Thread safety: Not thread-safe. Creates a Backplane from obs, which involves shared state. Do not call from multiple threads with the same observation.

Parameters:
  • mosaic_data – Body mosaic in lat/lon coordinates, typically obtained from BodyMosaic.to_bounded() or BodyMosaic.to_full().

  • obs – The oops Observation for which the model is being created.

  • body_name – Name of the planetary body (e.g. ‘MIMAS’).

  • latlon_type – Coordinate system for latitude/longitude. One of ‘centric’, ‘graphic’, or ‘squashed’. Must match the type used to build the mosaic.

  • lon_direction – Longitude direction. One of ‘east’ or ‘west’. Must match the direction used to build the mosaic.

Returns:

CartographicModelResult with the model image and resolution ratio, or None if the mosaic contains no valid data.

Photometric correction models for body and ring reprojections.

All models implement the PhotometricModel protocol and apply a correction to raw pixel brightness based on the local illumination and viewing geometry. Default is no correction (pass photometric_model=None to BodyMosaic or RingMosaic).

All angles are in radians throughout.

Bases: object

Lambert (Lambertian) photometric correction.

Divides the data by cos(incidence) to normalize for the amount of sunlight falling on the surface element. The emission angle is not included because Lambert’s law only describes the illumination term; the viewing geometry is independent. Near-grazing incidence is clamped to avoid division by near-zero values.

min_cos_incidence (default 0.01, ~84°) clamps the Lambert denominator; see the member entry below.

Raises:
  • TypeError – If min_cos_incidence is not a real scalar (bool is rejected).

  • ValueError – If min_cos_incidence is not finite or is not in [1e-15, 1] (valid cosine clamp range).

Apply Lambert photometric correction.

Parameters:
  • data – Raw pixel brightness values.

  • incidence – Incidence angle at each pixel (rad).

  • emission – Emission angle at each pixel (rad). Not used.

  • phase – Phase angle at each pixel (rad). Not used.

Returns:

Data divided by max(cos(incidence), min_cos_incidence).

Undo correct() (multiply by clamped cos(incidence)).

Parameters:
  • data – Corrected radiance / reflectance (same shape as in correct()).

  • incidence – Incidence angle per pixel (rad); cos is clamped with self.min_cos_incidence like correct().

  • emission – Accepted for API symmetry with correct(); not used.

  • phase – Accepted for API symmetry; not used.

Returns:

Uncorrected values data * max(cos(incidence), min_cos_incidence), NDArrayFloatType, same shape as data (inverse of division in correct() using the same clamping).

Bases: object

Lommel-Seeliger photometric correction.

Models single-scattering on a surface with a bidirectional reflectance proportional to 1/(mu0 + mu), where mu0=cos(incidence) and mu=cos(emission). The correction factor applied to the data is (mu0 + mu) / (2 * mu0), which normalizes out this scattering model.

min_cos_incidence defaults to 0.01; see the member entry below.

Raises:
  • TypeError – If a numeric field is not a real scalar (bool is rejected).

  • ValueError – If a field is not finite or is outside its allowed range.

Apply Lommel-Seeliger photometric correction.

Parameters:
  • data – Raw pixel brightness values.

  • incidence – Incidence angle at each pixel (rad).

  • emission – Emission angle at each pixel (rad).

  • phase – Phase angle at each pixel (rad). Not used.

Returns:

Data multiplied by denom / (2 * cos_i), where cos_i is max(cos(incidence), min_cos_incidence), cos_e = cos(emission), and denom is cos_i + cos_e with magnitude floored to min_denom while preserving sign (same rule as uncorrect()).

Undo correct() using the same incidence clamping and signed denom floor.

Parameters:
  • data – Values after Lommel-Seeliger correct().

  • incidence – Incidence angles (rad); cosine clamped with min_cos_incidence.

  • emission – Emission angles (rad); cos(emission) contributes to the denominator.

  • phase – Accepted for API symmetry; not used.

Returns:

NDArrayFloatType of same shape as data, data * (2*cos_i) / denom where denom is cos_i + cos_e with the same signed floor as correct().

Bases: object

Minnaert photometric correction.

Generalizes the Lambert model with a limb-darkening exponent k. For k=1 this reduces to the Lambert correction (1/cos_i). For k=0.5 this provides a uniform disk appearance across many surfaces.

The correction divides data by cos(incidence)^k * cos(emission)^(k-1).

Defaults: k = 0.5, min_cos_incidence = min_cos_emission = 0.01; see member entries below.

Raises:
  • TypeError – If a numeric field is not a real scalar (bool is rejected).

  • ValueError – If a field is not finite or cosine clamps are outside (0, 1].

Apply Minnaert photometric correction.

Parameters:
  • data – Raw pixel brightness values.

  • incidence – Incidence angle at each pixel (rad).

  • emission – Emission angle at each pixel (rad).

  • phase – Phase angle at each pixel (rad). Not used.

Returns:

Data divided by cos(incidence)^k * cos(emission)^(k-1).

Undo correct() using the same min_cos_incidence / min_cos_emission clamps.

Parameters:
  • data – Corrected radiance / reflectance (same shape as for correct()).

  • incidence – Incidence angles (rad); cos clamped to min_cos_incidence.

  • emission – Emission angles (rad); cos clamped to min_cos_emission.

  • phase – Accepted for API symmetry; not used.

Returns:

NDArrayFloatType, same shape as data, multiplying by cos_i**k * cos_e**(k-1) with the same clamped cosines as correct().

Bases: Protocol

Protocol for photometric correction applied during reprojection.

Implementations must provide a string name and a correct() method. The correct() method receives all three angles as keyword-only NDArrayFloatType parameters (all in radians) and returns the corrected data array.

Apply photometric correction to data.

Parameters:
  • data – Raw pixel brightness values to correct.

  • incidence – Incidence angle at each pixel (rad).

  • emission – Emission angle at each pixel (rad).

  • phase – Phase angle at each pixel (rad).

Returns:

Corrected pixel brightness values, same shape as data.

Return a LambertModel, LommelSeeligerModel, or MinnaertModel.

Parameters:

name – Stored model label from a reprojection/mosaic file, or None.

Returns:

A fresh model instance, or None when name is None or normalizes to an empty string / none / null (explicit “no model”).

Raises:

ValueError – If name is non-empty after normalization but not one of the supported aliases (see Notes).

Notes

Accepted aliases (case-insensitive, spaces and hyphens map to underscores): lambert; lommel_seeliger / lommelseeliger; minnaert.

Ring orbit models for co-rotating frame transformations.

Provides the RingOrbitModel frozen dataclass representing a Keplerian ring orbit with precession, along with pre-defined instances for the F ring core and B ring outer edge.

All angular quantities are in radians and all time quantities are in seconds (ET/TDB) unless otherwise stated. Day-based rates are converted internally.

F ring core orbit model from Albers et al. 2012 Table 3 Fit #2.

epoch_utc='2007-01-01' anchors the co-rotating mean-motion frame; w0 is the longitude of pericenter at J2000 (not at epoch_utc). The 2007 in the name refers to the co-rotation epoch.

Bases: object

Keplerian orbit model for a ring feature with apsidal precession.

All angular parameters are in radians. Rate parameters (dw, mean_motion) are in radians per day; they are converted to per-second internally when needed.

a (km) is the semi-major axis (positive). e is eccentricity in [0, 1). w0 is the longitude of pericenter at J2000 (rad); at observation time et (TDB seconds) the pericenter direction is w0 + dw * et / 86400. dw is apsidal precession (rad/day) from J2000. mean_motion (rad/day) drives the co-rotating frame. epoch_utc is an ISO UTC string anchoring that frame, independent of the J2000 apsidal reference.

This is a dataclasses.dataclass(); fields are documented on each member below.

__post_init__() None[source]

Validate parameters and cache the epoch in ET.

Convert co-rotating longitude (rad) to inertial longitude (rad).

Parameters:
  • co_long – Co-rotating longitude array (rad).

  • et – Observation time as ephemeris time (TDB seconds).

Returns:

Inertial longitude array (rad), wrapped to [0, 2*pi).

Convert inertial longitude (rad) to co-rotating longitude (rad).

Parameters:
  • longitude – Inertial longitude array (rad).

  • et – Observation time as ephemeris time (TDB seconds).

Returns:

Co-rotating longitude array (rad), wrapped to [0, 2*pi).

Return arrays of (longitude, radius) covering the full 0..2pi range.

Parameters:
  • et – Observation time as ephemeris time (TDB seconds).

  • step – Longitude step size (rad). Defaults to 0.01 degrees.

Returns:

Tuple of (longitudes, radii) arrays, each of length int(2*pi / step).

Raises:

ValueError – If step is not a finite positive number.

Return the ring radius (km) at each inertial longitude and time.

Uses the standard Keplerian orbit equation with a precessing pericenter. The pericenter direction at time et is w0 + dw * et: w0 is the value of curly-pi at J2000 (the standard epoch), and dw is integrated from J2000. The independent epoch_utc field anchors only the co-rotating mean-motion frame (see _longitude_shift).

Parameters:
  • longitude – Inertial (true) longitude array (rad).

  • et – Observation time as ephemeris time (TDB seconds).

Returns:

Radius in km at each element of longitude.

Return a pre-defined RingOrbitModel by its name, or None.

Parameters:

name – Model name (e.g. 'F-RING-CORE-ALBERS-2007').

Returns:

The matching RingOrbitModel from _KNOWN_ORBIT_MODELS, or None if the name is not found.

Raises: