2.23.3.4. pycsamt.format.adapters.modem3d#

ModEM 3-D -> PCSF adapter (Phase 3 of the PCSF format plan).

Converts a completed pycsamt.models.modem.results.InversionResult (3-D mode) into a backend-neutral PCSFModel with a grid3d geometry — the first genuinely new persisted 3-D volume artifact in the project (see PYCSAMT-PCSF-INVERSION-FORMAT-PLAN.md, §1: nothing else in the codebase currently writes one to disk; the web 3-D view only ever synthesizes a volume at render time from stacked 2-D sections).

Unlike Occam2D, ModEM’s model already carries its own real-world grid centre and rotation when a genuine ModEM run wrote the file — see the origin/rotation_deg attributes added to pycsamt.models.modem.model3d.ModEmModel3D alongside this adapter, which previously parsed and then silently discarded that trailing line.

Module Attributes

DEFAULT_AIR_THRESHOLD_OHM_M

Default cell resistivity (ohm.m) above which a ModEM 3-D cell is treated as the model's above-topography "air" / padding fill rather than resolved earth.

Functions

modem3d_to_pcsf(result, *[, model, data, ...])

Convert a ModEM 3-D InversionResult to a PCSFModel.

pycsamt.format.adapters.modem3d.modem3d_to_pcsf(result, *, model=None, data=None, station_elevations=None, air_threshold_ohm_m=100000000.0, station_z_convention='auto', topo=None, epsg=None, utm_zone=None, latlon=False, on_mismatch='raise', survey=None, created_by='', crs=None, description='')[source]

Convert a ModEM 3-D InversionResult to a PCSFModel.

Parameters:
  • result (InversionResult) – A loaded ModEM working directory (result.mode == "3d").

  • model (ModEmModel3D, optional) – Model to convert. Defaults to result.model_final, falling back to result.model_initial when no final model was parsed.

  • data (ModEmData, optional) – Source of station coordinates. Defaults to result.data_obs, falling back to result.data_pred. None when neither is available (PCSFModel.stations stays None rather than fabricating positions).

  • station_elevations (mapping of str to float, optional) – station_name -> elevation (m), overriding ModEM’s own station z (commonly a flat 0.0 placeholder — a real ModEM .dat file carries no topography). Matched stations also populate PCSFModel.topography; unmatched stations keep their real recorded z as-is (0.0 is a genuine value here, not “unknown”, unlike Occam2D’s equivalent parameter). Superseded per-station by topo when both are given.

  • air_threshold_ohm_m (float or None, default 1e8) – Cell resistivity (ohm.m) above which a cell is treated as ModEM’s above-topography “air” / padding fill rather than resolved earth, and set to nan in the canonical PCSFModel.resistivity. ModEM leaves the model cells above the real ground surface filled with air-like resistivity (1e8-1e13 ohm.m) even when the run declares no dedicated air layers (n_air == 0), and those cells otherwise hijack any auto colour scale (e.g. MapView’s fence view), crushing the real earth into a featureless band. PCSFModel.resistivity_native keeps the source model’s raw natural-log array unchanged for provenance. Leading complete air layers detected this way are also written to Grid3DGeometry.n_air (when the source model reported 0); metadata["air_mask"] records what was done. Pass None for an exact, unmasked passthrough of every cell.

  • station_z_convention ({"auto", "elevation", "depth_down"}, default "auto") – How to read a ModEM .dat file’s own Z(m) station column. ModEM’s model z-axis points downward, so a populated station Z is a depth below a datum, not an elevation – copied verbatim into StationTable.z it makes MapView’s topography drape render hills as hollows. "depth_down" forces the flip to an elevation (datum - Z; the datum is read from an ... m a.s.l. hint in the file’s # comments when present, else the deepest station is taken as 0 and the result is a relative elevation). "elevation" trusts the column as-is (what pycsamt’s own ModEM writer produces). "auto" (default) flips only when the .dat comment says the column is a positive-down depth; a flat all-zero column is always left untouched. metadata["station_z"] records the outcome.

  • topo (path-like, TopoTable, Sites/MapData-like, or mapping, optional) – A “smart” real-coordinate source resolved via pycsamt.format.topo_source.resolve_topo() – see pycsamt.format.adapters.occam2d.occam2d_to_pcsf()’s identical parameter for the full description. When given, it takes precedence over both station_elevations and the .dat file’s own GG_Lat/GG_Lon for every station it resolves (with a UserWarning if either was also supplied); a station it has no data for keeps its existing value. None (the default) leaves this adapter’s behaviour unaffected.

  • epsg (int | None) – Forwarded to pycsamt.format.topo_source.resolve_topo(); see occam2d_to_pcsf’s identical parameters.

  • utm_zone (Any | None) – Forwarded to pycsamt.format.topo_source.resolve_topo(); see occam2d_to_pcsf’s identical parameters.

  • latlon (bool) – Forwarded to pycsamt.format.topo_source.resolve_topo(); see occam2d_to_pcsf’s identical parameters.

  • on_mismatch (str) – Forwarded to pycsamt.format.topo_source.resolve_topo(); see occam2d_to_pcsf’s identical parameters.

  • survey (SurveyMeta or mapping, optional) – Survey-level metadata, stored the same way as in pycsamt.format.adapters.occam2d.occam2d_to_pcsf().

  • created_by (str, optional) – Passed straight through to PCSFModel.

  • crs (str, optional) – Passed straight through to PCSFModel.

  • description (str, optional) – Passed straight through to PCSFModel.

Returns:

geometry.kind == "grid3d", canonical linear-ohm.m resistivity in PCSFModel.resistivity (model.rho_linear, with above-topography air fill set to nan – see air_threshold_ohm_m), the original natural-log grid preserved unchanged in PCSFModel.resistivity_native, and iteration history (RMS, objective, model norm, Lagrange multiplier, step-size scaling alpha) from InversionResult.log when available. PCSFModel.stations’s lon/lat are populated from data’s own GG_Lat/GG_Lon columns (ModEmData.site_lonlat) when present, so the file is self-sufficiently geo-referenced without needing a separate known_stations match at load time. StationTable.z is a positive-up elevation – ModEM’s positive-down Z column is flipped when needed (see station_z_convention), so MapView’s topography drape shows hills as hills.

Return type:

PCSFModel

Raises:

ValueError – If result is not a 3-D ModEM result, or no model (explicit or resolved from result) is available.

Examples

>>> from pycsamt.models.modem.results import InversionResult
>>> from pycsamt.format.adapters.modem3d import modem3d_to_pcsf
>>> from pycsamt.format import write_pcsf
>>> result = InversionResult("modem_run")
>>> model = modem3d_to_pcsf(result)
>>> write_pcsf(model, "modem3d_run.pcsf")