pycsamt.format.schema#
In-memory schema for the pyCSAMT Common Subsurface Format (PCSF).
PCSF is the backend-neutral container every inversion result (Occam2D,
ModEM, MARE2DEM, DUHI) can be converted to, so pycsamt.format.io,
app/mapview, and the web 3-D view share one on-disk representation
instead of five ad hoc in-memory shapes. See
PYCSAMT-PCSF-INVERSION-FORMAT-PLAN.md at the repository root for the
full design rationale.
This module defines the schema only — geometry and container
dataclasses, the frozen list of supported geometry kinds, and shape
validation. Reading/writing .pcsf files lives in
pycsamt.format.io; per-backend conversion lives in
pycsamt.format.adapters (Phases 2-4).
Classes
|
Optional cached 3-D volume synthesized from stacked lines. |
|
Single-profile rectilinear geometry (Occam2D / DUHI-via-Occam2D). |
|
Native 3-D tensor volume geometry (ModEM). |
|
One profile within a |
|
A set of profiles plus real line geometry (fence/block views). |
|
Backend-neutral inversion-result container (one PCSF file). |
|
Survey station positions, shared across geometry kinds. |
|
Scalar-per-station topography (matches the existing convention in |
|
Gridded-DEM topography — a regular elevation surface independent of any station table. |
|
Native unstructured triangular mesh geometry (MARE2DEM). |
- class pycsamt.format.schema.Grid2DGeometry(x, z, x_nodes=None, z_nodes=None, origin=None, azimuth_deg=None)[source]
Bases:
PyCSAMTObjectSingle-profile rectilinear geometry (Occam2D / DUHI-via-Occam2D).
- Parameters:
x (ndarray (n_x,)) – Real station chainage, metres — never a solver’s mesh-local frame (see the Occam2D coordinate-frame note in
pycsamt.interp._base.ResistivityModel.from_occam2d()).z (ndarray (n_z,)) – Depth cell centres, metres, positive downward.
x_nodes (ndarray, optional) – Cell-edge coordinates, one longer than x/z.
z_nodes (ndarray, optional) – Cell-edge coordinates, one longer than x/z.
origin (ndarray (2,), optional) – Real-world offset when x is locally referenced.
azimuth_deg (float, optional) – Profile bearing, for georeferencing back to the survey line.
- x: ndarray
- z: ndarray
- validate()[source]
Validate object state.
Subclasses can override this hook. The base implementation intentionally accepts all states.
- Return type:
None
- class pycsamt.format.schema.Grid3DGeometry(x, y, z, x_nodes=None, y_nodes=None, z_nodes=None, origin=None, rotation_deg=0.0, n_air=0)[source]
Bases:
PyCSAMTObjectNative 3-D tensor volume geometry (ModEM).
- Parameters:
x (ndarray) – Cell-centre coordinates, metres.
y (ndarray) – Cell-centre coordinates, metres.
z (ndarray) – Cell-centre coordinates, metres.
x_nodes (ndarray, optional) – Cell-edge coordinates.
y_nodes (ndarray, optional) – Cell-edge coordinates.
z_nodes (ndarray, optional) – Cell-edge coordinates.
origin (ndarray (3,), optional) – Real-world grid origin.
rotation_deg (float, default 0.0) – Grid rotation about the vertical axis.
n_air (int, default 0) – Explicit air-layer count (unlike Occam2D’s inferred count).
- x: ndarray
- y: ndarray
- z: ndarray
- rotation_deg: float = 0.0
- n_air: int = 0
- validate()[source]
Validate object state.
Subclasses can override this hook. The base implementation intentionally accepts all states.
- Return type:
None
- class pycsamt.format.schema.UnstructuredMeshGeometry(nodes, connectivity, region_ids, plane='xz')[source]
Bases:
PyCSAMTObjectNative unstructured triangular mesh geometry (MARE2DEM).
Preserves the mesh as-is (no forced regrid onto a tensor grid), so a MARE2DEM result keeps its real element resolution.
- Parameters:
nodes (ndarray (n, 2) or (n, 3)) – Node coordinates, metres.
connectivity (ndarray (m, 3), int) – Triangle node indices.
region_ids (ndarray (m,), int) – Region id per triangle.
plane ({"xz", "xy", "3d"}, default "xz") – Physical plane the mesh lives in. MARE2DEM profiles are conventionally in
(y, z)but stored generically asplane="xz"with x holding the profile’s own along-line coordinate.
- nodes: ndarray
- connectivity: ndarray
- region_ids: ndarray
- plane: str = 'xz'
- validate()[source]
Validate object state.
Subclasses can override this hook. The base implementation intentionally accepts all states.
- Return type:
None
- class pycsamt.format.schema.LineEntry(line_id, geometry, resistivity, offset_y=0.0, offset_kind='synthetic', azimuth_deg=None)[source]
Bases:
PyCSAMTObjectOne profile within a
MultilineGeometry.- Parameters:
line_id (str) – Unique identifier for this line.
geometry (Grid2DGeometry) – The line’s own 2-D section geometry.
resistivity (ndarray (n_z, n_x)) – Canonical linear ohm.m resistivity for this line.
offset_y (float) – Cross-line position, metres.
offset_kind ({"real", "synthetic"}, default "synthetic") – Whether offset_y comes from real survey geometry or is a placeholder spacing for display only.
azimuth_deg (float, optional) – Line bearing.
- line_id: str
- geometry: Grid2DGeometry
- resistivity: ndarray
- offset_y: float = 0.0
- offset_kind: str = 'synthetic'
- validate()[source]
Validate object state.
Subclasses can override this hook. The base implementation intentionally accepts all states.
- Return type:
None
- class pycsamt.format.schema.DerivedVolume(grid, resistivity, derivation_method='linear_interp', derived_from=<factory>, synthesized=True)[source]
Bases:
PyCSAMTObjectOptional cached 3-D volume synthesized from stacked lines.
Kept explicitly tagged as synthesized so a reader never mistakes a stack-interpolated volume for a native 3-D inversion (see
derivation_method/synthesizedin the design plan’s §2).- Parameters:
- grid: Grid3DGeometry
- resistivity: ndarray
- derivation_method: str = 'linear_interp'
- synthesized: bool = True
- validate()[source]
Validate object state.
Subclasses can override this hook. The base implementation intentionally accepts all states.
- Return type:
None
- class pycsamt.format.schema.MultilineGeometry(lines=<factory>, derived_volume=None)[source]
Bases:
PyCSAMTObjectA set of profiles plus real line geometry (fence/block views).
Formalizes what
pycsamt/app/web/callbacks/map3d.pycurrently reconstructs at render time from a stack of independent 2-D sections. Each line carries its own resistivity; the optionalderived_volumeis a documented, reproducible synthesis rather than a render-time-only side effect.- Parameters:
derived_volume (DerivedVolume | None)
- derived_volume: DerivedVolume | None = None
- validate()[source]
Validate object state.
Subclasses can override this hook. The base implementation intentionally accepts all states.
- Return type:
None
- class pycsamt.format.schema.StationTable(name=<factory>, x=<factory>, y=<factory>, z=<factory>, line_id=None, lon=None, lat=None)[source]
Bases:
PyCSAMTObjectSurvey station positions, shared across geometry kinds.
x/y/zare geometry-local (along-profile chainage forgrid2d, the model grid’s own frame forgrid3d, whatever frame the caller supplied formesh_unstructured) — never assumed to be real-world geographic coordinates, per SPEC.md’s ownload_pcsf_linesconvention.lon/lat, when present, are the one explicit, unambiguous carrier of real-world position: WGS84 decimal degrees, the same convention every other real-coordinate source in this codebase already uses (EDI headers, a ModEM.datfile’sGG_Lat/GG_Loncolumns,pycsamt.map._core.StationRecord). A single-linegrid2d(or any other kind’s) PCSF file that sets these needs no separateknown_stationsmatch to place its stations on a real basemap.- Parameters:
- x: ndarray
- y: ndarray
- z: ndarray
- validate()[source]
Validate object state.
Subclasses can override this hook. The base implementation intentionally accepts all states.
- Return type:
None
- class pycsamt.format.schema.TopographyPerStation(station_id=<factory>, elevation=<factory>)[source]
Bases:
PyCSAMTObjectScalar-per-station topography (matches the existing convention in
pycsamt.map.topo).- elevation: ndarray
- validate()[source]
Validate object state.
Subclasses can override this hook. The base implementation intentionally accepts all states.
- Return type:
None
- class pycsamt.format.schema.TopographyRaster(x, y, elevation)[source]
Bases:
PyCSAMTObjectGridded-DEM topography — a regular elevation surface independent of any station table.
Unlike
TopographyPerStation, this carries no station identifiers at all: it is a standalone terrain surface a consumer can sample at any coordinate, not a per-station lookup table. It introduces no GDAL/rasterio-class dependency — construction is via plainx/y/elevationarrays a caller has already obtained by whatever means it likes (seepycsamt.format.topography.topography_from_grid()); PCSF itself never parses a georeferenced raster file format.- Parameters:
x (ndarray (n_x,)) – Grid x-coordinates (or longitude), increasing.
y (ndarray (n_y,)) – Grid y-coordinates (or latitude), increasing.
elevation (ndarray (n_y, n_x)) – Elevation surface, metres, sampled on the
(y, x)meshgrid implied by x/y — the same row-major conventionnumpy.meshgrid(x, y)(defaultindexing="xy") produces.
- x: ndarray
- y: ndarray
- elevation: ndarray
- validate()[source]
Validate object state.
Subclasses can override this hook. The base implementation intentionally accepts all states.
- Return type:
None
- class pycsamt.format.schema.PCSFModel(geometry, resistivity=None, resistivity_native=None, resistivity_native_encoding=None, uncertainty=None, sensitivity=None, resistivity_by_region=None, resistivity_by_node=None, stations=None, topography=None, survey=<factory>, history=<factory>, source_backend='generic', created_by='', created_at='', crs=None, description='', metadata=<factory>, boreholes=None)[source]
Bases:
PyCSAMTObject,MetadataMixinBackend-neutral inversion-result container (one PCSF file).
- Parameters:
geometry (Grid2DGeometry | Grid3DGeometry | UnstructuredMeshGeometry | MultilineGeometry) – The model’s geometry, discriminated by
geometry.kind.resistivity (ndarray, optional) – Canonical linear ohm.m resistivity. Required for
grid2d/grid3d/mesh_unstructuredgeometries; must beNoneformultiline(each line carries its own resistivity — seeLineEntry).resistivity_native (ndarray, optional) – Passthrough of the source backend’s own array, for provenance.
resistivity_native_encoding ({"log10", "ln", "linear"}, optional) – Encoding of resistivity_native. Required whenever resistivity_native is given — never assumed.
uncertainty (ndarray, optional) – Same shape as resistivity, when available from the source.
sensitivity (ndarray, optional) – Same shape as resistivity, when available from the source.
resistivity_by_region (ndarray, optional) – Per-region resistivity table (
mesh_unstructuredonly), alongside the per-cell resistivity expanded from it.resistivity_by_node (ndarray, optional) – Per-node resistivity table (
mesh_unstructuredonly), shape(n_nodes,)– the natural output shape of a graph-based model (e.g. a GCN) that predicts one value per mesh vertex rather than per cell. Kept alongside the per-cell resistivity expanded from it (seepycsamt.format.adapters.generic.mesh_to_pcsf()), the same provenance relationship resistivity_by_region has to its own per-cell expansion.stations (StationTable, optional)
topography (TopographyPerStation | TopographyRaster, optional)
survey (dict) – Free-form survey metadata. Adapters populate this from
pycsamt.metadataobjects (SurveyMeta,BBox,ProvenanceMeta) via their own dict conversion; PCSF itself does not require a specific metadata class here.history (dict of ndarray) – Optional per-iteration series (e.g.
{"rms": ..., "lambda": ...}) from anInversionHistory-like source.source_backend (str, default "generic") –
"occam2d"|"modem3d"|"mare2dem"|"duhi"|"generic".crs (str, optional) – A pyproj-compatible CRS string.
created_by (str)
created_at (str)
description (str)
boreholes (Any | None)
- geometry: Grid2DGeometry | Grid3DGeometry | UnstructuredMeshGeometry | MultilineGeometry
- stations: StationTable | None = None
- topography: TopographyPerStation | TopographyRaster | None = None
- source_backend: str = 'generic'
- created_by: str = ''
- created_at: str = ''
- description: str = ''
- validate()[source]
Validate object state.
Subclasses can override this hook. The base implementation intentionally accepts all states.
- Return type:
None