pycsamt.emtools.csumt#

Controlled-source ultra-audio MT depth and survey-planning tools.

The module converts apparent resistivity and transmitter frequency into Bostick depth estimates, evaluates vertical resolution and depth coverage, designs CSUMT frequency schedules, and plots depth sections for survey sites.

Module Attributes

BOSTICK_CONST

Bostick depth constant in metres:

F_MIN_CSUMT

9.6 kHz (zhang2025).

F_MAX_CSUMT

614.4 kHz (zhang2025).

Functions

bostick_depth(sites, *[, recursive, on_dup, ...])

Bostick depth estimate per station per frequency from measured data.

bostick_depth_from_rho(rho, freq)

Bostick depth estimate D(f) from apparent resistivity.

depth_coverage_table(sites, *[, recursive, ...])

Summary depth-coverage statistics per station.

frequency_for_depth(depth_m, rho)

Invert the Bostick formula: return the frequency (Hz) that maps to a given depth for a background resistivity rho.

frequency_schedule(target_depths, ...[, ...])

Design a CSUMT frequency schedule that samples a set of target depths.

plot_depth_section(sites, *[, log_color, ...])

Pseudosection of Bostick depth across stations and periods/frequencies.

vertical_resolution(sites, *[, ...])

Vertical resolution ΔD between adjacent frequencies per station.

vertical_resolution_pair(rho, f_lo, f_hi)

Vertical resolution ΔD between two adjacent frequencies.

pycsamt.emtools.csumt.bostick_depth_from_rho(rho, freq)[source]#

Bostick depth estimate D(f) from apparent resistivity.

D(f) = 356 × √(ρ_a / f) [metres]

Parameters:
  • rho (float or array) – Apparent resistivity ρ_a in Ω·m. Broadcastable with freq.

  • freq (float or array) – Frequency in Hz.

Returns:

Depth in metres, same shape as broadcast of rho and freq.

Return type:

numpy.ndarray

References

Zhang et al. (2025), Eq. (1), Measurement.

pycsamt.emtools.csumt.vertical_resolution_pair(rho, f_lo, f_hi)[source]#

Vertical resolution ΔD between two adjacent frequencies.

ΔD = 356 × √ρ_c × (1/√f_lo − 1/√f_hi) [metres; f_lo < f_hi]

Parameters:
  • rho (float) – Characteristic (apparent) resistivity ρ_c in Ω·m.

  • f_lo (float) – Lower frequency in Hz (deeper penetration).

  • f_hi (float) – Higher frequency in Hz (shallower penetration).

Returns:

Vertical resolution in metres. Positive when f_lo < f_hi.

Return type:

float

References

Zhang et al. (2025), Eq. (2), Measurement.

pycsamt.emtools.csumt.frequency_for_depth(depth_m, rho)[source]#

Invert the Bostick formula: return the frequency (Hz) that maps to a given depth for a background resistivity rho.

f = ρ × (356 / D)² [Hz]

Parameters:
  • depth_m (float or array) – Target depth(s) in metres.

  • rho (float) – Background apparent resistivity in Ω·m.

Returns:

Frequency in Hz, same shape as depth_m.

Return type:

numpy.ndarray

pycsamt.emtools.csumt.frequency_schedule(target_depths, rho_estimate, *, f_min=9600.0, f_max=614400.0, min_resolution_m=None, fill_decades=False, per_decade=3, as_khz=False)[source]#

Design a CSUMT frequency schedule that samples a set of target depths.

Each target depth is converted to a frequency via frequency_for_depth(), then clipped to [f_min, f_max]. Optionally, intermediate frequencies can be inserted to guarantee a minimum vertical resolution between consecutive depth levels.

Parameters:
  • target_depths (float or array) – Target depths in metres (deepest first or any order — sorted internally).

  • rho_estimate (float) – Background apparent resistivity ρ (Ω·m) used for the conversion.

  • f_min (float, default=9.6e3) – Minimum transmitter frequency in Hz (lower bound of CSUMT range).

  • f_max (float, default=614.4e3) – Maximum transmitter frequency in Hz (upper bound of CSUMT range).

  • min_resolution_m (float or None) – If given, insert additional frequencies between adjacent target depths whenever their vertical resolution would exceed this value.

  • fill_decades (bool, default=False) – If True, add per_decade log-spaced frequencies within each decade of the schedule to smooth coverage.

  • per_decade (int, default=3) – Number of extra frequencies to insert per decade when fill_decades is True.

  • as_khz (bool, default=False) – If True, return frequencies in kHz instead of Hz.

