adam_core.photometry.bandpasses package

Bandpass response curves and asteroid spectral templates.

This subpackage vendors (as package data) a curated set of: - instrument filter response curves (throughput vs wavelength), normalized and stored in Parquet - asteroid reflectance templates (C, S, and mixes like NEO/MBA), also stored in Parquet - precomputed template×filter integrals used to derive color terms efficiently

The initial implementation is data-only: it is designed so magnitude.py can later resolve (observatory_code, reported_band) -> canonical filter_id and use precomputed integrals for higher-fidelity conversions, without changing behavior yet.

class adam_core.photometry.bandpasses.BandpassCurves(table: Table, **kwargs: int | float | str)[source]

Bases: Table

Canonical bandpass response curves.

Each row represents a single filter response curve: wavelength (nm) and a normalized dimensionless throughput (0..1).

band

A column for storing large strings (over 231 bytes long). Large string data is stored in variable-length chunks.

filter_id

A column for storing large strings (over 231 bytes long). Large string data is stored in variable-length chunks.

instrument

A column for storing large strings (over 231 bytes long). Large string data is stored in variable-length chunks.

schema: ClassVar[pa.Schema] = filter_id: large_string not null instrument: large_string not null band: large_string not null wavelength_nm: large_list<item: double> not null   child 0, item: double throughput: large_list<item: double> not null   child 0, item: double source: large_string not null
source

A column for storing large strings (over 231 bytes long). Large string data is stored in variable-length chunks.

throughput

A column for storing large lists of values (over 231 objects).

Unless you need to represent data with more than 2**31 elements, prefer ListColumn.

The values in the list can be of any type.

Note that all quivr Tables are storing lists of values, so this column type is only useful for storing lists of lists.

Parameters:
  • value_type – The type of the values in the list.

  • nullable – Whether the list can contain null values.

  • metadata – A dictionary of metadata to attach to the column.

  • validator – A validator to run against the column’s values.

wavelength_nm

A column for storing large lists of values (over 231 objects).

Unless you need to represent data with more than 2**31 elements, prefer ListColumn.

The values in the list can be of any type.

Note that all quivr Tables are storing lists of values, so this column type is only useful for storing lists of lists.

Parameters:
  • value_type – The type of the values in the list.

  • nullable – Whether the list can contain null values.

  • metadata – A dictionary of metadata to attach to the column.

  • validator – A validator to run against the column’s values.

class adam_core.photometry.bandpasses.ObservatoryBandMap(table: Table, **kwargs: int | float | str)[source]

Bases: Table

Map (MPC observatory_code, reported band) -> canonical filter_id.

key is a convenience column: f”{observatory_code}|{reported_band}”.

filter_id

A column for storing large strings (over 231 bytes long). Large string data is stored in variable-length chunks.

key

A column for storing large strings (over 231 bytes long). Large string data is stored in variable-length chunks.

observatory_code

A column for storing large strings (over 231 bytes long). Large string data is stored in variable-length chunks.

reported_band

A column for storing large strings (over 231 bytes long). Large string data is stored in variable-length chunks.

schema: ClassVar[pa.Schema] = observatory_code: large_string not null reported_band: large_string not null filter_id: large_string not null key: large_string not null
class adam_core.photometry.bandpasses.AsteroidTemplates(table: Table, **kwargs: int | float | str)[source]

Bases: Table

Asteroid reflectance templates, including fixed population mixes.

reflectance is dimensionless and should be normalized at 550 nm.

citation

A column for storing large strings (over 231 bytes long). Large string data is stored in variable-length chunks.

reflectance

A column for storing large lists of values (over 231 objects).

Unless you need to represent data with more than 2**31 elements, prefer ListColumn.

The values in the list can be of any type.

Note that all quivr Tables are storing lists of values, so this column type is only useful for storing lists of lists.

Parameters:
  • value_type – The type of the values in the list.

  • nullable – Whether the list can contain null values.

  • metadata – A dictionary of metadata to attach to the column.

  • validator – A validator to run against the column’s values.

schema: ClassVar[pa.Schema] = template_id: large_string not null wavelength_nm: large_list<item: double> not null   child 0, item: double reflectance: large_list<item: double> not null   child 0, item: double weight_C: double not null weight_S: double not null citation: large_string not null
template_id

A column for storing large strings (over 231 bytes long). Large string data is stored in variable-length chunks.

wavelength_nm

A column for storing large lists of values (over 231 objects).

Unless you need to represent data with more than 2**31 elements, prefer ListColumn.

The values in the list can be of any type.

Note that all quivr Tables are storing lists of values, so this column type is only useful for storing lists of lists.

Parameters:
  • value_type – The type of the values in the list.

  • nullable – Whether the list can contain null values.

  • metadata – A dictionary of metadata to attach to the column.

  • validator – A validator to run against the column’s values.

weight_C

A column for storing 64-bit floating point numbers.

weight_S

A column for storing 64-bit floating point numbers.

class adam_core.photometry.bandpasses.TemplateBandpassIntegrals(table: Table, **kwargs: int | float | str)[source]

Bases: Table

Precomputed template×filter integrals.

The stored scalar is intended for photon-counting synthetic photometry:

I = ∫ F_sun(λ) * R_ast(λ) * T(λ) * λ dλ

where F_sun is the adopted solar spectrum, R_ast is reflectance, and T is throughput.

filter_id

A column for storing large strings (over 231 bytes long). Large string data is stored in variable-length chunks.

integral_photon

A column for storing 64-bit floating point numbers.

schema: ClassVar[pa.Schema] = template_id: large_string not null filter_id: large_string not null integral_photon: double not null
template_id

A column for storing large strings (over 231 bytes long). Large string data is stored in variable-length chunks.

adam_core.photometry.bandpasses.load_bandpass_curves() BandpassCurves[source]
adam_core.photometry.bandpasses.load_observatory_band_map() ObservatoryBandMap[source]
adam_core.photometry.bandpasses.load_asteroid_templates() AsteroidTemplates[source]
adam_core.photometry.bandpasses.load_template_integrals() TemplateBandpassIntegrals[source]
adam_core.photometry.bandpasses.map_to_canonical_filter_bands(observatory_codes: Array | ChunkedArray | ndarray[tuple[Any, ...], dtype[object_]] | Iterable[str], bands: Array | ChunkedArray | ndarray[tuple[Any, ...], dtype[object_]] | Iterable[str], *, allow_fallback_filters: bool = True, on_unknown: Literal['raise', 'skip'] = 'raise') ndarray[tuple[Any, ...], dtype[object_]][source]

Suggest canonical (vendored) bandpass filter IDs for a set of observations.

This function is intended to be called by users before passing filters into bandpass-driven magnitude APIs. It applies the following resolution strategy:

  • If the provided band is already a canonical vendored filter_id (i.e., we have a curve for it), it is passed through unchanged.

  • Else, if (observatory_code, band) is present in ObservatoryBandMap, that mapping is used.

  • Else, apply a conservative fallback for generic bands:

    u/g/r/i/z -> SDSS_u/g/r/i/z y -> PS1_y

Parameters:
  • observatory_codes (array-like) – MPC observatory codes.

  • bands (array-like) – Reported band labels OR canonical vendored filter IDs.

  • allow_fallback_filters (bool, optional) –

    If True, allow generic-band fallbacks when no (observatory_code, band) mapping is available:

    u/g/r/i/z -> SDSS_u/g/r/i/z y -> PS1_y

    If False, raise if any row would require those fallbacks. Canonical filter_id inputs are always passed through. Defaults to True.

  • on_unknown (Literal["raise", "skip"], optional) –

    Behavior when a row cannot be resolved to a vendored canonical filter_id through pass-through, the observatory-band mapping table, or the generic u/g/r/i/z/y fallback set (if enabled).

    ”raise” (default): raise ValueError listing the unresolvable

    observatory_code|band pairs. Backward-compatible with prior behavior; the returned ndarray is dense with no None entries.

    ”skip”: leave unresolvable rows as None in the returned ndarray

    and do not raise. Callers must tolerate None entries (typically by skipping bandpass-dependent computation for those rows). Useful for ingest pipelines (e.g. precovery against MPC astrometry) where some fraction of rows genuinely have no canonical bandpass — amateur “clear” / unfiltered reports, observatory codes whose reported band is not in the vendored mapping table, etc. — and the right behavior is to keep those rows in the dataset while marking them as not photometrically gated.

Returns:

Canonical vendored filter_id strings. When on_unknown="skip" the ndarray dtype remains object and may contain None entries for rows that could not be resolved; otherwise every entry is a non-empty string.

Return type:

ndarray

adam_core.photometry.bandpasses.assert_filter_ids_have_curves(filter_ids: Array | ChunkedArray | ndarray[tuple[Any, ...], dtype[object_]] | Iterable[str]) None[source]

Raise if any filter_id is not present in vendored BandpassCurves.

adam_core.photometry.bandpasses.get_integrals(template_id: str, filter_ids: ndarray[tuple[Any, ...], dtype[object_]]) ndarray[tuple[Any, ...], dtype[float64]][source]

Return solar-weighted mean reflectance values for template_id across filter_ids.

Supports both vendored templates (precomputed) and custom templates registered at runtime via register_custom_template.

adam_core.photometry.bandpasses.compute_mix_integrals(weight_C: float, weight_S: float, filter_ids: ndarray[tuple[Any, ...], dtype[object_]]) ndarray[tuple[Any, ...], dtype[float64]][source]

Compute integrals for a C/S linear mix using precomputed base integrals.

This avoids recomputing any convolution and supports arbitrary weights.

adam_core.photometry.bandpasses.bandpass_delta_mag(composition: str | tuple[float, float], source_filter_id: str, target_filter_id: str) float[source]

Compute a constant magnitude offset between two canonical filters for a composition.

The delta is defined as:

Δm = m_target - m_source = -2.5 log10(<R>_target / <R>_source)

where <R> is the solar-weighted band-averaged reflectance for the composition (see get_integrals).

adam_core.photometry.bandpasses.bandpass_color_terms(composition: str | tuple[float, float], *, source_filter_id: str = 'V', target_filter_ids: Iterable[str] | None = None) dict[str, float][source]

Return delta magnitudes relative to source_filter_id for a set of canonical filters.

Returns:

Mapping: target_filter_id -> Δm where Δm = m_target - m_source.

Return type:

dict

adam_core.photometry.bandpasses.register_custom_template(template_id: str, wavelength_nm: ndarray[tuple[Any, ...], dtype[float64]], reflectance: ndarray[tuple[Any, ...], dtype[float64]]) None[source]

Register a custom reflectance template in-process and compute missing integrals lazily.

Notes

  • This does not modify vendored Parquet data.

  • This is intended for NumPy paths. JAX-compiled tables in magnitude.py cannot be extended at runtime without recompilation.

Submodules