2.9.1.14. pycsamt.seg.spectra#
Functions
|
Synthesize a |
Classes
|
Container for |
|
Read and write |
|
Convenience facade for spectra access. |
|
Minimal container for the |
Exceptions
Warning emitted for recoverable EDI SPECTRA inconsistencies. |
- class pycsamt.seg.spectra.SpectraSECT(*args, verbose=0, logger=None, **kws)[source]
Bases:
EDIComponentBaseMinimal container for the
>=SPECTRASECTheader.The class parses and serializes the spectra section header that precedes one or more
>SPECTRAdata blocks. It collects the option key/values and the ordered set of measurement IDs that the spectra apply to, as described by the SEG EDI convention [SpectraSECT-1].- Parameters:
- Variables:
sectid (str or None) – Section identifier, often a site name. Some files omit this or use a numeric ID.
nchan (int or None) – Number of channels in the spectra set.
nfreq (int or None) – Number of frequencies expected in the section.
maxblks (int or None) – Maximum number of blocks. Rarely used.
meas_ids (list of str) – Ordered measurement ID list that follows the option lines in
>=SPECTRASECT.start_data_lines_num (int or None) – Line index in the EDI where the first
>SPECTRAblock begins. Set byfrom_file().
Notes
Parsing is tolerant to case and extra whitespace.
Unknown header keys are ignored instead of raising.
The measurement ID list is collected from the header body once option lines end.
The start of the spectra data is detected by the first
>SPECTRAtag, by the next>=...tag, or by end of file, whichever comes first.For consistent processing, maintain the same frequency set across related data sections, as recommended in the EDI spec [SpectraSECT-1].
See also
SpectraIOReader/writer for the
>SPECTRAdata blocks.MTEMAPHeader for
>=MTSECTor>=EMAPSECT. The spectra frequency set should match the MT set.TSectHeader for
>=TSERIESSECT(time series).
Examples
Read only the header and measurement IDs:
>>> sect = SpectraSECT.from_file("site.edi") >>> sect.nfreq, sect.nchan (128, 5) >>> sect.meas_ids[:2] ['HX1', 'HY1']
Serialize a header:
>>> sect.nfreq = 3 >>> sect.meas_ids = ["HX", "HY", "EX", "EY"] >>> lines = sect.write() >>> print("".join(lines).strip()) >=SPECTRASECT SECTID=... NCHAN=... NFREQ=3 MAXBLKS=... // 4 HX HY EX EY
References
- class pycsamt.seg.spectra.SpectraIO(*args, verbose=0, logger=None, **kws)[source]
Bases:
EDIComponentBaseRead and write
>SPECTRAdata blocks.A spectra section contains one block per frequency. Each block begins with a
>SPECTRAline that holds options such as frequency and bandwidth, optionally followed by a comment with the number of values, then one or more lines of numeric values.Known options are normalized:
FREQ: floatROTSPEC: intBW: floatAVGT: float
Unrecognized options are preserved in a free-form mapping so that vendor-specific metadata is not lost.
- Parameters:
- Variables:
blocks (list of _SpectraBlock) – Parsed spectra blocks, one per frequency. Each block stores header options, the optional value count hint, and the numeric values.
Notes
from_file()reads successive>SPECTRAblocks starting from a given line or from the first match in the file.Values are parsed as floats; non-numeric tokens in data lines are ignored rather than raising.
The writer orders known options first in the header line, then appends extra options sorted by key. Both option keys and values are written in upper case.
Line formatting uses the per-line and float format defaults from
Baseunless you provide explicit overrides.
See also
SpectraSECTHeader container for spectra sections.
TSIOTime-series counterpart for
>TSERIES.
Examples
Read all spectra blocks:
>>> io = SpectraIO.from_file("site.edi") >>> len(io.blocks) 128 >>> b0 = io.blocks[0] >>> b0.freq, b0.bw (..., ...)
Build and serialize blocks:
>>> from pycsamt.seg.spectra import _SpectraBlock >>> io = SpectraIO() >>> blk = _SpectraBlock() >>> blk.freq = 10.0 >>> blk.rotspec = 1 >>> blk.values = [0.1, 0.2, 0.3] >>> io.blocks.append(blk) >>> lines = io.write(per_line=2, float_fmt="{: .3E}") >>> print("".join(lines).strip()) >SPECTRA FREQ=10.0 ROTSPEC=1 // 3 1.000E-01 2.000E-01 3.000E-01
References
[SpectraIO-1]SEG EDI standard, “Spectra Data Sections”.
- blocks: list[_SpectraBlock]
- classmethod from_file(edi_path, start_line=None)[source]
- class pycsamt.seg.spectra.SpectraMixin[source]
Bases:
objectConvenience facade for spectra access.
This mixin exposes a compact API that host classes can reuse to discover and read spectra sections in an EDI file.
- from_file(edi_fn)[source]
Return a
SpectraSECTparsed from the first>=SPECTRASECTheader inedi_fn.- Parameters:
edi_fn (str)
- Return type:
- read_blocks(edi_fn)[source]
Return a
SpectraIOby scanning all subsequent>SPECTRAblocks that belong to the section discovered bySpectraSECT.
Notes
Use this mixin in higher-level readers so spectra handling remains consistent and centralized. The method pair mirrors the design used for MT/EMAP headers and for time series sections.
See also
SpectraSECTHeader parsing and serialization.
SpectraIOData block reader/writer.
MTEMAPMT/EMAP section header, often used alongside spectra for the same dataset.
Examples
>>> class Reader(SpectraMixin): ... pass >>> sect = Reader.from_file("site.edi") >>> io = Reader.read_blocks("site.edi") >>> len(io.blocks) > 0 True
References
[SpectraMixin-1]SEG EDI standard, “Spectra Data Sections”.
- class pycsamt.seg.spectra.Spectra(name=None, *, verbose=0)[source]
Bases:
EMBaseContainer for
>SPECTRAblocks grouped per frequency.The class gathers one spectra record per frequency and exposes typed header fields (frequency, rotation flag, bandwidth, and averaging time) together with the numeric values stored in each block. It is a compact, array- oriented view on top of
SpectraSECTandSpectraIO.- Parameters:
- Variables:
freq (ndarray, shape
(n_blk,)) – Frequency (Hz) per block. Missing values are set tonp.nan.rotspec (ndarray of int, shape
(n_blk,)) – Rotation specifier per block. Missing values are set to-1.bw (ndarray, shape
(n_blk,)) – Nominal bandwidth (Hz) per block ornp.nan.avgt (ndarray, shape
(n_blk,)) – Averaging time (s) per block ornp.nan.values (list of ndarray) – Numeric payload for each block. Lengths may differ across blocks, as allowed by the SEG format.
n_values (ndarray of int, shape
(n_blk,)) – Number of values in each block (as parsed or counted).
Notes
Blocks may contain vendor-specific options beyond the canonical
FREQ,ROTSPEC,BW, andAVGT. Those options are preserved when round-tripping viato_io(). The class does not impose a common length across spectra vectors; if you require a 2-D array, pad thevalueslist explicitly.The constructor itself does not read files. Use
from_io()orfrom_file()to populate an instance from sections and data blocks.To recover a format-neutral EMTF document with full FCU-compatible covariance from this container, use
pycsamt.emtf.EMTF.from_edi_spectra()orpycsamt.emtf.converters.spectra.spectra_to_emtf()on thepycsamt.emtfside rather than a method on this class — spectra parsing stays inpycsamt.seg, transfer-function/covariance recovery stays in the EMTF interoperability layer.- from_io(sect, io) : classmethod
Build a
SpectrafromSpectraSECTandSpectraIO.
- from_file(path) : classmethod
Convenience that calls
SpectraSECT.from_fileandSpectraIO.from_file, then delegates tofrom_io().
- to_io()[source]
Serialize the current state to a fresh pair (
SpectraSECT,SpectraIO) that can be written back to an EDI file.- Return type:
Examples
Read, inspect, and serialize spectra:
from pycsamt.seg.spectra import Spectra sp = Spectra.from_file("site.edi") f = sp.freq first = sp.values[0] sect2, io2 = sp.to_io() # writer can now combine sect2.write() and io2.write()
See also
pycsamt.seg.spectra.SpectraSECTHeader for
>=SPECTRASECTsections.pycsamt.seg.spectra.SpectraIOReader/writer for
>SPECTRAblocks.pycsamt.seg.EDIFileHigh-level dispatcher that can attach spectra to an EDI session.
References
[Spectra-1]SEG EDI standard, Spectra Data Sections. Society of Exploration Geophysicists.
[Spectra-2]Chave, A. D., & Jones, A. G. (2012). The Magnetotelluric Method: Theory and Practice. Cambridge Univ. Press.
- parsed_nfreq: int
- property fcu_cross_spectra: ndarray[source]
Return spectra in the EMTF-FCU cross-power convention.
Spectra.Sretains the historical pyCSAMT conventionchannel_i * conj(channel_j)so existing callers andto_Z()are unchanged by Phase 8. EMTF FCU uses the conjugate conventionconj(channel_i) * channel_j.EDI SPECTRA input keeps an exact FCU view in
_S_fcu. For spectra constructed through the historical pyCSAMT API, the FCU view is therefore the element-wise complex conjugate ofS.
- property missing_mask: ndarray | None[source]
Return the per-frequency missing cross-spectral component mask.
- classmethod from_io(sect, io, *, empty=1e+32, verbose=0)[source]
- Parameters:
sect (SpectraSECT)
io (SpectraIO)
empty (float)
verbose (int)
- Return type:
- classmethod from_file(path, *, empty=1e+32, verbose=0)[source]
Read a
Spectradirectly from an EDI file path.Convenience wrapper around
from_io()that callsSpectraSECT.from_fileandSpectraIO.from_fileinternally.
- to_edi(source_edi=None, *, station_name=None, e_labels=('EX', 'EY'), h_labels=('HX', 'HY'), ridge=None, estimate_error=False, dof=None)[source]
Convert cross-spectra to an MT-impedance
EDIFile.Calls
to_Z()and assembles a complete>=MTSECT/>FREQ/>ZXXR/>ZXYR/ … EDI ready to be saved withwrite().The structural sections (
>HEAD,>INFO,>=DEFINEMEAS) are re-used from source_edi when provided, preserving all acquisition metadata; otherwise a minimal header is synthesised from theSpectrametadata.According to the SEG EDI standard (§ 7.53, 12.1), an MT data section requires:
>=MTSECT SECTID=... NFREQ=... HX=... HY=... HZ=... EX=... EY=... >FREQ //N ... >ZXXR ROT=ZROT //N ... >ZXXI ROT=ZROT //N ... ... >END
The measurement IDs for
HX,HY, … in>=MTSECTare resolved fromid_to_chtype(populated bySpectraSECTfrom>HMEAS/>EMEASlines).- Parameters:
source_edi (str, Path, or EDIFile, optional) – Spectra EDI file whose
>HEAD,>INFO, and>=DEFINEMEASsections are copied into the output. Pass the same path used withfrom_file()to produce a fully metadata-rich result. WhenNone, a minimal header is synthesised.station_name (str, optional) – Override for the
DATAIDin>HEADandSECTIDin>=MTSECT. Defaults toname.e_labels (tuple of str) – Electric channel type labels forwarded to
to_Z().h_labels (tuple of str) – Horizontal magnetic channel type labels forwarded to
to_Z().ridge (float, optional) – Tikhonov regularisation forwarded to
to_Z().estimate_error (bool) – If
True, propagate 1-σ errors into>ZXX.VAR… blocks.dof (float or ndarray, optional) – Effective degrees of freedom forwarded to
to_Z().
- Returns:
Fully populated MT-impedance container. Call
write()to save.- Return type:
- Raises:
EdIDataError – If
to_Z()fails (channel types not resolved, singular magnetic block, etc.).
Examples
Convert and save:
sp = Spectra.from_file("site.edi") ed = sp.to_edi("site.edi", estimate_error=False) out = ed.write(savepath="mt_output/")
Convert with a custom station name and error propagation:
ed = sp.to_edi( "site.edi", station_name="HBH03_imp", estimate_error=True, dof=24.0, ) out = ed.write(savepath="mt_output/")
Verify the round-trip:
from pycsamt.seg.edi import EDIFile ed2 = EDIFile(out) assert ed2.Z.n_freq == sp.n_freq
- to_io()[source]
- Return type:
- validate_frequency_count(*, policy='raise')[source]
Validate
SPECTRASECT.NFREQagainst parsed/usable blocks.- Parameters:
policy ({"raise", "warn", "ignore"}) – Action when the declared count differs from either the number of parsed
>SPECTRAblocks or the number of usable frequency blocks. FCU historically stops on this inconsistency;warnis provided for recovery of heterogeneous archives.- Returns:
Trueif the declaredNFREQmatches both the parsed and usable block counts (or noNFREQwas declared);Falsewhen a mismatch is found andpolicyis"warn"or"ignore".- Return type:
- Raises:
ValueError – If
policyis not one of"raise","warn","ignore".EdIDataError – If a mismatch is found and
policy="raise".
- rotate(theta_deg, *, pairs=None)[source]
- to_Z(*, id_to_chtype=None, e_labels=('EX', 'EY'), h_labels=('HX', 'HY'), use_remote=False, ridge=None, estimate_error=True, dof=None)[source]
Recover an impedance tensor
Zand, if available, the tipper from cross-spectra stored in thisSpectra.The method resolves channel types, extracts the electric and magnetic sub-blocks, and computes per-frequency
Z = S_EH @ inv(S_HH). If a vertical magnetic channel is present it also computes the tipperT = S_ZH @ inv(S_HH). Optional ridge regularization can be applied to stabilize the magnetic block.- Parameters:
id_to_chtype (dict of str to str, optional) – Mapping from measurement IDs (as recorded in
>=SPECTRASECTorDefineMeas) to channel types ("HX","HY","HZ","EX","EY"). If omitted, the method usesself.id_to_chtypewhen available, otherwise it interpretsself.chan_idsdirectly as labels.e_labels (tuple of str, default (
"EX","EY")) – Labels that identify the two electric channels used for theEblock.h_labels (tuple of str, default (
"HX","HY")) – Labels that identify the two horizontal magnetic channels used for theHblock.use_remote (bool, default
False) – When duplicate electric channels exist (e.g., local and remote), choose the second occurrence for theEblock ifTrue; otherwise choose the first.ridge (float, optional) – Non-negative Tikhonov regularization added to
S_HHprior to inversion,S_HH + ridge * I.estimate_error (bool, default
True) – IfTrue, estimate per-component 1-sigma standard errors forZ(and tipper when available) usingcompute_errors_from_Sand the degrees of freedom given bydof(or inferred; see Notes).dof (float or ndarray, optional) – Effective degrees of freedom per frequency. If an array is provided it must broadcast to
n_freq. IfNoneandestimate_errorisTrue, the method tries to infer DoF from metadata viaeffective_dof_from_metausingsegnum, oravgt * bwas a fallback.
- Returns:
z_obj (
pycsamt.z.z.Z) – Impedance object on the spectra frequency grid withzpopulated and, when estimated,z_errset.tip (
pycsamt.z.tipper.TipperorNone) – Tipper on the same grid whenHZis available. When errors are estimated, tipper uncertainties are attached.
- Raises:
EdIDataError – If spectra are empty, channel types cannot be resolved, or the stabilized magnetic block is singular.
Notes
Per frequency,
Zis formed asZ = S_EH @ inv(S_HH), whereS_EHis the cross-spectra between E and H, andS_HHis the magnetic auto/cross block. If a vertical magnetic channel is available, the tipper is computed asT = S_ZH @ inv(S_HH).Channel type resolution proceeds in this order:
explicit
id_to_chtypeargument,self.id_to_chtypefrom the section header orDefineMeas,direct interpretation of
self.chan_ids.
When both local and remote electric channels are present, setting
use_remote=Truechooses the second occurrence as a simple heuristic. Frequency ordering is preserved.Uncertainties are computed by first-order propagation under a complex-Wishart model and scale as
1 / sqrt(DoF). If DoF cannot be determined for every frequency, no per-frequency array is attached at all:z_err(andtip.tipper_errwhen applicable) come back asNonerather than an array of NaN.Examples
>>> Zhat, That = spectra.to_Z() >>> Zhat, _ = spectra.to_Z(use_remote=True, ridge=1e-6) >>> Zhat, _ = spectra.to_Z(dof=np.full(spectra.n_freq, 24.0))
See also
Spectra.from_ZInverse operation that synthesizes spectra.
spectra_from_ZFunctional wrapper for the inverse operation.
effective_dof_from_metaInfer DoF from
segnum,avgtandbw.compute_errors_from_SPer-frequency uncertainty estimator.
References
[Spectra-to-Z-1]Chave, A. D., & Jones, A. G. (2012). The Magnetotelluric Method: Theory and Practice. Cambridge University Press.
[Spectra-to-Z-2]Bendat, J. S., & Piersol, A. G. (2011). Random Data: Analysis and Measurement Procedures. Wiley.
- classmethod from_Z(z_obj, **kws)[source]
Create a
Spectrafrom a transfer functionZ.This class method is a thin, convenience wrapper around
spectra_from_Z(). It synthesizes a full Hermitian cross–spectral density tensor from the impedance tensorZ(f)and optional inputs that control magnetic power and tipper usage.- Parameters:
z_obj (
Z) – Input impedance object. The attributesz_obj.z(shape(n, 2, 2)) andz_obj.freq(shape(n,)) must be set.**kws (Any) – Forwarded to
spectra_from_Z(). See that function for the complete set of options such asS_HH,H_psd,tipper,include_hz, andchan_order.
- Returns:
A spectra container on the same frequency grid as
z_obj. Channel order follows the requestedchan_order(default:HX, HY, EX, EY).- Return type:
- Raises:
EdIDataError – If
z_objis incomplete (missingzorfreq).
Notes
Absolute spectral levels are not carried by the impedance tensor. To obtain physically scaled spectra, provide magnetic spectra via
S_HHorH_psd. If neither is given, a unit–power assumption is used (S_HH = I), which is suitable for tests but not for quantitative analysis.This method does not infer per–frequency metadata such as bandwidth or averaging time; those fields are initialized with zeros/NaNs.
Examples
>>> ed = EDIFile("site_imp.edi") >>> sp = Spectra.from_Z( ... ed.Z, ... H_psd=(np.ones(ed.Z.n_freq), np.ones(ed.Z.n_freq), None), ... ) >>> sect, io = sp.to_io() >>> _ = ed.write_new_edi( ... edi_fn="site_with_synth_spec.edi", ... Spectra=sp, ... )
See also
spectra_from_ZFunctional API that performs the synthesis.
pycsamt.seg.ops.synthesize_spectra_from_zLow–level array helper used under the hood.
Spectra.to_ZInverse operation (spectra → Z).
References
[Spectra-from-Z-1]Chave, A. D., & Jones, A. G. (2012). The Magnetotelluric Method: Theory and Practice. Cambridge Univ. Press.
[Spectra-from-Z-2]Bendat, J. S., & Piersol, A. G. (2011). Random Data: Analysis and Measurement Procedures. Wiley.
[Spectra-from-Z-3]SEG EDI MT/EMAP standard (1987). MTNet.
- exception pycsamt.seg.spectra.SpectraValidationWarning[source]
Bases:
UserWarningWarning emitted for recoverable EDI SPECTRA inconsistencies.