Returns:

Sorted frequencies in Hz (or kHz if as_khz is True).

Return type:

numpy.ndarray

References

Zhang et al. (2025), “Controlled source ultra-audio frequency magnetotellurics (CSUMT) transmitter”, Measurement.

pycsamt.emtools.csumt.bostick_depth(sites, *, recursive=True, on_dup='replace', strict=False, verbose=0)[source]#

Bostick depth estimate per station per frequency from measured data.

Uses the apparent resistivity derived from the off-diagonal impedance tensor components (geometric mean):

D(f) = 356 × √(ρ_a(f) / f) [metres]

Parameters:
  • sites (path, EDI-like, Sites, or iterable) – Any input accepted by ensure_sites().

  • recursive (bool) – Forwarded to ensure_sites().

  • on_dup (str) – Forwarded to ensure_sites().

  • strict (bool) – Forwarded to ensure_sites().

  • verbose (int) – Forwarded to ensure_sites().

Returns:

One row per (station, frequency) with columns: station, freq_hz, period_s, rho_a_ohmm, depth_m.

Return type:

pandas.DataFrame

References

Zhang et al. (2025), Eq. (1).

pycsamt.emtools.csumt.vertical_resolution(sites, *, rho_override=None, recursive=True, on_dup='replace', strict=False, verbose=0)[source]#

Vertical resolution ΔD between adjacent frequencies per station.

For each consecutive pair (f_lo, f_hi) in the station’s frequency list (sorted ascending), computes:

ΔD = D(f_lo) − D(f_hi) [metres]

using the Bostick depths derived from the measured ρ_a. Alternatively, supply rho_override to use a fixed background resistivity with the analytical formula 356 × √ρ × (1/√f_lo 1/√f_hi).

Parameters:
  • sites (path, EDI-like, Sites, or iterable)

  • rho_override (float or None) – If given, use this constant resistivity for all ΔD calculations (analytical formula) instead of the per-frequency ρ_a.

  • recursive (bool) – Forwarded to ensure_sites().

  • on_dup (str) – Forwarded to ensure_sites().

  • strict (bool) – Forwarded to ensure_sites().

  • verbose (int) – Forwarded to ensure_sites().

Returns:

Columns: station, freq_lo_hz, freq_hi_hz, depth_lo_m, depth_hi_m, delta_depth_m, rho_a_ohmm.

Return type:

pandas.DataFrame

pycsamt.emtools.csumt.depth_coverage_table(sites, *, recursive=True, on_dup='replace', strict=False, verbose=0)[source]#

Summary depth-coverage statistics per station.

Parameters:
  • sites (path, EDI-like, Sites, or iterable)

  • recursive (bool) – Forwarded to ensure_sites().

  • on_dup (str) – Forwarded to ensure_sites().

  • strict (bool) – Forwarded to ensure_sites().

  • verbose (int) – Forwarded to ensure_sites().

Returns:

One row per station with columns: station, n_freq, freq_min_hz, freq_max_hz, depth_min_m, depth_max_m, mean_resolution_m, median_resolution_m.

Return type:

pandas.DataFrame

pycsamt.emtools.csumt.plot_depth_section(sites, *, log_color=True, sort_by='name', cmap='viridis_r', figsize=(10.0, 5.0), period_axis=True, recursive=True, on_dup='replace', strict=False, verbose=0, ax=None)[source]#

Pseudosection of Bostick depth across stations and periods/frequencies.

Each cell (station × period) is coloured by the Bostick depth D(f) = 356 √(ρ_a / f).

Parameters:
  • sites (path, EDI-like, Sites, or iterable)

  • log_color (bool, default=True) – Color by log10(depth) instead of depth.

  • sort_by ({"name", "lon", "lat"}) – Station ordering along the x-axis.

  • cmap (str, default="viridis_r") – Matplotlib colormap name.

  • figsize ((float, float), default=(10, 5))

  • period_axis (bool, default=True) – If True y-axis is period (s); otherwise frequency (Hz).

  • recursive (bool) – Forwarded to ensure_sites().

  • on_dup (str) – Forwarded to ensure_sites().

  • strict (bool) – Forwarded to ensure_sites().

  • verbose (int) – Forwarded to ensure_sites().

  • ax (matplotlib.axes.Axes, optional)

Return type:

matplotlib.axes.Axes