Site Containers#
The pycsamt.site.base module provides the station-centric containers
used throughout the site layer. These containers wrap SEG-EDI objects without
replacing the lower-level EDI parser. Their purpose is to make common survey
operations easier: station lookup, coordinate access, tensor inspection,
DataFrame export, bulk selection, profile preparation, and writing cleaned
sites back to disk.
The main objects are:
Object |
Scope |
Main use |
|---|---|---|
One EDI-like site. |
Shared accessors for name, coordinates, frequency, impedance, resistivity, phase, tipper, metadata, quality flags, and DataFrame export. |
|
One concrete station. |
High-level wrapper around one |
|
Many stations. |
Ordered collection wrapper with integer indexing, name lookup, selection, batch edits, topography alignment, profile conversion, and export. |
|
API boundary helper. |
Coerce compatible EDI-like inputs into a |
|
API boundary helper. |
Unwrap |
Where Containers Fit#
The site containers sit above pycsamt.seg and below the higher-level
workflow layers.
Layer |
Main object |
Responsibility |
|---|---|---|
EDI parsing |
Read, store, and write one SEG-EDI file. |
|
EDI collection |
Discover and parse many EDI files from paths, folders, or glob patterns. |
|
Site layer |
Expose station-oriented accessors, editing, filtering, summaries, and survey preparation helpers. |
|
Downstream workflows |
Selection, diagnostics, export, profiles, inversion, agents. |
Use prepared site containers as consistent inputs. |
Use EDIFile or EDICollection when you are primarily parsing
SEG-EDI data. Use Site or Sites when you are preparing,
inspecting, selecting, or editing station data.
Creating One Site#
Create a Site from a parsed pycsamt.seg.edi.EDIFile.
1from pycsamt.seg.edi import EDIFile
2from pycsamt.site.base import Site
3
4edi = EDIFile("data/edi/S01.edi")
5site = Site(edi)
6
7print(site.name)
8print(site.coords)
9print(site.summary())
The wrapper keeps the original EDI object available as site.edi and
through Site.to_edi(). Prefer the Site accessors for routine
work, and unwrap to EDI only when you need lower-level EDI functionality.
1raw = site.to_edi()
2detached = site.to_edi(copy=True)
Station Identity#
Station identity is normalized from EDI HEAD fields. The name resolution
order is:
dataid;station;sitename;name;STATION;the file stem, when header fields are missing.
When a Site is created, the constructor attempts to stabilize the EDI
header so that dataid and, when absent, station match the resolved
site stem. This makes name lookup and downstream joins more predictable.
1site = Site(EDIFile("data/edi/LINE01_012.edi"))
2
3print(site.name)
4print(site.meta)
Rename a site with Site.rename():
1renamed = site.rename("L01_012")
2
3print(site.name) # original unchanged
4print(renamed.name) # new wrapper
Use inplace=True when the existing wrapper should be modified:
1site.rename("L01_012", inplace=True)
Coordinates#
Coordinates are exposed as (lat, lon, elev) in decimal degrees and meters.
1lat, lon, elev = site.coords
2print(lat, lon, elev)
Update coordinates with Site.set_coords():
1moved = site.set_coords(10.25, 20.75, 640.0)
2print(moved.coords)
Like Site.rename(), coordinate updates are copy-returning by default and
in-place when requested:
1site.set_coords(10.25, 20.75, 640.0, inplace=True)
Array Accessors#
The container exposes the most common station arrays as properties.
Property |
Meaning |
Shape convention |
|---|---|---|
|
Frequency vector in Hz. |
|
|
Complex impedance tensor. |
Usually |
|
Impedance uncertainty. |
Aligned with |
|
Apparent resistivity. |
Aligned with impedance components. |
|
Impedance phase in degrees. |
Aligned with impedance components. |
|
Vertical magnetic transfer function. |
|
|
Header and optional |
Python dictionary. |
Example:
1print(site.freq)
2print(site.z.shape if site.z is not None else "no Z")
3print(site.quality_flags())
Quality And Component Checks#
Use Site.quality_flags() for coarse array availability checks.
1flags = site.quality_flags()
2
3if not flags["has_z"]:
4 print(f"{site.name} has no finite impedance tensor")
Use Site.has_component() when a specific impedance or tipper component
matters.
1if site.has_component("Zxy") and site.has_component("Zyx"):
2 print("off-diagonal impedance components are available")
3
4if site.has_component("tipper"):
5 print("tipper is available")
Supported impedance component names are Zxx, Zxy, Zyx, and
Zyy. Tipper checks accept tip, tx, ty, and tipper.
DataFrame Export#
Site.to_dataframe() exports core arrays into frequency-indexed
pandas.DataFrame objects. This is the quickest way to inspect one
station in a notebook or build masks for editing.
1z = site.to_dataframe("z")
2rp = site.to_dataframe("resphase")
3tip = site.to_dataframe("tipper")
4
5print(z.head())
6print(rp.head())
7print(tip.head())
The accepted kind values are:
Kind |
Aliases |
Columns |
|---|---|---|
|
|
|
|
|
|
|
|
|
Pass api=True when a pyCSAMT APIFrame is required:
1frame = site.to_dataframe("z", api=True)
2print(frame.kind)
3print(frame.df.head())
Creating A Collection#
Use Sites when working with more than one station.
1from pycsamt.seg.edi import EDIFile
2from pycsamt.site.base import Sites
3
4edis = [
5 EDIFile("data/edi/S01.edi"),
6 EDIFile("data/edi/S02.edi"),
7 EDIFile("data/edi/S03.edi"),
8]
9
10sites = Sites(edis)
11
12print(len(sites))
13print([site.name for site in sites])
If your input is a directory or glob pattern, parse it first with
pycsamt.seg.collection.EDICollection, then wrap it:
1from pycsamt.seg.collection import EDICollection
2from pycsamt.site.base import Sites
3
4collection = EDICollection.from_sources("data/edi")
5sites = Sites(collection)
For API boundaries that may receive several input types, use to_sites():
1from pycsamt.site.base import to_sites
2
3sites = to_sites(collection)
Unwrapping Back To EDI#
The site layer is intentionally reversible. Use to_edis() when a
workflow has prepared, filtered, renamed, or edited Site objects but
the next function expects raw EDI objects.
1from pycsamt.site.base import to_edis
2
3raw = to_edis(site)
4edis = to_edis(sites)
5collection = to_edis(sites, as_collection=True)
By default, unwrapping is shallow: the returned EDI objects are the same
objects stored by the wrappers. Pass copy=True when the caller should be
able to mutate the returned objects independently.
1detached_edis = to_edis(sites, copy=True)
The helper also accepts mixed inputs, path-like sources, raw EDI objects, and
existing EDICollection instances. Invalid
items are skipped unless strict=True is requested.
1edis = to_edis([site, raw_edi, "data/edi"], strict=False)
2checked = to_edis(sites, strict=True, progress=True)
Use the collection methods when you are already holding a Sites
instance:
1edis = sites.to_edis()
2collection = sites.to_edicollection(copy=True)
Sites.from_any is another entry point when you want pyCSAMT’s session
normalization to interpret heterogeneous inputs:
1sites = Sites.from_any("data/edi")
Collection Lookup#
Sites preserves input order and supports integer indexing,
case-insensitive name lookup, and safe lookup.
1first = sites[0]
2same = sites.by_index(0)
3station = sites["s02"]
4maybe = sites.get("missing")
5
6print(first.name)
7print(same.name)
8print(station.name)
9print(maybe is None)
sites["missing"] raises KeyError. Use Sites.get() when missing
stations are acceptable.
The Sites.as_list() method returns the underlying EDI objects:
1edi_objects = sites.as_list()
This is useful when passing a prepared collection into utilities that still
operate directly on EDI objects. For new API boundaries, prefer
Sites.to_edis() or to_edis() because they also support copying,
progress display, strict validation, and collection output.
Mapping And Selection#
Use Sites.map() to apply a lightweight operation to every station:
1names = sites.map(lambda site: site.name)
2coverage = sites.map(lambda site: site.summary()["nfreq"])
For simple collection filtering, use Sites.select():
1subset = sites.select(names=["S01", "S03"])
2with_zxy = sites.select(predicate=lambda site: site.has_component("Zxy"))
For richer selection by glob names, frequency coverage, coordinates, chainage, or data quality, use the functions documented in Site Selection.
Bulk Edits#
Sites.edit_all() applies common operations across the collection.
1renamed = sites.edit_all(
2 rename=lambda name: f"LINE01_{name}",
3 inplace=False,
4)
5
6sliced = sites.edit_all(
7 freq_slice=slice(1, None),
8 inplace=False,
9)
The optional mask callback receives the output of
site.to_dataframe("z") and returns a boolean mask. Rows where the mask is
False are set to NaN in the impedance tensor.
1def keep_lower_frequencies(frame):
2 cutoff = frame.index.to_series().median()
3 return frame.index <= cutoff
4
5masked = sites.edit_all(mask=keep_lower_frequencies)
Use pycsamt.site.edit when you need more explicit editing functions
such as tensor rotation, coordinate table assignment, frequency range
selection, or resistivity/phase recomputation.
Topography Alignment#
Sites.with_topography() updates site coordinates and elevation from a
table-like object. Station identifiers are matched by normalized names.
1import pandas as pd
2
3topo = pd.DataFrame(
4 {
5 "station": ["S01", "S02"],
6 "latitude": [10.125, 10.250],
7 "longitude": [20.500, 20.625],
8 "elevation": [640.0, 655.0],
9 }
10)
11
12updated = sites.with_topography(topo, inplace=False)
13print(updated["S01"].coords)
Unmatched stations are left unchanged. Use this after loading raw EDI files when field GPS or corrected elevation tables are authoritative.
Closest Site#
Sites.closest() finds the nearest station to a target coordinate.
1nearest = sites.closest(lat=10.20, lon=20.55)
2
3if nearest is not None:
4 print(nearest.name)
Add tol in meters when a maximum distance is required:
1nearest = sites.closest(lat=10.20, lon=20.55, tol=500.0)
If the closest station is farther than tol, the method returns None.
Profiles#
Sites.to_profile() converts station coordinates into a survey-line
profile for line-ordered work.
1profile = sites.to_profile(origin=(10.0, 20.0), azimuth=90.0)
2
3if hasattr(profile, "chainages"):
4 print(profile.chainages)
5else:
6 print([site.name for site in profile["sites"]])
When pycsamt.site.profile.Profile is available, the method returns a
rich profile object. Otherwise it returns a fallback dictionary containing
origin, azimuth, and line-ordered sites.
For more control over profile inference, chainage, and spacing statistics, continue to Location And Profiles.
Writing Sites#
Sites.write() writes one EDI file per station into a directory.
1paths = sites.write(
2 "outputs/clean_edi",
3 template="{station}.edi",
4 exist_ok=True,
5)
6
7for path in paths:
8 print(path)
For richer export workflows, including manifest CSV files and zip packages, use the functions documented in Export And Reporting.
Common Patterns#
Inspect one station:
1site = sites["S01"]
2print(site.summary())
3print(site.to_dataframe("resphase").head())
Build a QC table:
1import pandas as pd
2
3qc = pd.DataFrame([site.summary() for site in sites])
4print(qc[["name", "nfreq", "components", "tipper"]])
Select, align, and export:
1selected = sites.select(predicate=lambda site: site.has_component("Zxy"))
2updated = selected.with_topography(topo)
3updated.write("outputs/selected_edi", exist_ok=True)
Common Mistakes#
- Assuming every object has
Sites.from_path Use
pycsamt.seg.collection.EDICollection.from_sources,Sites.from_any(), orto_sites()depending on the input form.- Editing
site.edidirectly during routine workflows Direct EDI edits are sometimes necessary, but the site helpers keep name, coordinate, and array conventions more consistent.
- Forgetting copy versus in-place behaviour
Site.rename(),Site.set_coords(),Site.set_empty(),Sites.edit_all(), andSites.with_topography()return new objects by default unlessinplace=Trueis used.- Comparing station names before normalization
Wrap EDI files as
SiteorSitesbefore doing name-based joins or lookups.- Using
summaryas a substitute for data inspection summaryis a quick overview. UseSite.to_dataframe(),Site.quality_flags(), and the diagnostics in Computed Diagnostics for deeper checks.
Next Pages#
Continue with:
Site Selection for station filtering;
Site Editing for explicit single-site and collection edits;
Location And Profiles for coordinates, topography, distances, and chainage;
Computed Diagnostics for strike, resistivity, phase, and tipper diagnostics.