pycsamt.zonge.components#

pycsamt.zonge.components#

Top-level module that aggregates all Zonge data components into a single namespace for convenient importing.

This module re-exports all primary component classes for handling various aspects of Zonge AVG data, including measurements, survey geometry, core scientific values (resistivity, phase, impedance), and quality-control metrics.

class pycsamt.zonge.components.Frequency(data=None, meta=None, *, name=None)#

Bases: AVGComponentBase

Frequency axis manager (Hz) for AVG tables.

Goals#

  • Read from legacy and modern frames (column aliases handled)

  • Enforce positivity (> 0 Hz) while tolerating missing markers

  • Offer stable unique grids across stations/components

  • Provide a compact to_xarray() for downstream use

Notes

  • Legacy decimals like ‘.5’ are parsed correctly.

  • Missing values (‘*’, ‘’, None) become NaN and are ignored in summaries. Non-positive numeric entries raise FrequencyError.

required: set[str] = {}#
provides: set[str] = {'freq'}#
read(source, meta=None, **kws)#

Load frequency values from a tidy frame or a flat vector.

If source is a DataFrame, we try to keep station / comp when present. Otherwise we inject conservative defaults: station=NaN, comp=’ExHy’.

Parameters:
Return type:

None

write()#

Emit a compact CSV block with the contextual columns that we manage (station, freq, comp), suitable for round-tripping.

Return type:

list[str]

unique(*, sort=True, dropna=True, rtol=1e-06, atol=1e-12)#

Unique global frequency grid with tolerance deduplication.

Parameters:
Return type:

ndarray

by_station(*, rtol=1e-06, atol=1e-12)#

Per-station unique frequency grids (sorted).

Parameters:
Return type:

dict[float, ndarray]

property n_unique: int#

Number of unique frequencies in the table.

static logspace(decade_start, decade_stop, n_points)#

Canonical log-spaced grid (10**start → 10**stop), inclusive.

Parameters:
  • decade_start (int)

  • decade_stop (int)

  • n_points (int)

Return type:

ndarray

to_xarray(*, coords=('station', 'freq', 'comp'), attrs=None)#

Convert to an xarray.Dataset. We include freq as a data variable as well, which is helpful in some consumers; the coordinate is still the same freq axis created by coords.

Parameters:
Parameters:
class pycsamt.zonge.components.Amps(data=None, meta=None, *, name=None)#

Bases: AVGComponentBase

Transmitter current amplitude container (unit: A).

The class normalises the amps column to numeric, tracks a few useful stats, and can (optionally) export itself as a small CSV block. Context columns are preserved.

Examples

>>> amps = Amps.from_avg((df, meta))
>>> amps.stats.mean
12.7
>>> ds = amps.to_xarray()   # optional grid for convenience
Parameters:
required: set[str] = {}#
provides: set[str] = {'amps'}#
read(source, meta=None)#

Parse source and populate the amps column as float.

Non-numeric entries (‘*’, blanks) become NaN. Context columns (station/freq/comp) are kept when present.

Parameters:
Return type:

None

property stats: _AmpStats#

Return min/max/mean/median/count snapshot.

as_series()#

Return the amps column as a Series (copy).

Return type:

Series

to_frame()#

Return a small table with context + amps only.

Return type:

DataFrame

to_xarray(*, coords=('station', 'freq', 'comp'), attrs=None)#

Optional convenience: grid the column into an xarray dataset (dims: station × freq × comp) with a single data-variable called amps.

Parameters:
write()#

Serialise as a compact CSV fragment. We keep context columns if present so the block remains useful alone.

Return type:

Sequence[str]

class pycsamt.zonge.components.CompMeas(data=None, meta=None, *, name=None, verbose=0)#

Bases: AVGComponentBase

Enumeration/validator for classical CSAMT component labels.

The class guarantees a canonical comp column with allowed values (case-sensitive): {'ExHy','ExHx','EyHy','EyHx'}. A few common case variants are accepted and normalized.

Typical usage#

>>> cm = CompMeas.from_avg((df, meta))
>>> cm.unique
['ExHy']  # for a scalar survey with one component
required: set[str] = {}#
provides: set[str] = {'comp'}#
read(source, meta=None)#

Ensure a normalised comp column exists.

  • If missing, default to ‘ExHy’ (legacy kind-1 style).

  • If present, normalise values and validate membership.

Parameters:
Return type:

None

write()#

Serialise the component block as a compact CSV fragment.

Only the context columns and comp are emitted to keep files readable. Disk I/O is the caller’s responsibility.

Return type:

Sequence[str]

property unique: list[str]#

Sorted unique component labels.

Parameters:
class pycsamt.zonge.components.Station(unit='m', normalize=False, allow_ragged=True, values=<factory>, names=<factory>, index_by_value=<factory>, index_by_name=<factory>)#

