2.8. pycsamt.site#
Survey-site containers, station selection, profile management, editing, computed geometry, export, and reporting helpers.
Survey sites, station collections, diagnostics, editing, and export helpers.
- class pycsamt.site.SiteMixin(source, *, on_loss='warn')#
Bases:
CoreObjectLightweight wrapper exposing station-centric accessors and utilities for a single
EDIFile.The mixin normalizes common site operations around the underlying EDI content, including coordinate handling, impedance arrays, tipper, derived resistivity/phase, and convenient export to
pandas.DataFrame.Notes
The station name is resolved from EDI HEAD fields in the following order:
dataid,station,sitename,name,STATION. If none is present, the file stem is used. See_station_name().The Z tensor is treated as an array of shape
(n, 2, 2)or flattened to(n, 4)as needed. The order is:Zxx, Zxy, Zyx, Zyy.See also
pycsamt.seg.edi.EDIFileParsed SEG-EDI container.
pycsamt.site.base.SiteConcrete site wrapper that enforces a stable ID.
pycsamt.site.base.SitesCollection helper for multiple sites.
References
[SiteMixin-1]SEG EDI Format. Society of Exploration Geophysicists. Commonly used magnetotelluric exchange format.
- Parameters:
source (Any)
on_loss (str)
- property edi: EDIFile#
The underlying
EDIFile.- Returns:
When this site was constructed from an EDI object, the same object every time. When constructed from an
EMTFXML document, an EDI view is materialized on first access viapycsamt.emtf.converters.edi.emtf_to_edi()and cached, so this always returns the same object on repeated access (safe for in-place mutation and identity-keyed caches elsewhere in the codebase).- Return type:
Notes
Materializing from XML may emit a
DataLossWarning(or raise, depending onon_losspassed at construction) if the source document holds metadata the historical EDI format cannot represent.
- property tf: Any#
The underlying
EMTFdocument.- Returns:
When this site was constructed from an XML document, the same object every time. When constructed from an EDI object, a format-neutral view is materialized on first access via
pycsamt.emtf.converters.edi.edi_to_emtf()and cached (lossless – XML is a strict superset of EDI).- Return type:
See also
site_meta,site_layout,provenance,processing,copyright,quality_metaTypedmod:pycsamt.metadata accessors built on top of this document.
- property name: str#
Station identifier resolved from the EDI header or file stem.
- Returns:
Station name used for lookups and display.
- Return type:
Notes
The resolution order is defined in
_station_name(). XML-native sites resolve the name directly from theEMTFdocument without forcing EDI materialization.
- property coords: tuple[float, float, float]#
Geographic coordinates of the site.
Notes
This accessor relies on
_get_coords()which parses EDI HEAD latitude, longitude and elevation. XML-native sites read directly from theEMTFdocument without forcing EDI materialization.
- property freq: Any#
Frequency vector extracted from the Z section.
- Returns:
One-dimensional array of frequencies in Hz, or
Noneif missing.- Return type:
array-like or None
See also
to_dataframeTabular export of arrays at each frequency.
- property z: Any#
Complex impedance tensor across frequencies.
- Returns:
Array with shape
(n, 2, 2)or flattened to(n, 4)depending on context, orNoneif absent.- Return type:
array-like or None
Notes
Flattening order is
Zxx, Zxy, Zyx, Zyy.
- property z_err: Any#
Uncertainty associated with the impedance tensor.
- Returns:
Error array aligned with
SiteMixin.z, orNoneif absent.- Return type:
array-like or None
- property rho: Any#
Apparent resistivity derived from the impedance tensor.
- Returns:
Resistivity values per component and frequency, or
Noneif not computed or absent.- Return type:
array-like or None
Notes
Derived fields may be recomputed downstream when the Z tensor or frequency vector is updated.
- property phase: Any#
Impedance phase (degrees) derived from the tensor.
- Returns:
Phase values per component and frequency, or
Noneif not computed or absent.- Return type:
array-like or None
- property tipper: Any#
Vertical magnetic transfer function (tipper).
- Returns:
Two columns
(Tx, Ty)per frequency, orNoneif missing.- Return type:
array-like or None
- property meta: dict[str, Any]#
Minimal metadata snapshot collected from the EDI.
- Returns:
Dictionary that may include
station,name,lat,lon,elev,dataid,sitename, and anINFOsub-dict if present.- Return type:
Notes
Values are read on a best-effort basis and non-existing keys are omitted.
- to_dataframe(kind='z', *, api=None)#
Export core arrays to a tidy
pandas.DataFrame.- Parameters:
kind ({"z", "imp", "impedance", "resphase", "rp",) – “rho_phase”, “tip”, “tipper”, “t”}, optional Selects which quantity to export. The default is
"z".api (bool | None)
- Returns:
Frame indexed by frequency (name
"f"). Columns depend onkind: -"z":Zxx, Zxy, Zyx, Zyy(complex values). -"resphase": pairs of columns per componentrho_*andphi_*."tipper":Tx, Ty.
- Return type:
- Raises:
ValueError – If
kindis not recognized.
Notes
Missing arrays yield empty frames with the correct index.
Examples
>>> df = site.to_dataframe("z") >>> df.columns Index(["Zxx","Zxy","Zyx","Zyy"], dtype="object")
See also
quality_flagsQuick presence checks of available arrays.
- quality_flags()#
Report presence and basic validity of key arrays.
- Returns:
Flags:
has_freq,has_z,has_z_err,has_rho,has_phase,has_tipper. A flag isTrueif the array exists, has non-zero size, and all values are finite.- Return type:
Examples
>>> site.quality_flags()["has_z"] True
- has_component(comp)#
Check if a given component contains any finite value.
- Parameters:
comp (str) – One of
"Zxx","Zxy","Zyx","Zyy"for impedance, or"tip","tx","ty","tipper"for tipper.- Returns:
Trueif the component exists and has at least one finite value.- Return type:
Notes
Component names are case-insensitive.
Examples
>>> site.has_component("Zxy") True
- summary()#
Summarize site identity, geometry, and data coverage.
- Returns:
Keys include:
name,nfreq,lat,lon,elev,components(present Z components), andtipper(boolean).- Return type:
Examples
>>> s = site.summary() >>> s["name"], s["nfreq"] ('E01', 37)
- rename(new, *, inplace=False)#
Set a new station identifier across common header fields.
- Parameters:
- Returns:
The modified site (new instance unless
inplace).- Return type:
Notes
The method writes to EDI HEAD fields
dataid,station,sitename,name(best effort) and also updatesedi.name. Downstream containers that derive station IDs from the file stem may be configured to preferedi.nameto preserve the rename.Examples
>>> s2 = site.rename("X_E01") >>> s2.name 'X_E01'
- set_coords(lat, lon, elev=None, *, inplace=False)#
Update the site coordinates in the EDI HEAD section.
- Parameters:
lat (float) – Latitude in decimal degrees.
lon (float) – Longitude in decimal degrees.
elev (float, optional) – Elevation in meters. If
None, elevation is left unchanged. The default isNone.inplace (bool, optional) – If
True, modify this instance. IfFalse, return a newSite. The default isFalse.
- Returns:
The modified site (new instance unless
inplace).- Return type:
Notes
Latitude and longitude are validated by utility functions to ensure plausible values.
Examples
>>> site = site.set_coords(10.0, 20.0, 100.0) >>> site.coords (10.0, 20.0, 100.0)
- set_empty(*, inplace=False)#
Clear Z-related arrays to an empty dataset.
- Parameters:
inplace (bool, optional) – If
True, modify this instance. IfFalse, return a newSite. The default isFalse.- Returns:
The modified site (new instance unless
inplace).- Return type:
Notes
The following arrays are replaced with empty arrays:
freq,z,z_error,rho, andphase. Use this to initialize a skeleton record without data.Examples
>>> s2 = site.set_empty() >>> s2.to_dataframe("z").empty True
- class pycsamt.site.Site(source, *, on_loss='warn')#
Bases:
SiteMixinHigh-level wrapper for a single MT/CSAMT site backed by an
EDIFile. The class enforces a stable, file-stem-based station identifier and exposes convenient accessors for coordinates, impedance Z, tipper, and derived quantities.Sitealso accepts anEMTFXML document instead of an EDI object – seefrom_xml(). Either way,ediandtfare both always available: the representation not natively supplied is lazily materialized and cached from the other viapycsamt.emtf.converters.edi.edi_to_emtf()/emtf_to_edi, so every existing EDI-shaped accessor keeps working unchanged regardless of which format the site was built from.When constructed from EDI, the constructor normalizes EDI
HEADfields so thatdataid(and, if absent,station) matches the site stem resolved by_stem_from_edi(). If an in-memoryedi.nameexists, the stem may prefer it so that a prior rename is preserved. This normalization improves name-based indexing, deterministic selection, and downstream joins in collections. XML-native sites keep the station identity already recorded in the document instead.- Parameters:
source (pycsamt.seg.edi.EDIFile or pycsamt.emtf.document.EMTF) – Parsed SEG-EDI container, or an EMTF XML document, holding one station. The EDI file may be constructed from disk or synthesized in memory.
on_loss ({"warn", "raise", "ignore"}, default "warn") – Policy applied if
ediis later materialized from an XML-native site and the document holds metadata the historical EDI format cannot represent.
- Variables:
edi (pycsamt.seg.edi.EDIFile) – Underlying (possibly lazily materialized) EDI object. Use with care; prefer the typed accessors of
SiteMixin(e.g.,freq,z).tf (pycsamt.emtf.document.EMTF) – Underlying (possibly lazily materialized) EMTF XML document. See also
site_meta,provenance,processing,site_layout,copyright,quality_meta.backend (str) –
"edi"or"xml"– which representation is native.name (str) – Normalized station identifier. By default this equals the file stem, unless a previous explicit rename is in effect.
coords (tuple of float) – Geographic location as
(lat, lon, elev). Latitude and longitude are in degrees; elevation is in meters.
Notes
- Identity policy
The site identity is derived from header fields in the following order:
dataid,station,sitename,name,STATION. If none are present, the file stem is used. The constructor ensures thatdataidis set to the resolved stem to stabilize lookups.- Array conventions
The impedance tensor \(Z\) may be represented as a 3D array with shape
(n, 2, 2)or flattened to(n, 4)in the component orderZxx, Zxy, Zyx, Zyy. Frequencies are 1D of lengthn. The tipper has two columnsTxandTy.- Derived fields
Apparent resistivity and phase are derived from \(Z\) and the frequency vector. When Z or frequency slices are applied, recomputation is triggered after arrays are aligned to avoid inconsistent shapes.
- Robustness
Accessors are defensive. Missing arrays produce empty frames or
None. Coordinates are validated for range using utility checks.
Examples
- Basic construction and inspection
>>> from pycsamt.seg.edi import EDIFile >>> from pycsamt.site.base import Site >>> e = EDIFile("E01.edi") # parse from disk >>> s = Site(e) >>> s.name 'E01' >>> s.coords (..., ..., ...) >>> s.summary()["nfreq"] >= 0 True
- Tabular export
>>> from pycsamt.site.base import Site >>> dfz = s.to_dataframe("z") >>> list(dfz.columns) ['Zxx', 'Zxy', 'Zyx', 'Zyy'] >>> dfrp = s.to_dataframe("resphase") >>> sorted([c for c in dfrp.columns if c.startswith("rho_")])[:2] ['rho_zxx', 'rho_zxy']
- Rename without mutating the original instance
>>> s2 = s.rename("X_E01") # returns a new Site >>> s2.name 'X_E01' >>> s.name # original unchanged 'E01'
- Coordinate update
>>> s3 = s.set_coords(10.0, 20.0, 100.0) >>> s3.coords (10.0, 20.0, 100.0)
- With a collection
>>> from pycsamt.site.base import Sites >>> e2 = EDIFile("E02.edi") >>> col = Sites([s.edi, Site(e2).edi]) >>> [t.name for t in col] ['E01', 'E02'] >>> col["E02"].summary()["name"] 'E02'
See also
pycsamt.site.base.SiteMixinMixin providing typed accessors and utilities.
pycsamt.site.base.SitesCollection helper for selection, slicing, and bulk edits.
pycsamt.seg.edi.EDIFileLow-level SEG-EDI container.
References
[Site-1]SEG EDI Format Specification. Society of Exploration Geophysicists. Exchange format for magnetotelluric and related EM data.
[Site-2]Chave, A. D., and Jones, A. G. (Eds.) (2012). The Magnetotelluric Method. Cambridge University Press.
[Site-3]Simpson, F., and Bahr, K. (2005). Practical Magnetotellurics. Cambridge University Press.
- classmethod from_edi(source, *, on_loss='warn')#
Construct a
Sitefrom an EDI object or a path to one.- Parameters:
source (pycsamt.seg.edi.EDIFile or str or pathlib.Path) – Parsed EDI object, or a path that will be read via
EDIFile(source).on_loss ({"warn", "raise", "ignore"}, default "warn") – Policy used if this site’s
tfis later materialized and something needs to be converted back.
- Returns:
A site backed natively by EDI.
- Return type:
See also
from_xmlConstruct from an EMTF XML document instead.
- classmethod from_xml(source, *, on_loss='warn')#
Construct a
Sitefrom an EMTF XML document or path.- Parameters:
source (pycsamt.emtf.document.EMTF or str or pathlib.Path) – Parsed EMTF document, or a path that will be read via
pycsamt.emtf.document.EMTF.from_xml().on_loss ({"warn", "raise", "ignore"}, default "warn") – Policy applied when this site’s
ediview is later materialized and the document holds metadata the historical EDI format cannot represent.
- Returns:
A site backed natively by the richer EMTF XML model;
z,freq,tipper, and friends keep working exactly as for an EDI-backed site (via a cached, lazily materialized EDI view), whiletf,site_meta,provenance, and related properties expose the full richer metadata.- Return type:
See also
from_ediConstruct from a SEG EDI object instead.
Site.to_xmlSerialize a site back to EMTF XML.
- to_xml(target=None, **kwargs)#
Serialize this site to EMTF XML.
- Parameters:
target (str or pathlib.Path, optional) – Destination path. If
None, the XML document is returned as a string instead of being written.**kwargs – Forwarded to
pycsamt.emtf.document.EMTF.write_xml()(whentargetis given) orpycsamt.emtf.document.EMTF.to_xml()(otherwise).
- Returns:
The XML document as a string when
targetisNone; otherwise the return value ofwrite_xml().- Return type:
str or Any
See also
from_xmlThe inverse constructor.
tfThe underlying
EMTFdocument used here.
- to_edi(*, copy=False)#
Return the underlying EDI object.
- Parameters:
copy (bool, default False) – If
True, return a best-effort deep copy of the wrapped EDI object. If copying fails, the original object is returned.- Returns:
EDI object wrapped by this
Site.- Return type:
See also
pycsamt.site.base.to_edisGeneral unwrapping helper for
Site/Sitesand mixed inputs.
- class pycsamt.site.Sites(edic, *, on_loss='warn')#
Bases:
CoreObjectContainer for multiple
Siteobjects with convenient indexing, selection, and bulk edit operations.Siteswraps each providedEDIFileinto aSite, ensuring that station identity is normalized consistently. You can iterate, index by integer, or look up by case-insensitive station name. Bulk operations such as renaming, frequency slicing, and masking are provided viaedit_all().- Parameters:
edic (pycsamt.seg.collection.EDICollection or sequence of) –
- pycsamt.seg.edi.EDIFile, pycsamt.emtf.document.EMTF, or
Parsed EDI collection, or any sequence mixing EDI objects, EMTF XML documents, and already-constructed
Siteinstances. Items are wrapped intoSiteinstances (existingSiteitems are used as-is) in the order provided.on_loss (str)
- Variables:
_items (list of Site) – Internal sequence of sites. This is considered private. Iterate over
Sitesinstead of accessing it directly.
Notes
- Identity and lookup
Each site inside the container uses the same naming policy as
Site. Name-based lookups withsites["E01"]are case-insensitive and match the normalized station name. If duplicates exist, the first match is returned.- Order preservation
Ordering of input items is preserved. Integer indexing with
sites[i]retrieves the i-thSite.- Bulk edits
edit_all()supports three common operations: -rename: compute a new name from the old name. -freq_slice: apply a frequency slice (slice)consistently across Z, freq, errors, and derived fields.
mask: apply a boolean mask to the Z tensor rows.
Use
inplace=Trueto modify the container, otherwise a newSitesis returned.- Geospatial helpers
closest()uses geodetic distance to find the nearest site to a given latitude and longitude. Sites with missing or non-finite coordinates are skipped.- Topography integration
with_topography()aligns site coordinates and elevation with a user-provided frame, returning a new container unlessinplace=Trueis requested.- Profile conversion
to_profile()attempts to build aProfilewhen that optional dependency is available. Otherwise, a lightweight dict describing a chainage-ordered sequence is returned.- Persistence
write()emits one EDI file per site into a target directory. If an EDI object providesto_file, it is used; otherwise a placeholder is written.- Robustness and errors
__getitem__raisesKeyErrorwhen a name is not found. Preferget()to obtainNoneinstead.Bulk operations ignore missing arrays on a best-effort basis so that other arrays can still be processed.
Examples
- Build from a few EDI files
>>> from pycsamt.seg.edi import EDIFile >>> from pycsamt.site.base import Sites >>> e1, e2 = EDIFile("E01.edi"), EDIFile("E02.edi") >>> sites = Sites([e1, e2]) >>> len(sites) 2 >>> [s.name for s in sites] ['E01', 'E02']
- Indexing and lookup
>>> sites[0].name 'E01' >>> sites["e02"].name 'E02' >>> sites.get("missing") is None True
- Bulk rename without mutating the original container
>>> def rnm(n): ... return "X_" + n >>> out = sites.edit_all(rename=rnm, inplace=False) >>> [s.name for s in out] ['X_E01', 'X_E02'] >>> [s.name for s in sites] ['E01', 'E02']
- Frequency slice across all arrays
>>> sl = slice(1, None) # drop the first frequency >>> out2 = sites.edit_all(freq_slice=sl, inplace=False) >>> f0 = sites["E01"].freq >>> f1 = out2["E01"].freq >>> len(f1) == len(f0) - 1 True
- Selection by names or predicate
>>> subset = sites.select(names=["E02"]) >>> [s.name for s in subset] ['E02'] >>> # predicate: keep sites with tipper available >>> subset2 = sites.select( ... predicate=lambda s: s.has_component("tipper") ... ) >>> isinstance(subset2, Sites) True
- Nearest station to a target location
>>> near = sites.closest(lat=10.0, lon=20.0, tol=None) >>> near is None or hasattr(near, "name") True
- Persist to a directory
>>> import tempfile, pathlib >>> tmp = pathlib.Path(tempfile.mkdtemp()) >>> out_paths = sites.write( ... tmp, template="{station}.edi", exist_ok=True ... ) >>> all(p.exists() for p in out_paths) True
See also
pycsamt.site.base.SiteSite wrapper used for each element in the container.
pycsamt.seg.collection.EDICollectionParsed collection produced by the core parser.
pycsamt.site.profile.ProfileOptional profile object produced by
to_profile().
References
[Sites-1]SEG EDI Format Specification. Society of Exploration Geophysicists.
[Sites-2]Chave, A. D., and Jones, A. G. (2012). The Magnetotelluric Method. Cambridge University Press.
[Sites-3]Simpson, F., and Bahr, K. (2005). Practical Magnetotellurics. Cambridge University Press.
- by_index(i)#
Retrieve a site by zero-based index.
- Parameters:
i (int) – Position in the container.
- Returns:
The site at the requested index.
- Return type:
Examples
>>> sites.by_index(0).name == sites[0].name True
- get(name)#
Safe lookup by case-insensitive station name.
- Parameters:
name (str) – Station identifier to find.
- Returns:
Matching site, or
Noneif not present.- Return type:
Site or None
Examples
>>> sites.get("missing") is None True >>> sites.get("E01").name 'E01'
See also
__getitem__Raises on missing names.
- as_list()#
Return the underlying list of EDI objects.
- Returns:
The EDI objects corresponding to each site.
- Return type:
Notes
This is useful when passing the dataset to utilities that operate on EDI-level structures rather than on sites.
Examples
>>> edis = sites.as_list() >>> hasattr(edis[0], "get_section") True
- ordered(by=None, *, inplace=False, min_linearity=None, max_cross_track_ratio=None, min_coordinate_fraction=None)#
Return sites in a deterministic spatial or identity order.
by='auto'applies chainage ordering only when the finite coordinates describe one credible, approximately straight survey line. Otherwise it preserves input order.by='chainage'forces projection onto the PCA profile axis; sites without usable coordinates are retained at the end in their original order.Other modes are
'input','station'(natural numeric station order),'latitude'/'lat', and'longitude'/'lon'. Station names remain identifiers and are never changed.
- to_edis(*, copy=False, progress=False, verbose=0)#
Return the underlying EDI objects as a list.
- Parameters:
- Returns:
EDI objects in site order.
- Return type:
See also
to_edicollectionReturn an
EDICollectioninstead.pycsamt.site.base.to_edisGeneral unwrapping helper.
- to_edicollection(*, copy=False, progress=False, verbose=0)#
Return the underlying EDI objects as an
EDICollection.- Parameters:
- Returns:
Collection built from the underlying EDI objects.
- Return type:
pycsamt.seg.collection.EDICollection
- to_emtf_list()#
Return the underlying EMTF XML documents as a list.
- Returns:
One document per site, in site order. EDI-native sites are lazily converted and cached via
Site.tf; XML-native sites are returned as-is, with no information loss.- Return type:
- write_xml(outdir, **kwargs)#
Write one EMTF XML file per site into a directory.
- Parameters:
outdir (str or pathlib.Path) – Destination directory. It is created if missing.
**kwargs – Forwarded to
Site.to_xml()for each site.
- Returns:
Paths to the written files, named
"{station}.xml".- Return type:
list of pathlib.Path
See also
to_emtf_listIn-memory equivalent without writing to disk.
Sites.writeThe EDI-side equivalent.
- closest(lat, lon, tol=None)#
Find the closest site to a target coordinate using geodetic distance.
- Parameters:
- Returns:
Nearest site or
Noneif all sites are too far or lack valid coordinates.- Return type:
Site or None
Notes
Coordinates are validated. Sites with non-finite values are skipped. Distance is computed in meters using a geodetic model.
Examples
>>> near = sites.closest(10.0, 20.0) >>> near is None or hasattr(near, "name") True >>> sites.closest(0.0, 0.0, tol=1.0) is None True
- map(fn)#
Apply a function to every site and collect the results.
- Parameters:
fn (callable) – Function of signature
fn(site) -> Any.- Returns:
Results collected in order.
- Return type:
Examples
>>> sites.map(lambda s: s.name)[:2] ['E01', 'E02']
- rename(names, *, inplace=False, missing='raise', allow_duplicates=False)#
Rename stations from a mapping, sequence, or callable.
- update_metadata(updates, *, inplace=False, missing='raise', allow_duplicates=False)#
Apply declarative station, HEAD, INFO, and coordinate updates.
- edit_all(*, rename=None, freq_slice=None, mask=None, inplace=False)#
Bulk-edit all sites with optional rename, frequency slicing, and tensor masking.
- Parameters:
rename (callable, optional) – Function
rename(old_name) -> new_name. If provided, each site is renamed accordingly.freq_slice (slice, optional) – Row-wise slice applied consistently to frequency, impedance Z, errors, and derived arrays.
mask (callable, optional) – Function
mask(df) -> bool_serieswheredfis the output ofsite.to_dataframe("z"). Rows where the mask isFalseare set toNaNin Z.inplace (bool, optional) – If
True, modify this container and return it. IfFalse, return a newSites. Default isFalse.
- Returns:
The edited container (possibly the same instance).
- Return type:
Notes
When
inplace=False, sites are shallow-cloned so that edits do not affect the original container.Frequency slicing is applied atomically to avoid temporary shape mismatches between
freqand Z-derived arrays.Missing arrays are tolerated on a best-effort basis.
Examples
- Rename with a prefix
>>> def rnm(n): ... return "X_" + n >>> out = sites.edit_all(rename=rnm) >>> [s.name for s in out][:2] ['X_E01', 'X_E02']
- Slice away the first frequency
>>> sl = slice(1, None) >>> out2 = sites.edit_all(freq_slice=sl) >>> len(out2["E01"].freq) == len(sites["E01"].freq) - 1 True
- Mask the top half of rows in Z
>>> def top_half(frame): ... m = np.ones(len(frame), dtype=bool) ... m[: len(frame) // 2] = False ... return m >>> out3 = sites.edit_all(mask=top_half) >>> df = out3["E01"].to_dataframe("z") >>> np.isnan(df.iloc[0].values).all() True
See also
Site.renamePer-site rename helper.
Site.to_dataframeSource for building masks.
- with_topography(frame, *, inplace=False)#
Align site coordinates and elevation from a tabular frame.
- Parameters:
frame (Any) – A table-like object (e.g.,
pandas.DataFrame) with station identifiers and columns for latitude, longitude, and elevation. Column names are resolved by the topography utility.inplace (bool, optional) – If
True, modify this container and return it. IfFalse, return a newSites. Default isFalse.
- Returns:
Container with updated coordinates.
- Return type:
Notes
Sites are matched by normalized station identifiers. The operation is performed on a best-effort basis; unmatched stations are left unchanged.
Examples
>>> import pandas as pd >>> df = pd.DataFrame( ... { ... "station": ["E01", "E02"], ... "latitude": [10.0, 11.0], ... "longitude": [20.0, 21.0], ... "elevation": [100.0, 200.0], ... } ... ) >>> out = sites.with_topography(df, inplace=False) >>> tuple(round(v, 3) for v in out["E01"].coords) (10.0, 20.0, 100.0)
- select(names=None, predicate=None)#
Filter sites by explicit names or by a boolean predicate.
- Parameters:
names (sequence of str, optional) – Case-insensitive station names to retain. If provided, this takes precedence over
predicate.predicate (callable, optional) – Function
predicate(site) -> bool. Sites for which the function returnsTrueare retained.
- Returns:
New container with the selected sites.
- Return type:
Notes
If neither
namesnorpredicateis provided, the method returns a shallow copy of the current container.Examples
>>> subset = sites.select(names=["E02"]) >>> [s.name for s in subset] ['E02'] >>> subset2 = sites.select(predicate=lambda s: s.has_component("Zxy")) >>> isinstance(subset2, Sites) True
- classmethod from_any(source, topo_src=None)#
Construct a container from heterogeneous inputs by using a normalized loading session.
- Parameters:
source (Any) – Input that can be understood by the loader. Supported cases include: - an
EDICollection, - a list ofEDIFile, - a singleEDIFile, - or an iterable that yields EDIs.topo_src (Any, optional) – Optional topography source passed to the session for use during loading. The default is
None.
- Returns:
Parsed container. Returns an empty container if the input cannot be interpreted.
- Return type:
Notes
The method uses
normalize_session()to handle parsing, discovery, and optional topography alignment in a consistent way.Examples
>>> from pycsamt.seg.collection import EDICollection >>> # edicol = ... # suppose we already parsed a folder >>> # sites = Sites.from_any(edicol) >>> # isinstance(sites, Sites) True
- write(outdir, *, template='{station}.edi', exist_ok=False)#
Write one EDI file per site to a directory.
- Parameters:
outdir (str or pathlib.Path) – Destination directory. It is created if missing.
template (str, optional) – Filename template. The token
{station}is replaced by the normalized station name. Default is"{station}.edi".exist_ok (bool, optional) – If
Falseand a file already exists, raiseFileExistsError. IfTrue, overwrite. Default isFalse.
- Returns:
Paths to the written files.
- Return type:
list of pathlib.Path
- Raises:
FileExistsError – If a target file exists and
exist_okisFalse.
Notes
Serialization goes through
pycsamt.emtf.converters.edi.write_edi(), which writes the underlyingEDIFileto an exact target path (working aroundwrite()’s own default of deriving anew_-prefixed name under a localedi_out/directory when not given an explicitnew_edifn/savepath).Examples
>>> import tempfile, pathlib >>> tmp = pathlib.Path(tempfile.mkdtemp()) >>> paths = sites.write(tmp, exist_ok=True) >>> all(p.exists() for p in paths) True
- to_profile(origin, azimuth, *, crs=None)#
Convert sites to a 1D profile aligned with a specified azimuth, returning either a rich Profile object or a lightweight fallback.
- Parameters:
- Returns:
If
Profileis available, a Profile is returned. Otherwise a dict is returned with keys"origin","azimuth", and"sites"in chainage order.- Return type:
Profile or dict
Notes
The fallback computes local chainage by a flat approximation around
origin:\[\begin{split}ch = dx * \\sin(az) + dy * \\cos(az)\end{split}\]where
dxanddyare metric offsets relative to the origin. Sites lacking valid coordinates are skipped.Examples
>>> prof = sites.to_profile(origin=(0.0, 0.0), azimuth=90.0) >>> hasattr(prof, "chainages") or isinstance(prof, dict) True
See also
pycsamt.site.profile.ProfileRich profile object when available.
- pycsamt.site.to_edis(x, *, as_collection=False, copy=False, recursive=True, on_dup='replace', strict=False, verbose=0, progress=False)#
Unwrap site-like inputs to raw EDI objects.
This is the inverse boundary of
to_sites(). It accepts a singleSite, aSitescollection, anEDICollection, raw EDI objects, path-like inputs, or mixed iterables containing those forms. The returned objects are the underlying EDI containers used by low-level writers, exporters, and EM processing functions.- Parameters:
x (Any) – Site-like input to unwrap. Supported values include
Site,Sites,EDIFile,EDICollection, path-like inputs, or iterables containing site/EDI-like objects.as_collection (bool, default False) – If
True, return anEDICollection. Otherwise a single input returns one EDI object and multi-item inputs return a list.copy (bool, default False) – If
True, return best-effort deep copies of the EDI objects. If copying fails for an item, that item is returned unchanged.recursive (bool, default True) – Forwarded to path-like discovery through
EDICollection.on_dup ({'replace', 'keep', 'keep_first', 'keep_last', 'raise'}, default 'replace') – Duplicate station policy.
replaceandkeepare forwarded to path loading.keep_first,keep_last, andraiseare enforced after collection construction.strict (bool, default False) – If
True, raise when an object cannot be unwrapped to EDI. IfFalse, invalid items are skipped.verbose (int, default 0) – Verbosity forwarded to collection construction and duplicate policy diagnostics.
progress (bool or {'auto'}, default False) – Enable progress display while unwrapping iterable inputs.
- Returns:
Raw EDI object(s), depending on the input shape and
as_collection.- Return type:
Notes
The operation is shallow by default. It returns the same EDI objects wrapped by
SiteorSites. Passcopy=Truewhen the caller should be able to mutate the returned objects independently.Examples
>>> from pycsamt.site.base import Site, Sites, to_edis >>> site = Site(edi) >>> raw = to_edis(site) >>> raw is edi True >>> raws = to_edis(Sites([edi])) >>> len(raws) 1 >>> coll = to_edis(Sites([edi]), as_collection=True) >>> len(coll) 1
See also
to_sitesWrap raw EDI-like inputs into
Sites.Site.to_ediConvenience method for one
Site.Sites.to_edisConvenience method for a
Sitescollection.
- pycsamt.site.rotate(site, angle_deg, *, inplace=False)#
Rotate impedance tensor Z (and tipper T, if present) by an azimuthal angle in degrees.
The rotation is applied in the horizontal plane using the similarity transform \(Z' = R Z R^{-1}\), where \(R\) is the 2x2 rotation matrix built from
angle_deg. When a tipper is available (either on the EDI object asT/TIP/Tipor attached toZ), the 2-component vector is rotated consistently.- Parameters:
site (Any) – An EDI-like object (e.g.,
pycsamt.seg.edi.EDIFile) or wrapper exposing aZsection compatible with a complex 2x2 impedance array and, optionally, a tipper.angle_deg (float) – Rotation angle in degrees. Positive values rotate the measurement axes according to the internal convention of this package. If your acquisition system defines the sign oppositely, use the negative of your desired angle.
inplace (bool, optional) – If
True, mutatesitein place. Otherwise, work on a shallow copy and return that copy. Default isFalse.
- Returns:
The rotated object. If
inplaceisTrue, this is the same object assite; otherwise a new object.- Return type:
Any
Notes
Error arrays (
z_erroror aliases) are rotated with a magnitude-only scheme (using absolute values of the rotation matrices) as a pragmatic best-effort. This is a common, but approximate, practice.Only arrays with shapes consistent with MT tensors (
(n, 2, 2)for Z,(n, 2)for T) are rotated. Other shapes are ignored silently.The function is no-throw by design. If a section is not present or incompatible, it is skipped.
Examples
>>> from pycsamt.seg.edi import EDIFile >>> from pycsamt.site.edit import rotate >>> ed = EDIFile("path/to/station.edi") >>> ed_rot = rotate(ed, 30.0) # copy by default >>> ed_rot2 = rotate(ed, -45.0, inplace=True)
See also
select_freqSubset rows by frequency range or indices.
renameRename the station using a policy or explicit name.
pycsamt.site.edit.rotate_allBroadcast rotation over a collection.
References
[rotate-1]Simpson, F. and Bahr, K. (2005). Practical Magnetotellurics. Cambridge Univ. Press.
[rotate-2]SEG EDI format usage notes for MT tensors.
- pycsamt.site.select_freq(site, *, fmin=None, fmax=None, keep=None, inplace=False)#
Subset the dataset along frequency by range or explicit indices, keeping all affected arrays aligned.
This applies the selection to every frequency-indexed array found on the object, including Z, Z errors, derived resistivity/phase, and any tipper arrays resident on either the root EDI object or under its
Zsection.- Parameters:
site (Any) – An EDI-like object (e.g.,
pycsamt.seg.edi.EDIFile) with a discoverable frequency vector.fmin (float, optional) – Keep rows with
freq >= fmin. Ignored ifNone.fmax (float, optional) – Keep rows with
freq <= fmax. Ignored ifNone.keep (Iterable[int] or numpy.ndarray, optional) – Explicit indices or a boolean mask to keep. If provided,
fminandfmaxare ignored. Use integer indices for exact row picks, or a boolean mask of the same length as the frequency vector.inplace (bool, optional) – If
True, mutatesitein place. Otherwise, operate on a shallow copy. Default isFalse.
- Returns:
The object after selection. If
inplaceisTrue, this is the same object assite; otherwise a new object.- Return type:
Any
Notes
All known aliases are sliced consistently (e.g., frequency, Z, Z error, resistivity, phase, tipper, and related per-row arrays) to preserve alignment.
If the frequency vector is empty or missing, the call is a no-op.
The function is no-throw by design; incompatible shapes are skipped silently.
Examples
Keep only rows with frequency >= 10 Hz:
>>> from pycsamt.seg.edi import EDIFile >>> from pycsamt.site.edit import select_freq >>> ed = EDIFile("path/to/station.edi") >>> ed_hi = select_freq(ed, fmin=10.0)
Keep the first and last rows explicitly:
>>> sel = [0, -1] >>> ed_edge = select_freq(ed, keep=sel)
Apply in place:
>>> _ = select_freq(ed, fmin=1.0, fmax=100.0, inplace=True)
See also
References
[select-freq-1]SEG EDI format usage notes for frequency-indexed MT arrays.
- pycsamt.site.rename(site, name=None, policy=None, *, inplace=False)#
Rename a station using an explicit name or a policy function.
This updates common station identifiers across the EDI header and attempts to keep them in sync so that downstream code resolves the new name consistently.
- Parameters:
site (Any) – An EDI-like object (e.g.,
pycsamt.seg.edi.EDIFile) or wrapper with a modifiable HEAD section.name (str, optional) – Explicit new station name to set. If provided, this takes precedence over
policy.policy (Callable[[str], str], optional) – A function mapping the current station name to a new one. Ignored when
nameis provided.inplace (bool, optional) – If
True, mutatesitein place. Otherwise, operate on a shallow copy. Default isFalse.
- Returns:
The object with updated identifiers. If
inplaceisTrue, this is the same object assite; otherwise a new object.- Return type:
Any
Notes
The function writes multiple header fields when present (e.g.,
dataid,station, and other common aliases) and also mirrors the name toedi.name. This increases the chance that name resolution remains stable across different readers.The rename operation does not touch on-disk filenames. File paths remain unchanged unless you later write out using a template that depends on the station name.
If both
nameandpolicyare given,namewins.
Examples
Policy-based rename:
>>> from pycsamt.seg.edi import EDIFile >>> from pycsamt.site.edit import rename >>> ed = EDIFile("path/to/station.edi") >>> ed2 = rename(ed, policy=lambda n: f"X_{n}")
Explicit name, in place:
>>> _ = rename(ed, name="ST123A", inplace=True)
See also
rotateRotate Z and tipper by an azimuth angle.
select_freqSubset rows by frequency range or indices.
pycsamt.site.edit.rename_allBroadcast rename over a collection.
pycsamt.site.base.SiteWrapper that resolves a stable site name for indexing.
References
[rename-1]SEG EDI format field naming and common aliases for station identifiers.
- pycsamt.site.set_coords(site, *, lat=None, lon=None, elev=None, inplace=False)#
Set geographic coordinates on the EDI header.
Only the values explicitly provided are updated. The call delegates to the same coordinate writer used by the Site API, so downstream tools see consistent lat, lon, and elev fields.
- Parameters:
site (Any) – An EDI-like object (e.g.,
pycsamt.seg.edi.EDIFile) or wrapper exposing a mutable HEAD section.lat (float, optional) – Latitude in degrees. If
None, the field is left unchanged.lon (float, optional) – Longitude in degrees. If
None, the field is left unchanged.elev (float, optional) – Elevation in meters. If
None, the field is left unchanged.inplace (bool, optional) – If
True, mutatesitein place. Otherwise, work on a shallow copy and return that copy. Default isFalse.
- Returns:
The updated object. If
inplaceisTrue, this is the same object assite; otherwise a new object.- Return type:
Any
Notes
The function validates numeric types and writes to common HEAD attribute names (
lat,lon,elev).If a field is not present in the header, a best-effort attribute is created.
Examples
>>> from pycsamt.seg.edi import EDIFile >>> from pycsamt.site.edit import set_coords >>> ed = EDIFile("path/to/station.edi") >>> ed2 = set_coords(ed, lat=35.1, lon=12.8, elev=1234.0) >>> _ = set_coords(ed, lat=36.0, inplace=True)
See also
pycsamt.site.base.Site.set_coordsObject-oriented wrapper.
pycsamt.site.edit.set_coords_allBroadcast over a collection.
References
[set-coords-1]SEG EDI format, HEAD section fields for station coordinates.
- pycsamt.site.fill_missing(site, *, how='zero', components=('Z', 'Tip'), inplace=False)#
Replace missing or non-finite values in Z and/or tipper arrays with zeros or NaNs.
The operation preserves shapes and alignment across arrays. If an array is absent, a new one is allocated with the correct shape inferred from the frequency vector.
- Parameters:
site (Any) – An EDI-like object with a discoverable frequency vector and optionally Z and tipper sections.
how ({"zero", "nan"}, optional) – Replacement policy. Use
"zero"to fill with numeric zeros. Use"nan"to fill with NaN for all non-finite entries. Default is"zero".components (Iterable[str], optional) – Which components to process. Accepts items like
"Z"or"Tip"(case-insensitive). Default is("Z", "Tip").inplace (bool, optional) – If
True, mutate in place. Otherwise, operate on a shallow copy and return that copy. Default isFalse.
- Returns:
The object after filling. If
inplaceisTrue, this is the same object assite; otherwise a new object.- Return type:
Any
Notes
Z arrays are expected as shape
(n, 2, 2)and tipper as(n, 2). Only arrays with the expected shapes are modified or allocated.When Z exists, the function also fills common aliases for errors and derived quantities, such as
z_error,rho(resistivity), andphasearrays, if present.The frequency vector length
ndefines the number of rows used for any new arrays.This function is no-throw by design. Incompatible or absent pieces are skipped silently.
Examples
Fill Z and tipper with zeros where values are non-finite:
>>> from pycsamt.seg.edi import EDIFile >>> from pycsamt.site.edit import fill_missing >>> ed = EDIFile("path/to/station.edi") >>> ed2 = fill_missing(ed, how="zero")
Fill only Z with NaNs, in place:
>>> _ = fill_missing(ed, how="nan", components=("Z",), inplace=True)
See also
select_freqSubset rows by frequency while keeping arrays aligned.
rotateRotate Z and tipper by an azimuth angle.
References
[fill-missing-1]Simpson, F. and Bahr, K. (2005). Practical Magnetotellurics. Cambridge Univ. Press.
[fill-missing-2]SEG EDI format usage notes for MT arrays and tipper.
- pycsamt.site.recompute_res_phase(site, *, inplace=False)#
Recompute apparent resistivity and phase from the impedance tensor Z for a single site.
The function looks for a
Zsection and, if present, calls itscompute_resistivity_phase()method. The operation is best-effort and suppresses exceptions.- Parameters:
site (Any) – An EDI-like object (
EDIFile) or a wrapper exposing aZsection with the expected API.inplace (bool, optional) – If
True, mutate the given object in place. Otherwise work on a shallow copy and return it. Default isFalse.
- Returns:
The mutated object (in place) or a new object (copy).
- Return type:
Any
Notes
Derived quantities are typically written under common aliases (e.g.,
rhoorresistivityfor apparent resistivity in ohm-m, andphasein degrees).The method assumes Z has shape
(n, 2, 2)and that a frequency vector is present. If these are missing or incompatible, nothing is changed.
Examples
Single-site:
>>> from pycsamt.seg.edi import EDIFile >>> from pycsamt.site.edit import recompute_res_phase >>> ed = EDIFile("path/to/station.edi") >>> ed2 = recompute_res_phase(ed)
In place:
>>> _ = recompute_res_phase(ed, inplace=True)
See also
select_freqKeep a subset of rows by frequency.
fill_missingEnsure arrays are allocated and finite before recomputation.
pycsamt.site.base.Site.to_dataframeInspect derived arrays.
References
[recompute-res-phase-1]Simpson, F. and Bahr, K. (2005). Practical Magnetotellurics. Cambridge Univ. Press.
[recompute-res-phase-2]SEG EDI format usage notes for derived MT quantities.
- pycsamt.site.rotate_all(sites, angle_deg, *, inplace=False)#
Rotate every site in a collection by an azimuthal angle in degrees.
This is the broadcast variant of
rotate(). It accepts either aSiteswrapper or any iterable of EDI-like objects and returns a newSitesunlessinplaceis requested.- Parameters:
sites (Any) – A
pycsamt.site.base.Sitesinstance or any iterable of EDI-like objects.angle_deg (float) – Rotation angle in degrees, passed through to
rotate().inplace (bool, optional) – If
True, attempt to apply the rotation in place on the given container. Otherwise, return a newSites. Default isFalse.
- Returns:
A sites collection holding the rotated items, or the original container when mutated in place.
- Return type:
Notes
The function preserves the input order of items.
If some items lack compatible arrays, they are skipped silently.
Examples
Using a list of EDI files:
>>> from pycsamt.seg.edi import EDIFile >>> from pycsamt.site.edit import rotate_all >>> eds = [EDIFile("A.edi"), EDIFile("B.edi")] >>> ro = rotate_all(eds, 15.0)
Using a Sites wrapper:
>>> from pycsamt.site.base import Sites >>> sites = Sites(eds) >>> ro2 = rotate_all(sites, -30.0)
See also
rotateSingle-site rotation.
select_freq_allBroadcast selection by frequency.
- pycsamt.site.select_freq_all(sites, *, fmin=None, fmax=None, keep=None, inplace=False)#
Subset all sites in a collection along frequency, keeping arrays aligned.
This is the broadcast variant of
select_freq(). It accepts aSiteswrapper or any iterable of EDI-like objects and returns a newSitesunlessinplaceis requested.- Parameters:
sites (Any) – A
pycsamt.site.base.Sitesinstance or any iterable of EDI-like objects.fmin (float, optional) – Keep rows with
freq >= fmin. Ignored ifNone.fmax (float, optional) – Keep rows with
freq <= fmax. Ignored ifNone.keep (Iterable[int] or numpy.ndarray, optional) – Explicit indices or a boolean mask to keep. If provided,
fminandfmaxare ignored.inplace (bool, optional) – If
True, attempt to modify the given container in place. Otherwise, return a newSites. Default isFalse.
- Returns:
A sites collection with selection applied, or the original container when mutated in place.
- Return type:
Notes
All known frequency-indexed arrays are sliced in sync for each site (Z, errors, derived quantities, and tipper).
Items missing a frequency vector are left unchanged.
Examples
>>> from pycsamt.seg.edi import EDIFile >>> from pycsamt.site.base import Sites >>> from pycsamt.site.edit import select_freq_all >>> eds = [EDIFile("A.edi"), EDIFile("B.edi")] >>> sites = Sites(eds) >>> out = select_freq_all(sites, fmin=1.0, fmax=100.0)
Use explicit row indices for all sites:
>>> out2 = select_freq_all(eds, keep=[0, -1])
See also
select_freqSingle-site selection by frequency.
rotate_allBroadcast rotation over a collection.
References
[select-freq-all-1]SEG EDI format usage notes for frequency-indexed MT arrays.
- pycsamt.site.rename_all(sites, *, policy=None, name_fn=None, inplace=False)#
Batch rename a collection of sites.
This is the broadcast variant of
rename(). It accepts aSiteswrapper or any iterable of EDI-like objects and produces a newSites(unlessinplaceisTrue).- Parameters:
sites (Any) – A
pycsamt.site.base.Sitesinstance or any iterable of EDI-like objects.policy (Callable[[str], str], optional) – Function mapping the current station name to a new one, e.g.
lambda n: f"X_{n}". Ignored ifname_fnis provided.name_fn (Callable[[Any], str], optional) – Function mapping each EDI object to a new name, e.g. from the file stem. This takes precedence over
policyand is useful to guarantee uniqueness across sites.inplace (bool, optional) – If
True, attempt to modify the given container in place. Otherwise, return a newSites. Default isFalse.
- Returns:
A collection holding the renamed items, or the original container when mutated in place.
- Return type:
Notes
The rename updates common header identifiers and mirrors the name to
edi.namefor robust downstream resolution.If multiple sites share the same original name, a simple
policylikelambda n: "X_" + nmay produce duplicate outputs. Prefername_fnthat uses a unique attribute (e.g., the file stem) to avoid collisions.The function preserves input order and is no-throw; items that cannot be renamed are skipped.
Examples
Policy-based rename for all items:
>>> from pycsamt.site.edit import rename_all >>> out = rename_all(eds, policy=lambda n: f"X_{n}")
Unique names from file stems:
>>> from pathlib import Path >>> out = rename_all( ... eds, ... name_fn=lambda e: f"X_{Path(getattr(e, 'path', '')).stem}", ... )
See also
renameSingle-site rename helper.
set_coords_allBatch coordinate assignment.
pycsamt.site.base.SitesCollection wrapper used here.
References
[rename-all-1]SEG EDI format field naming conventions for station identifiers.
- pycsamt.site.set_coords_all(sites, src, *, inplace=False)#
Batch set coordinates for a collection of sites.
Coordinates can be provided by a callable, a mapping keyed by station name, or an object exposing a
.frameattribute with tabular data.- Parameters:
sites (Any) – A
pycsamt.site.base.Sitesinstance or any iterable of EDI-like objects.src (Any) –
- One of:
callable(edi) -> (lat, lon, elev)mapping[name] -> (lat, lon, elev)object with
.frameDataFrame-like with columns:stationplus eitherlat/lonorlatitude/longitude, and optionallyelev/elevation.
inplace (bool, optional) – If
True, attempt to modify the given container in place. Otherwise, return a newSites. Default isFalse.
- Returns:
A collection with updated coordinates, or the original container when mutated in place.
- Return type:
Notes
The lookup order is:
callablethenmappingby station name, then the optional.frametable. The first source that returns a non-Nonetriple is used.Latitude and longitude are expected in degrees; elevation in meters.
The function preserves input order and is no-throw; items without a matching entry are left unchanged.
Examples
From a mapping keyed by names:
>>> from pycsamt.site.edit import set_coords_all >>> coords = {"S01": (35.1, 12.8, 1234.0)} >>> out = set_coords_all(eds, coords)
From a callable using file stems:
>>> from pathlib import Path >>> def pick(edi): ... stem = Path(getattr(edi, "path", "")).stem ... return (10.0, 20.0, 100.0) if stem == "S01" else \ ... (11.0, 21.0, 110.0) >>> out = set_coords_all(eds, pick)
From a pandas DataFrame holder:
>>> class Holder: ... def __init__(self, frame): ... self.frame = frame >>> out = set_coords_all(eds, Holder(df))
See also
set_coordsSingle-site coordinate update.
rename_allBatch rename helper.
pycsamt.site.base.Site.set_coordsOOP variant per site.
References
[set-coords-all-1]SEG EDI HEAD section fields for station coordinates.
- pycsamt.site.set_coords_from_table(sites, table, *, columns=None, crs_from=None, to_crs='EPSG:4326', inplace=False)#
Set site coordinates for many EDI files from a table.
This high-level helper accepts a wide range of table-like objects (CSV path, pandas DataFrame, numpy structured array, or list of dicts / tuples). It normalizes column names, optionally projects easting/northing to lon/lat, builds a mapping
{station: (lat, lon, elev)}, and delegates toset_coords_all().- Parameters:
sites (Any) – A
Sitesinstance, an iterable ofEDIFileobjects, or anything accepted byset_coords_all().table (Any) –
- One of:
Path to a CSV or whitespace-delimited text file.
A
pandas.DataFrame.A numpy structured array.
A list of dicts or a list of tuples.
columns (dict, optional) – Explicit column mapping. Keys are canonical names and values are the actual column names present in
table. Supported canonical keys are:'station','lat','lon','elev','easting','northing'. Matching is case-insensitive.crs_from (str, optional) – Source CRS used when the table provides
eastingandnorthinginstead oflatandlon. Required in that case. Example:'EPSG:32631'for UTM 31N.to_crs (str, default "EPSG:4326") – Target CRS for output coordinates. The default is WGS84 lon/lat.
inplace (bool, default False) – If
True, mutate the given collection and return it. Otherwise return a newSiteswith updated EDI objects.
- Returns:
The same semantics as
set_coords_all(): either the mutated input (inplace=True) or a newSitesinstance.- Return type:
Any
- Raises:
ValueError – If the
stationcolumn cannot be resolved, or if neither (lat,lon) nor (easting,northing) can be resolved, or ifcrs_fromis required but missing.ImportError – If projection is needed (
easting/northingpresent) butpyprojis not installed.
Notes
Column detection is case-insensitive and understands common aliases:
station:station,name,site,id.lat:lat,latitude.lon:lon,long,longitude.elev:elev,elevation,z.easting:easting,x.northing:northing,y.
When both geographic and projected fields are present, the geographic pair (
lat,lon) is preferred. If only projected fields are present, a validcrs_frommust be provided andpyprojwill be used for projection.Examples
Load from a CSV path with standard columns:
>>> from pycsamt.site.edit import set_coords_from_table >>> from pycsamt.site.base import Sites >>> edis = Sites([...]) # your EDI files >>> out = set_coords_from_table( ... edis, "coords.csv", inplace=False ... ) >>> isinstance(out, Sites) True
Pass a DataFrame with aliases and an explicit mapping:
>>> import pandas as pd >>> df = pd.DataFrame({ ... "name": ["S01", "S02"], ... "latitude": [35.1, 35.2], ... "long": [12.8, 12.9], ... "elevation": [120.0, 130.0], ... }) >>> out = set_coords_from_table( ... edis, ... df, ... columns={"station": "name", ... "lat": "latitude", ... "lon": "long", ... "elev": "elevation"}, ... inplace=False, ... )
Use easting/northing with a source CRS:
>>> df = pd.DataFrame({ ... "station": ["S10"], ... "easting": [400000.0], ... "northing": [5750000.0], ... }) >>> out = set_coords_from_table( ... edis, ... df, ... crs_from="EPSG:32631", # UTM 31N ... inplace=False, ... )
See also
set_coords_allBroadcast setting of coordinates using a mapping.
set_coordsSingle-site coordinate update helper.
References
[set-coords-from-table-1]EPSG Geodetic Parameter Registry, https://epsg.org/
[set-coords-from-table-2]pyproj documentation, https://pyproj4.github.io/pyproj/
- pycsamt.site.set_coords_from_en(site, easting, northing, *, crs_from, elev=None, to_crs='EPSG:4326', inplace=False)#
Project (easting, northing) to lon/lat and set a site’s coords.
This convenience wraps projection and assignment for a single EDI site. It projects the provided easting/northing from
crs_fromtoto_crs(default WGS84 lon/lat), then callsset_coords().- Parameters:
site (Any) – A single EDI-like object compatible with
set_coords().easting (float) – Easting value in meters for the source CRS.
northing (float) – Northing value in meters for the source CRS.
crs_from (str) – The EPSG or PROJ string that identifies the source CRS, for example
'EPSG:32631'for UTM 31N.elev (float, optional) – Elevation in meters to store in the EDI header. If not provided, the previous elevation is kept (if any).
to_crs (str, default "EPSG:4326") – Target CRS for output coordinates. The default is WGS84 lon/lat.
inplace (bool, default False) – If
True, mutate the given object and return it. Otherwise work on a copy and return the copy.
- Returns:
The mutated site (
inplace=True) or a new site object with updated coordinates.- Return type:
Any
- Raises:
ImportError – If
pyprojis not installed.Exception – Any errors raised by the underlying projection engine or by
set_coords()may propagate.
Notes
Projection uses
pyprojwithalways_xy=Trueso that the axis order is interpreted as (lon, lat). Units are assumed to be meters for the easting and northing values.The returned object follows the same semantics as
set_coords(). If you need to update many sites, preferset_coords_from_table()orset_coords_all().Examples
Update a single site from UTM 31N (EPSG:32631) coordinates:
>>> from pycsamt.site.edit import set_coords_from_en >>> site = ... # an EDIFile >>> site2 = set_coords_from_en( ... site, ... easting=400000.0, ... northing=5750000.0, ... crs_from="EPSG:32631", ... elev=250.0, ... inplace=False, ... )
Do the update in place and keep the existing elevation:
>>> _ = set_coords_from_en( ... site, ... easting=500000.0, ... northing=4600000.0, ... crs_from="EPSG:32630", ... inplace=True, ... )
See also
set_coordsAssign lat, lon, elev on a single site.
set_coords_from_tableBatch update from tabular input.
set_coords_allBroadcast update using a mapping.
References
[set-coords-from-en-1]EPSG Geodetic Parameter Registry, https://epsg.org/
[set-coords-from-en-2]pyproj documentation, https://pyproj4.github.io/pyproj/
- pycsamt.site.by_names(sites, patterns, *, case=False)#
Select sites by matching station names against one or more patterns.
This is a flexible name-based selector that accepts several pattern types:
string with optional glob-like wildcards
*and?compiled regular expression (
re.Pattern)callable
fn(name)->booliterable of any mix of the above
A site is kept if any pattern matches its station name. Matching is stable: the relative order of kept sites is the same as in the input.
- Parameters:
sites (Any) – A
Sitesinstance, anEDICollection, a sequence ofEDIFileobjects, or any iterable yielding EDI-like objects.patterns (Iterable[Any] or Any) – One pattern or an iterable of patterns. See the list above for supported pattern types.
case (bool, optional) – If
True, perform case-sensitive matching. IfFalse(default) names and string patterns are upper-cased before comparison.
- Returns:
A new
Siteswrapper containing only the matched EDI items. The original container is not modified.- Return type:
Notes
String patterns support a minimal glob syntax.
*matches any sequence (possibly empty) and?matches any single character. If you need full regular expressions, pass a compiledre.Pattern.When multiple patterns are given, the match is an OR over all patterns. Matching uses the station name as returned by
station_name(ed)which reflects header normalization.Examples
>>> from pycsamt.site.base import Sites >>> from pycsamt.site.selection import by_names >>> sites = Sites([e1, e2, e3]) # EDIFile objects >>> out = by_names(sites, "K*") # glob: all names starting K >>> [s.name for s in out] ['K01', 'K02']
>>> import re >>> rx = re.compile(r"^S0[1-3]$") >>> out = by_names(sites, rx) >>> [s.name for s in out] ['S01', 'S02', 'S03']
>>> out = by_names(sites, lambda n: n.endswith("A")) >>> [s.name for s in out] ['X1A', 'X2A']
See also
pycsamt.site.selection.by_indexSelect by numeric positions.
pycsamt.site.selection.by_predicateKeep sites for which a boolean predicate returns True.
pycsamt.site.selection.by_freqKeep sites that contain data within a frequency window.
References
[by-names-1]Python re module documentation.
[by-names-2]Unix shell-style wildcards (glob) convention.
- pycsamt.site.by_index(sites, indices)#
Select sites by zero-based numeric indices, supporting negative indices.
Indices are normalized exactly like Python sequence indexing:
-1addresses the last item,-2the one before last, and so on. Out-of-range or non-integer indices are ignored. The resulting subset preserves the original ordering of the selected items, not the order in which indices are provided.- Parameters:
- Returns:
A new
Siteswrapper containing only items at the requested positions. If no valid indices remain after normalization, an emptySitesis returned.- Return type:
Notes
Duplicate indices are de-duplicated in the output since the selection is implemented as a membership test over the set of normalized indices. The relative order of kept items is the same as in the original sequence.
Examples
>>> from pycsamt.site.base import Sites >>> from pycsamt.site.selection import by_index >>> sites = Sites([e1, e2, e3]) # names: A, B, C >>> out = by_index(sites, [0, -1]) # first and last >>> [s.name for s in out] ['A', 'C']
>>> out = by_index(sites, 1) # single integer >>> [s.name for s in out] ['B']
>>> out = by_index(sites, [10, -10]) # both invalid -> empty >>> len(out) 0
See also
pycsamt.site.selection.by_namesName-based matching using strings, regex, or callables.
pycsamt.site.selection.by_chainageSelect by stored chainage range when available.
pycsamt.site.base.Sites.by_indexRandom access to a single site by position.
- pycsamt.site.by_chainage(sites, smin, smax)#
Select sites whose stored chainage falls within a closed interval.
This helper reads the chainage value first from the EDI
HEADsection (head.chainage) and, if missing, from a top-level attributeedi.chainage. Sites for which a numeric chainage cannot be determined are silently skipped.- Parameters:
- Returns:
A new
Siteswrapper containing only the EDI items whose chainage \(c\) satisfies \(smin \\le c \\le smax\).- Return type:
Notes
Chainage is a linear reference commonly used along profiles or lines, typically measured in meters from a chosen origin. If chainage is not present on a site, that site is excluded. The original order of sites is preserved among the kept items.
Examples
>>> from pycsamt.site.base import Sites >>> from pycsamt.site.selection import by_chainage >>> s = Sites([e1, e2, e3]) # EDIFile objects >>> out = by_chainage(s, smin=100.0, smax=300.0) >>> [t.name for t in out] ['L02', 'L03']
See also
pycsamt.site.selection.by_indexSelect by zero-based positions with negative support.
pycsamt.site.selection.by_namesSelect by station names using glob, regex, or callables.
pycsamt.site.selection.by_freqKeep sites that contain data in a frequency window.
pycsamt.site.base.Sites.to_profileBuild a profile or ordered view along a line.
References
[by-chainage-1]Linear referencing and chainage in civil engineering.
- pycsamt.site.by_freq(sites, fmin, fmax)#
Select sites that contain at least one data row with frequency inside a closed interval.
A site is kept if its frequency array
fcontains any finite value satisfying \(fmin \le f \le fmax\). Sites with empty or non-finite frequency arrays are skipped.- Parameters:
- Returns:
A new
Siteswrapper containing only the EDI items with at least one finite frequency in the requested window.- Return type:
Notes
Frequencies are obtained via
pycsamt.site.utils.get_freq(ed). The check is membership based (any row in range), not a full slicing or resampling. Usepycsamt.site.edit.select_freq()to actually subset rows by frequency.Examples
>>> from pycsamt.site.base import Sites >>> from pycsamt.site.selection import by_freq >>> s = Sites([e1, e2, e3]) # EDIFile objects >>> out = by_freq(s, fmin=0.5, fmax=2.0) >>> [t.name for t in out] ['A02', 'A03']
See also
pycsamt.site.selection.by_namesName-based selection using glob, regex, or callables.
pycsamt.site.selection.by_chainageSelect by stored chainage range when available.
pycsamt.site.edit.select_freqSubset frequency rows within sites.
- pycsamt.site.by_bbox(sites, minlat, minlon, maxlat, maxlon)#
Select sites that fall inside an axis-aligned geographic box.
The selection is performed in latitude/longitude degrees and assumes a geographic CRS (WGS84-like). A site is kept if its stored coordinates satisfy
\[minlat \le lat \le maxlat \;\;\text{and}\;\; minlon \le lon \le maxlon .\]- Parameters:
sites (Any) – A
Sitesinstance, anEDICollection, a sequence ofEDIFileobjects, or any iterable yielding EDI-like items.minlat (float) – Latitude and longitude bounds in degrees. Bounds are inclusive.
minlon (float) – Latitude and longitude bounds in degrees. Bounds are inclusive.
maxlat (float) – Latitude and longitude bounds in degrees. Bounds are inclusive.
maxlon (float) – Latitude and longitude bounds in degrees. Bounds are inclusive.
- Returns:
A new
Siteswrapper with only the items whose coords are inside the box.- Return type:
Notes
This is a simple axis-aligned test in lat/lon and does not handle antimeridian wrapping. If longitudes cross the antimeridian (for example, from 170 to -170 deg), split the selection into two boxes and union the results. Coordinates are retrieved via
pycsamt.site.utils.get_coords().Examples
>>> from pycsamt.site.base import Sites >>> from pycsamt.site.selection import by_bbox >>> s = Sites([e1, e2, e3]) # EDIFile objects >>> out = by_bbox(s, 24.0, 9.0, 27.0, 11.0) >>> [site.name for site in out] ['S01', 'S03']
See also
pycsamt.site.selection.by_freqKeep sites with at least one frequency inside a window.
pycsamt.site.selection.by_chainageSelect by stored chainage range.
pycsamt.site.selection.by_predicateArbitrary user-defined filtering.
pycsamt.site.base.Sites.closestFind the closest site to a target coordinate.
References
[by-bbox-1]Snyder, J. P., “Map Projections: A Working Manual”, USGS Professional Paper 1395.
- pycsamt.site.by_predicate(sites, pred)#
Select sites using a user-supplied predicate function.
The predicate is called for each EDI-like object and should return
Trueto keep the site. Any exception raised by the predicate is caught and treated as aFalse(site is not kept). This makes bulk filtering robust against occasional data issues.- Parameters:
- Returns:
A new
Siteswrapper containing only the sites for whichpred(site)returnedTrue.- Return type:
Notes
The objects passed to
predare the raw EDI containers, not theSitewrapper. If you prefer the wrapper API, wrap the object inside the predicate:lambda ed: Site(ed).has_component("Zxy").Examples
Keep sites that have at least 3 frequency rows:
>>> from pycsamt.site.base import Sites, Site >>> from pycsamt.site.selection import by_predicate >>> s = Sites([e1, e2, e3]) >>> out = by_predicate( ... s, lambda ed: Site(ed).freq is not None and len(Site(ed).freq) >= 3 ... ) >>> [t.name for t in out] ['A01', 'A03']
Keep sites whose name matches a rule:
>>> import re >>> from pycsamt.site.utils import station_name >>> rule = re.compile(r"^X_") >>> out = by_predicate(s, lambda ed: bool(rule.search(station_name(ed)))) >>> [t.name for t in out] ['X_E01', 'X_E02']
See also
pycsamt.site.selection.by_namesName-based selection with glob or regex patterns.
pycsamt.site.selection.drop_emptyRemove sites with no usable data arrays.
pycsamt.site.base.Sites.selectSelection API on the wrapper.
References
[by-predicate-1]Gamble, T. D. et al., “Magnetotellurics with a remote reference”, Geophysics, 44(1), 53-68, 1979.
- pycsamt.site.keep_finite_z(sites)#
Keep sites that contain at least one finite impedance value.
A site is considered to have finite data if either of the following is true:
The impedance tensor array (
Z.zorZ._z) contains any finite real or imaginary entry.If the tensor is not present, a resistivity array (
Z._resistivityorZ.rho) exists and has at least one finite value.
- Parameters:
sites (Any) – A
Sitesinstance, anEDICollection, a sequence ofEDIFileobjects, or any iterable yielding EDI-like items.- Returns:
A new
Siteswrapper with only the sites that contain finite impedance (or resistivity) values.- Return type:
Notes
This function is intended as a coarse pre-filter to remove empty placeholders and fully invalid sites before more costly processing. It does not inspect errors or phases, and it does not modify the data. If a site has a
Zcontainer but all arrays are missing or fully non-finite, the site is dropped.Examples
>>> from pycsamt.site.base import Sites >>> from pycsamt.site.selection import keep_finite_z >>> s = Sites([e1, e2, e3]) >>> out = keep_finite_z(s) >>> [t.name for t in out] ['MT01', 'MT03']
See also
pycsamt.site.selection.drop_emptyRemove sites with empty frequency or missing Z section.
pycsamt.site.edit.fill_missingAllocate arrays and replace invalid entries.
pycsamt.site.compute.res_at_freqCompute apparent resistivity at a specific frequency.
- pycsamt.site.mask_large_phase_err(sites, thresh)#
Filter out sites whose maximum phase-error exceeds a threshold.
For each site, the function inspects the phase-error array when present (common attribute names are tried, e.g.
_phase_errorphase_err). If no phase-error array is found, the site is conservatively kept. Otherwise, the site is kept only when the maximum finite phase-error is less than or equal tothresh.- Parameters:
- Returns:
New wrapper containing only sites that pass the phase error test.
- Return type:
Notes
The check uses a “best effort” attribute lookup and ignores non-finite values during the maximum computation. If the phase-error array is entirely missing, the site is kept. This behavior makes the filter robust when some sites did not store uncertainty products.
Examples
>>> from pycsamt.site.base import Sites >>> from pycsamt.site.selection import mask_large_phase_err >>> s = Sites([e1, e2, e3]) >>> out = mask_large_phase_err(s, thresh=10.0) >>> [t.name for t in out] ['E01', 'E03']
See also
pycsamt.site.selection.keep_finite_zKeep sites that contain at least one finite impedance.
pycsamt.site.selection.drop_emptyRemove sites with no usable arrays.
pycsamt.site.edit.fill_missingAllocate arrays and replace invalid entries.
References
[mask-large-phase-err-1]Gamble, T. D., Goubau, W. M., Clarke, J., “Magneto- tellurics with a remote reference”, Geophysics, 44(1), 53-68, 1979.
- pycsamt.site.drop_empty(sites)#
Drop sites that are effectively empty.
A site is considered empty when either:
The frequency vector is missing or has zero length.
The impedance container
Zis missing.The
Zcontainer is present but holds no usable arrays (for example, nozand no resistivity surrogate).
- Parameters:
sites (Any) – A
Sitesobject, anEDICollection, a sequence ofEDIFileobjects, or any iterable yielding EDI-like items.- Returns:
New wrapper that excludes empty sites.
- Return type:
Notes
This is a coarse, fast filter that checks structural presence and basic array availability. It does not test for NaN-only content; for that, consider
pycsamt.site.selection.keep_finite_z().Examples
>>> from pycsamt.site.base import Sites >>> from pycsamt.site.selection import drop_empty >>> s = Sites([e1, e2, e3]) >>> out = drop_empty(s) >>> [t.name for t in out] ['MT01', 'MT02']
See also
pycsamt.site.selection.keep_finite_zKeep only sites with finite impedance or resistivity.
pycsamt.site.selection.by_freqKeep sites that touch a target frequency window.
- pycsamt.site.strike_estimate(obj, *, method='swift', api=None)#
Estimate a strike angle from impedance tensors.
This computes a 2D geoelectric strike angle in degrees. The routine supports either a single site or many sites. For a single site a scalar angle is returned. For multiple sites a
pandas.DataFrameis returned with one row per site.- Parameters:
obj (Any) – A single EDI-like object (e.g.
EDIFile) or an iterable of EDI-like objects. Each item must expose a.Zsection of shape(n_freq, 2, 2)or be convertible to such.method (str, optional) –
Strike method. Allowed values are:
"swift"(default): grid search over 0..179 degrees that minimizes the diagonal power after rotation."groom": alias of"swift"in this lightweight mode."phase_diff": heuristic that returns0or90degrees based on the relative magnitude of off-diagonals.
api (bool | None)
- Returns:
If
objis a single site, returns a float angle in degrees within[0, 180). Ifobjis iterable, returns aDataFramewith columns:station,method,theta_deg.- Return type:
Notes
The Swift-style criterion rotates the impedance tensor \(Z\) by a test angle \(\\theta\) and minimizes
\[\begin{split}J(\\theta) = \lvert Z'_{xx} \rvert^2 + \lvert Z'_{yy} \rvert^2 ,\end{split}\]where \(Z'\) is the rotated tensor. The returned angle is the argmin over a 1 degree grid in 0..179.
The
"phase_diff"fallback returns0if median \(\\lvert Z_{xy} \rvert \ge \lvert Z_{yx} \rvert\), else90. It is intended for degraded or sparse data.This function does not alter data. If you need deterministic behavior for incomplete arrays, consider preparing tensors with
pycsamt.site.edit.fill_missing().Examples
Single site, Swift estimate:
>>> from pycsamt.seg.edi import EDIFile >>> from pycsamt.site import compute as cmp, edit as ed >>> edf = EDIFile("S01.edi") >>> edf = ed.fill_missing( ... edf, how="zero", components=("Z",), inplace=False ... ) >>> ang = cmp.strike_estimate(edf, method="swift") >>> 0.0 <= ang < 180.0 True
Many sites, returning a DataFrame:
>>> e1 = EDIFile("S01.edi") >>> e2 = EDIFile("S02.edi") >>> df = cmp.strike_estimate([e1, e2], method="phase_diff") ... >>> list(df.columns) ['station', 'method', 'theta_deg']
See also
pycsamt.site.edit.rotateRotate site tensors by a user angle.
pycsamt.site.compute.phase_slopePhase slope diagnostic over a frequency band.
References
[strike-estimate-1]Swift, C. M., 1967. A magnetotelluric investigation of an electrical conductivity anomaly in the southwestern United States. PhD thesis, MIT.
[strike-estimate-2]Groom, R. W., and R. C. Bailey, 1989. Decomposition of magnetotelluric impedance tensors in the presence of local three dimensional galvanic distortion. JGR.
- pycsamt.site.res_at_freq(obj, freq, *, how='nearest', api=None)#
Evaluate apparent resistivity at a target frequency.
Computes apparent resistivity for the \(Z_{xy}\) and \(Z_{yx}\) components at a requested frequency. Works with a single site or a collection. For a single site, a dict is returned. For multiple sites, a
pandas.DataFrameis returned.- Parameters:
obj (Any) – A single EDI-like object (e.g.
EDIFile) or an iterable of such objects. Each item must expose a.Zsection of shape(n_freq, 2, 2)and a frequency vector.freq (float) – Query frequency in Hz.
how (str, optional) –
Selection mode:
"nearest"(default): choose the nearest available frequency in the site data and report that value."interp": linearly interpolate resistivity versus frequency usingnumpy.interp. Interpolation occurs on linear frequency, not log frequency.
api (bool | None)
- Returns:
If
objis a single site, returns a dictionary with keys"res_xy","res_yx","f_used". Ifobjis iterable, returns aDataFramewith columnsstation,res_xy,res_yx,f_used.- Return type:
Notes
Apparent resistivity \(\\rho_a\) is computed as
\[\begin{split}\rho_a = \frac{\lvert Z \rvert^2} {\mu_0\,2\pi\\,f} ,\end{split}\]where \(Z\) is the complex impedance for the selected component, \(\\mu_0\) is the magnetic permeability of free space, and \(f\) is frequency in Hz.
When
how="interp", the function first computes \(\rho_a\) at all native frequencies, then interpolates the result to the query frequency using linear interpolation in frequency. If the frequency vector or impedance is missing,NaNvalues are returned.Examples
Single site, nearest selection:
>>> from pycsamt.seg.edi import EDIFile >>> from pycsamt.site import compute as cmp, edit as ed >>> edf = EDIFile("S01.edi") >>> edf = ed.fill_missing( ... edf, how="zero", components=("Z",), inplace=False ... ) >>> out = cmp.res_at_freq(edf, 150.0, how="nearest") ... >>> set(out.keys()) == {"res_xy", "res_yx", "f_used"} ... True
Single site, interpolated:
>>> out = cmp.res_at_freq(edf, 150.0, how="interp") ... >>> out["f_used"] 150.0
Many sites, DataFrame:
>>> e1 = EDIFile("S01.edi") >>> e2 = EDIFile("S02.edi") >>> df = cmp.res_at_freq([e1, e2], 1.0, how="interp") ... >>> list(df.columns) ['station', 'res_xy', 'res_yx', 'f_used']
See also
pycsamt.site.compute.strike_estimateEstimate 2D strike angle from Z.
pycsamt.site.edit.select_freqSubset site data by frequency criteria.
References
[res-at-freq-1]Vozoff, K., 1991. The magnetotelluric method. In Electromagnetic methods in applied geophysics.
[res-at-freq-2]Simpson, F., and K. Bahr, 2005. Practical Magnetotellurics. Cambridge University Press.
- pycsamt.site.phase_slope(obj, band, *, api=None)#
Estimate phase slopes within a frequency band.
For each site, this computes the least-squares slope of phase (degrees) versus \(\log_{10}(f)\) over the requested band. Two slopes are reported, one for \(Z_{xy}\) and one for \(Z_{yx}\).
If a single site is provided, a dictionary is returned. If an iterable of sites is provided, a
pandas.DataFrameis returned with one row per station.- Parameters:
- Returns:
Single site ->
{"slope_xy": float, "slope_yx": float}. Multi-site -> DataFrame with columns["station", "slope_xy", "slope_yx"].- Return type:
Notes
The phase series for each off-diagonal component is computed as
\[\begin{split}\phi(f) = \operatorname{angle}(Z(f)) \times 180/\\pi ,\end{split}\]then a straight line is fit
\[\begin{split}\phi(f) \approx a\\,\\log_{10}(f) + b\end{split}\]using
numpy.polyfit(x, y, 1)where \(x=\\log_{10}(f)\). The reported slope is \(a\) in units of degrees per decade.Rows or sites with missing data in the band are reported as
NaN. The function does not unwrap phase.Examples
Single site:
>>> from pycsamt.seg.edi import EDIFile >>> from pycsamt.site import compute as cmp, edit as ed >>> edf = EDIFile("S01.edi") >>> edf = ed.fill_missing( ... edf, how="zero", components=("Z",), inplace=False ... ) >>> out = cmp.phase_slope(edf, band=(1.0, 1000.0)) ... >>> set(out.keys()) == {"slope_xy", "slope_yx"} ... True
Many sites:
>>> e1 = EDIFile("S01.edi") >>> e2 = EDIFile("S02.edi") >>> df = cmp.phase_slope([e1, e2], band=(0.1, 10.0)) ... >>> list(df.columns) ['station', 'slope_xy', 'slope_yx']
See also
pycsamt.site.compute.strike_estimateStrike angle by Swift-style criterion.
pycsamt.site.compute.res_at_freqApparent resistivity at a target frequency.
References
[phase-slope-1]Simpson, F., and K. Bahr, 2005. Practical Magnetotellurics. Cambridge University Press.
[phase-slope-2]Vozoff, K., 1991. The magnetotelluric method. In Electromagnetic methods in applied geophysics.
- pycsamt.site.tipper_magnitude(obj, *, per_freq=False, api=None)#
Summarize or tabulate tipper magnitudes.
Computes the magnitude of the tipper vector per frequency as
\[\lVert \mathbf{T} \rVert = \sqrt{\lvert T_x \rvert^2 + \lvert T_y \rvert^2} ,\]where \(T_x, T_y\) are the complex tipper components. The result can be returned as per-frequency values or summarized statistics.
For a single site, returns a dict. For an iterable of sites, returns a
pandas.DataFrame.- Parameters:
obj (Any) – A single EDI-like object (e.g.
EDIFile) or an iterable of such objects. The tipper may be attached ased.Tip,ed.T, ored.TIPand must expose a 2-component array shaped(n_freq, 2)or(n_freq, 1, 2).per_freq (bool, optional) – If
False(default), return summary statistics (mean, median, max). IfTrue, return per-frequency values.api (bool | None)
- Returns:
- Single site:
per_freq=False->{"mean", "median", "max"}per_freq=True->{"freq", "mag"}
- Multi-site:
per_freq=False-> DataFrame with columns["station", "mean", "median", "max"]per_freq=True-> DataFrame with columns["station", "freq", "mag"]
- Return type:
Notes
If the site has no tipper section, summary statistics are
NaNand per-frequency mode yields an empty result for that site. To initialize missing arrays, considerpycsamt.site.edit.fill_missing()withcomponents=("Tip",).Frequencies are reported from the site frequency vector. The function assumes the tipper array and frequency vector are aligned along their first dimension.
Examples
Single site, summary stats:
>>> from pycsamt.seg.edi import EDIFile >>> from pycsamt.site import compute as cmp, edit as ed >>> edf = EDIFile("S01.edi") >>> edf = ed.fill_missing( ... edf, how="zero", components=("Tip",), inplace=False ... ) >>> s = cmp.tipper_magnitude(edf, per_freq=False) ... >>> set(s.keys()) == {"mean", "median", "max"} ... True
Single site, per-frequency:
>>> out = cmp.tipper_magnitude(edf, per_freq=True) ... >>> list(out.keys()) ['freq', 'mag']
Many sites, summary:
>>> e1 = EDIFile("S01.edi") >>> e2 = EDIFile("S02.edi") >>> df = cmp.tipper_magnitude([e1, e2], per_freq=False) ... >>> list(df.columns) ['station', 'mean', 'median', 'max']
See also
pycsamt.site.edit.fill_missingInitialize or sanitize Z/Tip arrays in a site.
pycsamt.site.compute.res_at_freqApparent resistivity at a target frequency.
References
[tipper-magnitude-1]Simpson, F., and K. Bahr, 2005. Practical Magnetotellurics. Cambridge University Press.
- pycsamt.site.write_site(site, path)#
Write a single site (EDI) to a target path.
This is a thin, best-effort adapter around several common EDI writer spellings. The function will create parent directories as needed and then try, in order, the following methods on
siteuntil one succeeds:write(new_edifn=path)write(path)to_file(path)save(path)
If none of these exist or succeed, a
RuntimeErroris raised.- Parameters:
site (Any) – An EDI-like object. It can be a
pycsamt.seg.edi.EDIFileor any object exposing one of the writer methods listed above.path (str or pathlib.Path) – Destination file path. Parent directories are created if they do not exist.
- Returns:
The resolved output path.
- Return type:
Notes
This function does not enforce overwrite policy. Whether an existing file is replaced depends on the underlying writer implementation of the provided
siteobject.Examples
>>> from pathlib import Path >>> from pycsamt.site.export import write_site >>> class Dummy: ... def to_file(self, p): # minimal writer ... Path(p).write_text("# dummy edi\\n", encoding="utf-8") >>> out = write_site(Dummy(), Path("out") / "S01.edi") >>> out.name 'S01.edi' >>> out.exists() True
See also
pycsamt.site.export.write_sitesBatch writing with templated filenames and optional manifest.
pycsamt.site.export.pack_zipArchive a set of sites into a zip.
References
[write-site-1]Python Software Foundation. “pathlib” and “io” modules.
- pycsamt.site.write_sites(sites, outdir, *, template='{station}.edi', exist_ok=False, manifest_csv=None)#
Write a collection of sites to a directory using a filename template.
The function accepts many input forms (
Sites, anEDICollection, any iterable of EDI-like objects, or a single object) and writes each item tooutdir. Filenames are rendered from a context and thetemplatestring.Supported template keys (filled via a safe formatter):
{station}: current station name{index}: zero-based index in the iteration order{lat},{lon},{elev}: header coordinates, or NaN{chainage}: optional header chainage, or NaN
If the rendered name does not end with
.edi, the extension is appended automatically.- Parameters:
sites (Any) – A
Sitesinstance, anEDICollection, any iterable of EDI-like objects, or a single EDI-like object. EDI-like means it implements one of:write(new_edifn=...),write(...),to_file(...), orsave(...).outdir (str or pathlib.Path) – Output directory. It is created if it does not exist.
template (str, optional) – Filename template. Defaults to
"{station}.edi".exist_ok (bool, optional) – If
False(default), raiseFileExistsErroron the first name collision insideoutdir. IfTrue, allow overwriting subject to the writer behavior.manifest_csv (str or pathlib.Path or None, optional) – If provided, write a CSV manifest with one row per written site. Columns are:
index, station, lat, lon, elev, chainage, filename, path.
- Returns:
Paths to the files written, in the same order as the input iteration.
- Return type:
list of pathlib.Path
Notes
The
indexused in templating and in the manifest is the zero-based position in the input order. Coordinate fields come from the EDI header when available; missing values are written as NaN.Examples
>>> from pathlib import Path >>> from pycsamt.site.export import write_sites >>> class EdiToFile: ... def __init__(self, name): ... self._n = name ... ... def to_file(self, p): ... Path(p).write_text(f"# {self._n}\\n", encoding="utf-8") ... ... # station name is taken from header helpers when present, ... # but the template can still use {index}. >>> outdir = Path("eds_out") >>> paths = write_sites( ... [EdiToFile("S01"), EdiToFile("S02")], ... outdir, ... template="{index:03d}_{station}", ... ) >>> [p.exists() for p in paths] [True, True]
>>> # Write with a manifest >>> mpath = Path("eds_out") / "manifest.csv" >>> _ = write_sites( ... [EdiToFile("S01"), EdiToFile("S02")], ... outdir, ... template="{station}", ... exist_ok=True, ... manifest_csv=mpath, ... ) >>> mpath.exists() True
See also
pycsamt.site.base.Sites.writeHigher-level convenience bound to a
Sitescollection.pycsamt.site.export.pack_zipCreate a zip archive instead of a directory tree.
References
[write-sites-1]Python Software Foundation. “csv” module.
- pycsamt.site.pack_zip(sites, out_zip, *, template='{station}.edi', manifest_csv=None)#
Pack a set of sites into a zip archive using a filename template.
Each input item is written to a temporary directory first, then added to the
out_ziparchive usingZIP_DEFLATED. Filenames inside the archive are rendered from the same context as inwrite_sites(). If a name lacks the.edisuffix, it is appended automatically.Optionally, a CSV manifest can be written alongside the archive.
- Parameters:
sites (Any) – A
Sitesinstance, anEDICollection, any iterable of EDI-like objects, or a single EDI-like object.out_zip (str or pathlib.Path) – Destination zip file path. Parent directories are created as needed.
template (str, optional) – Filename template for entries stored in the archive. Defaults to
"{station}.edi".manifest_csv (str or pathlib.Path or None, optional) – If provided, write a CSV manifest next to the zip. Columns:
index, station, lat, lon, elev, chainage, filename, path.
- Returns:
The path to the created zip archive.
- Return type:
Notes
Files are staged in a temporary directory and then compressed with
zipfile.ZIP_DEFLATED. Theindexused in templating and the manifest corresponds to the input iteration order. This function does not delete or modify any original EDI sources.Examples
>>> from pathlib import Path >>> from zipfile import ZipFile >>> from pycsamt.site.export import pack_zip >>> class EdiSave: ... def __init__(self, name): ... self._n = name ... ... def to_file(self, p): ... Path(p).write_text(f"# {self._n}\\n", encoding="utf-8") >>> zpath = Path("out_bundle") / "sites.zip" >>> out = pack_zip( ... [EdiSave("A01"), EdiSave("A02")], ... zpath, ... template="{station}.edi", ... manifest_csv=Path("out_bundle") / "manifest.csv", ... ) >>> out == zpath, zpath.exists() (True, True) >>> with ZipFile(zpath, "r") as zf: ... sorted(zf.namelist()) ['A01.edi', 'A02.edi']
See also
pycsamt.site.export.write_sitesWrite files to a directory instead of an archive.
References
[pack-zip-1]Python Software Foundation. “zipfile” module.
- class pycsamt.site.MetadataChange(index, old_name, new_name, changed_fields, status='updated', error=None, requested_fields=(), before=None, after=None)#
Bases:
objectDescribe the metadata changes attempted for one station.
- Parameters:
index (int) – Zero-based position of the station in the input collection.
old_name (str) – Station identity before editing.
new_name (str) – Station identity after editing. For a failed operation this remains equal to
old_name.changed_fields (tuple of str) – Canonical paths of fields whose values changed.
status ({'updated', 'unchanged', 'error'}, default='updated') – Outcome of the station-level operation.
error (str or None, default=None) – Error message captured when
status='error'.requested_fields (tuple of str, default=()) – Canonical paths requested by the metadata specification.
before (mapping or None, default=None) – Audit snapshots surrounding the operation.
after (mapping or None, default=None) – Audit snapshots surrounding the operation.
- Variables:
Notes
Instances are immutable. Use
to_dict()when serializing an audit or constructing a tabular report.Examples
>>> from pycsamt.site import MetadataChange >>> change = MetadataChange( ... 0, "18-012A", "L01_012", ("name", "head.project") ... ) >>> change.status 'updated' >>> change.to_dict()["changed_fields"] ['name', 'head.project']
See also
SiteMetadataEditor.auditReturn all station records as a DataFrame.
- to_dict()#
Return the record as a serialization-friendly dictionary.
- Returns:
Dataclass fields with tuple-valued field lists converted to ordinary lists.
- Return type:
dict of str to Any
Examples
>>> from pycsamt.site import MetadataChange >>> record = MetadataChange(0, "A01", "B01", ("name",)) >>> record.to_dict()["changed_fields"] ['name']
See also
SiteMetadataEditor.auditBuild a DataFrame from change records.
- class pycsamt.site.SiteMetadataEditor(updates, *, missing='raise', allow_duplicates=False, on_error='raise', validate_coordinates=True, allow_empty_names=False, validators=None)#
Bases:
objectApply declarative, validated, and auditable EDI metadata changes.
- Parameters:
updates (mapping, sequence, callable, pandas.DataFrame, or path-like) – Metadata source. A mapping may be keyed by current station identity or may be one specification applied to every station. A sequence is aligned with input order. A callable receives an EDI object and, optionally, its zero-based index. DataFrames and CSV files require a station column named
station,name,site,dataid, orid.missing ({'raise', 'warn', 'ignore'}, default='raise') – Policy for source keys that match no input station.
allow_duplicates (bool, default=False) – Permit duplicate final station identities. Keeping the default avoids ambiguous selection and export filenames.
on_error ({'raise', 'warn', 'ignore'}, default='raise') – Station-level failure policy.
raisepreserves batch atomicity;warnandignoreretain failed stations unchanged and commit successful stations.validate_coordinates (bool, default=True) – Validate finite latitude, longitude, and elevation values and enforce geographic latitude/longitude bounds.
allow_empty_names (bool, default=False) – Permit an empty final station identity.
validators (sequence of callable or None, default=None) – Additional validators called after each staged update. A validator receives the staged EDI and, optionally, its index. Returning
Falserejects the station; raising an exception records that exception.
- Variables:
updates (Any) – Original metadata source.
on_error (missing,) – Configured unmatched-key and station-error policies.
allow_empty_names (allow_duplicates, validate_coordinates,) – Validation switches.
validators (tuple of callable) – Custom validators in execution order.
records (list of MetadataChange) – Audit records from the latest
apply()orplan()call.output_paths (list of pathlib.Path) – Paths written by the latest
apply_and_write()call.
Notes
A station specification recognizes
name/station,lat,lon,elev,coords,head,info,sections,set,unset, andtransform. Generic paths default toHEAD. Explicit path forms arehead.<field>,info.<field>,edi.<field>, andsection.<name>.<field>.All changes are staged on deep copies. With
on_error='raise', an in-place batch is committed only after every station and final identity constraint passes validation.Examples
Rename stations and update acquisition metadata:
>>> from pycsamt.site import SiteMetadataEditor >>> editor = SiteMetadataEditor( ... { ... "18-012A": { ... "name": "L01_012", ... "coords": (5.25, -3.75, 120.0), ... "head": {"project": "LINE_01"}, ... } ... } ... ) >>> # updated = editor.apply(sites) >>> # editor.audit()[["old_name", "new_name", "status"]]
Generic actions can address nested fields:
>>> editor = SiteMetadataEditor( ... { ... "18-012A": { ... "set": {"info.processingtag": "reviewed"}, ... "transform": {"head.elev": lambda value: value + 1.5}, ... "unset": ["head.county"], ... } ... } ... )
See also
update_metadataUpdate one site or EDI-like object.
update_metadata_allUpdate a station collection.
rename_sitesRename from a mapping, sequence, or callable.
pycsamt.site.export.write_sitesExport edited stations separately.
- records_: list[MetadataChange]#
- apply(source, *, inplace=False)#
Apply the configured metadata updates.
- Parameters:
- Returns:
One-site inputs retain their logical type. Collection inputs return
Sitesunless the input is already aSitesobject edited in place.- Return type:
- Raises:
KeyError – If metadata keys are unmatched and
missing='raise'.ValueError – If names, coordinates, actions, or validators fail validation.
TypeError – If the source cannot be staged safely or an action has an invalid type.
Notes
All edits are first performed on private copies. With
inplace=Trueandon_error='raise', the original object is updated only after the complete batch passes validation.warnandignoredeliberately commit successful stations while retaining failed stations unchanged.Examples
>>> from pycsamt.site import SiteMetadataEditor >>> editor = SiteMetadataEditor({"A01": {"name": "L01_001"}}) >>> # renamed = editor.apply(sites) >>> # renamed["L01_001"].name
See also
planPreview and validate without modifying the source.
apply_and_writeApply and export in one operation.
auditReturn records from the latest operation.
- plan(source, *, api=False)#
Validate and preview changes without modifying the source.
- Parameters:
source (Site, Sites, EDI-like object, or iterable of EDI-like objects) – Station data used to evaluate the configured changes.
api (bool or None, default=False) – Passed to the API-view wrapper.
Falsereturns a pandas DataFrame,Trueforces an API frame, andNonedefers to the global API-view configuration.
- Returns:
Audit preview with one row per input station.
- Return type:
- Raises:
KeyError, ValueError, TypeError – Propagated from staged resolution and validation, according to the configured policies.
Notes
Actions run only on staged copies, so callable transformations and validators are evaluated realistically. A later
apply()invokes callables again; stateful callables should therefore be avoided.Examples
>>> from pycsamt.site import SiteMetadataEditor >>> editor = SiteMetadataEditor({"A01": {"elev": 125.0}}) >>> # preview = editor.plan(sites) >>> # preview[["old_name", "changed_fields", "status"]]
- apply_and_write(source, outdir, *, inplace=False, template='{station}.edi', exist_ok=False, manifest_csv=None)#
Apply metadata changes and export the resulting stations.
- Parameters:
source (Site, Sites, EDI-like object, or iterable of EDI-like objects) – Station data to edit and export.
outdir (path-like) – Destination directory.
inplace (bool, default=False) – Commit staged metadata changes back into
source.template (str, default='{station}.edi') – Export filename template accepted by
pycsamt.site.export.write_sites().exist_ok (bool, default=False) – Permit destinations that already exist.
manifest_csv (path-like or None, default=None) – Optional manifest CSV destination.
- Returns:
Edited result. Written paths are available in
output_paths_.- Return type:
- Raises:
KeyError, ValueError, TypeError – Propagated from metadata resolution and validation.
FileExistsError – If an export destination exists and
exist_ok=False.RuntimeError – If an EDI backend cannot write a station.
Notes
Editing and persistence remain separate internally:
apply()is completed beforepycsamt.site.export.write_sites()is called.Examples
>>> from pycsamt.site import SiteMetadataEditor >>> editor = SiteMetadataEditor({"A01": {"name": "L01_001"}}) >>> # result = editor.apply_and_write(sites, "renamed_edi") >>> # [path.name for path in editor.output_paths_]
See also
applyApply without writing files.
pycsamt.site.export.write_sitesExport an existing collection.
- audit(*, api=False)#
Return records from the latest operation as a table.
- Parameters:
api (bool or None, default=False) –
Falsereturns a pandas DataFrame,Trueforces an API frame, andNonedefers to the global API-view configuration.- Returns:
Columns correspond to
MetadataChangefields. Before any operation, an empty table with the stable audit schema is returned.- Return type:
Examples
>>> from pycsamt.site import SiteMetadataEditor >>> editor = SiteMetadataEditor({"A01": {"name": "B01"}}) >>> list(editor.audit(api=False).columns[:4]) ['index', 'old_name', 'new_name', 'changed_fields']
See also
MetadataChangeStation-level audit record.
planPopulate the audit through a non-mutating preview.
applyPopulate the audit while applying updates.
- pycsamt.site.rename_sites(sites, names, *, inplace=False, missing='raise', allow_duplicates=False, allow_empty_names=False)#
Rename stations from a mapping, aligned sequence, or callable.
- Parameters:
sites (Sites, iterable of EDI-like objects, Site, or EDI-like object) – Stations to rename.
names (mapping, sequence of str, or callable) – A mapping relates current names to new names. A sequence is aligned with input order. A callable receives an EDI object and, optionally, its zero-based index, and returns the new name.
inplace (bool, default=False) – Commit synchronized identities back into the input.
missing ({'raise', 'warn', 'ignore'}, default='raise') – Policy for mapping keys that match no station.
allow_duplicates (bool, default=False) – Permit duplicate final identities.
allow_empty_names (bool, default=False) – Permit empty final identities.
- Returns:
Renamed station data.
- Return type:
- Raises:
KeyError – If a mapping key is unmatched and
missing='raise'.ValueError – If names are duplicate or empty under the configured policy, or a sequence length differs from the number of stations.
TypeError – If
namesor the station source is unsupported.
Notes
Renaming synchronizes object-level identity, common
HEADaliases, and linkedSECTIDvalues. It does not rename an existing source file; exporting withtemplate='{station}.edi'uses the new identity.Examples
>>> from pycsamt.site import rename_sites >>> mapping = {"18-012A": "L01_012", "18-013A": "L01_013"} >>> # renamed = rename_sites(sites, mapping)
Generate names from input order:
>>> # renamed = rename_sites( >>> # sites, lambda _edi, index: f"L22_{index + 1:03d}" >>> # )
See also
update_metadataUpdate one station and its metadata.
update_metadata_allApply richer station-specific specifications.
SiteMetadataEditorReusable editor with planning and audit records.
pycsamt.site.export.write_sitesExport using updated station names.
- pycsamt.site.update_metadata(site, update, *, inplace=False, validate_coordinates=True, validators=None)#
Update metadata for one site or EDI-like object.
- Parameters:
site (Site or EDI-like object) – Object to update.
update (mapping) – One metadata specification. Supported keys are
name,station,lat,lon,long,elev,coords,head,info,sections,set,unset, andtransform.inplace (bool, default=False) – Commit the staged state into
siterather than returning an independent copy.validate_coordinates (bool, default=True) – Enforce finite geographic coordinate values and valid latitude and longitude ranges.
validators (sequence of callable or None, default=None) – Additional staged-object validators.
- Returns:
Updated object with the same logical single-site form as the input.
- Return type:
Site or EDI-like object
- Raises:
ValueError – If a field, coordinate, station identity, or validator is invalid.
TypeError – If the update specification or input cannot be handled safely.
Examples
>>> from pycsamt.site import update_metadata >>> update = { ... "name": "L01_012", ... "coords": (5.25, -3.75, 120.0), ... "info": {"processingtag": "reviewed"}, ... } >>> # reviewed = update_metadata(site, update)
See also
update_metadata_allApply station-specific updates to a collection.
SiteMetadataEditorConfigure validation, planning, and audit behavior.
rename_sitesRename one or many stations using a compact interface.
- pycsamt.site.update_metadata_all(sites, updates, *, inplace=False, missing='raise', allow_duplicates=False, on_error='raise', validate_coordinates=True, allow_empty_names=False, validators=None)#
Apply metadata specifications to a station collection.
- Parameters:
sites (Sites, iterable of EDI-like objects, Site, or EDI-like object) – Input station data.
updates (mapping, sequence, callable, pandas.DataFrame, or path-like) – Metadata source accepted by
SiteMetadataEditor.inplace (bool, default=False) – Commit staged objects back into the supplied input.
missing ({'raise', 'warn', 'ignore'}, default='raise') – Policy for update keys that match no station.
allow_duplicates (bool, default=False) – Permit duplicate final station identities.
on_error ({'raise', 'warn', 'ignore'}, default='raise') – Station-level failure policy.
validate_coordinates (bool, default=True) – Validate geographic coordinates before committing.
allow_empty_names (bool, default=False) – Permit empty final station identities.
validators (sequence of callable or None, default=None) – Additional validators applied to each staged station.
- Returns:
Updated data. Collection-like inputs normally return
Sites.- Return type:
- Raises:
KeyError – If station-keyed metadata contains unmatched keys and
missing='raise'.ValueError – If the batch violates metadata or identity constraints.
TypeError – If the source, metadata source, or action is unsupported.
Examples
Use an explicit station mapping:
>>> from pycsamt.site import update_metadata_all >>> updates = { ... "A01": {"name": "L01_001", "head": {"project": "L01"}}, ... "A02": {"name": "L01_002", "elev": 121.0}, ... } >>> # updated = update_metadata_all(sites, updates)
A DataFrame or CSV review table can use columns such as
station,new_name,latitude, andhead.project.See also
update_metadataUpdate one site.
SiteMetadataEditor.applyApply with a reusable configured editor.
SiteMetadataEditor.planPreview a batch before committing.
rename_sitesRename a collection without a full metadata specification.
- class pycsamt.site.EDIRecomputeRecord(source, output, line, station, status, message='')#
Bases:
objectPer-station outcome for an EDI recomputation workflow.
- Variables:
source (pathlib.Path or None) – Source EDI path when known.
output (pathlib.Path or None) – Written EDI path when
write=Trueand the station was written successfully.line (str or None) – Line/group name inferred from the source directory.
station (str) – Station name after recomputation and optional renaming.
status (str) –
"ok"for success or"failed"when processing continued after an error.message (str, default "") – Optional diagnostic message.
- Parameters:
- class pycsamt.site.EDIRecomputeResult(sites, records, output_root=None, items=<factory>)#
Bases:
objectResult returned by
EDIRecomputer.- Variables:
sites (pycsamt.site.base.Sites) – Recomputed EDI objects wrapped as sites.
records (list of EDIRecomputeRecord) – Per-station processing and writing outcomes.
output_root (pathlib.Path or None) – Root directory used for exported EDI files.
- Parameters:
- records: list[EDIRecomputeRecord]#
- property failed: list[EDIRecomputeRecord]#
Return failed records.
- class pycsamt.site.EDIRecomputer(output_root=None, output_name='recomputed_edis', preserve_line_dirs=True, template='{station}.edi', overwrite=False, write=True, manifest_csv=True, rotate_angle=None, rotate_components=<factory>, fmin=None, fmax=None, keep_freq=None, fill_missing_values=None, recompute_resphase=True, rename_policy=None, datatype=None, synthesize_spectra=False, recursive=True, strict=False, on_dup='replace', copy=True, progress=False, verbose=0, progress_callback=None)#
Bases:
objectRecompute and rewrite EDI files using pyCSAMT conventions.
This class is a workflow layer over the lower-level site helpers. It accepts EDI objects, EDI collections, files, line folders, or survey folders, applies a sequence of optional normalizations, and can write pyCSAMT-generated EDI files to a new output tree.
- Parameters:
output_root (str or pathlib.Path, optional) – Root directory for recomputed EDI files. If omitted, a
recomputed_edisdirectory is created next to a selected line folder, or inside a selected survey folder.output_name (str, default "recomputed_edis") – Directory name used when
output_rootis not provided.preserve_line_dirs (bool, default True) – If
True, write each inferred line into its own subdirectory underoutput_root. IfFalse, write all recomputed EDI files directly underoutput_root.template (str, default "{station}.edi") – Filename template. Available keys are
station,index,line, andsource_stem.overwrite (bool, default False) – Allow replacing existing output files.
write (bool, default True) – If
False, only return recomputed in-memory objects.manifest_csv (bool or str or pathlib.Path, default True) – Write a CSV manifest.
Truewrites<output_root>/manifest.csv. A path writes there.rotate_angle (float, optional) – Rotation angle in degrees. If omitted, no rotation is applied.
rotate_components (iterable of str, default ("Z", "Tip")) – Components to rotate. Accepts values such as
"Z","impedance","Tip", and"tipper".fmin (float, optional) – Frequency range to keep before recomputation.
fmax (float, optional) – Frequency range to keep before recomputation.
keep_freq (iterable of int, optional) – Explicit frequency indices or mask passed to
pycsamt.site.edit.select_freq().fill_missing_values ({"zero", "nan"}, optional) – Missing-value policy passed to
pycsamt.site.edit.fill_missing().recompute_resphase (bool, default True) – Recompute apparent resistivity and phase from impedance.
rename_policy (callable, optional) – Function mapping the current station name to a new name.
datatype (str, optional) – EDI writer datatype override, for example
"mt"or"emap".synthesize_spectra (bool, default False) – Ask the pyCSAMT EDI writer to synthesize spectra when possible and missing.
recursive (bool, default True) – Recurse while discovering EDI files inside line folders.
strict (bool, default False) – Raise on read/process/write errors instead of recording failed manifest rows.
on_dup ({"replace", "keep"}, default "replace") – Duplicate station policy during loading.
copy (bool, default True) – Recompute copies of loaded EDI objects. Keep this enabled when the original objects should remain unchanged.
progress (bool or {"auto"}, default False) – Show progress while recomputing.
verbose (int, default 0) – Verbosity for loading, processing, and writing.
progress_callback (Callable[[int, int, str, str, str], None] | None)
- pycsamt.site.recompute_edi(edi, *, rotate_angle=None, rotate_components=('Z', 'Tip'), fmin=None, fmax=None, keep_freq=None, fill_missing_values=None, recompute_resphase=True, rename_policy=None, copy=True)#
Recompute one EDI object.
The operation is copy-returning by default. It can rotate transfer functions, subset frequencies, fill missing values, recompute apparent resistivity/phase, and rename station ids.
- pycsamt.site.recompute_edis(source, **kwargs)#
Convenience function for
EDIRecomputer.Examples
>>> result = recompute_edis("WILLY_DATA", rotate_angle=30.0) >>> result.paths [...]
- Parameters:
- Return type:
- class pycsamt.site.SiteReport(site)#
Bases:
objectStatistics and display for a single
Site.- Parameters:
site (Site-like) – Any object that exposes
name,coords,freq,z,rho,phase, andtipperas perSiteMixin.
Examples
from pycsamt.site.report import SiteReport rep = SiteReport(site) rep.report() # rich terminal output d = rep.to_dict() # machine-readable dict
- report(*, detail=False)#
Print a rich panel with site statistics.
- Parameters:
detail (bool) – If
True, include per-frequency Z and ρ–φ tables.- Return type:
None
- to_dataframe(kind='resphase', *, api=None)#
Export site arrays to a
pandas.DataFrame.
- class pycsamt.site.SitesReport(sites)#
Bases:
objectStatistics and display for a
Sitescollection.- Parameters:
sites (Sites-like) – Any iterable of
Site-like objects.
Examples
from pycsamt.site.report import SitesReport rep = SitesReport(sites) rep.report() # full survey panel + per-station table rep.report(top=10) # first 10 stations only df = rep.to_dataframe() # one row per station
- report(*, top=None, detail=False)#
Print a full survey report.
- to_dataframe(*, api=None)#
Return a
pandas.DataFramewith one row per station.
2.8.1. Site Modules#
|
|
|
|
|
|
|
Declarative, auditable editing of EDI station metadata. |
|
|
|
|
|
|
|
pycsamt.site.report |
|
|
|
|
|