2.7.5.1. pycsamt.airborne.validation#
Shared parameter validation and normalization for pycsamt.airborne.
This module centralizes the boundary-validation logic that would otherwise
be reimplemented independently by pycsamt.airborne.base,
pycsamt.airborne.navigation, and each technology adapter
(pycsamt.airborne.mobilemt, pycsamt.airborne.ztem,
pycsamt.airborne.afmag). Every helper accepts an error_cls
keyword so a technology adapter can keep raising its own public exception
type (for example MobileMTValidationError) while sharing one
implementation, instead of every adapter re-declaring an equivalent
private helper under a different name.
Structural, type, and shape validation is the majority of this module.
Scientific invariants that are specific to one technology (for example
the MobileMT 3x2 admittance matrix shape) remain the responsibility of
the owning adapter module, consistent with the pyCSAMT convention that
public methods validate near the API boundary while private helpers
may assume already-validated internal state. A small number of helpers
(reference_station_mapping(), merge_remote_reference_processing())
go slightly beyond pure validation into shared EMTF-metadata assembly,
because that assembly logic was independently duplicated across
technology adapters just as much as the shape checks were – keeping
it out of this module would not have made the package simpler, only
moved the duplication somewhere less discoverable.
Functions
|
Return a stripped, non-empty string identifier. |
|
Return |
|
Merge a duck-typed reference station into remote-reference metadata. |
|
Return a validated |
|
Return a validated |
|
Return value as a stripped tuple, requiring it to equal expected. |
|
Return a validated 1-D, finite, strictly positive vector. |
|
Return a validated |
|
Return a validated 1-D float vector aligned to size, or |
|
Return a validated length-size tuple of opaque values, or |
|
Return a stripped identifier, or |
|
Return value as a finite, strictly positive |
|
Return a boolean record-coverage mask of length n_samples. |
|
Return a validated array with a leading sample axis of n_samples. |
|
Return a duck-typed reference station as a plain |
|
Return validated |
|
Return |
- pycsamt.airborne.validation.emtf_class()[source]
Return
pycsamt.emtf.EMTF, imported lazily.Both
pycsamt.airborne.baseandpycsamt.airborne.qcneedEMTFonly forisinstancechecks. Importing it lazily here, once, avoids a hard import-time dependency onpycsamt.emtffrom either module while keeping the check itself in one place instead of duplicated per module.
- pycsamt.airborne.validation.clean_identifier(value, *, name, error_cls=<class 'ValueError'>)[source]
Return a stripped, non-empty string identifier.
- Parameters:
- Returns:
The stripped identifier.
- Return type:
- Raises:
error_cls – If value is empty after stripping.
- pycsamt.airborne.validation.normalize_optional_identifier(value)[source]
Return a stripped identifier, or
Noneif absent/blank.Unlike
clean_identifier(), an empty result is not an error: this is for genuinely optional identifiers (for example a reference station’sstation_idbefore it falls back to aSiteMetaname), where “not supplied” and “supplied but blank” should collapse to the sameNonerather than one being valid and the other raising.
- pycsamt.airborne.validation.normalize_positive_float(value, *, name, error_cls=<class 'ValueError'>)[source]
Return value as a finite, strictly positive
float.Shared by every technology
SystemSpecpublishing a single positive descriptive rate/measurement (a sampling rate, an output rate, a coil angle, …) as opposed to a range; seenormalize_frequency_range()for the two-value case.
- pycsamt.airborne.validation.normalize_count_range(value, *, name, error_cls=<class 'ValueError'>)[source]
Return a validated
(low, high)count with0 < low <= high.Shared by every technology
SystemSpecpublishing a typical minimum/maximum item count (for example a typical processed frequency-window count). Unlikenormalize_frequency_range(), equality (low == high) is valid here: a system with a fixed count still has “typical min == typical max”.
- pycsamt.airborne.validation.normalize_numeric_vector(value, *, name, size, error_cls=<class 'ValueError'>)[source]
Return a validated 1-D float vector aligned to size, or
None.- Parameters:
value (array-like or None) – Candidate numeric vector.
Nonepasses through unchanged rather than being treated as a physical zero.name (str) – Parameter name used in error messages.
size (int) – Required vector length.
error_cls (type, default ValueError) – Exception type raised on shape/finiteness violations.
- Returns:
NaNvalues are permitted: an individual missing sample is represented bynan, never by a fabricated zero.- Return type:
- Raises:
error_cls – If value is not 1-D, its length does not match size, or it contains an infinite value.
- pycsamt.airborne.validation.normalize_object_vector(value, *, name, size, error_cls=<class 'ValueError'>)[source]
Return a validated length-size tuple of opaque values, or
None.Used for sample-aligned fields, such as timestamps, whose element type is not itself numeric or geophysical.
- pycsamt.airborne.validation.normalize_frequency(value, *, name='frequency', error_cls=<class 'ValueError'>)[source]
Return a validated 1-D, finite, strictly positive vector.
- Parameters:
value (array-like) – Candidate frequency (Hz) or period (s) values. A scalar is promoted to a length-1 array.
name (str, default "frequency") – Parameter name used in error messages; pass
"periods"when validating a period axis instead of a frequency axis.error_cls (type, default ValueError) – Exception type raised on shape/positivity violations.
- Returns:
Finite, strictly positive values.
- Return type:
- Raises:
error_cls – If value is not 1-D, is empty, or contains a non-finite or non-positive value.
- pycsamt.airborne.validation.resolve_frequency_or_periods(*, frequency, periods, error_cls=<class 'ValueError'>)[source]
Return validated
(frequency, periods)from exactly one input.Exactly one of frequency or periods must be supplied; the other axis is derived as its reciprocal. This is the shared contract used by every airborne technology adapter that accepts either axis.
- pycsamt.airborne.validation.resolve_line_frequency_grid(frequency, *, n_samples, n_frequency, error_cls=<class 'ValueError'>)[source]
Return
(common_frequency, frequency_rows)for one flight line.- Parameters:
frequency (array-like) – Either one shared frequency vector of shape
(n_frequency,)or a per-sample grid of shape(n_samples, n_frequency).n_samples (int) – Number of navigation samples on the line.
n_frequency (int) – Number of frequency samples expected from the response data.
error_cls (type, default ValueError) – Exception type raised on shape violations.
- Returns:
Exactly one of
(common_frequency, None)or(None, frequency_rows).- Return type:
(ndarray or None, ndarray or None)
- Raises:
error_cls – If frequency is 1-D but its length does not match n_frequency, or if it is neither a valid
(n_frequency,)vector nor a(n_samples, n_frequency)matrix.
Notes
The shared 1-D case is fully validated here via
normalize_frequency(). The per-sample 2-D case is only shape-checked: each row’s own finiteness/positivity is validated lazily, once per attached sample, by the caller (typically via anothernormalize_frequency()call inside its per-sample loop). This means a row for a sample excluded by a line’srecord_maskis never required to be valid – consistent with the rest of this module’s missing-is-not-invalid stance, since a masked-out sample contributes no record for that row to belong to.
- pycsamt.airborne.validation.normalize_frequency_range(value, *, name, error_cls=<class 'ValueError'>)[source]
Return a validated
(low, high)band with0 < low < high.Shared by every technology
SystemSpecthat publishes a nominal or practical frequency band as descriptive metadata.
- pycsamt.airborne.validation.normalize_fixed_channels(value, *, expected, name, error_cls=<class 'ValueError'>)[source]
Return value as a stripped tuple, requiring it to equal expected.
Several technology contracts (for example MobileMT’s
Ex/Eyadmittance inputs) fix the channel layout by scientific definition rather than by user choice. Centralizing this “must equal” check keeps the behavior and message consistent across adapters.
- pycsamt.airborne.validation.normalize_estimate_array(value, *, n_frequency, tail, name, error_cls=<class 'ValueError'>)[source]
Return a validated
(n_frequency, *tail)estimate array.A single
tail-shaped matrix is promoted to one frequency. This is the shared contract forVAR/INVSIGCOV/RESIDCOVpayloads across technology adapters.
- pycsamt.airborne.validation.normalize_sample_axis_array(value, *, name, n_samples, expected, error_cls=<class 'ValueError'>)[source]
Return a validated array with a leading sample axis of n_samples.
When
n_samples == 1a caller may omit the leading axis; it is promoted automatically. This is the shared contract used to attach per-sample transfer-function arrays (admittance, tipper, tensor, …) and per-sample statistical estimates to a flight line.
- pycsamt.airborne.validation.normalize_record_mask(value, *, n_samples, error_cls=<class 'ValueError'>)[source]
Return a boolean record-coverage mask of length n_samples.
Nonemeans every navigation sample has an attached EM record.
- pycsamt.airborne.validation.reference_station_mapping(reference_station, *, channel_fields)[source]
Return a duck-typed reference station as a plain
EMTF.attrsmap.Every technology’s
*ReferenceStationmetadata class (MobileMT’s, ZTEM’s, AFMAG’s) exposespreferred_id, one or more channel-name tuples, an optionalsite, and an optionalattrsdict; this is the shared shape those adapters build intoEMTF.attrs["<technology>"]["reference_station"].- Parameters:
reference_station (Any or None) – Duck-typed reference-station object exposing
preferred_id,site,attrs, and one attribute per name in channel_fields.NonereturnsNone.channel_fields (tuple of str) – Attribute names to read off reference_station and include verbatim under the same key, for example
("electric_channels",)for MobileMT or("measured_channels", "transfer_input_channels")for AirMt.
- Returns:
Nonewhen reference_station isNone; otherwise a mapping with"station_id", one entry per channel_fields name, and"site"/"attrs"when those are non-empty.- Return type:
dict or None
- pycsamt.airborne.validation.merge_remote_reference_processing(reference_station, processing, *, reference_type, technology, extra=mappingproxy({}), error_cls=<class 'ValueError'>)[source]
Merge a duck-typed reference station into remote-reference metadata.
reference_stationis each technology’s scientifically typed way to supply its fixed ground reference; a caller-suppliedprocessingis the generalProcessingMetaway. When both are given, they must describe the same reference site – this raises rather than silently letting one win. When only reference_station is given, aProcessingMetais synthesized around it soprocessingis always the one place downstream code (for exampleassess_airborne_qc()) looks for reference metadata, regardless of which technology built the EMTF.- Parameters:
reference_station (Any or None) – Duck-typed reference-station object exposing
preferred_id.Nonereturns processing unchanged.processing (ProcessingMeta or None) – Caller-supplied processing metadata to merge into.
reference_type (str) –
RemoteReferenceMeta.reference_typeto record, for example"fixed_ground_magnetic".technology (str) – Recorded as
extra["technology"]on the synthesizedRemoteReferenceMeta.extra (Mapping, optional) – Additional technology-specific
RemoteReferenceMeta.extraentries (for example measured/transfer channel names).error_cls (type, default ValueError) – Exception type raised on a genuine site conflict. The type check on processing itself always raises
TypeError, regardless of error_cls, since that failure is never a reference-station/processing conflict.
- Returns:
processing, either unchanged, merged with the synthesized remote reference, or newly created around it.
- Return type:
ProcessingMeta or None
- Raises:
TypeError – If processing is supplied and is not a
ProcessingMeta.error_cls – If processing already has a remote reference whose
siteconflicts with reference_station’s.