Bases: AVGComponentBase

One-dimensional survey-line geometry container.

This component reads the station coordinate from a tidy AVG frame (usually column 'station'), validates and stores unique positions, and (optionally) normalizes the origin to zero. It also derives a stable set of header keys ($Stn.*) for round-tripping modern headers.

Key features#

  • Accepts either a DataFrame (from AVG parsers) or raw arrays.

  • Handles ragged frequency coverage (no equal-count requirement).

  • Tracks units; internal helpers can work in metres when desired.

  • Derives $Stn.Beg / $Stn.Inc / $Stn.Left / $Stn.Right if grid-like.

  • Exposes dictionary mappings useful for downstream selection.

Notes

We do not modify the caller’s AVG frame; we keep our own view in self._frame that at minimum contains a numeric 'station' column and (if relevant) a 'station_m' column when the input length unit is feet (‘ft’) and conversion to metres is helpful.

unit: str#
normalize: bool#
allow_ragged: bool#
values: ndarray#
names: list[str]#
index_by_value: dict[float, ndarray]#
index_by_name: dict[str, ndarray]#
read(source, meta=None, *, unit=None, names=None, normalize=None, allow_ragged=None)#

Populate the component from source.

Parameters:
  • source (DataFrame | Sequence[float] | ndarray) – DataFrame with a 'station' column or a 1-D array of station values (possibly repeated across frequencies).

  • meta (Mapping[str, Any] | None) – Optional file metadata. If provided and unit is None, we try meta['Unit.Length'] for (‘m’|’ft’).

  • unit (str | None) – Length unit of source values. Defaults to ‘m’ or to meta['Unit.Length'] when available.

  • names (Sequence[str] | None) – Optional labels for unique station positions. If omitted, we auto-generate: ‘S00’, ‘S01’, …

  • normalize (bool | None) – When True, shift the origin so the first station is 0.0.

  • allow_ragged (bool | None) – When False, all stations must have identical row counts (one per frequency). When True (default), ragged coverage is allowed.

Return type:

None

write()#

Emit a small, human-friendly header preamble plus a CSV of the station coordinate. This is mainly useful for diagnostics and tests; full file writing should be orchestrated at a higher level.

Return type:

Sequence[str]

property n_unique: int#

Number of unique station positions.

property span: tuple[float, float] | None#

(min, max) of the station coordinate; None if empty.

property increment: float | None#

Grid increment if evenly spaced, else None.

label_map()#

Map station numeric value → generated label (e.g., ‘S03’).

Return type:

dict[float, str]

to_keywords()#

Derive a stable set of $Stn.* keys from current geometry:

  • Stn.Beg : first station

  • Stn.Inc : increment (when grid-like)

  • Stn.Left : left edge (min)

  • Stn.Right : right edge (max)

For convenience, we also mirror GDP-station versions when increment is grid-like: Stn.GdpBeg / Stn.GdpInc.

Return type:

dict[str, Any]

Parameters:
class pycsamt.zonge.components.Resistivity(data=None, meta=None, *, name=None, verbose=False)#

Bases: TensorBase

Apparent resistivity (\(\rho_a\)) per component.

This is a scalar variable (one number per row), but the class inherits the tensor-alignment logic so values land in the appropriate \(2\times 2\) slot given by comp.

Recognized source columns (legacy + modern)#

  • ARes.mag (modern)

  • Resistivity (legacy tables)

  • rho / Rho / ares.mag (variants)

Canonical internal column: 'rho'.

ivar VAR_NAME:

Canonical column in :pyattr:`frame` ("rho").

vartype VAR_NAME:

str

ivar ALIASES:

Ordered alias list used during read().

vartype ALIASES:

tuple[str, …]

ivar UNIT_ATTR:

Dataset attribute used for units ("Unit.Rho").

vartype UNIT_ATTR:

str

VAR_NAME: str = 'rho'#
UNIT_ATTR: str = 'Unit.Rho'#
read(source, meta=None, **kws)#

Parse source and produce a compact frame with station, freq, comp, rho. Coordinates are injected conservatively when absent (station=NaN, comp='ExHy').

Parameters:
Return type:

None

write(*, float_fmt='%.6g', na_rep='')#

Serialise to a compact CSV block with a small meta preamble (units + timestamp).

Parameters:
  • float_fmt (str)

  • na_rep (str)

Return type:

Sequence[str]

to_xarray(*, coords=('station', 'freq', 'comp'), attrs=None)#

Convert to an xarray.Dataset with one data variable (rho). Attributes include a stable unit hint under Unit.Rho.

Parameters:
Parameters:
class pycsamt.zonge.components.Phase(data=None, meta=None, *, name=None, verbose=False)#

