2.30.7.11. pycsamt.map.inversion#

Import geophysical inversion results into MapData.

A ModEM run inverts one 3-D resistivity volume for the whole survey — individual lines are not separate model files, they are paths of stations through that one volume. load_modem_lines() slices that volume into one 2-D vertical curtain per survey line (see pycsamt.models.modem.section) and returns a MapData carrying real station coordinates plus the precomputed sections, so the existing 3-D fence/depth builders in pycsamt.map.volume render inversion-sourced lines exactly like EDI-sourced ones — same real-geometry line placement, same UI.

Geo-referencing station coordinates#

Three sources are tried, in order, for each ModEM station:

  1. known_stations — a previously-loaded EDI MapData’s stations, matched by station id. Recommended: works for any inversion backend and lets a matched station’s line/elevation override the (less complete) values recoverable from the ModEM files alone.

  2. The ModEM .dat file’s own GG_Lat/GG_Lon columns (see pycsamt.models.modem.data.ModEmData.site_lonlat).

  3. Neither — the station keeps latitude=longitude=None and the 3-D builder falls back to synthetic index-based line spacing for that line (see pycsamt.map.geometry).

Functions

group_modem_stations(station_names, *[, ...])

Group ModEM station names into survey lines.

load_modem_lines(folder, *[, ...])

Load a ModEM 3-D inversion result folder as a multi-line MapData.

load_pcsf_lines(path, *[, known_stations, ...])

Load a backend-neutral .pcsf/.pcsm/.pcsm.gz file as a multi-line MapData.

pycsamt.map.inversion.group_modem_stations(station_names, *, known_stations=None)[source]

Group ModEM station names into survey lines.

Prefers matching each name against known_stations (e.g. previously loaded EDI stations) and using their line tag. Falls back to parsing the line token out of the station-name convention {survey}-{line}-{station}{suffix} (e.g. 23-18-001A -> line 18) — a heuristic, used only when a station has no match in known_stations.

Parameters:
Return type:

dict[str, list[str]]

pycsamt.map.inversion.load_modem_lines(folder, *, known_stations=None, fetch_elevation=True, verbose=0)[source]

Load a ModEM 3-D inversion result folder as a multi-line MapData.

Parameters:
  • folder (path-like) – A ModEM output directory. The matching final-iteration .rho/.dat pair is auto-detected by pycsamt.models.modem.results.InversionResult.

  • known_stations (iterable of StationRecord, optional) – Previously-loaded EDI stations (e.g. existing_map_data.stations) used to geo-reference and group ModEM stations by real coordinates/line name — see the module docstring.

  • fetch_elevation (bool, default True) – ModEM output carries no real elevation (unlike EDI, where it’s already in the file header, so “Drape topography” just works). When True, any station still missing an elevation after known_stations matching gets a best-effort online lookup (Open-Meteo) so topography isn’t silently flat by default. Failures (offline, API error, …) are swallowed — elevation simply stays unset, same as passing False.

  • verbose (int, default 0) – Verbosity forwarded to the ModEM readers.

Returns:

sites=None (no EDI backing); stations carries one StationRecord per ModEM station with coordinates resolved where possible; metadata["sections"] carries the precomputed per-line (x, z, rho) curtains consumed directly by pycsamt.map.volume.

Return type:

MapData

pycsamt.map.inversion.load_pcsf_lines(path, *, known_stations=None, fetch_elevation=True, verbose=0, mesh_z_samples=60)[source]

Load a backend-neutral .pcsf/.pcsm/.pcsm.gz file as a multi-line MapData.

Phase 7 of the PCSF format plan: the same route load_modem_lines() already established, but working from any backend’s converted grid2d/multiline PCSF file instead of a live ModEM folder — the view layer here carries no Occam2D/ModEM/MARE2DEM-specific logic, only PCSF’s own schema. Both encodings of the format are accepted transparently — see pycsamt.format.read_pcsf_or_pcsm() — since PCSM is a lossless ASCII projection of the exact same in-memory model.

pycsamt.map.volume’s 3-D builders need one real (x, z, rho) curtain per named station. For grid2d/multiline, a PCSF file’s own dense mesh column at each real station’s along-profile position is extracted (the nearest-column convention pycsamt.interp._base.ResistivityModel.column_nearest() also uses) — the full mesh resolution between stations is not carried into MapData, the same simplification load_modem_lines() already makes via pycsamt.models.modem.section.station_curtain(). For grid3d (native ModEM 3-D), the same nearest-cell sampling station_curtain uses for a live ModEM folder is applied here to the PCSF file’s own volume instead — see _grid3d_sections(). For mesh_unstructured (MARE2DEM), a station’s column instead comes from point-location on the mesh’s real triangulation (which triangle contains a given (x, z) query point) — a genuinely different algorithm from the other three kinds’ index lookups, since a triangular mesh carries no rectilinear index to begin with — see _mesh_unstructured_sections().

Parameters:
  • path (path-like) – A .pcsf, .pcsm, or .pcsm.gz file with geometry.kind "grid2d", "multiline", "grid3d", or "mesh_unstructured", and a populated PCSFModel.stations table.

  • known_stations (iterable of StationRecord, optional) – Previously-loaded EDI stations, used the same way load_modem_lines() uses them: when a station matches one here, its line/elevation/lon/lat take priority. Real geo-referencing does not strictly require this, though – StationTable’s own lon/lat (populated by occam2d_to_pcsf(station_lonlat=...), modem3d_to_pcsf’s GG_Lat/GG_Lon passthrough, or build_multiline_pcsf’s sta_lat/sta_lon), when present, are used as the fallback source – only an unmatched station in a file with neither falls back to synthetic line spacing.

  • fetch_elevation (bool, default True) – Best-effort online elevation lookup for any station still missing one after known_stations matching (see load_modem_lines()).

  • verbose (int, default 0) – Unused today; accepted for signature parity with load_modem_lines().

  • mesh_z_samples (int, default 60) – mesh_unstructured only: number of evenly spaced depth samples across the mesh’s own node z-range to query per station. A triangular mesh carries no separate z axis to reuse the way a rectilinear grid does, so this is a pragmatic, overridable resolution choice, not a property of the file itself. Ignored for every other geometry kind.

Returns:

sites=None; metadata["sections"] carries one precomputed curtain per line, consumed directly by pycsamt.map.volume.

Return type:

MapData

Raises:

ValueError – If the file has no station table, or (mesh_unstructured only) its resistivity is the compact per-region form rather than already expanded onto each triangle.