Bases: TensorBase

Impedance phase (\(\varphi\)) per component.

This class manages the impedance phase data, inheriting from TensorBase to allow its scalar values to be aligned into a \(2 \times 2\) tensor-like grid based on the component label.

Notes

Values are typically reported in milliradians in modern CSAVGW tables (Unit.Phase='mrad'). Use the convert_unit() method to switch to degrees when desired.

The internal canonical column name for phase data is phase.

Recognized source columns:

  • Z.phz (modern)

  • Phase (legacy)

  • phase, ZPHZ (common variants)

Variables:
  • VAR_NAME (str) – The canonical column name used in the internal frame ("phase").

  • UNIT_ATTR (str) – The dataset attribute key used for storing units ("Unit.Phase").

Parameters:

Examples

>>> from pycsamt.zonge import Phase
>>> import pandas as pd
>>> data = {"freq": [1024], "phase": [1000]}
>>> p = Phase()
>>> p.read(pd.DataFrame(data))
>>> p.frame['phase'].iloc[0]
1000.0
>>> p.convert_unit("deg")
>>> p.frame['phase'].iloc[0]
57.2957...

See also

Resistivity

Manages apparent resistivity data.

TensorBase

The base class providing

VAR_NAME: str = 'phase'#
UNIT_ATTR: str = 'Unit.Phase'#
read(source, meta=None, **kws)#

Parse source and produce a compact frame with station, freq, comp, phase. Coordinates are injected conservatively when absent (station=NaN, comp='ExHy'). Unit.Phase defaults to 'mrad'.

Parameters:
Return type:

None

write(*, float_fmt='%.6g', na_rep='')#

Serialise to a compact CSV block with a meta preamble carrying Unit.Phase and a UTC timestamp.

Parameters:
  • float_fmt (str)

  • na_rep (str)

Return type:

Sequence[str]

to_xarray(*, coords=('station', 'freq', 'comp'), attrs=None)#

Convert to an xarray.Dataset with one data variable (phase). Attributes include a stable unit hint under Unit.Phase.

Parameters:
convert_unit(target='mrad')#

Convert the phase values in place between \(\mathrm{mrad}\) and \(\mathrm{deg}\) and update Unit.Phase in :pyattr:`meta`.

\[1~\mathrm{mrad} = \frac{180}{\pi \cdot 1000}~\mathrm{deg}\]
Parameters:

target (str)

Return type:

None

class pycsamt.zonge.components.Z(data=None, meta=None, *, name=None, verbose=0)#

Bases: TensorBase

Complex impedance tensor (Z) component.

This class reads a tidy AVG table and computes the complex impedance Z from apparent resistivity (\(\rho_a\)) and impedance phase (\(\phi\)). It provides properties to access the complex tensor, its real and imaginary parts, and the propagated error.

The impedance is calculated using the standard formula [1]:

\[Z = \sqrt{\rho_a \cdot \omega \cdot \mu_0} \cdot e^{i \cdot \phi}\]

where \(\omega = 2\pi f\).

Variables:
  • z (pd.Series) – The complex impedance \(Z\) in Ohms [Ω].

  • z_imag (z_real,) – The real and imaginary parts of the impedance tensor.

  • z_err (pd.Series) – The propagated error in the magnitude of \(Z\), \(|dZ|\), in Ohms [Ω].

  • z_yy (z_xx, z_xy, z_yx,) – Convenience properties to access the individual components of the complex impedance tensor.

Parameters:

Examples

>>> from pycsamt.zonge import Z
>>> from pycsamt.zonge.avg import AVG
>>> avg = AVG.from_file('data/avg/K2.avg')
>>> z_component = avg.z
>>> # Get the complex impedance for all measurements
>>> complex_z_values = z_component.z
>>> # Get only the Z_xy component
>>> z_xy = z_component.z_xy

References

See also

TensorBase

The parent class providing tensor-shaping logic.

read(source, meta=None, **kws)#

Read and prepare data for impedance calculation.

Parameters:
Return type:

None

property z: Series#

Complex impedance Z [Ω].

property z_real: Series#

Real part of the impedance tensor, Z’ [Ω].

property z_imag: Series#

Imaginary part of the impedance tensor, Z’’ [Ω].

property z_err: Series#

Propagated error in the magnitude of Z, |dZ| [Ω].

Calculated via standard error propagation from the relative error in resistivity (dρ/ρ) and the absolute error in phase (dφ).

\[|dZ| \approx \sqrt{ (\frac{\partial |Z|}{\partial \rho} d\rho)^2 + (|Z| d\phi)^2 }\]

Since phase errors are often dominant and uncorrelated, a simpler estimate is often used:

\[|dZ| \approx \frac{1}{2} |Z| \frac{d\rho}{\rho}\]
property z_xx: Series#

Complex impedance for the Zxx component.

property z_xy: Series#

Complex impedance for the Zxy component.

property z_yx: Series#

Complex impedance for the Zyx component.

property z_yy: Series#

Complex impedance for the Zyy component.

property z_xx_err: Series#

Propagated error for the Zxx component.

property z_xy_err: Series#

Propagated error for the Zxy component.

property z_yx_err: Series#

Propagated error for the Zyx component.

property z_yy_err: Series#

Propagated error for the Zyy component.

to_tensor(*, var='z', station=None, agg='mean', fill_value=nan, sort_freq=True, align='union')#

Convert impedance data into a 2x2 tensor.

Parameters:
Return type:

tuple[ndarray, ndarray, ndarray]

to_xarray(*, var='z', station=None, agg='mean', fill_value=nan, attrs=None)#

Return a 3D or 4D xarray.DataArray.

Parameters:
write()#

Serializes the core Z data to a CSV block.

Return type:

Sequence[str]

class pycsamt.zonge.components.PcEmag(data=None, meta=None, *, name=None, verbose=False)#

Bases: PercentVarBase

Percent error on electric-field magnitude, \(|E|\).

This component normalizes legacy aliases into a canonical variable named pc_emag:

  • '%Emag' (legacy AMTAVG/MTEdit),

  • 'E.%err' (CSAVGW / modern),

  • case-sensitive exact matches are used.

Notes

Values are stored in percent; the dataset attribute Unit.Percent is set to '%' when exporting to xarray.Dataset.

Parameters:
VAR_NAME: ClassVar[str] = 'pc_emag'#
TITLE: ClassVar[str] = 'Percent |E| Variation'#
UNIT_ATTR: ClassVar[str] = 'Unit.Percent'#
class pycsamt.zonge.components.PcHmag(data=None, meta=None, *, name=None, verbose=False)#

Bases: PercentVarBase

Percent error on magnetic-field magnitude, \(|H|\).

This component normalizes legacy aliases into a canonical variable named pc_hmag:

  • '%Hmag' (legacy AMTAVG/MTEdit),

  • 'B.%err' (CSAVGW, where B denotes the H-field),

  • 'H.%err' (rare but seen).

Notes

Values are stored in percent; the dataset attribute Unit.Percent is set to '%' when exporting to xarray.Dataset.

Parameters:
VAR_NAME: ClassVar[str] = 'pc_hmag'#
TITLE: ClassVar[str] = 'Percent |H| Variation'#
UNIT_ATTR: ClassVar[str] = 'Unit.Percent'#
class pycsamt.zonge.components.PcRho(data=None, meta=None, *, name=None, verbose=False)#

Bases: PercentVarBase

Percent error on apparent resistivity, \(\rho_a\).

This component normalizes legacy aliases into a canonical variable named pc_rho:

  • '%Rho' (legacy AMTAVG/MTEdit),

  • 'ARes.%err' (CSAVGW),

  • 'rho.%err' (modern lower-case variant).

Notes

Values are stored in percent; the dataset attribute Unit.Percent is set to '%' when exporting to xarray.Dataset.

Parameters:
VAR_NAME: ClassVar[str] = 'pc_rho'#
TITLE: ClassVar[str] = 'Percent ρa Variation'#
UNIT_ATTR: ClassVar[str] = 'Unit.Percent'#
class pycsamt.zonge.components.SEphz(data=None, meta=None, *, name=None, verbose=False)#

Bases: PhaseStdBase

Standard deviation of E-phase.

Recognised source columns#

  • sEphz

  • E.perr

Internal canonical column: 'sephz'.

VAR_NAME: ClassVar[str] = 's_ephz'#
LABEL: ClassVar[str] = 'E phase σ (sEphz)'#
Parameters:
class pycsamt.zonge.components.SHphz(data=None, meta=None, *, name=None, verbose=False)#

Bases: PhaseStdBase

Standard deviation of H-phase.

Recognised source columns#

  • sHphz

  • H.perr

Internal canonical column: 'shphz'.

VAR_NAME: ClassVar[str] = 's_hphz'#
LABEL: ClassVar[str] = 'H phase σ (sHphz)'#
Parameters:
class pycsamt.zonge.components.SPhz(data=None, meta=None, *, name=None, verbose=False)#

Bases: PhaseStdBase

Standard deviation of impedance phase (Z).

Recognised source columns#

  • sPhz

  • Z.perr

Internal canonical column: 'sphz'.

VAR_NAME: ClassVar[str] = 's_phz'#
LABEL: ClassVar[str] = 'Z phase σ (sPhz)'#
Parameters: