diff --git a/simpeg_drivers-assets/uijson/direct_current_pseudo3d_forward.ui.json b/simpeg_drivers-assets/uijson/direct_current_batch2d_forward.ui.json similarity index 100% rename from simpeg_drivers-assets/uijson/direct_current_pseudo3d_forward.ui.json rename to simpeg_drivers-assets/uijson/direct_current_batch2d_forward.ui.json diff --git a/simpeg_drivers-assets/uijson/direct_current_pseudo3d_inversion.ui.json b/simpeg_drivers-assets/uijson/direct_current_batch2d_inversion.ui.json similarity index 100% rename from simpeg_drivers-assets/uijson/direct_current_pseudo3d_inversion.ui.json rename to simpeg_drivers-assets/uijson/direct_current_batch2d_inversion.ui.json diff --git a/simpeg_drivers-assets/uijson/induced_polarization_pseudo3d_forward.ui.json b/simpeg_drivers-assets/uijson/induced_polarization_batch2d_forward.ui.json similarity index 100% rename from simpeg_drivers-assets/uijson/induced_polarization_pseudo3d_forward.ui.json rename to simpeg_drivers-assets/uijson/induced_polarization_batch2d_forward.ui.json diff --git a/simpeg_drivers-assets/uijson/induced_polarization_pseudo3d_inversion.ui.json b/simpeg_drivers-assets/uijson/induced_polarization_batch2d_inversion.ui.json similarity index 100% rename from simpeg_drivers-assets/uijson/induced_polarization_pseudo3d_inversion.ui.json rename to simpeg_drivers-assets/uijson/induced_polarization_batch2d_inversion.ui.json diff --git a/simpeg_drivers/__init__.py b/simpeg_drivers/__init__.py index dfaeddd5..9142985e 100644 --- a/simpeg_drivers/__init__.py +++ b/simpeg_drivers/__init__.py @@ -46,43 +46,43 @@ def assets_path() -> Path: "direct current 3d": ( "simpeg_drivers.electricals.direct_current.three_dimensions.driver", { - "forward": "DirectCurrent3DForwardDriver", - "inversion": "DirectCurrent3DInversionDriver", + "forward": "DC3DForwardDriver", + "inversion": "DC3DInversionDriver", }, ), "direct current 2d": ( "simpeg_drivers.electricals.direct_current.two_dimensions.driver", { - "forward": "DirectCurrent2DForwardDriver", - "inversion": "DirectCurrent2DInversionDriver", + "forward": "DC2DForwardDriver", + "inversion": "DC2DInversionDriver", }, ), "direct current pseudo 3d": ( "simpeg_drivers.electricals.direct_current.pseudo_three_dimensions.driver", { - "forward": "DirectCurrentPseudo3DForwardDriver", - "inversion": "DirectCurrentPseudo3DInversionDriver", + "forward": "DCBatch2DForwardDriver", + "inversion": "DCBatch2DInversionDriver", }, ), "induced polarization 3d": ( "simpeg_drivers.electricals.induced_polarization.three_dimensions.driver", { - "forward": "InducedPolarization3DForwardDriver", - "inversion": "InducedPolarization3DInversionDriver", + "forward": "IP3DForwardDriver", + "inversion": "IP3DInversionDriver", }, ), "induced polarization 2d": ( "simpeg_drivers.electricals.induced_polarization.two_dimensions.driver", { - "forward": "InducedPolarization2DForwardDriver", - "inversion": "InducedPolarization2DInversionDriver", + "forward": "IP2DForwardDriver", + "inversion": "IP2DInversionDriver", }, ), "induced polarization pseudo 3d": ( "simpeg_drivers.electricals.induced_polarization.pseudo_three_dimensions.driver", { - "forward": "InducedPolarizationPseudo3DForwardDriver", - "inversion": "InducedPolarizationPseudo3DInversionDriver", + "forward": "IPBatch2DForwardDriver", + "inversion": "IPBatch2DInversionDriver", }, ), "joint surveys": ( @@ -91,7 +91,10 @@ def assets_path() -> Path: ), "fem": ( "simpeg_drivers.electromagnetics.frequency_domain.driver", - {"inversion": "FrequencyDomainElectromagneticsDriver"}, + { + "forward": "FrequenceyDomainElectromagneticsForwardDriver", + "inversion": "FDEMInversionDriver", + }, ), "joint cross gradient": ( "simpeg_drivers.joint.joint_cross_gradient.driver", @@ -99,32 +102,38 @@ def assets_path() -> Path: ), "tdem": ( "simpeg_drivers.electromagnetics.time_domain.driver", - {"inversion": "TimeDomainElectromagneticsDriver"}, + { + "forward": "TDEMForwardDriver", + "inversion": "TDEMInversionDriver", + }, ), "magnetotellurics": ( "simpeg_drivers.natural_sources.magnetotellurics.driver", - {"inversion": "MagnetotelluricsDriver"}, + { + "forward": "MTForwardDriver", + "inversion": "MTInversionDriver", + }, ), "tipper": ( "simpeg_drivers.natural_sources.tipper.driver", - {"inversion": "TipperDriver"}, + {"forward": "TipperForwardDriver", "inversion": "TipperInversionDriver"}, ), "gravity": ( "simpeg_drivers.potential_fields.gravity.driver", - {"inversion": "GravityInversionDriver", "forward": "GravityForwardDriver"}, + {"forward": "GravityForwardDriver", "inversion": "GravityInversionDriver"}, ), "magnetic scalar": ( "simpeg_drivers.potential_fields.magnetic_scalar.driver", { - "forward": "MagneticScalarForwardDriver", - "inversion": "MagneticScalarInversionDriver", + "forward": "MagneticForwardDriver", + "inversion": "MagneticInversionDriver", }, ), "magnetic vector": ( "simpeg_drivers.potential_fields.magnetic_vector.driver", { - "forward": "MagneticScalarForwardDriver", - "inversion": "MagneticVectorInversionDriver", + "forward": "MagneticForwardDriver", + "inversion": "MVIInversionDriver", }, ), } diff --git a/simpeg_drivers/components/data.py b/simpeg_drivers/components/data.py index 7cfa5a8e..4047c0af 100644 --- a/simpeg_drivers/components/data.py +++ b/simpeg_drivers/components/data.py @@ -17,7 +17,7 @@ if TYPE_CHECKING: from geoh5py.workspace import Workspace - from simpeg_drivers.params import InversionBaseParams + from simpeg_drivers.params import InversionBaseOptions from copy import deepcopy from re import findall @@ -78,10 +78,10 @@ class InversionData(InversionLocations): """ - def __init__(self, workspace: Workspace, params: InversionBaseParams): + def __init__(self, workspace: Workspace, params: InversionBaseOptions): """ :param: workspace: :obj`geoh5py.workspace.Workspace` workspace object containing location based data. - :param: params: Params object containing location based data parameters. + :param: params: Options object containing location based data parameters. """ super().__init__(workspace, params) self.locations: np.ndarray | None = None @@ -89,7 +89,6 @@ def __init__(self, workspace: Workspace, params: InversionBaseParams): self.indices: np.ndarray | None = None self.vector: bool | None = None self.n_blocks: int | None = None - self.components: list[str] | None = None self.observed: dict[str, np.ndarray] = {} self.predicted: dict[str, np.ndarray] = {} self.uncertainties: dict[str, np.ndarray] = {} @@ -106,8 +105,10 @@ def _initialize(self) -> None: """Extract data from the workspace using params data.""" self.vector = True if self.params.inversion_type == "magnetic vector" else False self.n_blocks = 3 if self.params.inversion_type == "magnetic vector" else 1 - self.components, self.observed, self.uncertainties = self.get_data() - self.has_tensor = InversionData.check_tensor(self.components) + self.components = self.params.active_components + self.observed = self.params.data + self.uncertainties = self.params.uncertainties + self.has_tensor = InversionData.check_tensor(self.params.components) self.locations = super().get_locations(self.params.data_object) if "2d" in self.params.inversion_type: @@ -280,7 +281,7 @@ def normalize( """ d = deepcopy(data) for chan in getattr(self.params.data_object, "channels", [None]): - for comp in self.components: + for comp in self.params.active_components: if isinstance(d[comp], dict): if d[comp][chan] is not None: d[comp][chan] *= self.normalizations[chan][comp] @@ -298,7 +299,7 @@ def get_normalizations(self): normalizations = {} for chan in getattr(self.params.data_object, "channels", [None]): normalizations[chan] = {} - for comp in self.components: + for comp in self.params.active_components: normalizations[chan][comp] = np.ones(self.mask.sum()) if comp in ["potential", "chargeability"]: normalizations[chan][comp] = 1 @@ -488,7 +489,7 @@ def survey(self): @property def n_data(self): n_data = 0 - for comp in self.components: + for comp in self.params.active_components: if isinstance(self.observed[comp], dict): for channel in self.observed[comp]: n_data += len(self.observed[comp][channel]) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index 38a876a6..18602085 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -18,10 +18,10 @@ from geoapps_utils.driver.params import BaseParams from simpeg_drivers.components.data import InversionData + from simpeg_drivers.params import BaseOptions import numpy as np from geoh5py.objects import Octree -from scipy.sparse import csr_matrix from simpeg import data, data_misfit, maps, meta, objective_function from simpeg_drivers.components.factories.simpeg_factory import SimPEGFactory @@ -30,9 +30,9 @@ class MisfitFactory(SimPEGFactory): """Build SimPEG global misfit function.""" - def __init__(self, params: BaseParams, models=None): + def __init__(self, params: BaseParams | BaseOptions, models=None): """ - :param params: Params object containing SimPEG object parameters. + :param params: Options object containing SimPEG object parameters. """ super().__init__(params) self.simpeg_object = self.concrete_object() diff --git a/simpeg_drivers/components/factories/receiver_factory.py b/simpeg_drivers/components/factories/receiver_factory.py index 8126c888..a038d4f9 100644 --- a/simpeg_drivers/components/factories/receiver_factory.py +++ b/simpeg_drivers/components/factories/receiver_factory.py @@ -20,6 +20,8 @@ if TYPE_CHECKING: from geoapps_utils.driver.params import BaseParams + from simpeg_drivers.params import BaseOptions + import numpy as np from geoapps_utils.utils.transformations import rotate_xyz @@ -29,9 +31,9 @@ class ReceiversFactory(SimPEGFactory): """Build SimPEG receivers objects based on factory type.""" - def __init__(self, params: BaseParams): + def __init__(self, params: BaseParams | BaseOptions): """ - :param params: Params object containing SimPEG object parameters. + :param params: Options object containing SimPEG object parameters. """ super().__init__(params) diff --git a/simpeg_drivers/components/factories/simpeg_factory.py b/simpeg_drivers/components/factories/simpeg_factory.py index 13f2ec74..723bad73 100644 --- a/simpeg_drivers/components/factories/simpeg_factory.py +++ b/simpeg_drivers/components/factories/simpeg_factory.py @@ -18,6 +18,8 @@ if TYPE_CHECKING: from geoapps_utils.driver.params import BaseParams + from simpeg_drivers.params import BaseOptions + # TODO Redesign simpeg factory to avoid pylint arguments-differ complaint @@ -62,7 +64,7 @@ class SimPEGFactory(ABC): "joint cross gradient", ] - def __init__(self, params: BaseParams): + def __init__(self, params: BaseParams | BaseOptions): """ :param params: Driver parameters object. """ diff --git a/simpeg_drivers/components/factories/simulation_factory.py b/simpeg_drivers/components/factories/simulation_factory.py index bcec02d9..2abd35f8 100644 --- a/simpeg_drivers/components/factories/simulation_factory.py +++ b/simpeg_drivers/components/factories/simulation_factory.py @@ -20,6 +20,8 @@ if TYPE_CHECKING: from geoapps_utils.driver.params import BaseParams + from simpeg_drivers.params import BaseOptions + from pathlib import Path import numpy as np @@ -29,9 +31,9 @@ class SimulationFactory(SimPEGFactory): - def __init__(self, params: BaseParams): + def __init__(self, params: BaseParams | BaseOptions): """ - :param params: Params object containing SimPEG object parameters. + :param params: Options object containing SimPEG object parameters. """ super().__init__(params) diff --git a/simpeg_drivers/components/factories/source_factory.py b/simpeg_drivers/components/factories/source_factory.py index 08524b76..a5ac083a 100644 --- a/simpeg_drivers/components/factories/source_factory.py +++ b/simpeg_drivers/components/factories/source_factory.py @@ -17,6 +17,8 @@ if TYPE_CHECKING: from geoapps_utils.driver.params import BaseParams + from simpeg_drivers.params import BaseOptions + from copy import deepcopy import numpy as np @@ -29,9 +31,9 @@ class SourcesFactory(SimPEGFactory): """Build SimPEG sources objects based on factory type.""" - def __init__(self, params: BaseParams): + def __init__(self, params: BaseParams | BaseOptions): """ - :param params: Params object containing SimPEG object parameters. + :param params: Options object containing SimPEG object parameters. """ super().__init__(params) diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index b9f76764..3235f180 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -19,6 +19,8 @@ if TYPE_CHECKING: from geoapps_utils.driver.params import BaseParams + from simpeg_drivers.params import BaseOptions + import numpy as np import simpeg.electromagnetics.time_domain as tdem from geoh5py.objects.surveys.electromagnetics.ground_tem import ( @@ -69,9 +71,9 @@ class SurveyFactory(SimPEGFactory): dummy = -999.0 - def __init__(self, params: BaseParams): + def __init__(self, params: BaseParams | BaseOptions): """ - :param params: Params object containing SimPEG object parameters. + :param params: Options object containing SimPEG object parameters. """ super().__init__(params) self.simpeg_object = self.concrete_object() diff --git a/simpeg_drivers/components/locations.py b/simpeg_drivers/components/locations.py index cc4f21b5..910209e1 100644 --- a/simpeg_drivers/components/locations.py +++ b/simpeg_drivers/components/locations.py @@ -17,7 +17,11 @@ if TYPE_CHECKING: from geoh5py.workspace import Workspace - from simpeg_drivers.params import InversionBaseParams + from simpeg_drivers.params import ( + BaseForwardOptions, + BaseInversionOptions, + InversionBaseParams, + ) import numpy as np from geoh5py.objects import ObjectBase, Points @@ -47,13 +51,19 @@ class InversionLocations: """ - def __init__(self, workspace: Workspace, params: InversionBaseParams): + def __init__( + self, + workspace: Workspace, + params: InversionBaseParams | BaseForwardOptions | BaseInversionOptions, + ): """ :param workspace: Geoh5py workspace object containing location based data. - :param params: Params object containing location based data parameters. + :param params: Options object containing location based data parameters. """ self.workspace = workspace - self._params: InversionBaseParams = params + self._params: ( + InversionBaseParams | BaseForwardOptions | BaseInversionOptions + ) = params self.mask: np.ndarray | None = None self.locations: np.ndarray | None = None @@ -121,6 +131,8 @@ def get_locations(self, entity: ObjectBase) -> np.ndarray: return locations def _filter(self, a, mask): + if a is None: + return None for k, v in a.items(): if not isinstance(v, np.ndarray): a.update({k: self._filter(v, mask)}) diff --git a/simpeg_drivers/components/meshes.py b/simpeg_drivers/components/meshes.py index b02972e1..45ce908e 100644 --- a/simpeg_drivers/components/meshes.py +++ b/simpeg_drivers/components/meshes.py @@ -23,7 +23,11 @@ from octree_creation_app.params import OctreeParams from octree_creation_app.utils import octree_2_treemesh, treemesh_2_octree -from simpeg_drivers.params import InversionBaseParams +from simpeg_drivers.params import ( + BaseForwardOptions, + BaseInversionOptions, + InversionBaseParams, +) from simpeg_drivers.utils.meshes import auto_mesh_parameters from simpeg_drivers.utils.utils import drape_2_tensor @@ -77,11 +81,11 @@ class InversionMesh: def __init__( self, workspace: Workspace, - params: InversionBaseParams, + params: InversionBaseParams | BaseForwardOptions | BaseInversionOptions, ) -> None: """ :param workspace: Workspace object containing mesh data. - :param params: Params object containing mesh parameters. + :param params: Options object containing mesh parameters. """ self.workspace = workspace self.params = params diff --git a/simpeg_drivers/components/topography.py b/simpeg_drivers/components/topography.py index 29544202..c1281cad 100644 --- a/simpeg_drivers/components/topography.py +++ b/simpeg_drivers/components/topography.py @@ -19,6 +19,7 @@ from geoh5py.workspace import Workspace from simpeg_drivers.components.meshes import InversionMesh + from simpeg_drivers.params import BaseOptions import warnings @@ -61,11 +62,11 @@ class InversionTopography(InversionLocations): def __init__( self, workspace: Workspace, - params: BaseParams, + params: BaseParams | BaseOptions, ): """ :param: workspace: :obj`geoh5py.workspace.Workspace` object containing location based data. - :param: params: Params object containing location based data parameters. + :param: params: Options object containing location based data parameters. """ super().__init__(workspace, params) self.locations: np.ndarray | None = None diff --git a/simpeg_drivers/components/windows.py b/simpeg_drivers/components/windows.py index 32454e28..b31361c4 100644 --- a/simpeg_drivers/components/windows.py +++ b/simpeg_drivers/components/windows.py @@ -18,6 +18,8 @@ from geoapps_utils.driver.params import BaseParams from geoh5py.workspace import Workspace + from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions + import numpy as np from geoh5py.objects import Grid2D, PotentialElectrode @@ -35,7 +37,7 @@ class InversionWindow: workspace: Geoh5py workspace object containing window data. params: - Params object containing window parameters. + Options object containing window parameters. window: Center and size defining window for data, topography, etc. @@ -49,10 +51,14 @@ class InversionWindow: window_keys = ["center_x", "center_y", "height", "width", "size", "center"] - def __init__(self, workspace: Workspace, params: BaseParams): + def __init__( + self, + workspace: Workspace, + params: BaseParams | BaseForwardOptions | BaseInversionOptions, + ): """ :param: workspace: Geoh5py workspace object containing window data. - :param: params: Params object containing window parameters. + :param: params: Options object containing window parameters. :param: window: """ self.workspace = workspace diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 57ad3e01..3bf16373 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -54,7 +54,11 @@ InversionWindow, ) from simpeg_drivers.components.factories import DirectivesFactory, MisfitFactory -from simpeg_drivers.params import InversionBaseParams, BaseInversionData +from simpeg_drivers.params import ( + InversionBaseParams, + BaseForwardOptions, + BaseInversionOptions, +) from simpeg_drivers.utils.utils import tile_locations mlogger = logging.getLogger("distributed") @@ -62,11 +66,13 @@ class InversionDriver(BaseDriver): - _params_class = InversionBaseParams # pylint: disable=E0601 + _params_class = InversionBaseParams | BaseForwardOptions | BaseInversionOptions # pylint: disable=E0601 _inversion_type: str | None = None _validations = None - def __init__(self, params: InversionBaseParams): + def __init__( + self, params: InversionBaseParams | BaseForwardOptions | BaseInversionOptions + ): super().__init__(params) self.inversion_type = self.params.inversion_type @@ -279,13 +285,27 @@ def out_group(self): return self._out_group @property - def params(self) -> InversionBaseParams: + def params(self) -> InversionBaseParams | BaseForwardOptions | BaseInversionOptions: """Application parameters.""" return self._params @params.setter - def params(self, val: BaseInversionData | InversionBaseParams | SweepParams): - if not isinstance(val, (BaseData, InversionBaseParams, SweepParams)): + def params( + self, + val: BaseForwardOptions + | BaseInversionOptions + | InversionBaseParams + | SweepParams, + ): + if not isinstance( + val, + ( + BaseForwardOptions, + BaseInversionOptions, + InversionBaseParams, + SweepParams, + ), + ): raise TypeError( "Parameters must be of type 'InversionBaseParams' or 'SweepParams'." ) @@ -508,8 +528,8 @@ def start(cls, filepath: str | Path, driver_class=None): with ifile.data["geoh5"].open(mode="r+"): params = driver_class._params_class.build(ifile) driver = driver_class(params) - driver.run() + driver.run() return driver diff --git a/simpeg_drivers/electricals/__init__.py b/simpeg_drivers/electricals/__init__.py index a5a4b0b4..df1e0e2a 100644 --- a/simpeg_drivers/electricals/__init__.py +++ b/simpeg_drivers/electricals/__init__.py @@ -12,12 +12,12 @@ from __future__ import annotations from .direct_current.three_dimensions import ( - DirectCurrent3DForwardParams, - DirectCurrent3DInversionParams, + DC3DForwardOptions, + DC3DInversionOptions, ) from .induced_polarization.three_dimensions.params import ( - InducedPolarization3DForwardParams, - InducedPolarization3DInversionParams, + IP3DForwardOptions, + IP3DInversionOptions, ) # pylint: disable=unused-import diff --git a/simpeg_drivers/electricals/direct_current/pseudo_three_dimensions/constants.py b/simpeg_drivers/electricals/direct_current/pseudo_three_dimensions/constants.py index 4c155330..a792f232 100644 --- a/simpeg_drivers/electricals/direct_current/pseudo_three_dimensions/constants.py +++ b/simpeg_drivers/electricals/direct_current/pseudo_three_dimensions/constants.py @@ -135,192 +135,6 @@ "distributed_workers": None, } -default_ui_json = { - "title": "Direct Current (DC) 3D Inversion", - "icon": "PotentialElectrode", - "inversion_type": "direct current pseudo 3d", - "line_object": { - "association": "Cell", - "dataType": "Referenced", - "group": "Data", - "main": True, - "label": "Line ID", - "parent": "data_object", - "value": None, - "tooltip": "Selects the data representing the different lines in the survey.", - }, - "data_object": { - "main": True, - "group": "Data", - "label": "Object", - "meshType": "{275ecee9-9c24-4378-bf94-65f3c5fbe163}", - "value": None, - }, - "potential_channel_bool": True, - "potential_channel": { - "association": "Cell", - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Potential (V/I)", - "parent": "data_object", - "value": None, - }, - "potential_uncertainty": { - "association": "Cell", - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "property": None, - "value": 1.0, - }, - "mesh": { - "group": "Mesh and models", - "main": True, - "label": "Mesh", - "meshType": "{4EA87376-3ECE-438B-BF12-3479733DED46}", - "optional": True, - "enabled": False, - "value": None, - "visible": True, - }, - "u_cell_size": { - "min": 0.0, - "group": "Mesh and models", - "main": True, - "enabled": True, - "label": "Easting core cell size (m)", - "value": 25.0, - }, - "v_cell_size": { - "min": 0.0, - "group": "Mesh and models", - "main": True, - "enabled": True, - "label": "Northing core cell size (m)", - "value": 25.0, - }, - "depth_core": { - "min": 0.0, - "group": "Mesh and models", - "main": True, - "enabled": True, - "label": "Depth of core (m)", - "value": 500.0, - }, - "horizontal_padding": { - "min": 0.0, - "group": "Mesh and models", - "main": True, - "enabled": True, - "label": "Horizontal padding (m)", - "value": 1000.0, - }, - "vertical_padding": { - "min": 0.0, - "group": "Mesh and models", - "main": True, - "dependencyType": "disabled", - "label": "Vertical padding (m)", - "value": 1000.0, - }, - "expansion_factor": { - "main": True, - "group": "Mesh and models", - "label": "Expansion factor", - "value": 1.1, - }, - "model_type": { - "choiceList": ["Conductivity (S/m)", "Resistivity (Ohm-m)"], - "main": True, - "group": "Mesh and models", - "label": "Model units", - "tooltip": "Select the units of the model.", - "value": "Conductivity (S/m)", - }, - "starting_model": { - "association": "Cell", - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": False, - "parent": "mesh", - "label": "Initial Conductivity (S/m)", - "property": None, - "value": 1e-3, - }, - "reference_model": { - "association": "Cell", - "dataType": "Float", - "main": True, - "group": "Mesh and models", - "isValue": True, - "optional": True, - "enabled": False, - "parent": "mesh", - "label": "Reference Conductivity (S/m)", - "property": None, - "value": 1e-3, - }, - "lower_bound": { - "association": "Cell", - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Lower bound", - "property": None, - "optional": True, - "value": 1e-8, - "enabled": False, - }, - "upper_bound": { - "association": "Cell", - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Upper bound", - "property": None, - "optional": True, - "value": 100.0, - "enabled": False, - }, - "tile_spatial": 1, - "files_only": { - "label": "Generate files only", - "group": "Python run preferences", - "main": True, - "value": False, - }, - "cleanup": { - "main": True, - "group": "Python run preferences", - "label": "Clean directory", - "value": True, - }, -} - -default_ui_json = dict(base_default_ui_json, **default_ui_json) - - -################ Validations ################# - -validations = { - "inversion_type": { - "required": True, - "values": ["direct current pseudo 3d", "direct current 2d"], - }, - "data_object": {"required": True, "types": [UUID, PotentialElectrode]}, -} - -validations = dict(base_validations, **validations) - app_initializer = { "geoh5": str(assets_path() / "FlinFlon_dcip.geoh5"), "data_object": UUID("{6e14de2c-9c2f-4976-84c2-b330d869cb82}"), diff --git a/simpeg_drivers/electricals/direct_current/pseudo_three_dimensions/driver.py b/simpeg_drivers/electricals/direct_current/pseudo_three_dimensions/driver.py index 6cd7a61b..b34a0e21 100644 --- a/simpeg_drivers/electricals/direct_current/pseudo_three_dimensions/driver.py +++ b/simpeg_drivers/electricals/direct_current/pseudo_three_dimensions/driver.py @@ -11,27 +11,28 @@ from __future__ import annotations -from simpeg_drivers.electricals.direct_current.pseudo_three_dimensions.constants import ( - validations, -) from simpeg_drivers.electricals.direct_current.pseudo_three_dimensions.params import ( - DirectCurrentPseudo3DForwardParams, - DirectCurrentPseudo3DInversionParams, + DCBatch2DForwardOptions, + DCBatch2DInversionOptions, ) from simpeg_drivers.electricals.direct_current.two_dimensions.params import ( - DirectCurrent2DForwardParams, - DirectCurrent2DInversionParams, + DC2DForwardOptions, + DC2DInversionOptions, ) -from simpeg_drivers.electricals.driver import BasePseudo3DDriver +from simpeg_drivers.electricals.driver import BaseBatch2DDriver + + +class DCBatch2DForwardDriver(BaseBatch2DDriver): + """Direct Current batch 2D forward driver.""" + _params_class = DCBatch2DForwardOptions + _params_2d_class = DC2DForwardOptions + _validations = {} -class DirectCurrentPseudo3DForwardDriver(BasePseudo3DDriver): - _params_class = DirectCurrentPseudo3DForwardParams - _params_2d_class = DirectCurrent2DForwardParams - _validations = validations +class DCBatch2DInversionDriver(BaseBatch2DDriver): + """Direct Current batch 2D inversion driver.""" -class DirectCurrentPseudo3DInversionDriver(BasePseudo3DDriver): - _params_class = DirectCurrentPseudo3DInversionParams - _params_2d_class = DirectCurrent2DInversionParams - _validations = validations + _params_class = DCBatch2DInversionOptions + _params_2d_class = DC2DInversionOptions + _validations = {} diff --git a/simpeg_drivers/electricals/direct_current/pseudo_three_dimensions/params.py b/simpeg_drivers/electricals/direct_current/pseudo_three_dimensions/params.py index 043a47f0..7f0901b6 100644 --- a/simpeg_drivers/electricals/direct_current/pseudo_three_dimensions/params.py +++ b/simpeg_drivers/electricals/direct_current/pseudo_three_dimensions/params.py @@ -11,31 +11,23 @@ from __future__ import annotations -from copy import deepcopy from typing import ClassVar from geoh5py.data import FloatData from geoh5py.objects import Octree, PotentialElectrode from simpeg_drivers import assets_path -from simpeg_drivers.electricals.direct_current.pseudo_three_dimensions.constants import ( - default_ui_json, - forward_defaults, - inversion_defaults, - validations, -) from simpeg_drivers.electricals.params import ( - BasePseudo3DParams, - DrapeModelData, - FileControlData, - LineSelectionData, + DrapeModelOptions, + FileControlOptions, + LineSelectionOptions, ) -from simpeg_drivers.params import BaseForwardData, BaseInversionData +from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions -class DirectCurrentPseudo3DForwardParams(BaseForwardData): +class DCBatch2DForwardOptions(BaseForwardOptions): """ - Parameter class for three dimensional direct current forward simulation. + Direct Current batch 2D forward options. :param data_object: DC survey object. :param potential_channel_bool: Potential channel boolean. @@ -50,7 +42,7 @@ class DirectCurrentPseudo3DForwardParams(BaseForwardData): name: ClassVar[str] = "Direct Current Pseudo 3D Forward" title: ClassVar[str] = "Direct Current (DC) 2D Batch Forward" default_ui_json: ClassVar[str] = ( - assets_path() / "uijson/direct_current_pseudo3d_forward.ui.json" + assets_path() / "uijson/direct_current_batch2d_forward.ui.json" ) inversion_type: str = "direct current pseudo 3d" @@ -58,16 +50,16 @@ class DirectCurrentPseudo3DForwardParams(BaseForwardData): data_object: PotentialElectrode potential_channel_bool: bool = True - line_selection: LineSelectionData + line_selection: LineSelectionOptions mesh: Octree | None = None - drape_model: DrapeModelData = DrapeModelData() + drape_model: DrapeModelOptions = DrapeModelOptions() model_type: str = "Conductivity (S/m)" - file_control: FileControlData = FileControlData() + file_control: FileControlOptions = FileControlOptions() -class DirectCurrentPseudo3DInversionParams(BaseInversionData): +class DCBatch2DInversionOptions(BaseInversionOptions): """ - Parameter class for three dimensional direct current inversion. + Direct Current batch 2D Inversion options. :param data_object: DC survey object. :param potential_channel: Potential data channel. @@ -85,7 +77,7 @@ class DirectCurrentPseudo3DInversionParams(BaseInversionData): name: ClassVar[str] = "Direct Current Pseudo 3D Inversion" title: ClassVar[str] = "Direct Current (DC) 2D Batch Inversion" default_ui_json: ClassVar[str] = ( - assets_path() / "uijson/direct_current_pseudo3d_inversion.ui.json" + assets_path() / "uijson/direct_current_batch2d_inversion.ui.json" ) inversion_type: str = "direct current pseudo 3d" @@ -94,58 +86,10 @@ class DirectCurrentPseudo3DInversionParams(BaseInversionData): data_object: PotentialElectrode potential_channel: FloatData potential_uncertainty: float | FloatData - line_selection: LineSelectionData + line_selection: LineSelectionOptions mesh: Octree | None = None - drape_model: DrapeModelData = DrapeModelData() + drape_model: DrapeModelOptions = DrapeModelOptions() model_type: str = "Conductivity (S/m)" - file_control: FileControlData = FileControlData() + file_control: FileControlOptions = FileControlOptions() length_scale_y: None = None y_norm: None = None - - -class DirectCurrentPseudo3DParams(BasePseudo3DParams): - """ - Parameter class for electrical->conductivity inversion. - """ - - _physical_property = "conductivity" - _inversion_type = "direct current 3d" - - def __init__(self, input_file=None, forward_only=False, **kwargs): - self._default_ui_json = deepcopy(default_ui_json) - self._forward_defaults = deepcopy(forward_defaults) - self._inversion_defaults = deepcopy(inversion_defaults) - self._validations = validations - self._potential_channel_bool = None - self._potential_channel = None - self._potential_uncertainty = None - - super().__init__(input_file=input_file, forward_only=forward_only, **kwargs) - - @property - def line_selection(self): - return LineSelectionData(line_object=self.line_object, line_id=1) - - @property - def potential_channel_bool(self): - return self._potential_channel_bool - - @potential_channel_bool.setter - def potential_channel_bool(self, val): - self.setter_validator("potential_channel_bool", val) - - @property - def potential_channel(self): - return self._potential_channel - - @potential_channel.setter - def potential_channel(self, val): - self.setter_validator("potential_channel", val, fun=self._uuid_promoter) - - @property - def potential_uncertainty(self): - return self._potential_uncertainty - - @potential_uncertainty.setter - def potential_uncertainty(self, val): - self.setter_validator("potential_uncertainty", val, fun=self._uuid_promoter) diff --git a/simpeg_drivers/electricals/direct_current/three_dimensions/__init__.py b/simpeg_drivers/electricals/direct_current/three_dimensions/__init__.py index 88282d2a..317ec4e2 100644 --- a/simpeg_drivers/electricals/direct_current/three_dimensions/__init__.py +++ b/simpeg_drivers/electricals/direct_current/three_dimensions/__init__.py @@ -9,7 +9,7 @@ # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -from .params import DirectCurrent3DForwardParams, DirectCurrent3DInversionParams +from .params import DC3DForwardOptions, DC3DInversionOptions # pylint: disable=unused-import # flake8: noqa diff --git a/simpeg_drivers/electricals/direct_current/three_dimensions/constants.py b/simpeg_drivers/electricals/direct_current/three_dimensions/constants.py index f7b574d0..c9df2d04 100644 --- a/simpeg_drivers/electricals/direct_current/three_dimensions/constants.py +++ b/simpeg_drivers/electricals/direct_current/three_dimensions/constants.py @@ -119,141 +119,6 @@ "distributed_workers": None, } -default_ui_json = { - "title": "Direct Current (DC) 3D Inversion", - "documentation": "https://mirageoscience-geoapps.readthedocs-hosted.com/en/stable/content/applications/dcip_inversion.html", - "icon": "PotentialElectrode", - "inversion_type": "direct current 3d", - "data_object": { - "main": True, - "group": "Data", - "label": "Object", - "meshType": "{275ecee9-9c24-4378-bf94-65f3c5fbe163}", - "value": None, - }, - "z_from_topo": { - "group": "Data", - "main": True, - "label": "Surface survey", - "tooltip": "Uncheck if borehole data is present", - "value": True, - }, - "potential_channel_bool": True, - "potential_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Potential (V/I)", - "parent": "data_object", - "value": None, - }, - "potential_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "property": None, - "value": 1.0, - }, - "model_type": { - "choiceList": ["Conductivity (S/m)", "Resistivity (Ohm-m)"], - "main": True, - "group": "Mesh and models", - "label": "Model units", - "tooltip": "Select the units of the model.", - "value": "Conductivity (S/m)", - }, - "starting_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": False, - "parent": "mesh", - "label": "Initial", - "property": None, - "value": 1e-1, - }, - "reference_model": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Reference", - "property": None, - "optional": True, - "enabled": False, - "value": 0.0, - }, - "lower_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Lower bound", - "property": None, - "optional": True, - "value": 1e-8, - "enabled": False, - }, - "upper_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Upper bound", - "property": None, - "optional": True, - "value": 100.0, - "enabled": False, - }, - "receivers_offset_z": { - "group": "Data pre-processing", - "label": "Z static offset", - "optional": True, - "enabled": False, - "value": 0.0, - "visible": False, - }, - "receivers_radar_drape": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data pre-processing", - "label": "Z radar offset", - "tooltip": "Apply a non-homogeneous offset to survey object from radar channel.", - "optional": True, - "parent": "data_object", - "value": None, - "enabled": False, - "visible": False, - }, -} - -default_ui_json = dict(base_default_ui_json, **default_ui_json) - - -################ Validations ################# - -validations = { - "inversion_type": { - "required": True, - "values": ["direct current 3d"], - }, - "data_object": {"required": True, "types": [UUID, PotentialElectrode]}, -} - -validations = dict(base_validations, **validations) - app_initializer = { "geoh5": str(assets_path() / "FlinFlon_dcip.geoh5"), "data_object": UUID("{6e14de2c-9c2f-4976-84c2-b330d869cb82}"), diff --git a/simpeg_drivers/electricals/direct_current/three_dimensions/driver.py b/simpeg_drivers/electricals/direct_current/three_dimensions/driver.py index 7e1014c4..fdda2261 100644 --- a/simpeg_drivers/electricals/direct_current/three_dimensions/driver.py +++ b/simpeg_drivers/electricals/direct_current/three_dimensions/driver.py @@ -13,15 +13,18 @@ from simpeg_drivers.driver import InversionDriver -from .constants import validations -from .params import DirectCurrent3DForwardParams, DirectCurrent3DInversionParams +from .params import DC3DForwardOptions, DC3DInversionOptions -class DirectCurrent3DForwardDriver(InversionDriver): - _params_class = DirectCurrent3DForwardParams - _validation = validations +class DC3DForwardDriver(InversionDriver): + """Direct Current 3D forward driver.""" + _params_class = DC3DForwardOptions + _validation = {} -class DirectCurrent3DInversionDriver(InversionDriver): - _params_class = DirectCurrent3DInversionParams - _validation = validations + +class DC3DInversionDriver(InversionDriver): + """Direct Current 3D inversion driver.""" + + _params_class = DC3DInversionOptions + _validation = {} diff --git a/simpeg_drivers/electricals/direct_current/three_dimensions/params.py b/simpeg_drivers/electricals/direct_current/three_dimensions/params.py index ba318393..177a7378 100644 --- a/simpeg_drivers/electricals/direct_current/three_dimensions/params.py +++ b/simpeg_drivers/electricals/direct_current/three_dimensions/params.py @@ -17,12 +17,12 @@ from geoh5py.data import FloatData from simpeg_drivers import assets_path -from simpeg_drivers.params import BaseForwardData, BaseInversionData +from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions -class DirectCurrent3DForwardParams(BaseForwardData): +class DC3DForwardOptions(BaseForwardOptions): """ - Direct current 3D forward parameters. + Direct Current 3D forward options. :param potential_channel_bool: Potential channel boolean. :param model_type: Specify whether the models are provided in @@ -42,9 +42,9 @@ class DirectCurrent3DForwardParams(BaseForwardData): model_type: str = "Conductivity (S/m)" -class DirectCurrent3DInversionParams(BaseInversionData): +class DC3DInversionOptions(BaseInversionOptions): """ - Direct current 3D inversion parameters. + Direct Current 3D inversion options. :param potential_channel: Potential data channel. :param potential_uncertainty: Potential data uncertainty channel. diff --git a/simpeg_drivers/electricals/direct_current/two_dimensions/__init__.py b/simpeg_drivers/electricals/direct_current/two_dimensions/__init__.py index d9121bdc..717653c5 100644 --- a/simpeg_drivers/electricals/direct_current/two_dimensions/__init__.py +++ b/simpeg_drivers/electricals/direct_current/two_dimensions/__init__.py @@ -9,7 +9,7 @@ # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -from .params import DirectCurrent2DForwardParams, DirectCurrent2DInversionParams +from .params import DC2DForwardOptions, DC2DInversionOptions -__all__ = ["DirectCurrent2DForwardParams", "DirectCurrent2DInversionParams"] +__all__ = ["DC2DForwardOptions", "DC2DInversionOptions"] diff --git a/simpeg_drivers/electricals/direct_current/two_dimensions/constants.py b/simpeg_drivers/electricals/direct_current/two_dimensions/constants.py index 94cf4c32..5d2c75f8 100644 --- a/simpeg_drivers/electricals/direct_current/two_dimensions/constants.py +++ b/simpeg_drivers/electricals/direct_current/two_dimensions/constants.py @@ -140,225 +140,6 @@ "gradient_type": "total", } -default_ui_json = { - "title": "Direct Current (DC) 2D Inversion", - "icon": "PotentialElectrode", - "inversion_type": "direct current 2d", - "line_object": { - "association": "Cell", - "dataType": "Referenced", - "group": "Data", - "main": True, - "label": "Line ID", - "parent": "data_object", - "value": None, - "tooltip": "Selects the data representing the different lines in the survey.", - }, - "line_id": { - "group": "Data", - "main": True, - "min": 1, - "label": "Line number", - "value": 1, - "tooltip": "Selects the line of data to be processed.", - }, - "data_object": { - "main": True, - "group": "Data", - "label": "Object", - "meshType": "{275ecee9-9c24-4378-bf94-65f3c5fbe163}", - "value": None, - }, - "z_from_topo": { - "group": "Data", - "main": True, - "label": "Surface survey", - "tooltip": "Uncheck if borehole data is present", - "value": False, - }, - "potential_channel_bool": True, - "potential_channel": { - "association": "Cell", - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Potential (V/I)", - "tooltip": "Potential: voltage normalized by current", - "parent": "data_object", - "value": None, - }, - "potential_uncertainty": { - "association": "Cell", - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "property": None, - "value": 1.0, - }, - "mesh": { - "group": "Mesh and models", - "main": True, - "optional": True, - "enabled": False, - "label": "Mesh", - "meshType": "{C94968EA-CF7D-11EB-B8BC-0242AC130003}", - "value": None, - }, - "u_cell_size": { - "min": 0.0, - "group": "Mesh and models", - "dependency": "mesh", - "dependencyType": "disabled", - "main": True, - "enabled": True, - "label": "Easting core cell size (m)", - "value": 25.0, - }, - "v_cell_size": { - "min": 0.0, - "group": "Mesh and models", - "dependency": "mesh", - "dependencyType": "disabled", - "main": True, - "enabled": True, - "label": "Northing core cell size (m)", - "value": 25.0, - }, - "depth_core": { - "min": 0.0, - "group": "Mesh and models", - "dependency": "mesh", - "dependencyType": "disabled", - "main": True, - "enabled": True, - "label": "Depth of core (m)", - "value": 500.0, - }, - "horizontal_padding": { - "min": 0.0, - "group": "Mesh and models", - "dependency": "mesh", - "dependencyType": "disabled", - "main": True, - "enabled": True, - "label": "Horizontal padding (m)", - "value": 1000.0, - }, - "vertical_padding": { - "min": 0.0, - "group": "Mesh and models", - "dependency": "mesh", - "dependencyType": "disabled", - "main": True, - "label": "Vertical padding (m)", - "value": 1000.0, - }, - "expansion_factor": { - "main": True, - "group": "Mesh and models", - "dependency": "mesh", - "dependencyType": "disabled", - "label": "Expansion factor", - "value": 1.1, - }, - "model_type": { - "choiceList": ["Conductivity (S/m)", "Resistivity (Ohm-m)"], - "main": True, - "group": "Mesh and models", - "label": "Model units", - "tooltip": "Select the units of the model.", - "value": "Conductivity (S/m)", - }, - "starting_model": { - "association": "Cell", - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": False, - "parent": "mesh", - "label": "Initial", - "property": None, - "value": 1e-3, - }, - "reference_model": { - "association": "Cell", - "dataType": "Float", - "main": True, - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Reference", - "property": None, - "optional": True, - "enabled": False, - "value": 1e-3, - }, - "lower_bound": { - "association": "Cell", - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Lower bound", - "property": None, - "optional": True, - "value": 1e-8, - "enabled": False, - }, - "upper_bound": { - "association": "Cell", - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Upper bound", - "property": None, - "optional": True, - "value": 100.0, - "enabled": False, - }, - "receivers_offset_z": { - "group": "Data pre-processing", - "label": "Z static offset", - "optional": True, - "enabled": False, - "value": 0.0, - "visible": False, - }, - "receivers_radar_drape": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data pre-processing", - "label": "Z radar offset", - "tooltip": "Apply a non-homogeneous offset to survey object from radar channel.", - "optional": True, - "parent": "data_object", - "value": None, - "enabled": False, - "visible": False, - }, - "tile_spatial": 1, -} - -default_ui_json = dict(base_default_ui_json, **default_ui_json) - -################ Validations ################# - -validations = { - "inversion_type": { - "required": True, - "values": ["direct current 2d"], - }, - "data_object": {"required": True, "types": [UUID, PotentialElectrode]}, -} - -validations = dict(base_validations, **validations) - app_initializer = { "geoh5": str(assets_path() / "FlinFlon_dcip.geoh5"), "data_object": UUID("{6e14de2c-9c2f-4976-84c2-b330d869cb82}"), diff --git a/simpeg_drivers/electricals/direct_current/two_dimensions/driver.py b/simpeg_drivers/electricals/direct_current/two_dimensions/driver.py index ab04f90b..0f5a6561 100644 --- a/simpeg_drivers/electricals/direct_current/two_dimensions/driver.py +++ b/simpeg_drivers/electricals/direct_current/two_dimensions/driver.py @@ -13,15 +13,18 @@ from simpeg_drivers.electricals.driver import Base2DDriver -from .constants import validations -from .params import DirectCurrent2DForwardParams, DirectCurrent2DInversionParams +from .params import DC2DForwardOptions, DC2DInversionOptions -class DirectCurrent2DForwardDriver(Base2DDriver): - _params_class = DirectCurrent2DForwardParams - _validations = validations +class DC2DForwardDriver(Base2DDriver): + """Direct Current 2D forward driver.""" + _params_class = DC2DForwardOptions + _validations = {} -class DirectCurrent2DInversionDriver(Base2DDriver): - _params_class = DirectCurrent2DInversionParams - _validations = validations + +class DC2DInversionDriver(Base2DDriver): + """Direct Current 2D inversion driver.""" + + _params_class = DC2DInversionOptions + _validations = {} diff --git a/simpeg_drivers/electricals/direct_current/two_dimensions/params.py b/simpeg_drivers/electricals/direct_current/two_dimensions/params.py index 45905548..2875ec77 100644 --- a/simpeg_drivers/electricals/direct_current/two_dimensions/params.py +++ b/simpeg_drivers/electricals/direct_current/two_dimensions/params.py @@ -19,20 +19,15 @@ from simpeg_drivers import assets_path from simpeg_drivers.electricals.params import ( - Base2DParams, - DrapeModelData, - LineSelectionData, -) -from simpeg_drivers.params import BaseForwardData, BaseInversionData - -from .constants import ( - validations, + DrapeModelOptions, + LineSelectionOptions, ) +from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions -class DirectCurrent2DForwardParams(BaseForwardData): +class DC2DForwardOptions(BaseForwardOptions): """ - Parameter class for two dimensional electrical->conductivity forward simulation. + Direct Current 2D forward options. :param potential_channel_bool: Potential channel boolean. :param line_selection: Line selection parameters. @@ -51,15 +46,15 @@ class DirectCurrent2DForwardParams(BaseForwardData): physical_property: str = "conductivity" potential_channel_bool: bool = True - line_selection: LineSelectionData + line_selection: LineSelectionOptions mesh: DrapeModel | None = None - drape_model: DrapeModelData + drape_model: DrapeModelOptions model_type: str = "Conductivity (S/m)" -class DirectCurrent2DInversionParams(BaseInversionData): +class DC2DInversionOptions(BaseInversionOptions): """ - Parameter class for two dimensional electrical->conductivity forward simulation. + Direct Current 2D inversion options. :param potential_channel: Potential data channel. :param potential_uncertainty: Potential data uncertainty channel. @@ -80,9 +75,9 @@ class DirectCurrent2DInversionParams(BaseInversionData): potential_channel: FloatData potential_uncertainty: float | FloatData | None = None - line_selection: LineSelectionData + line_selection: LineSelectionOptions mesh: DrapeModel | None = None - drape_model: DrapeModelData + drape_model: DrapeModelOptions model_type: str = "Conductivity (S/m)" length_scale_y: None = None y_norm: None = None diff --git a/simpeg_drivers/electricals/driver.py b/simpeg_drivers/electricals/driver.py index 947dd65d..d27fb85a 100644 --- a/simpeg_drivers/electricals/driver.py +++ b/simpeg_drivers/electricals/driver.py @@ -29,14 +29,16 @@ from simpeg_drivers.components.topography import InversionTopography from simpeg_drivers.components.windows import InversionWindow from simpeg_drivers.driver import InversionDriver -from simpeg_drivers.electricals.params import LineSelectionData +from simpeg_drivers.electricals.params import LineSelectionOptions from simpeg_drivers.line_sweep.driver import LineSweepDriver -from simpeg_drivers.params import BaseParams +from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions, BaseParams from simpeg_drivers.utils.surveys import extract_dcip_survey from simpeg_drivers.utils.utils import get_drape_model class Base2DDriver(InversionDriver): + """Base class for 2D DC and IP forward and inversion drivers.""" + @property def inversion_mesh(self) -> InversionMesh: """Inversion mesh""" @@ -72,9 +74,11 @@ def create_drape_mesh(self) -> DrapeModel: return mesh -class BasePseudo3DDriver(LineSweepDriver): - _params_class: type(BaseParams) - _params_2d_class: type(BaseParams) +class BaseBatch2DDriver(LineSweepDriver): + """Base class for batch 2D DC and IP forward and inversion drivers.""" + + _params_class: type(BaseForwardOptions, BaseInversionOptions) + _params_2d_class: type(BaseForwardOptions, BaseInversionOptions) _validations: dict _model_list: list[str] = [] @@ -89,17 +93,17 @@ def transfer_models(self, mesh: DrapeModel) -> dict[str, uuid.UUID | float]: :param mesh: Destination DrapeModel object. """ - models = {"starting_model": self.pseudo3d_params.starting_model} + models = {"starting_model": self.batch2d_params.starting_model} for model in self._model_list: - models[model] = getattr(self.pseudo3d_params, model) + models[model] = getattr(self.batch2d_params, model) - if not self.pseudo3d_params.forward_only: + if not self.batch2d_params.forward_only: for model in ["reference_model", "lower_bound", "upper_bound"]: - models[model] = getattr(self.pseudo3d_params, model) + models[model] = getattr(self.batch2d_params, model) - if self.pseudo3d_params.mesh is not None: - xyz_in = get_locations(self.workspace, self.pseudo3d_params.mesh) + if self.batch2d_params.mesh is not None: + xyz_in = get_locations(self.workspace, self.batch2d_params.mesh) xyz_out = mesh.centroids for name, model in models.items(): @@ -122,11 +126,11 @@ def write_files(self, lookup): kwargs_2d = {} with self.workspace.open(mode="r+"): - self._window = InversionWindow(self.workspace, self.pseudo3d_params) - self._inversion_data = InversionData(self.workspace, self.pseudo3d_params) + self._window = InversionWindow(self.workspace, self.batch2d_params) + self._inversion_data = InversionData(self.workspace, self.batch2d_params) self._inversion_data.save_data() self._inversion_topography = InversionTopography( - self.workspace, self.pseudo3d_params + self.workspace, self.batch2d_params ) for uid, trial in lookup.items(): @@ -144,7 +148,7 @@ def write_files(self, lookup): with Workspace.create(filepath) as iter_workspace: cell_mask: np.ndarray = ( - self.pseudo3d_params.line_selection.line_object.values + self.batch2d_params.line_selection.line_object.values == trial["line_id"] ) @@ -164,23 +168,23 @@ def write_files(self, lookup): "Models", receiver_locs, [ - self.pseudo3d_params.drape_model.u_cell_size, - self.pseudo3d_params.drape_model.v_cell_size, + self.batch2d_params.drape_model.u_cell_size, + self.batch2d_params.drape_model.v_cell_size, ], - self.pseudo3d_params.drape_model.depth_core, - [self.pseudo3d_params.drape_model.horizontal_padding] * 2 - + [self.pseudo3d_params.drape_model.vertical_padding, 1], - self.pseudo3d_params.drape_model.expansion_factor, + self.batch2d_params.drape_model.depth_core, + [self.batch2d_params.drape_model.horizontal_padding] * 2 + + [self.batch2d_params.drape_model.vertical_padding, 1], + self.batch2d_params.drape_model.expansion_factor, )[0] model_parameters = self.transfer_models(mesh) for key in self._params_2d_class.model_fields: - param = getattr(self.pseudo3d_params, key, None) + param = getattr(self.batch2d_params, key, None) if key not in ["title", "inversion_type"]: kwargs_2d[key] = param - self.pseudo3d_params.active_cells.topography_object.copy( + self.batch2d_params.active_cells.topography_object.copy( parent=iter_workspace, copy_children=True ) @@ -190,9 +194,9 @@ def write_files(self, lookup): "geoh5": iter_workspace, "mesh": mesh, "data_object": receiver_entity, - "line_selection": LineSelectionData( + "line_selection": LineSelectionOptions( line_object=receiver_entity.get_data( - self.pseudo3d_params.line_selection.line_object.name + self.batch2d_params.line_selection.line_object.name )[0], line_id=trial["line_id"], ), diff --git a/simpeg_drivers/electricals/induced_polarization/pseudo_three_dimensions/constants.py b/simpeg_drivers/electricals/induced_polarization/pseudo_three_dimensions/constants.py index edd5e580..4629b11d 100644 --- a/simpeg_drivers/electricals/induced_polarization/pseudo_three_dimensions/constants.py +++ b/simpeg_drivers/electricals/induced_polarization/pseudo_three_dimensions/constants.py @@ -143,203 +143,6 @@ "distributed_workers": None, } -default_ui_json = { - "title": "Induced Polarization (IP) 3D Inversion", - "icon": "PotentialElectrode", - "inversion_type": "induced polarization pseudo 3d", - "line_object": { - "association": "Cell", - "dataType": "Referenced", - "group": "Data", - "main": True, - "label": "Line ID", - "parent": "data_object", - "value": None, - "tooltip": "Selects the data representing the different lines in the survey.", - }, - "data_object": { - "main": True, - "group": "Data", - "label": "Object", - "meshType": "{275ecee9-9c24-4378-bf94-65f3c5fbe163}", - "value": None, - }, - "chargeability_channel_bool": True, - "chargeability_channel": { - "association": "Cell", - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Chargeability (V/V)", - "parent": "data_object", - "value": None, - }, - "chargeability_uncertainty": { - "association": "Cell", - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "property": None, - "value": 1.0, - }, - "mesh": { - "group": "Mesh and models", - "main": True, - "optional": True, - "enabled": False, - "label": "Mesh", - "meshType": "{4EA87376-3ECE-438B-BF12-3479733DED46}", - "value": None, - "visible": True, - }, - "model_type": { - "choiceList": ["Conductivity (S/m)", "Resistivity (Ohm-m)"], - "main": True, - "group": "Mesh and models", - "label": "Model units", - "tooltip": "Select the units of the model.", - "value": "Conductivity (S/m)", - }, - "conductivity_model": { - "association": "Cell", - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": True, - "parent": "mesh", - "label": "Conductivity (S/m)", - "property": None, - "value": 1e-3, - }, - "u_cell_size": { - "min": 0.0, - "group": "Mesh and models", - "main": True, - "enabled": True, - "label": "Easting core cell size (m)", - "value": 25.0, - }, - "v_cell_size": { - "min": 0.0, - "group": "Mesh and models", - "main": True, - "enabled": True, - "label": "Northing core cell size (m)", - "value": 25.0, - }, - "depth_core": { - "min": 0.0, - "group": "Mesh and models", - "main": True, - "enabled": True, - "label": "Depth of core (m)", - "value": 500.0, - }, - "horizontal_padding": { - "min": 0.0, - "group": "Mesh and models", - "main": True, - "enabled": True, - "label": "Horizontal padding (m)", - "value": 1000.0, - }, - "vertical_padding": { - "min": 0.0, - "group": "Mesh and models", - "main": True, - "dependencyType": "disabled", - "label": "Vertical padding (m)", - "value": 1000.0, - }, - "expansion_factor": { - "main": True, - "group": "Mesh and models", - "label": "Expansion factor", - "value": 1.1, - }, - "starting_model": { - "association": "Cell", - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": False, - "parent": "mesh", - "label": "Initial chargeability (V/V)", - "property": None, - "value": 1e-3, - }, - "reference_model": { - "association": "Cell", - "dataType": "Float", - "main": True, - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Reference chargeability (V/V)", - "property": None, - "optional": True, - "enabled": False, - "value": 1e-3, - }, - "lower_bound": { - "association": "Cell", - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Lower bound (V/V)", - "property": None, - "optional": True, - "value": 1e-8, - "enabled": False, - }, - "upper_bound": { - "association": "Cell", - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Upper bound (V/V)", - "property": None, - "optional": True, - "value": 100.0, - "enabled": False, - }, - "tile_spatial": 1, - "files_only": { - "label": "Generate files only", - "group": "Python run preferences", - "main": True, - "value": False, - }, - "cleanup": { - "main": True, - "group": "Python run preferences", - "label": "Clean directory", - "value": True, - }, -} - -default_ui_json = dict(base_default_ui_json, **default_ui_json) - - -################ Validations ################# - -validations = { - "inversion_type": { - "required": True, - "values": ["induced polarization pseudo 3d", "induced polarization 2d"], - }, - "data_object": {"required": True, "types": [UUID, PotentialElectrode]}, -} - -validations = dict(base_validations, **validations) - app_initializer = { "geoh5": str(assets_path() / "FlinFlon_dcip.geoh5"), "data_object": UUID("{6e14de2c-9c2f-4976-84c2-b330d869cb82}"), diff --git a/simpeg_drivers/electricals/induced_polarization/pseudo_three_dimensions/driver.py b/simpeg_drivers/electricals/induced_polarization/pseudo_three_dimensions/driver.py index 03c73c8d..b09813a3 100644 --- a/simpeg_drivers/electricals/induced_polarization/pseudo_three_dimensions/driver.py +++ b/simpeg_drivers/electricals/induced_polarization/pseudo_three_dimensions/driver.py @@ -11,29 +11,30 @@ from __future__ import annotations -from simpeg_drivers.electricals.driver import BasePseudo3DDriver -from simpeg_drivers.electricals.induced_polarization.pseudo_three_dimensions.constants import ( - validations, -) +from simpeg_drivers.electricals.driver import BaseBatch2DDriver from simpeg_drivers.electricals.induced_polarization.pseudo_three_dimensions.params import ( - InducedPolarizationPseudo3DForwardParams, - InducedPolarizationPseudo3DInversionParams, + IPBatch2DForwardOptions, + IPBatch2DInversionOptions, ) from simpeg_drivers.electricals.induced_polarization.two_dimensions.params import ( - InducedPolarization2DForwardParams, - InducedPolarization2DInversionParams, + IP2DForwardOptions, + IP2DInversionOptions, ) -class InducedPolarizationPseudo3DForwardDriver(BasePseudo3DDriver): - _params_class = InducedPolarizationPseudo3DForwardParams - _params_2d_class = InducedPolarization2DForwardParams - _validations = validations +class IPBatch2DForwardDriver(BaseBatch2DDriver): + """Induced Polarization batch 2D forward driver.""" + + _params_class = IPBatch2DForwardOptions + _params_2d_class = IP2DForwardOptions + _validations = {} _model_list = ["conductivity_model"] -class InducedPolarizationPseudo3DInversionDriver(BasePseudo3DDriver): - _params_class = InducedPolarizationPseudo3DInversionParams - _params_2d_class = InducedPolarization2DInversionParams - _validations = validations +class IPBatch2DInversionDriver(BaseBatch2DDriver): + """Induced Polarization batch 2D inversion driver.""" + + _params_class = IPBatch2DInversionOptions + _params_2d_class = IP2DInversionOptions + _validations = {} _model_list = ["conductivity_model"] diff --git a/simpeg_drivers/electricals/induced_polarization/pseudo_three_dimensions/params.py b/simpeg_drivers/electricals/induced_polarization/pseudo_three_dimensions/params.py index 9e4a6d7c..95085371 100644 --- a/simpeg_drivers/electricals/induced_polarization/pseudo_three_dimensions/params.py +++ b/simpeg_drivers/electricals/induced_polarization/pseudo_three_dimensions/params.py @@ -11,31 +11,23 @@ from __future__ import annotations -from copy import deepcopy from typing import ClassVar from geoh5py.data import FloatData from geoh5py.objects import Octree, PotentialElectrode from simpeg_drivers import assets_path -from simpeg_drivers.electricals.induced_polarization.pseudo_three_dimensions.constants import ( - default_ui_json, - forward_defaults, - inversion_defaults, - validations, -) from simpeg_drivers.electricals.params import ( - BasePseudo3DParams, - DrapeModelData, - FileControlData, - LineSelectionData, + DrapeModelOptions, + FileControlOptions, + LineSelectionOptions, ) -from simpeg_drivers.params import BaseForwardData, BaseInversionData +from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions -class InducedPolarizationPseudo3DForwardParams(BaseForwardData): +class IPBatch2DForwardOptions(BaseForwardOptions): """ - Parameter class for three dimensional induced polarization forward simulation. + Induced Polarization batch 2D forward options. :param data_object: DC/IP survey object. :param chargeability_channel_bool: Chargeability channel boolean. @@ -50,7 +42,7 @@ class InducedPolarizationPseudo3DForwardParams(BaseForwardData): name: ClassVar[str] = "Induced Polarization Pseudo 3D Forward" title: ClassVar[str] = "Induced Polarization (IP) 2D Batch Forward" default_ui_json: ClassVar[str] = ( - assets_path() / "uijson/induced_polarization_pseudo3d_forward.ui.json" + assets_path() / "uijson/induced_polarization_batch2d_forward.ui.json" ) inversion_type: str = "induced polarization pseudo 3d" @@ -58,16 +50,16 @@ class InducedPolarizationPseudo3DForwardParams(BaseForwardData): data_object: PotentialElectrode chargeability_channel_bool: bool = True - line_selection: LineSelectionData + line_selection: LineSelectionOptions mesh: Octree | None = None conductivity_model: float | FloatData - drape_model: DrapeModelData = DrapeModelData() - file_control: FileControlData = FileControlData() + drape_model: DrapeModelOptions = DrapeModelOptions() + file_control: FileControlOptions = FileControlOptions() -class InducedPolarizationPseudo3DInversionParams(BaseInversionData): +class IPBatch2DInversionOptions(BaseInversionOptions): """ - Parameter class for three dimensional induced polarization inversion. + Induced Polarization batch 2D inversion options. :param data_object: DC/IP survey object. :param chargeability_channel: Chargeability data channel. @@ -84,7 +76,7 @@ class InducedPolarizationPseudo3DInversionParams(BaseInversionData): name: ClassVar[str] = "Induced Polarization Pseudo 3D Inversion" title: ClassVar[str] = "Induced Polarization (IP) 2D Batch Inversion" default_ui_json: ClassVar[str] = ( - assets_path() / "uijson/induced_polarization_pseudo3d_inversion.ui.json" + assets_path() / "uijson/induced_polarization_batch2d_inversion.ui.json" ) inversion_type: str = "induced polarization pseudo 3d" @@ -93,68 +85,11 @@ class InducedPolarizationPseudo3DInversionParams(BaseInversionData): data_object: PotentialElectrode chargeability_channel: FloatData chargeability_uncertainty: float | FloatData - line_selection: LineSelectionData + line_selection: LineSelectionOptions mesh: Octree | None = None - drape_model: DrapeModelData = DrapeModelData() + drape_model: DrapeModelOptions = DrapeModelOptions() conductivity_model: float | FloatData lower_bound: float | FloatData | None = 0.0 - file_control: FileControlData = FileControlData() + file_control: FileControlOptions = FileControlOptions() length_scale_y: None = None y_norm: None = None - - -class InducedPolarizationPseudo3DParams(BasePseudo3DParams): - """ - Parameter class for electrical->chargeability inversion. - """ - - _physical_property = "chargeability" - _inversion_type = "induced polarization pseudo 3d" - - def __init__(self, input_file=None, forward_only=False, **kwargs): - self._default_ui_json = deepcopy(default_ui_json) - self._forward_defaults = deepcopy(forward_defaults) - self._inversion_defaults = deepcopy(inversion_defaults) - self._validations = validations - self._conductivity_model: float | None = 1e-3 - self._chargeability_channel_bool: bool = True - self._chargeability_channel = None - self._chargeability_uncertainty = None - - super().__init__(input_file=input_file, forward_only=forward_only, **kwargs) - - @property - def line_selection(self): - return LineSelectionData(line_object=self.line_object, line_id=1) - - @property - def conductivity_model(self): - return self._conductivity_model - - @conductivity_model.setter - def conductivity_model(self, value): - self.setter_validator("conductivity_model", value) - - @property - def chargeability_channel_bool(self): - return self._chargeability_channel_bool - - @chargeability_channel_bool.setter - def chargeability_channel_bool(self, value): - self.setter_validator("chargeability_channel_bool", value) - - @property - def chargeability_channel(self): - return self._chargeability_channel - - @chargeability_channel.setter - def chargeability_channel(self, value): - self.setter_validator("chargeability_channel", value) - - @property - def chargeability_uncertainty(self): - return self._chargeability_uncertainty - - @chargeability_uncertainty.setter - def chargeability_uncertainty(self, value): - self.setter_validator("chargeability_uncertainty", value) diff --git a/simpeg_drivers/electricals/induced_polarization/three_dimensions/__init__.py b/simpeg_drivers/electricals/induced_polarization/three_dimensions/__init__.py index c641f59d..73277c14 100644 --- a/simpeg_drivers/electricals/induced_polarization/three_dimensions/__init__.py +++ b/simpeg_drivers/electricals/induced_polarization/three_dimensions/__init__.py @@ -10,8 +10,8 @@ from .params import ( - InducedPolarization3DForwardParams, - InducedPolarization3DInversionParams, + IP3DForwardOptions, + IP3DInversionOptions, ) # pylint: disable=unused-import diff --git a/simpeg_drivers/electricals/induced_polarization/three_dimensions/constants.py b/simpeg_drivers/electricals/induced_polarization/three_dimensions/constants.py index 5d582215..063853b9 100644 --- a/simpeg_drivers/electricals/induced_polarization/three_dimensions/constants.py +++ b/simpeg_drivers/electricals/induced_polarization/three_dimensions/constants.py @@ -127,153 +127,6 @@ "distributed_workers": None, } -default_ui_json = { - "title": "Induced Polarization (IP) 3D Inversion", - "documentation": "https://mirageoscience-geoapps.readthedocs-hosted.com/en/stable/content/applications/dcip_inversion.html", - "icon": "PotentialElectrode", - "inversion_type": "induced polarization 3d", - "data_object": { - "main": True, - "group": "Data", - "label": "Object", - "meshType": "{275ecee9-9c24-4378-bf94-65f3c5fbe163}", - "value": None, - }, - "z_from_topo": { - "group": "Data", - "main": True, - "label": "Surface survey", - "tooltip": "Uncheck if borehole data is present", - "value": True, - }, - "chargeability_channel_bool": True, - "chargeability_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Chargeability (V/V)", - "parent": "data_object", - "value": None, - }, - "chargeability_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "property": None, - "value": 1.0, - }, - "starting_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": False, - "parent": "mesh", - "label": "Initial Chargeability (V/V)", - "property": None, - "min": 0.0, - "max": 10000.0, - "value": 0.0, - }, - "reference_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "main": True, - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Reference Chargeability (V/V)", - "property": None, - "optional": True, - "enabled": False, - "value": 0.0, - }, - "model_type": { - "choiceList": ["Conductivity (S/m)", "Resistivity (Ohm-m)"], - "main": True, - "group": "Mesh and models", - "label": "Model units", - "tooltip": "Select the units of the model.", - "value": "Conductivity (S/m)", - }, - "conductivity_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": True, - "parent": "mesh", - "label": "Conductivity (S/m)", - "property": None, - "value": 1e-3, - }, - "lower_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Lower bound (V/V)", - "property": None, - "optional": True, - "value": 0, - "enabled": False, - }, - "upper_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Upper bound (V/V", - "property": None, - "optional": True, - "value": 100.0, - "enabled": False, - }, - "receivers_offset_z": { - "group": "Data pre-processing", - "label": "Z static offset", - "optional": True, - "enabled": False, - "value": 0.0, - "visible": False, - }, - "receivers_radar_drape": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data pre-processing", - "label": "Z radar offset", - "tooltip": "Apply a non-homogeneous offset to survey object from radar channel.", - "optional": True, - "parent": "data_object", - "value": None, - "enabled": False, - "visible": False, - }, -} - -default_ui_json = dict(base_default_ui_json, **default_ui_json) - - -################ Validations ################## - -validations = { - "inversion_type": { - "required": True, - "values": ["induced polarization 3d"], - }, - "conductivity_model": {"required": True}, - "data_object": {"required": True, "types": [UUID, PotentialElectrode]}, -} - app_initializer = { "geoh5": str(assets_path() / "FlinFlon_dcip.geoh5"), "data_object": UUID("{6e14de2c-9c2f-4976-84c2-b330d869cb82}"), diff --git a/simpeg_drivers/electricals/induced_polarization/three_dimensions/driver.py b/simpeg_drivers/electricals/induced_polarization/three_dimensions/driver.py index 90943911..9cb0ba58 100644 --- a/simpeg_drivers/electricals/induced_polarization/three_dimensions/driver.py +++ b/simpeg_drivers/electricals/induced_polarization/three_dimensions/driver.py @@ -13,18 +13,21 @@ from simpeg_drivers.driver import InversionDriver -from .constants import validations from .params import ( - InducedPolarization3DForwardParams, - InducedPolarization3DInversionParams, + IP3DForwardOptions, + IP3DInversionOptions, ) -class InducedPolarization3DForwardDriver(InversionDriver): - _params_class = InducedPolarization3DForwardParams - _validations = validations +class IP3DForwardDriver(InversionDriver): + """Induced Polarization 3D forward driver.""" + _params_class = IP3DForwardOptions + _validations = {} -class InducedPolarization3DInversionDriver(InversionDriver): - _params_class = InducedPolarization3DInversionParams - _validations = validations + +class IP3DInversionDriver(InversionDriver): + """Induced Polarization 3D inversion driver.""" + + _params_class = IP3DInversionOptions + _validations = {} diff --git a/simpeg_drivers/electricals/induced_polarization/three_dimensions/params.py b/simpeg_drivers/electricals/induced_polarization/three_dimensions/params.py index aae7763a..6f6dffcd 100644 --- a/simpeg_drivers/electricals/induced_polarization/three_dimensions/params.py +++ b/simpeg_drivers/electricals/induced_polarization/three_dimensions/params.py @@ -17,12 +17,12 @@ from geoh5py.data import FloatData from simpeg_drivers import assets_path -from simpeg_drivers.params import BaseForwardData, BaseInversionData +from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions -class InducedPolarization3DForwardParams(BaseForwardData): +class IP3DForwardOptions(BaseForwardOptions): """ - Induced polarization 3D forward parameters. + Induced Polarization 3D forward options. :param chargeability_channel_bool: Chargeability channel boolean. :param conductivity_model: Conductivity model. @@ -41,9 +41,9 @@ class InducedPolarization3DForwardParams(BaseForwardData): conductivity_model: float | FloatData -class InducedPolarization3DInversionParams(BaseInversionData): +class IP3DInversionOptions(BaseInversionOptions): """ - Induced polarization 3D inversion parameters. + Induced Polarization 3D inversion options. :param chargeability_channel: Chargeability data channel. :param chargeability_uncertainty: Chargeability data uncertainty channel. diff --git a/simpeg_drivers/electricals/induced_polarization/two_dimensions/__init__.py b/simpeg_drivers/electricals/induced_polarization/two_dimensions/__init__.py index dbaf3358..13970f47 100644 --- a/simpeg_drivers/electricals/induced_polarization/two_dimensions/__init__.py +++ b/simpeg_drivers/electricals/induced_polarization/two_dimensions/__init__.py @@ -10,8 +10,8 @@ from .params import ( - InducedPolarization2DForwardParams, - InducedPolarization2DInversionParams, + IP2DForwardOptions, + IP2DInversionOptions, ) # pylint: disable=unused-import diff --git a/simpeg_drivers/electricals/induced_polarization/two_dimensions/constants.py b/simpeg_drivers/electricals/induced_polarization/two_dimensions/constants.py index 00bf5619..6157a9e3 100644 --- a/simpeg_drivers/electricals/induced_polarization/two_dimensions/constants.py +++ b/simpeg_drivers/electricals/induced_polarization/two_dimensions/constants.py @@ -141,235 +141,6 @@ "distributed_workers": None, } -default_ui_json = { - "title": "Induced Polarization (IP) 2D Inversion", - "icon": "PotentialElectrode", - "inversion_type": "induced polarization 2d", - "line_object": { - "association": "Cell", - "dataType": "Referenced", - "group": "Data", - "main": True, - "label": "Line ID", - "parent": "data_object", - "value": None, - "tooltip": "Selects the data representing the different lines in the survey.", - }, - "line_id": { - "group": "Data", - "main": True, - "min": 1, - "label": "Line number", - "value": 1, - "tooltip": "Selects the line of data to be processed.", - }, - "data_object": { - "main": True, - "group": "Data", - "label": "Object", - "meshType": "{275ecee9-9c24-4378-bf94-65f3c5fbe163}", - "value": None, - }, - "z_from_topo": { - "group": "Data", - "main": True, - "label": "Surface survey", - "tooltip": "Uncheck if borehole data is present", - "value": True, - }, - "chargeability_channel_bool": True, - "chargeability_channel": { - "association": "Cell", - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Chargeability (V/V)", - "parent": "data_object", - "value": None, - }, - "chargeability_uncertainty": { - "association": "Cell", - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "property": None, - "value": 1.0, - }, - "mesh": { - "group": "Mesh and models", - "main": True, - "optional": True, - "enabled": False, - "label": "Mesh", - "meshType": "{C94968EA-CF7D-11EB-B8BC-0242AC130003}", - "value": None, - }, - "u_cell_size": { - "min": 0.0, - "group": "Mesh and models", - "dependency": "mesh", - "dependencyType": "disabled", - "main": True, - "enabled": True, - "label": "Easting core cell size (m)", - "value": 25.0, - }, - "v_cell_size": { - "min": 0.0, - "group": "Mesh and models", - "dependency": "mesh", - "dependencyType": "disabled", - "main": True, - "enabled": True, - "label": "Northing core cell size (m)", - "value": 25.0, - }, - "depth_core": { - "min": 0.0, - "group": "Mesh and models", - "dependency": "mesh", - "dependencyType": "disabled", - "main": True, - "enabled": True, - "label": "Depth of core (m)", - "value": 500.0, - }, - "horizontal_padding": { - "min": 0.0, - "group": "Mesh and models", - "dependency": "mesh", - "dependencyType": "disabled", - "main": True, - "enabled": True, - "label": "Horizontal padding (m)", - "value": 1000.0, - }, - "vertical_padding": { - "min": 0.0, - "group": "Mesh and models", - "dependency": "mesh", - "dependencyType": "disabled", - "main": True, - "label": "Vertical padding (m)", - "value": 1000.0, - }, - "expansion_factor": { - "main": True, - "group": "Mesh and models", - "dependency": "mesh", - "dependencyType": "disabled", - "label": "Expansion factor", - "value": 1.1, - }, - "model_type": { - "choiceList": ["Conductivity (S/m)", "Resistivity (Ohm-m)"], - "main": True, - "group": "Mesh and models", - "label": "Model units", - "tooltip": "Select the units of the model.", - "value": "Conductivity (S/m)", - }, - "conductivity_model": { - "association": "Cell", - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": True, - "parent": "mesh", - "label": "Conductivity (S/m)", - "property": None, - "value": 1e-3, - }, - "starting_model": { - "association": "Cell", - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": False, - "parent": "mesh", - "label": "Initial chargeability (V/V)", - "property": None, - "value": 0.0, - }, - "reference_model": { - "association": "Cell", - "dataType": "Float", - "main": True, - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Reference chargeability (V/V)", - "property": None, - "optional": True, - "enabled": False, - "value": 0.0, - }, - "lower_bound": { - "association": "Cell", - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Lower bound (V/V)", - "property": None, - "optional": True, - "value": 0, - "enabled": False, - }, - "upper_bound": { - "association": "Cell", - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Upper bound (V/V)", - "property": None, - "optional": True, - "value": 100.0, - "enabled": False, - }, - "tile_spatial": 1, - "receivers_offset_z": { - "group": "Data pre-processing", - "label": "Z static offset", - "optional": True, - "enabled": False, - "value": 0.0, - "visible": False, - }, - "receivers_radar_drape": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data pre-processing", - "label": "Z radar offset", - "tooltip": "Apply a non-homogeneous offset to survey object from radar channel.", - "optional": True, - "parent": "data_object", - "value": None, - "enabled": False, - "visible": False, - }, -} - -default_ui_json = dict(base_default_ui_json, **default_ui_json) - -################ Validations ################# - -validations = { - "inversion_type": { - "required": True, - "values": ["induced polarization 2d"], - }, - "data_object": {"required": True, "types": [UUID, PotentialElectrode]}, -} - -validations = dict(base_validations, **validations) - app_initializer = { "geoh5": str(assets_path() / "FlinFlon_dcip.geoh5"), "data_object": UUID("{6e14de2c-9c2f-4976-84c2-b330d869cb82}"), diff --git a/simpeg_drivers/electricals/induced_polarization/two_dimensions/driver.py b/simpeg_drivers/electricals/induced_polarization/two_dimensions/driver.py index 11f8680d..09345225 100644 --- a/simpeg_drivers/electricals/induced_polarization/two_dimensions/driver.py +++ b/simpeg_drivers/electricals/induced_polarization/two_dimensions/driver.py @@ -13,18 +13,21 @@ from simpeg_drivers.electricals.driver import Base2DDriver -from .constants import validations from .params import ( - InducedPolarization2DForwardParams, - InducedPolarization2DInversionParams, + IP2DForwardOptions, + IP2DInversionOptions, ) -class InducedPolarization2DForwardDriver(Base2DDriver): - _params_class = InducedPolarization2DForwardParams - _validations = validations +class IP2DForwardDriver(Base2DDriver): + """Induced Polarization 2D forward driver.""" + _params_class = IP2DForwardOptions + _validations = {} -class InducedPolarization2DInversionDriver(Base2DDriver): - _params_class = InducedPolarization2DInversionParams - _validations = validations + +class IP2DInversionDriver(Base2DDriver): + """Induced Polarization 2D inversion driver.""" + + _params_class = IP2DInversionOptions + _validations = {} diff --git a/simpeg_drivers/electricals/induced_polarization/two_dimensions/params.py b/simpeg_drivers/electricals/induced_polarization/two_dimensions/params.py index 5a9e12bd..af179692 100644 --- a/simpeg_drivers/electricals/induced_polarization/two_dimensions/params.py +++ b/simpeg_drivers/electricals/induced_polarization/two_dimensions/params.py @@ -18,15 +18,15 @@ from simpeg_drivers import assets_path from simpeg_drivers.electricals.params import ( - DrapeModelData, - LineSelectionData, + DrapeModelOptions, + LineSelectionOptions, ) -from simpeg_drivers.params import BaseForwardData, BaseInversionData +from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions -class InducedPolarization2DForwardParams(BaseForwardData): +class IP2DForwardOptions(BaseForwardOptions): """ - Parameter class for two dimensional induced polarization forward simulation. + Induced Polarization 2D forward options. :param chargeability_channel_bool: Chargeability channel boolean. :param mesh: Optional mesh object if providing a heterogeneous model. @@ -45,15 +45,15 @@ class InducedPolarization2DForwardParams(BaseForwardData): physical_property: str = "chargeability" chargeability_channel_bool: bool = True - line_selection: LineSelectionData + line_selection: LineSelectionOptions mesh: DrapeModel | None = None - drape_model: DrapeModelData = DrapeModelData() + drape_model: DrapeModelOptions = DrapeModelOptions() conductivity_model: float | FloatData -class InducedPolarization2DInversionParams(BaseInversionData): +class IP2DInversionOptions(BaseInversionOptions): """ - Parameter class for two dimensional induced polarization forward simulation. + Induced Polarization 2D inversion options. :param chargeability_channel: Chargeability data channel. :param chargeability_uncertainty: Chargeability data uncertainty channel. @@ -76,9 +76,9 @@ class InducedPolarization2DInversionParams(BaseInversionData): chargeability_channel: FloatData chargeability_uncertainty: float | FloatData | None = None - line_selection: LineSelectionData + line_selection: LineSelectionOptions mesh: DrapeModel | None = None - drape_model: DrapeModelData = DrapeModelData() + drape_model: DrapeModelOptions = DrapeModelOptions() conductivity_model: float | FloatData lower_bound: float | FloatData | None = 0.0 length_scale_y: None = None diff --git a/simpeg_drivers/electricals/params.py b/simpeg_drivers/electricals/params.py index 70283758..ef27af59 100644 --- a/simpeg_drivers/electricals/params.py +++ b/simpeg_drivers/electricals/params.py @@ -11,13 +11,11 @@ from __future__ import annotations -from geoh5py.data import Data, DataAssociationEnum, ReferencedData +from geoh5py.data import DataAssociationEnum, ReferencedData from pydantic import BaseModel, ConfigDict, field_validator, model_validator -from simpeg_drivers.params import InversionBaseParams - -class LineSelectionData(BaseModel): +class LineSelectionOptions(BaseModel): """ Line selection parameters for 2D inversions. @@ -46,7 +44,7 @@ def line_id_referenced(self): return self -class DrapeModelData(BaseModel): +class DrapeModelOptions(BaseModel): """ Drape model parameters for 2D simulation/inversion]. @@ -66,7 +64,7 @@ class DrapeModelData(BaseModel): expansion_factor: float = 100.0 -class FileControlData(BaseModel): +class FileControlOptions(BaseModel): """ File control parameters for pseudo 3D simulations. @@ -76,144 +74,3 @@ class FileControlData(BaseModel): files_only: bool = False cleanup: bool = True - - -class Core2DParams(InversionBaseParams): - """ - Core parameter class for 2D electrical->conductivity inversion. - """ - - def __init__(self, input_file=None, forward_only=False, **kwargs): - self._line_object = None - self._u_cell_size: float = 25.0 - self._v_cell_size: float = 25.0 - self._depth_core: float = 100.0 - self._horizontal_padding: float = 100.0 - self._vertical_padding: float = 100.0 - self._expansion_factor: float = 100.0 - self._model_type = "Conductivity (S/m)" - - super().__init__(input_file=input_file, forward_only=forward_only, **kwargs) - - @property - def line_object(self): - """ReferenceData entity containing line information on poles.""" - return self._line_object - - @line_object.setter - def line_object(self, val): - self._line_object = val - - if isinstance(val, Data) and val.association is not DataAssociationEnum.CELL: - raise ValueError("Line identifier must be associated with cells.") - - @property - def model_type(self): - """Model units.""" - return self._model_type - - @model_type.setter - def model_type(self, val): - self.setter_validator("model_type", val) - - @property - def u_cell_size(self): - """""" - return self._u_cell_size - - @u_cell_size.setter - def u_cell_size(self, value): - self.setter_validator("u_cell_size", value) - - @property - def v_cell_size(self): - """""" - return self._v_cell_size - - @v_cell_size.setter - def v_cell_size(self, value): - self.setter_validator("v_cell_size", value) - - @property - def depth_core(self): - """""" - return self._depth_core - - @depth_core.setter - def depth_core(self, value): - self.setter_validator("depth_core", value) - - @property - def horizontal_padding(self): - """""" - return self._horizontal_padding - - @horizontal_padding.setter - def horizontal_padding(self, value): - self.setter_validator("horizontal_padding", value) - - @property - def vertical_padding(self): - """""" - return self._vertical_padding - - @vertical_padding.setter - def vertical_padding(self, value): - self.setter_validator("vertical_padding", value) - - @property - def expansion_factor(self): - """""" - return self._expansion_factor - - @expansion_factor.setter - def expansion_factor(self, value): - self.setter_validator("expansion_factor", value) - - -class Base2DParams(Core2DParams): - """ - Parameter class for electrical->induced polarization (IP) inversion. - """ - - def __init__(self, input_file=None, forward_only=False, **kwargs): - self._line_id = None - - super().__init__(input_file=input_file, forward_only=forward_only, **kwargs) - - @property - def line_id(self): - """Line ID to invert.""" - return self._line_id - - @line_id.setter - def line_id(self, val): - self._line_id = val - - -class BasePseudo3DParams(Core2DParams): - """ - Base parameter class for pseudo electrical->conductivity inversion. - """ - - def __init__(self, input_file=None, forward_only=False, **kwargs): - self._files_only = None - self._cleanup = None - - super().__init__(input_file=input_file, forward_only=forward_only, **kwargs) - - @property - def files_only(self): - return self._files_only - - @files_only.setter - def files_only(self, val): - self.setter_validator("files_only", val) - - @property - def cleanup(self): - return self._cleanup - - @cleanup.setter - def cleanup(self, val): - self.setter_validator("cleanup", val) diff --git a/simpeg_drivers/electromagnetics/frequency_domain/__init__.py b/simpeg_drivers/electromagnetics/frequency_domain/__init__.py index 9dc6d396..49293842 100644 --- a/simpeg_drivers/electromagnetics/frequency_domain/__init__.py +++ b/simpeg_drivers/electromagnetics/frequency_domain/__init__.py @@ -9,7 +9,10 @@ # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -from .params import FrequencyDomainElectromagneticsParams +from .params import ( + FDEMForwardOptions, + FDEMInversionOptions, +) # pylint: disable=unused-import # flake8: noqa diff --git a/simpeg_drivers/electromagnetics/frequency_domain/constants.py b/simpeg_drivers/electromagnetics/frequency_domain/constants.py index 4ecb2603..0ab64b34 100644 --- a/simpeg_drivers/electromagnetics/frequency_domain/constants.py +++ b/simpeg_drivers/electromagnetics/frequency_domain/constants.py @@ -11,8 +11,6 @@ from __future__ import annotations -from uuid import UUID - from geoh5py.objects.surveys.electromagnetics.airborne_fem import AirborneFEMReceivers import simpeg_drivers @@ -117,151 +115,3 @@ "generate_sweep": False, "distributed_workers": None, } - -default_ui_json = { - "title": "Frequency Domain Electromagnetic Inversion", - "icon": "surveyairborneem", - "inversion_type": "fem", - "data_object": { - "main": True, - "group": "Data", - "label": "Object", - "meshType": [ - "{b3a47539-0301-4b27-922e-1dde9d882c60}", # AirborneFEMReceivers - ], - "value": None, - }, - "z_real_channel_bool": { - "group": "Data", - "main": True, - "label": "Z real component", - "value": False, - }, - "z_real_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "z-real component", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "z_real_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "z_real_channel", - "dependencyType": "enabled", - "value": None, - }, - "z_imag_channel_bool": { - "group": "Data", - "main": True, - "label": "Z imag component", - "value": False, - }, - "z_imag_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "z-imag component", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "z_imag_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "z_imag_channel", - "dependencyType": "enabled", - "value": None, - }, - "model_type": { - "choiceList": ["Conductivity (S/m)", "Resistivity (Ohm-m)"], - "main": True, - "group": "Mesh and models", - "label": "Model units", - "tooltip": "Select the units of the model.", - "value": "Conductivity (S/m)", - }, - "starting_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": False, - "parent": "mesh", - "label": "Initial", - "property": None, - "value": 1e-3, - }, - "reference_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "main": True, - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Reference", - "property": None, - "optional": True, - "enabled": False, - "value": 1e-3, - }, - "lower_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Lower bound", - "property": None, - "optional": True, - "value": 1e-8, - "enabled": False, - }, - "upper_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Upper bound", - "property": None, - "optional": True, - "value": 100.0, - "enabled": False, - }, -} -default_ui_json = dict(base_default_ui_json, **default_ui_json) -validations = { - "inversion_type": { - "types": [str], - "required": True, - "values": ["fem"], - }, - "data_object": {"types": [str, UUID, AirborneFEMReceivers]}, - "z_real_channel": {"one_of": "data_channel"}, - "z_real_uncertainty": {"one_of": "uncertainty_channel"}, - "z_imag_channel": {"one_of": "data_channel"}, - "z_imag_uncertainty": {"one_of": "uncertainty_channel"}, -} -validations = dict(base_validations, **validations) -app_initializer = {} diff --git a/simpeg_drivers/electromagnetics/frequency_domain/driver.py b/simpeg_drivers/electromagnetics/frequency_domain/driver.py index 78dd8cc3..e517f174 100644 --- a/simpeg_drivers/electromagnetics/frequency_domain/driver.py +++ b/simpeg_drivers/electromagnetics/frequency_domain/driver.py @@ -13,13 +13,24 @@ from simpeg_drivers.driver import InversionDriver -from .constants import validations -from .params import FrequencyDomainElectromagneticsParams +from .params import ( + FDEMForwardOptions, + FDEMInversionOptions, +) -class FrequencyDomainElectromagneticsDriver(InversionDriver): - _params_class = FrequencyDomainElectromagneticsParams - _validations = validations +class FDEMForwardDriver(InversionDriver): + """Frequency Domain Electromagnetic forward driver.""" - def __init__(self, params: FrequencyDomainElectromagneticsParams): + _params_class = FDEMForwardOptions + _validations = {} + + def __init__(self, params: FDEMForwardOptions): super().__init__(params) + + +class FDEMInversionDriver(InversionDriver): + """Frequency Domain Electromagnetic inversion driver.""" + + _params_class = FDEMInversionOptions + _validations = {} diff --git a/simpeg_drivers/electromagnetics/frequency_domain/params.py b/simpeg_drivers/electromagnetics/frequency_domain/params.py index 2791f19a..9834aaef 100644 --- a/simpeg_drivers/electromagnetics/frequency_domain/params.py +++ b/simpeg_drivers/electromagnetics/frequency_domain/params.py @@ -11,68 +11,61 @@ from __future__ import annotations -from copy import deepcopy -from uuid import UUID +from pathlib import Path +from typing import ClassVar, TypeAlias + +from geoh5py.groups import PropertyGroup +from geoh5py.objects import ( + AirborneFEMReceivers, + LargeLoopGroundFEMReceivers, + MovingLoopGroundFEMReceivers, +) + +from simpeg_drivers import assets_path +from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions, EMDataMixin -from simpeg_drivers.params import InversionBaseParams -from .constants import ( - default_ui_json, - forward_defaults, - inversion_defaults, - validations, +Receivers: TypeAlias = ( + MovingLoopGroundFEMReceivers | LargeLoopGroundFEMReceivers | AirborneFEMReceivers ) -class FrequencyDomainElectromagneticsParams(InversionBaseParams): +class FDEMForwardOptions(EMDataMixin, BaseForwardOptions): """ - Parameter class for Frequency-domain Electromagnetic (FEM) -> conductivity inversion. + Frequency Domain Electromagnetic Forward options. + + :param z_real_channel_bool: Real impedance channel boolean. + :param z_imag_channel_bool: Imaginary impedance channel boolean. + :param model_type: Specify whether the models are provided in resistivity or conductivity. """ - _physical_property = "conductivity" - - def __init__(self, input_file=None, forward_only=False, **kwargs): - self._default_ui_json = deepcopy(default_ui_json) - self._forward_defaults = deepcopy(forward_defaults) - self._inversion_defaults = deepcopy(inversion_defaults) - self._inversion_type = "fem" - self._validations = validations - self._tx_offsets = None - self._z_real_channel_bool = None - self._z_real_channel = None - self._z_real_uncertainty = None - self._z_imag_channel_bool = None - self._z_imag_channel = None - self._z_imag_uncertainty = None - self._model_type = "Conductivity (S/m)" - - super().__init__(input_file=input_file, forward_only=forward_only, **kwargs) - - def data_channel(self, component: str): - """Return uuid of data channel.""" - return getattr(self, "_".join([component, "channel"]), None) - - def uncertainty_channel(self, component: str): - """Return uuid of uncertainty channel.""" - return getattr(self, "_".join([component, "uncertainty"]), None) - - def property_group_data(self, property_group: UUID): - """ - Return dictionary of channel/data. - - :param property_group: Property group uid - """ - channels = self.data_object.channels - if self.forward_only: - out = {k: None for k in channels} - else: - group = self.data_object.find_or_create_property_group( - name=property_group.name - ) - properties = [self.geoh5.get_entity(p)[0].values for p in group.properties] - out = {f: properties[i] for i, f in enumerate(channels)} - - return out + name: ClassVar[str] = "Frequency Domain Electromagnetics Forward" + title: ClassVar[str] = "Frequency-domain EM (FEM) Forward" + default_ui_json: ClassVar[Path] = assets_path() / "uijson/fem_forward.ui.json" + + inversion_type: str = "fem" + physical_property: str = "conductivity" + + data_object: Receivers + z_real_channel_bool: bool + z_imag_channel_bool: bool + model_type: str = "Conductivity (S/m)" + + @property + def tx_offsets(self): + """Return transmitter offsets from frequency metadata""" + + try: + offset_data = self.data_object.metadata["EM Dataset"][ + "Frequency configurations" + ] + tx_offsets = {k["Frequency"]: k["Offset"] for k in offset_data} + + except KeyError as exception: + msg = "Metadata must contain 'Frequency configurations' dictionary with 'Offset' data." + raise KeyError(msg) from exception + + return tx_offsets @property def unit_conversion(self): @@ -82,83 +75,52 @@ def unit_conversion(self): } return conversion[self.data_object.unit] - def data(self, component: str): - """Returns array of data for chosen data component.""" - property_group = self.data_channel(component) - return self.property_group_data(property_group) - - def uncertainty(self, component: str) -> float: - """Returns uncertainty for chosen data component.""" - uid = self.uncertainty_channel(component) - return self.property_group_data(uid) - - @property - def model_type(self): - """Model units.""" - return self._model_type - - @model_type.setter - def model_type(self, val): - self.setter_validator("model_type", val) - @property - def tx_offsets(self): - if self._tx_offsets is None and self.data_object is not None: - try: - offset_data = self.data_object.metadata["EM Dataset"][ - "Frequency configurations" - ] - self._tx_offsets = {k["Frequency"]: k["Offset"] for k in offset_data} - except KeyError as exception: - msg = "Metadata must contain 'Frequency configurations' dictionary with 'Offset' data." - raise KeyError(msg) from exception - - return self._tx_offsets - - @property - def z_real_channel_bool(self): - return self._z_real_channel_bool - - @z_real_channel_bool.setter - def z_real_channel_bool(self, val): - self.setter_validator("z_real_channel_bool", val) +class FDEMInversionOptions(EMDataMixin, BaseInversionOptions): + """ + Frequency Domain Electromagnetic Inversion options. - @property - def z_real_channel(self): - return self._z_real_channel + :param z_real_channel: Real impedance channel. + :param z_real_uncertainty: Real impedance uncertainty channel. + :param z_imag_channel: Imaginary impedance channel. + :param z_imag_uncertainty: Imaginary impedance uncertainty channel. + :param model_type: Specify whether the models are provided in resistivity or conductivity. + """ - @z_real_channel.setter - def z_real_channel(self, val): - self.setter_validator("z_real_channel", val, fun=self._uuid_promoter) + name: ClassVar[str] = "Frequency Domain Electromagnetics Inversion" + title: ClassVar[str] = "Frequency-domain EM (FEM) Inversion" + default_ui_json: ClassVar[Path] = assets_path() / "uijson/fem_inversion.ui.json" - @property - def z_real_uncertainty(self): - return self._z_real_uncertainty + inversion_type: str = "fem" + physical_property: str = "conductivity" - @z_real_uncertainty.setter - def z_real_uncertainty(self, val): - self.setter_validator("z_real_uncertainty", val, fun=self._uuid_promoter) + data_object: Receivers + z_real_channel: PropertyGroup | None = None + z_real_uncertainty: PropertyGroup | None = None + z_imag_channel: PropertyGroup | None = None + z_imag_uncertainty: PropertyGroup | None = None + model_type: str = "Conductivity (S/m)" @property - def z_imag_channel_bool(self): - return self._z_imag_channel_bool + def tx_offsets(self): + """Return transmitter offsets from frequency metadata""" - @z_imag_channel_bool.setter - def z_imag_channel_bool(self, val): - self.setter_validator("z_imag_channel_bool", val) + try: + offset_data = self.data_object.metadata["EM Dataset"][ + "Frequency configurations" + ] + tx_offsets = {k["Frequency"]: k["Offset"] for k in offset_data} - @property - def z_imag_channel(self): - return self._z_imag_channel + except KeyError as exception: + msg = "Metadata must contain 'Frequency configurations' dictionary with 'Offset' data." + raise KeyError(msg) from exception - @z_imag_channel.setter - def z_imag_channel(self, val): - self.setter_validator("z_imag_channel", val, fun=self._uuid_promoter) + return tx_offsets @property - def z_imag_uncertainty(self): - return self._z_imag_uncertainty - - @z_imag_uncertainty.setter - def z_imag_uncertainty(self, val): - self.setter_validator("z_imag_uncertainty", val, fun=self._uuid_promoter) + def unit_conversion(self): + """Return time unit conversion factor.""" + conversion = { + "Hertz (Hz)": 1.0, + } + return conversion[self.data_object.unit] diff --git a/simpeg_drivers/electromagnetics/time_domain/__init__.py b/simpeg_drivers/electromagnetics/time_domain/__init__.py index 0649217f..54036b7b 100644 --- a/simpeg_drivers/electromagnetics/time_domain/__init__.py +++ b/simpeg_drivers/electromagnetics/time_domain/__init__.py @@ -9,7 +9,10 @@ # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -from .params import TimeDomainElectromagneticsParams +from .params import ( + TDEMForwardOptions, + TDEMInversionOptions, +) # pylint: disable=unused-import # flake8: noqa diff --git a/simpeg_drivers/electromagnetics/time_domain/constants.py b/simpeg_drivers/electromagnetics/time_domain/constants.py index 6178d2cc..8958a028 100644 --- a/simpeg_drivers/electromagnetics/time_domain/constants.py +++ b/simpeg_drivers/electromagnetics/time_domain/constants.py @@ -11,8 +11,6 @@ from __future__ import annotations -from uuid import UUID - from geoh5py.objects import AirborneTEMReceivers, LargeLoopGroundTEMReceivers import simpeg_drivers @@ -122,200 +120,3 @@ "generate_sweep": False, "distributed_workers": None, } -default_ui_json = { - "title": "Time Domain Electromagnetic Inversion", - "icon": "surveyairborneem", - "inversion_type": "tdem", - "data_object": { - "main": True, - "group": "Data", - "label": "Object", - "meshType": [ - "{19730589-fd28-4649-9de0-ad47249d9aba}", - "{deebe11a-b57b-4a03-99d6-8f27b25eb2a8}", - ], - "value": None, - }, - "data_units": { - "choiceList": ["dB/dt (T/s)", "B (T)", "H (A/m)"], - "group": "Data", - "main": True, - "label": "Data type", - "tooltip": "Set the units of the data.", - "value": "dB/dt (T/s)", - }, - "z_channel_bool": { - "group": "Data", - "main": True, - "label": "Z component", - "value": False, - }, - "z_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "z-component", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "z_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "z_channel", - "dependencyType": "enabled", - "value": None, - }, - "x_channel_bool": { - "group": "Data", - "main": True, - "label": "X component", - "value": False, - }, - "x_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "x-component", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "x_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "x_channel", - "dependencyType": "enabled", - "value": None, - }, - "y_channel_bool": { - "group": "Data", - "main": True, - "label": "Y component", - "value": False, - }, - "y_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "y-component", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "y_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "y_channel", - "dependencyType": "enabled", - "value": None, - }, - "model_type": { - "choiceList": ["Conductivity (S/m)", "Resistivity (Ohm-m)"], - "main": True, - "group": "Mesh and models", - "label": "Model units", - "tooltip": "Select the units of the model.", - "value": "Conductivity (S/m)", - }, - "starting_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": False, - "parent": "mesh", - "label": "Initial", - "property": None, - "value": 1e-3, - }, - "reference_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "main": True, - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Reference", - "property": None, - "optional": True, - "enabled": False, - "value": 1e-3, - }, - "lower_bound": { - "association": "Cell", - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Lower bound", - "property": None, - "optional": True, - "value": 1e-8, - "enabled": False, - }, - "upper_bound": { - "association": "Cell", - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Upper bound", - "property": None, - "optional": True, - "value": 100.0, - "enabled": False, - }, - "store_sensitivities": { - "choiceList": ["ram", "disk"], - "group": "Compute", - "label": "Storage device", - "tooltip": "Only RAM storage available for now.", - "value": "ram", - }, -} -default_ui_json = dict(base_default_ui_json, **default_ui_json) -validations = { - "inversion_type": { - "types": [str], - "required": True, - "values": ["tdem"], - }, - "data_object": { - "types": [str, UUID, AirborneTEMReceivers, LargeLoopGroundTEMReceivers] - }, - "z_channel": {"one_of": "data_channel"}, - "z_uncertainty": {"one_of": "uncertainty_channel"}, - "x_channel": {"one_of": "data_channel"}, - "x_uncertainty": {"one_of": "uncertainty_channel"}, - "y_channel": {"one_of": "data_channel"}, - "y_uncertainty": {"one_of": "uncertainty_channel"}, -} -validations = dict(base_validations, **validations) -app_initializer = {} diff --git a/simpeg_drivers/electromagnetics/time_domain/driver.py b/simpeg_drivers/electromagnetics/time_domain/driver.py index 4e5ecb6b..17e840de 100644 --- a/simpeg_drivers/electromagnetics/time_domain/driver.py +++ b/simpeg_drivers/electromagnetics/time_domain/driver.py @@ -19,16 +19,76 @@ from simpeg_drivers.driver import InversionDriver from simpeg_drivers.utils.utils import tile_locations -from .constants import validations -from .params import TimeDomainElectromagneticsParams +from .params import ( + TDEMForwardOptions, + TDEMInversionOptions, +) + + +class TDEMForwardDriver(InversionDriver): + """Time Domain Electromagnetic forward driver.""" + + _params_class = TDEMForwardOptions + _validations = {} + + def get_tiles(self) -> list[np.ndarray]: + """ + Special method to tile the data based on the transmitters center locations. + + First the transmitter locations are grouped into groups using kmeans clustering. + Second, if the number of groups is less than the number of 'tile_spatial' value, the groups are + further divided into groups based on the clustering of receiver locations. + """ + if not isinstance(self.params.data_object, LargeLoopGroundTEMReceivers): + return super().get_tiles() + + tx_ids = self.params.data_object.transmitters.tx_id_property.values + unique_tile_ids = np.unique(tx_ids) + n_groups = np.min([len(unique_tile_ids), self.params.tile_spatial]) + locations = [] + for uid in unique_tile_ids: + locations.append( + np.mean( + self.params.data_object.transmitters.vertices[tx_ids == uid], + axis=0, + ) + ) + + # Tile transmitters spatially by loop center + tx_tiles = tile_locations( + np.vstack(locations), + n_groups, + method="kmeans", + ) + receivers_tx_ids = self.params.data_object.tx_id_property.values + tiles = [] + for _t_id, group in enumerate(tx_tiles): + sub_group = [] + for value in group: + receiver_ind = receivers_tx_ids == unique_tile_ids[value] + sub_group.append(np.where(receiver_ind)[0]) + + tiles.append(np.hstack(sub_group)) + + # If number of tiles remaining, brake up receivers spatially per transmitter + while len(tiles) < self.params.tile_spatial: + largest_group = np.argmax([len(tile) for tile in tiles]) + tile = tiles.pop(largest_group) + new_tiles = tile_locations( + self.params.data_object.vertices[tile], + 2, + method="kmeans", + ) + tiles += [tile[new_tiles[0]], tile[new_tiles[1]]] + + return tiles -class TimeDomainElectromagneticsDriver(InversionDriver): - _params_class = TimeDomainElectromagneticsParams - _validations = validations +class TDEMInversionDriver(InversionDriver): + """Time Domain Electromagnetic inversion driver.""" - def __init__(self, params: TimeDomainElectromagneticsParams): - super().__init__(params) + _params_class = TDEMInversionOptions + _validations = {} def get_tiles(self) -> list[np.ndarray]: """ diff --git a/simpeg_drivers/electromagnetics/time_domain/params.py b/simpeg_drivers/electromagnetics/time_domain/params.py index 6affbc8d..ffa15a44 100644 --- a/simpeg_drivers/electromagnetics/time_domain/params.py +++ b/simpeg_drivers/electromagnetics/time_domain/params.py @@ -11,95 +11,51 @@ from __future__ import annotations -from copy import deepcopy -from uuid import UUID +from pathlib import Path +from typing import ClassVar, TypeAlias + +from geoh5py.groups import PropertyGroup +from geoh5py.objects import ( + AirborneTEMReceivers, + LargeLoopGroundTEMReceivers, + MovingLoopGroundTEMReceivers, +) + +from simpeg_drivers import assets_path +from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions, EMDataMixin -from simpeg_drivers.params import InversionBaseParams -from .constants import ( - default_ui_json, - forward_defaults, - inversion_defaults, - validations, +Receivers: TypeAlias = ( + MovingLoopGroundTEMReceivers | LargeLoopGroundTEMReceivers | AirborneTEMReceivers ) -class TimeDomainElectromagneticsParams(InversionBaseParams): +class TDEMForwardOptions(EMDataMixin, BaseForwardOptions): """ - Parameter class for Time-domain Electromagnetic (TEM) -> conductivity inversion. + Time Domain Electromagnetic forward options. + + :param z_channel_bool: Z-component data channel boolean. + :param z_channel_uncertainty: Z-component data channel uncertainty. + :param x_channel_bool: X-component data channel boolean. + :param x_channel_uncertainty: X-component data channel uncertainty. + :param y_channel_bool: Y-component data channel boolean. + :param y_channel_uncertainty: Y-component data channel uncertainty. + :param model_type: Specify whether the models are provided in resistivity or conductivity. + :param data_units: Units for the TEM data """ - _physical_property = "conductivity" - - def __init__(self, input_file=None, forward_only=False, **kwargs): - self._default_ui_json = deepcopy(default_ui_json) - self._forward_defaults = deepcopy(forward_defaults) - self._inversion_defaults = deepcopy(inversion_defaults) - self._inversion_type = "tdem" - self._validations = validations - self._data_units = "dB/dt (T/s)" - self._z_channel_bool = None - self._z_channel = None - self._z_uncertainty = None - self._x_channel_bool = None - self._x_channel = None - self._x_uncertainty = None - self._y_channel_bool = None - self._y_channel = None - self._y_uncertainty = None - - self._model_type = "Conductivity (S/m)" - - super().__init__(input_file=input_file, forward_only=forward_only, **kwargs) - - def data_channel(self, component: str): - """Return uuid of data channel.""" - return getattr(self, "_".join([component, "channel"]), None) + name: ClassVar[str] = "Time Domain Electromagnetics Forward" + title: ClassVar[str] = "Time-domain EM (TEM) Forward" + default_ui_json: ClassVar[Path] = assets_path() / "uijson/tdem_forward.ui.json" - @property - def data_units(self): - return self._data_units - - @data_units.setter - def data_units(self, val): - self.setter_validator("data_units", val) - - def uncertainty_channel(self, component: str): - """Return uuid of uncertainty channel.""" - return getattr(self, "_".join([component, "uncertainty"]), None) - - def property_group_data(self, property_group: UUID): - data = {} - channels = self.data_object.channels - if self.forward_only: - return {k: None for k in channels} - else: - group = self.data_object.find_or_create_property_group( - name=property_group.name - ) - property_names = [ - self.geoh5.get_entity(p)[0].name for p in group.properties - ] - properties = [self.geoh5.get_entity(p)[0].values for p in group.properties] - for i, f in enumerate(channels): - try: - f_ind = property_names.index( - next(k for k in property_names if f"{f:.2e}" in k) - ) # Safer if data was saved with geoapps naming convention - data[f] = properties[f_ind] - except StopIteration: - data[f] = properties[i] # in case of other naming conventions - - return data - - @property - def model_type(self): - """Model units.""" - return self._model_type + inversion_type: str = "tdem" + physical_property: str = "conductivity" - @model_type.setter - def model_type(self, val): - self.setter_validator("model_type", val) + data_object: Receivers + z_channel_bool: bool | None = None + x_channel_bool: bool | None = None + data_units: str = "dB/dt (T/s)" + model_type: str = "Conductivity (S/m)" @property def unit_conversion(self): @@ -111,84 +67,44 @@ def unit_conversion(self): } return conversion[self.data_object.unit] - def data(self, component: str): - """Returns array of data for chosen data component.""" - property_group = self.data_channel(component) - return self.property_group_data(property_group) - def uncertainty(self, component: str) -> float: - """Returns uncertainty for chosen data component.""" - uid = self.uncertainty_channel(component) - return self.property_group_data(uid) - - @property - def z_channel_bool(self): - return self._z_channel_bool - - @z_channel_bool.setter - def z_channel_bool(self, val): - self.setter_validator("z_channel_bool", val) - - @property - def z_channel(self): - return self._z_channel - - @z_channel.setter - def z_channel(self, val): - self.setter_validator("z_channel", val, fun=self._uuid_promoter) - - @property - def z_uncertainty(self): - return self._z_uncertainty - - @z_uncertainty.setter - def z_uncertainty(self, val): - self.setter_validator("z_uncertainty", val, fun=self._uuid_promoter) - - @property - def x_channel_bool(self): - return self._x_channel_bool - - @x_channel_bool.setter - def x_channel_bool(self, val): - self.setter_validator("x_channel_bool", val) - - @property - def x_channel(self): - return self._x_channel - - @x_channel.setter - def x_channel(self, val): - self.setter_validator("x_channel", val, fun=self._uuid_promoter) - - @property - def x_uncertainty(self): - return self._x_uncertainty - - @x_uncertainty.setter - def x_uncertainty(self, val): - self.setter_validator("x_uncertainty", val, fun=self._uuid_promoter) - - @property - def y_channel_bool(self): - return self._y_channel_bool +class TDEMInversionOptions(EMDataMixin, BaseInversionOptions): + """ + Time Domain Electromagnetic Inversion options. + + :param z_channel: Z-component data channel. + :param z_uncertainty: Z-component data channel uncertainty. + :param x_channel: X-component data channel. + :param x_uncertainty: X-component data channel uncertainty. + :param y_channel: Y-component data channel. + :param y_uncertainty: Y-component data channel uncertainty. + :param model_type: Specify whether the models are provided in resistivity or conductivity. + :param data_units: Units for the TEM data + """ - @y_channel_bool.setter - def y_channel_bool(self, val): - self.setter_validator("y_channel_bool", val) + name: ClassVar[str] = "Time Domain Electromagnetics Inversion" + title: ClassVar[str] = "Time-domain EM (TEM) Inversion" + default_ui_json: ClassVar[Path] = assets_path() / "uijson/tdem_inversion.ui.json" - @property - def y_channel(self): - return self._y_channel + inversion_type: str = "tdem" + physical_property: str = "conductivity" - @y_channel.setter - def y_channel(self, val): - self.setter_validator("y_channel", val, fun=self._uuid_promoter) + data_object: Receivers + z_channel: PropertyGroup | None = None + z_uncertainty: PropertyGroup | None = None + x_channel: PropertyGroup | None = None + x_uncertainty: PropertyGroup | None = None + y_channel: PropertyGroup | None = None + y_uncertainty: PropertyGroup | None = None + data_units: str = "dB/dt (T/s)" + model_type: str = "Conductivity (S/m)" @property - def y_uncertainty(self): - return self._y_uncertainty - - @y_uncertainty.setter - def y_uncertainty(self, val): - self.setter_validator("y_uncertainty", val, fun=self._uuid_promoter) + def unit_conversion(self): + """Return time unit conversion factor.""" + conversion = { + "Seconds (s)": 1.0, + "Milliseconds (ms)": 1e-3, + "Microseconds (us)": 1e-6, + } + return conversion[self.data_object.unit] diff --git a/simpeg_drivers/line_sweep/driver.py b/simpeg_drivers/line_sweep/driver.py index 5987e358..19874de4 100644 --- a/simpeg_drivers/line_sweep/driver.py +++ b/simpeg_drivers/line_sweep/driver.py @@ -30,17 +30,19 @@ class LineSweepDriver(SweepDriver, InversionDriver): + """Line Sweep driver for batch 2D forward and inversion drivers.""" + def __init__(self, params): self._out_group = None self.workspace = params.geoh5 - self.pseudo3d_params = params + self.batch2d_params = params self.cleanup = params.file_control.cleanup if ( - hasattr(self.pseudo3d_params, "out_group") - and self.pseudo3d_params.out_group is None + hasattr(self.batch2d_params, "out_group") + and self.batch2d_params.out_group is None ): - self.pseudo3d_params.out_group = self.out_group + self.batch2d_params.out_group = self.out_group super().__init__(self.setup_params()) @@ -49,18 +51,18 @@ def out_group(self): """The SimPEGGroup""" if self._out_group is None: with fetch_active_workspace(self.workspace, mode="r+"): - name = self.pseudo3d_params.inversion_type.capitalize() - if self.pseudo3d_params.forward_only: + name = self.batch2d_params.inversion_type.capitalize() + if self.batch2d_params.forward_only: name += "Forward" else: name += "Inversion" # with fetch_active_workspace(self.geoh5, mode="r+"): self._out_group = SimPEGGroup.create( - self.pseudo3d_params.geoh5, name=name + self.batch2d_params.geoh5, name=name ) - self.pseudo3d_params.out_group = self._out_group - self.pseudo3d_params.update_group_options() + self.batch2d_params.out_group = self._out_group + self.batch2d_params.update_group_options() return self._out_group @@ -78,7 +80,7 @@ def setup_params(self): ) if not (ui_json_path).is_file(): with self.workspace.open(): - self.pseudo3d_params.write_ui_json( + self.batch2d_params.write_ui_json( path=h5_file_path.parent / ui_json_path.name ) generate( @@ -91,7 +93,7 @@ def setup_params(self): / (re.sub(r"\.ui$", "", h5_file_path.stem) + "_sweep.ui.json") ) with self.workspace.open(mode="r"): - lines = self.pseudo3d_params.line_selection.line_object.values + lines = self.batch2d_params.line_selection.line_object.values ifile.data["line_id_start"] = int(lines.min()) ifile.data["line_id_end"] = int(lines.max()) ifile.data["line_id_n"] = len(np.unique(lines)) @@ -121,7 +123,7 @@ def line_files(path: str | Path): def collect_results(self): path = Path(self.workspace.h5file).parent files = LineSweepDriver.line_files(str(path)) - line_ids = self.pseudo3d_params.line_selection.line_object.values + line_ids = self.batch2d_params.line_selection.line_object.values data = {} drape_models = [] @@ -138,7 +140,7 @@ def collect_results(self): if isinstance(child, PotentialElectrode) ) line_data = survey.get_entity( - self.pseudo3d_params.line_selection.line_object.name + self.batch2d_params.line_selection.line_object.name ) if not line_data: @@ -154,7 +156,7 @@ def collect_results(self): local_simpeg_group = mesh.parent.copy( name=f"Line {line}", - parent=self.pseudo3d_params.out_group, + parent=self.batch2d_params.out_group, copy_children=False, ) local_simpeg_group.options = mesh.parent.options @@ -187,21 +189,21 @@ def collect_results(self): with open(ws.h5file.parent / "SimPEG.log", "w", encoding="utf8") as f: f.write("".join(log_lines)) - self.pseudo3d_params.data_object.add_data(data) + self.batch2d_params.data_object.add_data(data) - if self.pseudo3d_params.mesh is None: + if self.batch2d_params.mesh is None: return # interpolate drape model children common to all drape models into octree active = active_from_xyz( - self.pseudo3d_params.mesh, self.inversion_topography.locations + self.batch2d_params.mesh, self.inversion_topography.locations ) common_children = set.intersection( *[{c.name for c in d.children} for d in drape_models] ) children = {n: [n] * len(drape_models) for n in common_children} octree_model = drape_to_octree( - self.pseudo3d_params.mesh, drape_models, children, active, method="nearest" + self.batch2d_params.mesh, drape_models, children, active, method="nearest" ) # interpolate last iterations for each drape model into octree @@ -221,14 +223,14 @@ def collect_results(self): label: [c[last_iterations[i]] for i, c in enumerate(iter_children)] } octree_model = drape_to_octree( - self.pseudo3d_params.mesh, + self.batch2d_params.mesh, drape_models, children, active, method="nearest", ) - octree_model.copy(parent=self.pseudo3d_params.out_group) + octree_model.copy(parent=self.batch2d_params.out_group) def collect_line_data(self, survey, line_indices, data): """ diff --git a/simpeg_drivers/natural_sources/__init__.py b/simpeg_drivers/natural_sources/__init__.py index 4c01f5d1..e50ae978 100644 --- a/simpeg_drivers/natural_sources/__init__.py +++ b/simpeg_drivers/natural_sources/__init__.py @@ -9,8 +9,11 @@ # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -from .magnetotellurics import MagnetotelluricsParams -from .tipper import TipperParams +from .magnetotellurics import ( + MTForwardOptions, + MTInversionOptions, +) +from .tipper import TipperForwardOptions, TipperInversionOptions # pylint: disable=unused-import # flake8: noqa diff --git a/simpeg_drivers/natural_sources/magnetotellurics/__init__.py b/simpeg_drivers/natural_sources/magnetotellurics/__init__.py index bb61690f..9197c4b9 100644 --- a/simpeg_drivers/natural_sources/magnetotellurics/__init__.py +++ b/simpeg_drivers/natural_sources/magnetotellurics/__init__.py @@ -9,7 +9,7 @@ # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -from .params import MagnetotelluricsParams +from .params import MTForwardOptions, MTInversionOptions # pylint: disable=unused-import # flake8: noqa diff --git a/simpeg_drivers/natural_sources/magnetotellurics/constants.py b/simpeg_drivers/natural_sources/magnetotellurics/constants.py index a25caf4e..dcec848c 100644 --- a/simpeg_drivers/natural_sources/magnetotellurics/constants.py +++ b/simpeg_drivers/natural_sources/magnetotellurics/constants.py @@ -149,354 +149,6 @@ "distributed_workers": None, } -default_ui_json = { - "title": "Magnetotellurics Inversion", - "icon": "surveymagnetotellurics", - "inversion_type": "magnetotellurics", - "data_object": { - "main": True, - "group": "Data", - "label": "Object", - "meshType": "{b99bd6e5-4fe1-45a5-bd2f-75fc31f91b38}", - "value": None, - }, - "zxx_real_channel_bool": { - "group": "Data", - "main": True, - "label": "Zxx real", - "value": False, - }, - "zxx_real_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Zxx real", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "zxx_real_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "zxx_real_channel", - "dependencyType": "enabled", - "value": None, - }, - "zxx_imag_channel_bool": { - "group": "Data", - "main": True, - "label": "Zxx imaginary", - "value": False, - }, - "zxx_imag_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Zxx imaginary", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "zxx_imag_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "zxx_imag_channel", - "dependencyType": "enabled", - "value": None, - }, - "zxy_real_channel_bool": { - "group": "Data", - "main": True, - "label": "Zxy real", - "value": False, - }, - "zxy_real_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Zxy real", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "zxy_real_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "zxy_real_channel", - "dependencyType": "enabled", - "value": None, - }, - "zxy_imag_channel_bool": { - "group": "Data", - "main": True, - "label": "Zxy imaginary", - "value": False, - }, - "zxy_imag_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Zxy imaginary", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "zxy_imag_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "zxy_imag_channel", - "dependencyType": "enabled", - "value": None, - }, - "zyx_real_channel_bool": { - "group": "Data", - "main": True, - "label": "Zyx real", - "value": False, - }, - "zyx_real_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Zyx real", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "zyx_real_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "zyx_real_channel", - "dependencyType": "enabled", - "value": None, - }, - "zyx_imag_channel_bool": { - "group": "Data", - "main": True, - "label": "Zyx imaginary", - "value": False, - }, - "zyx_imag_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Zyx imaginary", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "zyx_imag_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "zyx_imag_channel", - "dependencyType": "enabled", - "value": None, - }, - "zyy_real_channel_bool": { - "group": "Data", - "main": True, - "label": "Zyy real", - "value": False, - }, - "zyy_real_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Zyy real", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "zyy_real_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "zyy_real_channel", - "dependencyType": "enabled", - "value": None, - }, - "zyy_imag_channel_bool": { - "group": "Data", - "main": True, - "label": "Zyy imaginary", - "value": False, - }, - "zyy_imag_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Zyy imaginary", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "zyy_imag_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "zyy_imag_channel", - "dependencyType": "enabled", - "value": None, - }, - "model_type": { - "choiceList": ["Conductivity (S/m)", "Resistivity (Ohm-m)"], - "main": True, - "group": "Mesh and models", - "label": "Model units", - "tooltip": "Select the units of the model.", - "value": "Conductivity (S/m)", - }, - "starting_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": False, - "parent": "mesh", - "label": "Initial", - "property": None, - "value": 1e-3, - }, - "reference_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "main": True, - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Reference", - "property": None, - "optional": True, - "enabled": False, - "value": 1e-3, - }, - "background_conductivity": { - "group": "Mesh and models", - "main": True, - "label": "Background", - "property": None, - "value": 1e-3, - }, - "lower_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Lower bound", - "property": None, - "optional": True, - "value": 1e-8, - "enabled": False, - }, - "upper_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Upper bound", - "property": None, - "optional": True, - "value": 100.0, - "enabled": False, - }, -} - -default_ui_json = dict(base_default_ui_json, **default_ui_json) - - -################ Validations ################# -validations = { - "inversion_type": { - "types": [str], - "required": True, - "values": ["magnetotellurics"], - }, - "data_object": {"types": [str, UUID, MTReceivers]}, - "zxx_real_channel": {"one_of": "data_channel"}, - "zxx_real_uncertainty": {"one_of": "uncertainty_channel"}, - "zxx_imag_channel": {"one_of": "data_channel"}, - "zxx_imag_uncertainty": {"one_of": "uncertainty_channel"}, - "zxy_real_channel": {"one_of": "data_channel"}, - "zxy_real_uncertainty": {"one_of": "uncertainty_channel"}, - "zxy_imag_channel": {"one_of": "data_channel"}, - "zxy_imag_uncertainty": {"one_of": "uncertainty_channel"}, - "zyx_real_channel": {"one_of": "data_channel"}, - "zyx_real_uncertainty": {"one_of": "uncertainty_channel"}, - "zyx_imag_channel": {"one_of": "data_channel"}, - "zyx_imag_uncertainty": {"one_of": "uncertainty_channel"}, - "zyy_real_channel": {"one_of": "data_channel"}, - "zyy_real_uncertainty": {"one_of": "uncertainty_channel"}, - "zyy_imag_channel": {"one_of": "data_channel"}, - "zyy_imag_uncertainty": {"one_of": "uncertainty_channel"}, -} -validations = dict(base_validations, **validations) - app_initializer = { "geoh5": str(assets_path() / "FlinFlon_natural_sources.geoh5"), "topography_object": UUID("{cfabb8dd-d1ad-4c4e-a87c-7b3dd224c3f5}"), diff --git a/simpeg_drivers/natural_sources/magnetotellurics/driver.py b/simpeg_drivers/natural_sources/magnetotellurics/driver.py index b293ad71..9a8e56ac 100644 --- a/simpeg_drivers/natural_sources/magnetotellurics/driver.py +++ b/simpeg_drivers/natural_sources/magnetotellurics/driver.py @@ -13,13 +13,18 @@ from simpeg_drivers.driver import InversionDriver -from .constants import validations -from .params import MagnetotelluricsParams +from .params import MTForwardOptions, MTInversionOptions -class MagnetotelluricsDriver(InversionDriver): - _params_class = MagnetotelluricsParams - _validations = validations +class MTForwardDriver(InversionDriver): + """Magnetotellurics forward driver.""" - def __init__(self, params: MagnetotelluricsParams): - super().__init__(params) + _params_class = MTForwardOptions + _validations = {} + + +class MTInversionDriver(InversionDriver): + """Magnetotellurics inversion driver.""" + + _params_class = MTInversionOptions + _validations = {} diff --git a/simpeg_drivers/natural_sources/magnetotellurics/params.py b/simpeg_drivers/natural_sources/magnetotellurics/params.py index 19df502f..db0df7f9 100644 --- a/simpeg_drivers/natural_sources/magnetotellurics/params.py +++ b/simpeg_drivers/natural_sources/magnetotellurics/params.py @@ -11,310 +11,108 @@ from __future__ import annotations -from copy import deepcopy -from uuid import UUID +from pathlib import Path +from typing import ClassVar -from simpeg_drivers.params import InversionBaseParams +from geoh5py.data import FloatData +from geoh5py.groups import PropertyGroup +from geoh5py.objects import MTReceivers -from .constants import ( - default_ui_json, - forward_defaults, - inversion_defaults, - validations, -) +from simpeg_drivers import assets_path +from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions, EMDataMixin -class MagnetotelluricsParams(InversionBaseParams): +class MTForwardOptions(EMDataMixin, BaseForwardOptions): """ - Parameter class for magnetotelluric->conductivity inversion. + Magnetotellurics forward options. + + :param zxx_real_channel_bool: Boolean for zxx real channel. + :param zxx_imag_channel_bool: Boolean for zxx imaginary channel. + :param zxy_real_channel_bool: Boolean for zxy real channel. + :param zxy_imag_channel_bool: Boolean for zxy imaginary channel. + :param zyx_real_channel_bool: Boolean for zyx real channel. + :param zyx_imag_channel_bool: Boolean for zyx imaginary channel. + :param zyy_real_channel_bool: Boolean for zyy real channel. + :param zyy_imag_channel_bool: Boolean for zyy imaginary channel. + :param background_conductivity: Background conductivity model. + :param model_type: Specify whether the models are provided in resistivity or conductivity. """ - _physical_property = "conductivity" + name: ClassVar[str] = "Magnetotellurics Forward" + title: ClassVar[str] = "Magnetotellurics Forward" + default_ui_json: ClassVar[Path] = ( + assets_path() / "uijson/magnetotellurics_forward.ui.json" + ) - def __init__(self, input_file=None, forward_only=False, **kwargs): - self._default_ui_json = deepcopy(default_ui_json) - self._forward_defaults = deepcopy(forward_defaults) - self._inversion_defaults = deepcopy(inversion_defaults) - self._inversion_type = "magnetotellurics" - self._validations = validations - self._zxx_real_channel_bool = None - self._zxx_real_channel = None - self._zxx_real_uncertainty = None - self._zxx_imag_channel_bool = None - self._zxx_imag_channel = None - self._zxx_imag_uncertainty = None - self._zxy_real_channel_bool = None - self._zxy_real_channel = None - self._zxy_real_uncertainty = None - self._zxy_imag_channel_bool = None - self._zxy_imag_channel = None - self._zxy_imag_uncertainty = None - self._zyx_real_channel_bool = None - self._zyx_real_channel = None - self._zyx_real_uncertainty = None - self._zyx_imag_channel_bool = None - self._zyx_imag_channel = None - self._zyx_imag_uncertainty = None - self._zyy_real_channel_bool = None - self._zyy_real_channel = None - self._zyy_real_uncertainty = None - self._zyy_imag_channel_bool = None - self._zyy_imag_channel = None - self._zyy_imag_uncertainty = None - self._background_conductivity = None - self._model_type = "Conductivity (S/m)" + inversion_type: str = "magnetotellurics" + physical_property: str = "conductivity" - super().__init__(input_file=input_file, forward_only=forward_only, **kwargs) - - def data_channel(self, component: str): - """Return uuid of data channel.""" - return getattr(self, "_".join([component, "channel"]), None) - - def uncertainty_channel(self, component: str): - """Return uuid of uncertainty channel.""" - return getattr(self, "_".join([component, "uncertainty"]), None) - - def property_group_data(self, property_group: UUID): - data = {} - frequencies = self.data_object.channels - if self.forward_only: - return {k: None for k in frequencies} - else: - group = next( - k - for k in self.data_object.property_groups - if k.uid == property_group.uid - ) - property_names = [ - self.geoh5.get_entity(p)[0].name for p in group.properties - ] - properties = [self.geoh5.get_entity(p)[0].values for p in group.properties] - for i, f in enumerate(frequencies): - try: - f_ind = property_names.index( - next(k for k in property_names if f"{f:.2e}" in k) - ) # Safer if data was saved with geoapps naming convention - data[f] = properties[f_ind] - except StopIteration: - data[f] = properties[i] # in case of other naming conventions - - return data - - def data(self, component: str): - """Returns array of data for chosen data component.""" - property_group = self.data_channel(component) - return self.property_group_data(property_group) - - def uncertainty(self, component: str) -> float: - """Returns uncertainty for chosen data component.""" - uid = self.uncertainty_channel(component) - return self.property_group_data(uid) - - @property - def model_type(self): - """Model units.""" - return self._model_type - - @model_type.setter - def model_type(self, val): - self.setter_validator("model_type", val) - - @property - def zxx_real_channel_bool(self): - return self._zxx_real_channel_bool - - @zxx_real_channel_bool.setter - def zxx_real_channel_bool(self, val): - self.setter_validator("zxx_real_channel_bool", val) - - @property - def zxx_real_channel(self): - return self._zxx_real_channel - - @zxx_real_channel.setter - def zxx_real_channel(self, val): - self.setter_validator("zxx_real_channel", val, fun=self._uuid_promoter) - - @property - def zxx_real_uncertainty(self): - return self._zxx_real_uncertainty - - @zxx_real_uncertainty.setter - def zxx_real_uncertainty(self, val): - self.setter_validator("zxx_real_uncertainty", val, fun=self._uuid_promoter) - - @property - def zxx_imag_channel_bool(self): - return self._zxx_imag_channel_bool - - @zxx_imag_channel_bool.setter - def zxx_imag_channel_bool(self, val): - self.setter_validator("zxx_imag_channel_bool", val) + data_object: MTReceivers + zxx_real_channel_bool: bool | None = None + zxx_imag_channel_bool: bool | None = None + zxy_real_channel_bool: bool | None = None + zxy_imag_channel_bool: bool | None = None + zyx_real_channel_bool: bool | None = None + zyx_imag_channel_bool: bool | None = None + zyy_real_channel_bool: bool | None = None + zyy_imag_channel_bool: bool | None = None + background_conductivity: float | FloatData + model_type: str = "Conductivity (S/m)" @property - def zxx_imag_channel(self): - return self._zxx_imag_channel + def channels(self) -> list[str]: + return ["_".join(k.split("_")[:2]) for k in self.__dict__ if "channel" in k] - @zxx_imag_channel.setter - def zxx_imag_channel(self, val): - self.setter_validator("zxx_imag_channel", val, fun=self._uuid_promoter) - - @property - def zxx_imag_uncertainty(self): - return self._zxx_imag_uncertainty - - @zxx_imag_uncertainty.setter - def zxx_imag_uncertainty(self, val): - self.setter_validator("zxx_imag_uncertainty", val, fun=self._uuid_promoter) - - @property - def zxy_real_channel_bool(self): - return self._zxy_real_channel_bool - - @zxy_real_channel_bool.setter - def zxy_real_channel_bool(self, val): - self.setter_validator("zxy_real_channel_bool", val) - - @property - def zxy_real_channel(self): - return self._zxy_real_channel - - @zxy_real_channel.setter - def zxy_real_channel(self, val): - self.setter_validator("zxy_real_channel", val, fun=self._uuid_promoter) - - @property - def zxy_real_uncertainty(self): - return self._zxy_real_uncertainty - - @zxy_real_uncertainty.setter - def zxy_real_uncertainty(self, val): - self.setter_validator("zxy_real_uncertainty", val, fun=self._uuid_promoter) - - @property - def zxy_imag_channel_bool(self): - return self._zxy_imag_channel_bool - - @zxy_imag_channel_bool.setter - def zxy_imag_channel_bool(self, val): - self.setter_validator("zxy_imag_channel_bool", val) - - @property - def zxy_imag_channel(self): - return self._zxy_imag_channel - - @zxy_imag_channel.setter - def zxy_imag_channel(self, val): - self.setter_validator("zxy_imag_channel", val, fun=self._uuid_promoter) - - @property - def zxy_imag_uncertainty(self): - return self._zxy_imag_uncertainty - @zxy_imag_uncertainty.setter - def zxy_imag_uncertainty(self, val): - self.setter_validator("zxy_imag_uncertainty", val, fun=self._uuid_promoter) - - @property - def zyx_real_channel_bool(self): - return self._zyx_real_channel_bool - - @zyx_real_channel_bool.setter - def zyx_real_channel_bool(self, val): - self.setter_validator("zyx_real_channel_bool", val) - - @property - def zyx_real_channel(self): - return self._zyx_real_channel - - @zyx_real_channel.setter - def zyx_real_channel(self, val): - self.setter_validator("zyx_real_channel", val, fun=self._uuid_promoter) - - @property - def zyx_real_uncertainty(self): - return self._zyx_real_uncertainty - - @zyx_real_uncertainty.setter - def zyx_real_uncertainty(self, val): - self.setter_validator("zyx_real_uncertainty", val, fun=self._uuid_promoter) - - @property - def zyx_imag_channel_bool(self): - return self._zyx_imag_channel_bool - - @zyx_imag_channel_bool.setter - def zyx_imag_channel_bool(self, val): - self.setter_validator("zyx_imag_channel_bool", val) - - @property - def zyx_imag_channel(self): - return self._zyx_imag_channel - - @zyx_imag_channel.setter - def zyx_imag_channel(self, val): - self.setter_validator("zyx_imag_channel", val, fun=self._uuid_promoter) - - @property - def zyx_imag_uncertainty(self): - return self._zyx_imag_uncertainty - - @zyx_imag_uncertainty.setter - def zyx_imag_uncertainty(self, val): - self.setter_validator("zyx_imag_uncertainty", val, fun=self._uuid_promoter) - - @property - def zyy_real_channel_bool(self): - return self._zyy_real_channel_bool - - @zyy_real_channel_bool.setter - def zyy_real_channel_bool(self, val): - self.setter_validator("zyy_real_channel_bool", val) - - @property - def zyy_real_channel(self): - return self._zyy_real_channel - - @zyy_real_channel.setter - def zyy_real_channel(self, val): - self.setter_validator("zyy_real_channel", val, fun=self._uuid_promoter) - - @property - def zyy_real_uncertainty(self): - return self._zyy_real_uncertainty - - @zyy_real_uncertainty.setter - def zyy_real_uncertainty(self, val): - self.setter_validator("zyy_real_uncertainty", val, fun=self._uuid_promoter) - - @property - def zyy_imag_channel_bool(self): - return self._zyy_imag_channel_bool - - @zyy_imag_channel_bool.setter - def zyy_imag_channel_bool(self, val): - self.setter_validator("zyy_imag_channel_bool", val) - - @property - def zyy_imag_channel(self): - return self._zyy_imag_channel - - @zyy_imag_channel.setter - def zyy_imag_channel(self, val): - self.setter_validator("zyy_imag_channel", val, fun=self._uuid_promoter) - - @property - def zyy_imag_uncertainty(self): - return self._zyy_imag_uncertainty - - @zyy_imag_uncertainty.setter - def zyy_imag_uncertainty(self, val): - self.setter_validator("zyy_imag_uncertainty", val, fun=self._uuid_promoter) - - @property - def background_conductivity(self): - return self._background_conductivity +class MTInversionOptions(EMDataMixin, BaseInversionOptions): + """ + Magnetotellurics inversion options. + + :param zxx_real_channel: Real component of Zxx data. + :param zxx_real_uncertainty: Real component of Zxx uncertainty. + :param zxx_imag_channel: Imaginary component of Zxx data. + :param zxx_imag_uncertainty: Imaginary component of Zxx uncertainty. + :param zxy_real_channel: Real component of Zxy data. + :param zxy_real_uncertainty: Real component of Zxy uncertainty. + :param zxy_imag_channel: Imaginary component of Zxy data. + :param zxy_imag_uncertainty: Imaginary component of Zxy uncertainty. + :param zyx_real_channel: Real component of Zyx data. + :param zyx_real_uncertainty: Real component of Zyx uncertainty. + :param zyx_imag_channel: Imaginary component of Zyx data. + :param zyx_imag_uncertainty: Imaginary component of Zyx uncertainty. + :param zyy_real_channel: Real component of Zyy data. + :param zyy_real_uncertainty: Real component of Zyy uncertainty. + :param zyy_imag_channel: Imaginary component of Zyy data. + :param zyy_imag_uncertainty: Imaginary component of Zyy uncertainty. + :param background_conductivity: Background conductivity model. + :param model_type: Specify whether the models are provided in resistivity or conductivity. + """ - @background_conductivity.setter - def background_conductivity(self, val): - self.setter_validator("background_conductivity", val, fun=self._uuid_promoter) + name: ClassVar[str] = "Magnetotellurics Inversion" + title: ClassVar[str] = "Magnetotellurics Inversion" + default_ui_json: ClassVar[Path] = ( + assets_path() / "uijson/magnetotellurics_inversion.ui.json" + ) + + inversion_type: str = "magnetotellurics" + physical_property: str = "conductivity" + + data_object: MTReceivers + zxx_real_channel: PropertyGroup | None = None + zxx_real_uncertainty: PropertyGroup | None = None + zxx_imag_channel: PropertyGroup | None = None + zxx_imag_uncertainty: PropertyGroup | None = None + zxy_real_channel: PropertyGroup | None = None + zxy_real_uncertainty: PropertyGroup | None = None + zxy_imag_channel: PropertyGroup | None = None + zxy_imag_uncertainty: PropertyGroup | None = None + zyx_real_channel: PropertyGroup | None = None + zyx_real_uncertainty: PropertyGroup | None = None + zyx_imag_channel: PropertyGroup | None = None + zyx_imag_uncertainty: PropertyGroup | None = None + zyy_real_channel: PropertyGroup | None = None + zyy_real_uncertainty: PropertyGroup | None = None + zyy_imag_channel: PropertyGroup | None = None + zyy_imag_uncertainty: PropertyGroup | None = None + background_conductivity: float | FloatData + model_type: str = "Conductivity (S/m)" diff --git a/simpeg_drivers/natural_sources/tipper/__init__.py b/simpeg_drivers/natural_sources/tipper/__init__.py index 2cb63156..f9e29ee4 100644 --- a/simpeg_drivers/natural_sources/tipper/__init__.py +++ b/simpeg_drivers/natural_sources/tipper/__init__.py @@ -9,7 +9,7 @@ # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -from .params import TipperParams +from .params import TipperForwardOptions, TipperInversionOptions # pylint: disable=unused-import # flake8: noqa diff --git a/simpeg_drivers/natural_sources/tipper/constants.py b/simpeg_drivers/natural_sources/tipper/constants.py index 1355c375..ddfd6c24 100644 --- a/simpeg_drivers/natural_sources/tipper/constants.py +++ b/simpeg_drivers/natural_sources/tipper/constants.py @@ -11,8 +11,6 @@ from __future__ import annotations -from uuid import UUID - from geoh5py.objects.surveys.electromagnetics.tipper import TipperReceivers import simpeg_drivers @@ -133,210 +131,4 @@ "distributed_workers": None, } -default_ui_json = { - "title": "Tipper Inversion", - "icon": "surveyztem", - "documentation": "https://mirageoscience-simpeg-drivers.readthedocs-hosted.com/en/stable/intro.html", - "inversion_type": "tipper", - "data_object": { - "main": True, - "group": "Data", - "label": "Object", - "meshType": "{0b639533-f35b-44d8-92a8-f70ecff3fd26}", - "value": None, - }, - "txz_real_channel_bool": { - "group": "Data", - "main": True, - "label": "Txz real", - "value": False, - }, - "txz_real_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Txz real", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "txz_real_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "txz_real_channel", - "dependencyType": "enabled", - "value": None, - }, - "txz_imag_channel_bool": { - "group": "Data", - "main": True, - "label": "Txz imaginary", - "value": False, - }, - "txz_imag_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Txz imaginary", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "txz_imag_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "txz_imag_channel", - "dependencyType": "enabled", - "value": None, - }, - "tyz_real_channel_bool": { - "group": "Data", - "main": True, - "label": "Tyz real", - "value": False, - }, - "tyz_real_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Tyz real", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "tyz_real_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "tyz_real_channel", - "dependencyType": "enabled", - "value": None, - }, - "tyz_imag_channel_bool": { - "group": "Data", - "main": True, - "label": "Tyz imaginary", - "value": False, - }, - "tyz_imag_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Tyz imaginary", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "tyz_imag_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "dataGroupType": "Multi-element", - "main": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "tyz_imag_channel", - "dependencyType": "enabled", - "value": None, - }, - "model_type": { - "choiceList": ["Conductivity (S/m)", "Resistivity (Ohm-m)"], - "main": True, - "group": "Mesh and models", - "label": "Model units", - "tooltip": "Select the units of the model.", - "value": "Conductivity (S/m)", - }, - "starting_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": False, - "parent": "mesh", - "label": "Initial", - "property": None, - "value": 1e-3, - }, - "reference_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "main": True, - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Reference", - "property": None, - "optional": True, - "enabled": False, - "value": 1e-3, - }, - "background_conductivity": { - "group": "Mesh and models", - "main": True, - "label": "Background", - "property": None, - "value": 1e-3, - }, - "lower_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Lower bound", - "property": None, - "optional": True, - "value": 1e-8, - "enabled": False, - }, - "upper_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Upper bound", - "property": None, - "optional": True, - "value": 100.0, - "enabled": False, - }, -} -default_ui_json = dict(base_default_ui_json, **default_ui_json) -validations = { - "inversion_type": { - "required": True, - "values": ["tipper"], - }, - "data_object": {"required": True, "types": [str, UUID, TipperReceivers]}, -} app_initializer = {} diff --git a/simpeg_drivers/natural_sources/tipper/driver.py b/simpeg_drivers/natural_sources/tipper/driver.py index ec86f368..6b2a836c 100644 --- a/simpeg_drivers/natural_sources/tipper/driver.py +++ b/simpeg_drivers/natural_sources/tipper/driver.py @@ -13,13 +13,18 @@ from simpeg_drivers.driver import InversionDriver -from .constants import validations -from .params import TipperParams +from .params import TipperForwardOptions, TipperInversionOptions -class TipperDriver(InversionDriver): - _params_class = TipperParams - _validations = validations +class TipperForwardDriver(InversionDriver): + """Tipper forward driver.""" - def __init__(self, params: TipperParams): - super().__init__(params) + _params_class = TipperForwardOptions + _validations = {} + + +class TipperInversionDriver(InversionDriver): + """Tipper inversion driver.""" + + _params_class = TipperInversionOptions + _validations = {} diff --git a/simpeg_drivers/natural_sources/tipper/params.py b/simpeg_drivers/natural_sources/tipper/params.py index d1ca825a..664454b1 100644 --- a/simpeg_drivers/natural_sources/tipper/params.py +++ b/simpeg_drivers/natural_sources/tipper/params.py @@ -11,202 +11,76 @@ from __future__ import annotations -from copy import deepcopy -from uuid import UUID +from pathlib import Path +from typing import ClassVar -from simpeg_drivers.params import InversionBaseParams +from geoh5py.data import FloatData +from geoh5py.groups import PropertyGroup +from geoh5py.objects import TipperReceivers -from .constants import ( - default_ui_json, - forward_defaults, - inversion_defaults, - validations, -) +from simpeg_drivers import assets_path +from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions, EMDataMixin -class TipperParams(InversionBaseParams): +class TipperForwardOptions(EMDataMixin, BaseForwardOptions): """ - Parameter class for magnetotelluric->conductivity inversion. + Tipper forward options. + + :param txz_real_channel_bool: Boolean for txz real channel. + :param txz_imag_channel_bool: Boolean for txz imaginary channel. + :param tyz_real_channel_bool: Boolean for tyz real channel. + :param tyz_imag_channel_bool: Boolean for tyz imaginary channel. + :param background_conductivity: Background conductivity model. + :param model_type: Specify whether the models are provided in resistivity or conductivity. """ - _physical_property = "conductivity" - - def __init__(self, input_file=None, forward_only=False, **kwargs): - self._default_ui_json = deepcopy(default_ui_json) - self._forward_defaults = deepcopy(forward_defaults) - self._inversion_defaults = deepcopy(inversion_defaults) - self._inversion_type = "tipper" - self._validations = validations - self._txz_real_channel_bool = None - self._txz_real_channel = None - self._txz_real_uncertainty = None - self._txz_imag_channel_bool = None - self._txz_imag_channel = None - self._txz_imag_uncertainty = None - self._tyz_real_channel_bool = None - self._tyz_real_channel = None - self._tyz_real_uncertainty = None - self._tyz_imag_channel_bool = None - self._tyz_imag_channel = None - self._tyz_imag_uncertainty = None - self._background_conductivity = None - self._model_type = "Conductivity (S/m)" - - super().__init__(input_file=input_file, forward_only=forward_only, **kwargs) - - def data_channel(self, component: str): - """Return uuid of data channel.""" - return getattr(self, "_".join([component, "channel"]), None) - - def uncertainty_channel(self, component: str): - """Return uuid of uncertainty channel.""" - return getattr(self, "_".join([component, "uncertainty"]), None) - - def property_group_data(self, property_group: UUID): - data = {} - frequencies = self.data_object.channels - if self.forward_only: - return {k: None for k in frequencies} - else: - group = next( - k - for k in self.data_object.property_groups - if k.uid == property_group.uid - ) - property_names = [ - self.geoh5.get_entity(p)[0].name for p in group.properties - ] - properties = [self.geoh5.get_entity(p)[0].values for p in group.properties] - for i, f in enumerate(frequencies): - try: - f_ind = property_names.index( - next(k for k in property_names if f"{f:.2e}" in k) - ) # Safer if data was saved with geoapps naming convention - data[f] = properties[f_ind] - except StopIteration: - data[f] = properties[i] # in case of other naming conventions - - return data - - def data(self, component: str): - """Returns array of data for chosen data component.""" - property_group = self.data_channel(component) - return self.property_group_data(property_group) - - def uncertainty(self, component: str) -> float: - """Returns uncertainty for chosen data component.""" - uid = self.uncertainty_channel(component) - return self.property_group_data(uid) - - @property - def model_type(self): - """Model units.""" - return self._model_type - - @model_type.setter - def model_type(self, val): - self.setter_validator("model_type", val) - - @property - def txz_real_channel_bool(self): - return self._txz_real_channel_bool - - @txz_real_channel_bool.setter - def txz_real_channel_bool(self, val): - self.setter_validator("txz_real_channel_bool", val) - - @property - def txz_real_channel(self): - return self._txz_real_channel - - @txz_real_channel.setter - def txz_real_channel(self, val): - self.setter_validator("txz_real_channel", val, fun=self._uuid_promoter) - - @property - def txz_real_uncertainty(self): - return self._txz_real_uncertainty - - @txz_real_uncertainty.setter - def txz_real_uncertainty(self, val): - self.setter_validator("txz_real_uncertainty", val, fun=self._uuid_promoter) - - @property - def txz_imag_channel_bool(self): - return self._txz_imag_channel_bool - - @txz_imag_channel_bool.setter - def txz_imag_channel_bool(self, val): - self.setter_validator("txz_imag_channel_bool", val) - - @property - def txz_imag_channel(self): - return self._txz_imag_channel - - @txz_imag_channel.setter - def txz_imag_channel(self, val): - self.setter_validator("txz_imag_channel", val, fun=self._uuid_promoter) - - @property - def txz_imag_uncertainty(self): - return self._txz_imag_uncertainty - - @txz_imag_uncertainty.setter - def txz_imag_uncertainty(self, val): - self.setter_validator("txz_imag_uncertainty", val, fun=self._uuid_promoter) - - @property - def tyz_real_channel_bool(self): - return self._tyz_real_channel_bool - - @tyz_real_channel_bool.setter - def tyz_real_channel_bool(self, val): - self.setter_validator("tyz_real_channel_bool", val) - - @property - def tyz_real_channel(self): - return self._tyz_real_channel - - @tyz_real_channel.setter - def tyz_real_channel(self, val): - self.setter_validator("tyz_real_channel", val, fun=self._uuid_promoter) - - @property - def tyz_real_uncertainty(self): - return self._tyz_real_uncertainty - - @tyz_real_uncertainty.setter - def tyz_real_uncertainty(self, val): - self.setter_validator("tyz_real_uncertainty", val, fun=self._uuid_promoter) - - @property - def tyz_imag_channel_bool(self): - return self._tyz_imag_channel_bool - - @tyz_imag_channel_bool.setter - def tyz_imag_channel_bool(self, val): - self.setter_validator("tyz_imag_channel_bool", val) - - @property - def tyz_imag_channel(self): - return self._tyz_imag_channel - - @tyz_imag_channel.setter - def tyz_imag_channel(self, val): - self.setter_validator("tyz_imag_channel", val, fun=self._uuid_promoter) - - @property - def tyz_imag_uncertainty(self): - return self._tyz_imag_uncertainty - - @tyz_imag_uncertainty.setter - def tyz_imag_uncertainty(self, val): - self.setter_validator("tyz_imag_uncertainty", val, fun=self._uuid_promoter) + name: ClassVar[str] = "Tipper Forward" + title: ClassVar[str] = "Tipper Forward" + default_ui_json: ClassVar[Path] = assets_path() / "uijson/tipper_forward.ui.json" - @property - def background_conductivity(self): - return self._background_conductivity + inversion_type: str = "tipper" + physical_property: str = "conductivity" - @background_conductivity.setter - def background_conductivity(self, val): - self.setter_validator("background_conductivity", val, fun=self._uuid_promoter) + data_object: TipperReceivers + txz_real_channel_bool: bool | None = None + txz_imag_channel_bool: bool | None = None + tyz_real_channel_bool: bool | None = None + tyz_imag_channel_bool: bool | None = None + background_conductivity: float | FloatData + model_type: str = "Conductivity (S/m)" + + +class TipperInversionOptions(EMDataMixin, BaseInversionOptions): + """ + Tipper Inversion options. + + :param txz_real_channel: Real component of Txz tipper data. + :param txz_real_uncertainty: Real component of Txz tipper uncertainty. + :param txz_imag_channel: Imaginary component of Txz tipper data. + :param txz_imag_uncertainty: Imaginary component of Txz tipper uncertainty. + :param tyz_real_channel: Real component of Tyz tipper data. + :param tyz_real_uncertainty: Real component of Tyz tipper uncertainty. + :param tyz_imag_channel: Imaginary component of Tyz tipper data. + :param tyz_imag_uncertainty: Imaginary component of Tyz tipper uncertainty. + :param background_conductivity: Background conductivity model. + :param model_type: Specify whether the models are provided in resistivity or conductivity. + """ + + name: ClassVar[str] = "Tipper Inversion" + title: ClassVar[str] = "Tipper Inversion" + default_ui_json: ClassVar[Path] = assets_path() / "uijson/tipper_inversion.ui.json" + + inversion_type: str = "tipper" + physical_property: str = "conductivity" + + data_object: TipperReceivers + txz_real_channel: PropertyGroup | None = None + txz_real_uncertainty: PropertyGroup | None = None + txz_imag_channel: PropertyGroup | None = None + txz_imag_uncertainty: PropertyGroup | None = None + tyz_real_channel: PropertyGroup | None = None + tyz_real_uncertainty: PropertyGroup | None = None + tyz_imag_channel: PropertyGroup | None = None + tyz_imag_uncertainty: PropertyGroup | None = None + background_conductivity: float | FloatData + model_type: str = "Conductivity (S/m)" diff --git a/simpeg_drivers/params.py b/simpeg_drivers/params.py index 7e5d9c99..f43a69d1 100644 --- a/simpeg_drivers/params.py +++ b/simpeg_drivers/params.py @@ -15,28 +15,30 @@ import warnings from copy import deepcopy from pathlib import Path -from typing import ClassVar +from typing import ClassVar, TypeAlias from uuid import UUID import numpy as np from geoapps_utils.driver.data import BaseData from geoapps_utils.driver.params import BaseParams from geoh5py.data import BooleanData, FloatData, NumericData -from geoh5py.groups import SimPEGGroup, UIJsonGroup -from geoh5py.objects import DrapeModel, Octree, Points +from geoh5py.groups import PropertyGroup, SimPEGGroup, UIJsonGroup +from geoh5py.objects import Octree, Points from geoh5py.shared.utils import fetch_active_workspace from geoh5py.ui_json import InputFile -from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator +from pydantic import BaseModel, ConfigDict, field_validator, model_validator -# from simpeg_drivers import assets_path +InversionDataDict: TypeAlias = ( + dict[str, np.ndarray | None] | dict[str, dict[float, np.ndarray | None]] +) # pylint: disable=too-many-lines # TODO: Remove this disable when all params are BaseData -class ActiveCellsData(BaseModel): +class ActiveCellsOptions(BaseModel): """ Active cells data as a topography surface or 3d model. @@ -60,7 +62,7 @@ def at_least_one(cls, data): return data -class CoreData(BaseData): +class CoreOptions(BaseData): """ Core parameters shared by inverse and forward operations. @@ -99,7 +101,7 @@ class CoreData(BaseData): z_from_topo: bool = False mesh: Octree | None starting_model: float | FloatData - active_cells: ActiveCellsData + active_cells: ActiveCellsOptions tile_spatial: int = 1 parallelized: bool = True n_cpu: int | None = None @@ -154,39 +156,64 @@ def workpath(self): return Path(self.geoh5.h5file).parent @property - def channels(self) -> list[str]: - return [k.split("_")[0] for k in self.__dict__ if "channel" in k] + def components(self) -> list[str]: + """Return list of component names.""" + return [self._component_name(k) for k in self.__dict__ if "channel" in k] - def data_channel(self, component: str) -> NumericData | None: - """Return the data object associated with the component.""" - return getattr(self, "_".join([component, "channel"]), None) + @property + def active_components(self) -> list[str]: + """Return list of active components.""" + return [ + k + for k in self.components + if getattr(self, "_".join([k, "channel"])) is not None + ] - def data(self, component: str) -> np.ndarray | None: - """Returns array of data for chosen data component if it exists.""" - data_entity = self.data_channel(component) - if isinstance(data_entity, NumericData): - return data_entity.values.astype(float) - return None + @property + def data(self) -> InversionDataDict: + """Return dictionary of data components and associated values.""" + out = {} + for k in self.active_components: + out[k] = self.component_data(k) + return out - def uncertainty_channel(self, component: str) -> NumericData | None: - """Return the uncertainty object associated with the component.""" - return getattr(self, "_".join([component, "uncertainty"]), None) + @property + def uncertainties(self) -> InversionDataDict: + """Return dictionary of unceratinty components and associated values.""" + out = {} + for k in self.active_components: + out[k] = self.component_uncertainty(k) + return out - def uncertainty(self, component: str) -> np.ndarray | None: - """Returns uncertainty for chosen data component if it exists.""" + def component_data(self, component: str) -> np.ndarray | None: + """Return data values associated with the component.""" + data = getattr(self, "_".join([component, "channel"]), None) + if isinstance(data, NumericData): + data = data.values + return data - uncertainty_entity = self.uncertainty_channel(component) - if isinstance(uncertainty_entity, NumericData): - return uncertainty_entity.values.astype(float) + def component_uncertainty(self, component: str) -> np.ndarray | None: + """ + Return uncertainty values associated with the component. - data = self.data(component) - if data is not None: - if isinstance(uncertainty_entity, int | float): - return np.array([float(uncertainty_entity)] * len(data)) - else: - return data * 0.0 + 1.0 # Default + If the uncertainty is a float, it will be broadcasted to the same + shape as the data. - return None + :param component: Component name. + """ + data = getattr(self, "_".join([component, "uncertainty"]), None) + if isinstance(data, NumericData): + data = data.values + elif isinstance(data, float): + data *= np.ones_like(self.component_data(component)) + + return data + + def _component_name(self, component: str) -> str: + """Strip the '_channel' and '_channel_bool' suffixes from data name.""" + return "_".join( + [k for k in component.split("_") if k not in ["channel", "bool"]] + ) @property def padding_cells(self) -> int: @@ -200,7 +227,7 @@ def padding_cells(self) -> int: return 4 if self.inversion_type in ["fem", "tdem"] else 6 -class BaseForwardData(CoreData): +class BaseForwardOptions(CoreOptions): """ Base class for forward parameters. @@ -209,17 +236,12 @@ class BaseForwardData(CoreData): forward_only: bool = True @property - def components(self) -> list[str]: - """Retrieve component names used to index channel and uncertainty data.""" - comps = [] - for c in self.channels: - if getattr(self, f"{c}_channel_bool", False): - comps.append(c) - - return comps + def active_components(self) -> list[str]: + """Return list of active components.""" + return [k for k in self.components if getattr(self, f"{k}_channel_bool")] -class BaseInversionData(CoreData): +class BaseInversionOptions(CoreOptions): """ Base class for inversion parameters. @@ -298,12 +320,12 @@ class BaseInversionData(CoreData): lower_bound: float | FloatData | None = None upper_bound: float | FloatData | None = None - alpha_s: float | FloatData = 1.0 + alpha_s: float | FloatData | None = 1.0 length_scale_x: float | FloatData = 1.0 length_scale_y: float | FloatData = 1.0 length_scale_z: float | FloatData = 1.0 - s_norm: float | FloatData = 0.0 + s_norm: float | FloatData | None = 0.0 x_norm: float | FloatData = 2.0 y_norm: float | FloatData = 2.0 z_norm: float | FloatData = 2.0 @@ -345,15 +367,51 @@ class BaseInversionData(CoreData): distributed_workers: int | None = None no_data_value: float | None = None - @property - def components(self) -> list[str]: - """Retrieve component names used to index channel and uncertainty data.""" - comps = [] - for c in self.channels: - if getattr(self, f"{c}_channel", False): - comps.append(c) - return comps +class EMDataMixin: + """ + Mixin class to add data and uncertainty access from property groups. + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def component_data(self, component: str): + """Return data values associated with the component.""" + property_group = getattr(self, "_".join([component, "channel"]), None) + return self.property_group_data(property_group) + + def component_uncertainty(self, component: str): + """Return uncertainty values associated with the component.""" + property_group = getattr(self, "_".join([component, "uncertainty"]), None) + return self.property_group_data(property_group) + + def property_group_data(self, property_group: PropertyGroup): + """ + Return dictionary of channel/data. + + :param property_group: Property group uid + """ + frequencies = self.data_object.channels + if property_group is None: + return {f: None for f in frequencies} + + data = {} + group = next( + k for k in self.data_object.property_groups if k.uid == property_group.uid + ) + property_names = [self.geoh5.get_entity(p)[0].name for p in group.properties] + properties = [self.geoh5.get_entity(p)[0].values for p in group.properties] + for i, f in enumerate(frequencies): + try: + f_ind = property_names.index( + next(k for k in property_names if f"{f:.2e}" in k) + ) # Safer if data was saved with geoapps naming convention + data[f] = properties[f_ind] + except StopIteration: + data[f] = properties[i] # in case of other naming conventions + + return data class InversionBaseParams(BaseParams): @@ -460,7 +518,7 @@ def __init__( @property def active_cells(self): - return ActiveCellsData( + return ActiveCellsOptions( topography_object=self.topography_object, topography=self.topography, active_model=self.active_model, diff --git a/simpeg_drivers/potential_fields/__init__.py b/simpeg_drivers/potential_fields/__init__.py index e2531d7b..5719cb6f 100644 --- a/simpeg_drivers/potential_fields/__init__.py +++ b/simpeg_drivers/potential_fields/__init__.py @@ -9,14 +9,14 @@ # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -from .gravity.params import GravityForwardParams, GravityInversionParams +from .gravity.params import GravityForwardOptions, GravityInversionOptions from .magnetic_scalar.params import ( - MagneticScalarForwardParams, - MagneticScalarInversionParams, + MagneticForwardOptions, + MagneticInversionOptions, ) from .magnetic_vector.params import ( - MagneticVectorForwardParams, - MagneticVectorInversionParams, + MVIForwardOptions, + MVIInversionOptions, ) # pylint: disable=unused-import diff --git a/simpeg_drivers/potential_fields/gravity/__init__.py b/simpeg_drivers/potential_fields/gravity/__init__.py index 88e122d0..b144f1ec 100644 --- a/simpeg_drivers/potential_fields/gravity/__init__.py +++ b/simpeg_drivers/potential_fields/gravity/__init__.py @@ -9,7 +9,7 @@ # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -from .params import GravityForwardParams, GravityInversionParams +from .params import GravityForwardOptions, GravityInversionOptions # pylint: disable=unused-import # flake8: noqa diff --git a/simpeg_drivers/potential_fields/gravity/constants.py b/simpeg_drivers/potential_fields/gravity/constants.py index 98287ae9..9d2d08e0 100644 --- a/simpeg_drivers/potential_fields/gravity/constants.py +++ b/simpeg_drivers/potential_fields/gravity/constants.py @@ -148,417 +148,6 @@ "distributed_workers": None, } -default_ui_json = { - "title": "Gravity Inversion", - "documentation": "https://mirageoscience-geoapps.readthedocs-hosted.com/en/stable/content/applications/grav_mag_inversion.html", - "icon": "surveyairbornegravity", - "inversion_type": "gravity", - "data_object": { - "main": True, - "group": "Data", - "label": "Object", - "meshType": [ - "{202C5DB1-A56D-4004-9CAD-BAAFD8899406}", - "{6A057FDC-B355-11E3-95BE-FD84A7FFCB88}", - "{F26FEBA3-ADED-494B-B9E9-B2BBCBE298E1}", - "{48F5054A-1C5C-4CA4-9048-80F36DC60A06}", - "{b020a277-90e2-4cd7-84d6-612ee3f25051}", - "{b54f6be6-0eb5-4a4e-887a-ba9d276f9a83}", - "{5ffa3816-358d-4cdd-9b7d-e1f7f5543e05}", - ], - "value": None, - }, - "gz_channel_bool": { - "group": "Data", - "main": True, - "label": "Gz (mGal)", - "value": False, - }, - "gz_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Gz (mGal)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "gz_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "gz_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "gx_channel_bool": { - "group": "Data", - "main": True, - "label": "Gx (mGal)", - "value": False, - }, - "gx_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Gx (mGal)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "gx_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "gx_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "gy_channel_bool": { - "group": "Data", - "main": True, - "label": "Gy (mGal)", - "value": False, - }, - "gy_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Gy (mGal)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "gy_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "gy_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "guv_channel_bool": { - "group": "Data", - "main": True, - "label": "Guv (Eo)", - "value": False, - }, - "guv_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Guv (Eo)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "guv_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "guv_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "gxy_channel_bool": { - "group": "Data", - "main": True, - "label": "Gxy/Gne (Eo)", - "value": False, - }, - "gxy_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Gxy/Gne (Eo)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "gxy_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "gxy_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "gxx_channel_bool": { - "group": "Data", - "main": True, - "label": "Gxx (Eo)", - "value": False, - }, - "gxx_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Gxx (Eo)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "gxx_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "gxx_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "gyy_channel_bool": { - "group": "Data", - "main": True, - "label": "Gyy (Eo)", - "value": False, - }, - "gyy_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Gyy (Eo)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "gyy_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "gyy_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "gzz_channel_bool": { - "group": "Data", - "main": True, - "label": "Gzz (Eo)", - "value": False, - }, - "gzz_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Gzz (Eo)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "gzz_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "gzz_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "gxz_channel_bool": { - "group": "Data", - "main": True, - "label": "Gxz (Eo)", - "value": False, - }, - "gxz_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Gxz (Eo)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "gxz_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "gxz_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "gyz_channel_bool": { - "group": "Data", - "main": True, - "label": "Gyz (Eo)", - "value": False, - }, - "gyz_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Gyz (Eo)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "gyz_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "gyz_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "coolingRate": { - "group": "Optimization", - "label": "Iterations per beta", - "value": 1, - "min": 1, - "LineEdit": False, - "max": 10, - "precision": 1, - "verbose": 2, - "enabled": True, - }, - "starting_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": True, - "parent": "mesh", - "label": "Initial density (g/cc)", - "property": None, - "value": 1e-3, - }, - "reference_model": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "optional": True, - "enabled": False, - "parent": "mesh", - "label": "Reference density (g/cc)", - "property": None, - "value": 0.0, - }, - "lower_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Lower bound (g/cc)", - "property": None, - "optional": True, - "value": -10.0, - "enabled": False, - }, - "upper_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Upper bound (g/cc)", - "property": None, - "optional": True, - "value": 10.0, - "enabled": False, - }, -} -default_ui_json = dict(base_default_ui_json, **default_ui_json) -validations = { - "inversion_type": { - "required": True, - "values": ["gravity"], - }, - "data_object": {"types": [str, UUID, Points, Surface, Grid2D]}, - "gz_channel": {"one_of": "data channel"}, - "gz_uncertainty": {"one_of": "uncertainty channel"}, - "guv_channel": {"one_of": "data channel"}, - "guv_uncertainty": {"one_of": "uncertainty channel"}, - "gxy_channel": {"one_of": "data channel"}, - "gxy_uncertainty": {"one_of": "uncertainty channel"}, - "gxx_channel": {"one_of": "data channel"}, - "gxx_uncertainty": {"one_of": "uncertainty channel"}, - "gyy_channel": {"one_of": "data channel"}, - "gyy_uncertainty": {"one_of": "uncertainty channel"}, - "gzz_channel": {"one_of": "data channel"}, - "gzz_uncertainty": {"one_of": "uncertainty channel"}, - "gxz_channel": {"one_of": "data channel"}, - "gxz_uncertainty": {"one_of": "uncertainty channel"}, - "gyz_channel": {"one_of": "data channel"}, - "gyz_uncertainty": {"one_of": "uncertainty channel"}, - "gx_channel": {"one_of": "data channel"}, - "gx_uncertainty": {"one_of": "uncertainty channel"}, - "gy_channel": {"one_of": "data channel"}, - "gy_uncertainty": {"one_of": "uncertainty channel"}, -} -validations = dict(base_validations, **validations) app_initializer = { "geoh5": str(assets_path() / "FlinFlon.geoh5"), "monitoring_directory": str((assets_path() / "Temp").resolve()), diff --git a/simpeg_drivers/potential_fields/gravity/driver.py b/simpeg_drivers/potential_fields/gravity/driver.py index 3362d4d5..2eb81e52 100644 --- a/simpeg_drivers/potential_fields/gravity/driver.py +++ b/simpeg_drivers/potential_fields/gravity/driver.py @@ -12,18 +12,21 @@ from __future__ import annotations from simpeg_drivers.driver import InversionDriver -from simpeg_drivers.potential_fields.gravity.constants import validations from simpeg_drivers.potential_fields.gravity.params import ( - GravityForwardParams, - GravityInversionParams, + GravityForwardOptions, + GravityInversionOptions, ) class GravityForwardDriver(InversionDriver): - _params_class = GravityForwardParams - _validation = validations + """Gravity forward driver.""" + + _params_class = GravityForwardOptions + _validation = {} class GravityInversionDriver(InversionDriver): - _params_class = GravityInversionParams - _validations = validations + """Gravity inversion driver.""" + + _params_class = GravityInversionOptions + _validations = {} diff --git a/simpeg_drivers/potential_fields/gravity/params.py b/simpeg_drivers/potential_fields/gravity/params.py index 26d745e6..b819431c 100644 --- a/simpeg_drivers/potential_fields/gravity/params.py +++ b/simpeg_drivers/potential_fields/gravity/params.py @@ -17,12 +17,12 @@ from geoh5py.data import FloatData from simpeg_drivers import assets_path -from simpeg_drivers.params import BaseForwardData, BaseInversionData +from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions -class GravityForwardParams(BaseForwardData): +class GravityForwardOptions(BaseForwardOptions): """ - Gravity forward parameters. + Gravity forward options. :param gx_channel_bool: gx channel boolean. :param gy_channel_bool: gy channel boolean. @@ -53,9 +53,9 @@ class GravityForwardParams(BaseForwardData): gzz_channel_bool: bool = False -class GravityInversionParams(BaseInversionData): +class GravityInversionOptions(BaseInversionOptions): """ - Gravity inversion parameters. + Gravity inversion options. :param gx_channel: gx channel. :param gy_channel: gy channel. diff --git a/simpeg_drivers/potential_fields/magnetic_scalar/__init__.py b/simpeg_drivers/potential_fields/magnetic_scalar/__init__.py index 7890c218..95a0c2a6 100644 --- a/simpeg_drivers/potential_fields/magnetic_scalar/__init__.py +++ b/simpeg_drivers/potential_fields/magnetic_scalar/__init__.py @@ -9,7 +9,7 @@ # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -from .params import MagneticScalarForwardParams, MagneticScalarInversionParams +from .params import MagneticForwardOptions, MagneticInversionOptions # pylint: disable=unused-import # flake8: noqa diff --git a/simpeg_drivers/potential_fields/magnetic_scalar/constants.py b/simpeg_drivers/potential_fields/magnetic_scalar/constants.py index 8ee7e8e9..f9cc88d3 100644 --- a/simpeg_drivers/potential_fields/magnetic_scalar/constants.py +++ b/simpeg_drivers/potential_fields/magnetic_scalar/constants.py @@ -150,449 +150,6 @@ "distributed_workers": None, } -default_ui_json = { - "title": "Magnetic Susceptibility Inversion", - "documentation": "https://mirageoscience-geoapps.readthedocs-hosted.com/en/stable/content/applications/grav_mag_inversion.html", - "icon": "surveyairbornegravity", - "inversion_type": "magnetic scalar", - "inducing_field_strength": { - "min": 0.0, - "max": 100000.0, - "precision": 2, - "lineEdit": False, - "main": True, - "group": "Inducing Field", - "label": "Strength (nT)", - "value": 50000.0, - }, - "inducing_field_inclination": { - "min": -90.0, - "max": 90.0, - "precision": 2, - "lineEdit": False, - "main": True, - "group": "Inducing Field", - "label": "Inclination (deg)", - "value": 90.0, - }, - "inducing_field_declination": { - "min": -180.0, - "max": 180.0, - "precision": 2, - "lineEdit": False, - "main": True, - "group": "Inducing Field", - "label": "Declination (deg)", - "value": 0.0, - }, - "data_object": { - "main": True, - "group": "Data", - "label": "Object", - "meshType": [ - "{202C5DB1-A56D-4004-9CAD-BAAFD8899406}", - "{6A057FDC-B355-11E3-95BE-FD84A7FFCB88}", - "{F26FEBA3-ADED-494B-B9E9-B2BBCBE298E1}", - "{48F5054A-1C5C-4CA4-9048-80F36DC60A06}", - "{b020a277-90e2-4cd7-84d6-612ee3f25051}", - "{4b99204c-d133-4579-a916-a9c8b98cfccb}", - "{028e4905-cc97-4dab-b1bf-d76f58b501b5}", - ], - "value": None, - }, - "tmi_channel_bool": { - "group": "Data", - "main": True, - "label": "TMI (nT)", - "value": False, - }, - "tmi_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "TMI (nT)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "tmi_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "tmi_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "bxx_channel_bool": { - "group": "Data", - "main": True, - "label": "Bxx (nT/m)", - "value": False, - }, - "bxx_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Bxx (nT/m)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "bxx_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "bxx_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "bxy_channel_bool": { - "group": "Data", - "main": True, - "label": "Bxy (nT/m)", - "value": False, - }, - "bxy_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Bxy (nT/m)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "bxy_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "bxy_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "bxz_channel_bool": { - "group": "Data", - "main": True, - "label": "Bxz (nT/m)", - "value": False, - }, - "bxz_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Bxz (nT/m)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "bxz_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "bxz_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "byy_channel_bool": { - "group": "Data", - "main": True, - "label": "Byy (nT/m)", - "value": False, - }, - "byy_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Byy (nT/m)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "byy_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "byy_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "byz_channel_bool": { - "group": "Data", - "main": True, - "label": "Byz (nT/m)", - "value": False, - }, - "byz_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Byz (nT/m)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "byz_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "byz_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "bzz_channel_bool": { - "group": "Data", - "main": True, - "label": "Bzz (nT/m)", - "value": False, - }, - "bzz_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Bzz (nT/m)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "bzz_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "bzz_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "bx_channel_bool": { - "group": "Data", - "main": True, - "label": "Bx (nT)", - "value": False, - }, - "bx_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Bx (nT)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "bx_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "bx_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "by_channel_bool": { - "group": "Data", - "main": True, - "label": "By (nT)", - "value": False, - }, - "by_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "By (nT)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "by_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "by_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "bz_channel_bool": { - "group": "Data", - "main": True, - "label": "Bz (nT)", - "value": False, - }, - "bz_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Bz (nT)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "bz_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "bz_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "coolingRate": { - "group": "Optimization", - "label": "Iterations per beta", - "value": 1, - "min": 1, - "LineEdit": False, - "max": 10, - "precision": 1, - "verbose": 2, - "enabled": True, - }, - "starting_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": True, - "parent": "mesh", - "label": "Initial susceptibility (SI)", - "property": None, - "value": 1e-4, - }, - "reference_model": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "optional": True, - "enabled": False, - "parent": "mesh", - "label": "Reference susceptibility (SI)", - "property": None, - "value": 0.0, - }, - "lower_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Lower bound (SI)", - "property": None, - "optional": True, - "value": 0.0, - "enabled": False, - }, - "upper_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "parent": "mesh", - "label": "Upper bound (SI)", - "property": None, - "optional": True, - "value": 1.0, - "enabled": False, - }, -} -default_ui_json = dict(base_default_ui_json, **default_ui_json) -validations = { - "inversion_type": { - "required": True, - "values": ["magnetic scalar"], - }, - "data_object": {"types": [str, UUID, Points, Surface, Grid2D]}, - "tmi_channel": {"one_of": "data channel"}, - "tmi_uncertainty": {"one_of": "uncertainty channel"}, - "bxx_channel": {"one_of": "data channel"}, - "bxx_uncertainty": {"one_of": "uncertainty channel"}, - "bxy_channel": {"one_of": "data channel"}, - "bxy_uncertainty": {"one_of": "uncertainty channel"}, - "bxz_channel": {"one_of": "data channel"}, - "bxz_uncertainty": {"one_of": "uncertainty channel"}, - "byy_channel": {"one_of": "data channel"}, - "byy_uncertainty": {"one_of": "uncertainty channel"}, - "byz_channel": {"one_of": "data channel"}, - "byz_uncertainty": {"one_of": "uncertainty channel"}, - "bzz_channel": {"one_of": "data channel"}, - "bzz_uncertainty": {"one_of": "uncertainty channel"}, - "bx_channel": {"one_of": "data channel"}, - "bx_uncertainty": {"one_of": "uncertainty channel"}, - "by_channel": {"one_of": "data channel"}, - "by_uncertainty": {"one_of": "uncertainty channel"}, - "bz_channel": {"one_of": "data channel"}, - "bz_uncertainty": {"one_of": "uncertainty channel"}, -} - -validations = dict(base_validations, **validations) - app_initializer = { "geoh5": str(assets_path() / "FlinFlon.geoh5"), "monitoring_directory": str((assets_path() / "Temp").resolve()), diff --git a/simpeg_drivers/potential_fields/magnetic_scalar/driver.py b/simpeg_drivers/potential_fields/magnetic_scalar/driver.py index ce7d8ae4..36daa6c8 100644 --- a/simpeg_drivers/potential_fields/magnetic_scalar/driver.py +++ b/simpeg_drivers/potential_fields/magnetic_scalar/driver.py @@ -12,18 +12,21 @@ from __future__ import annotations from simpeg_drivers.driver import InversionDriver -from simpeg_drivers.potential_fields.magnetic_scalar.constants import validations from simpeg_drivers.potential_fields.magnetic_scalar.params import ( - MagneticScalarForwardParams, - MagneticScalarInversionParams, + MagneticForwardOptions, + MagneticInversionOptions, ) -class MagneticScalarForwardDriver(InversionDriver): - _params_class = MagneticScalarForwardParams - _validations = validations +class MagneticForwardDriver(InversionDriver): + """Magnetic forward driver.""" + _params_class = MagneticForwardOptions + _validations = {} -class MagneticScalarInversionDriver(InversionDriver): - _params_class = MagneticScalarInversionParams - _validations = validations + +class MagneticInversionDriver(InversionDriver): + """Magnetic inversion driver.""" + + _params_class = MagneticInversionOptions + _validations = {} diff --git a/simpeg_drivers/potential_fields/magnetic_scalar/params.py b/simpeg_drivers/potential_fields/magnetic_scalar/params.py index db5d8d45..b1eb06c8 100644 --- a/simpeg_drivers/potential_fields/magnetic_scalar/params.py +++ b/simpeg_drivers/potential_fields/magnetic_scalar/params.py @@ -17,12 +17,12 @@ from geoh5py.data import FloatData from simpeg_drivers import assets_path -from simpeg_drivers.params import BaseForwardData, BaseInversionData +from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions -class MagneticScalarForwardParams(BaseForwardData): +class MagneticForwardOptions(BaseForwardOptions): """ - Magnetic scalar forward parameters. + Magnetic forward options. :param tmi_channel_bool: Total magnetic intensity channel boolean. :param bx_channel_bool: bx channel boolean. @@ -57,9 +57,9 @@ class MagneticScalarForwardParams(BaseForwardData): bzz_channel_bool: bool = False -class MagneticScalarInversionParams(BaseInversionData): +class MagneticInversionOptions(BaseInversionOptions): """ - Magnetic scalar inversion parameters. + Magnetic inversion options. :param tmi_channel: Total magnetic intensity channel. :param bx_channel: bx channel. diff --git a/simpeg_drivers/potential_fields/magnetic_vector/__init__.py b/simpeg_drivers/potential_fields/magnetic_vector/__init__.py index 9990018d..2f630c96 100644 --- a/simpeg_drivers/potential_fields/magnetic_vector/__init__.py +++ b/simpeg_drivers/potential_fields/magnetic_vector/__init__.py @@ -9,7 +9,7 @@ # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -from .params import MagneticVectorForwardParams, MagneticVectorInversionParams +from .params import MVIForwardOptions, MVIInversionOptions # pylint: disable=unused-import # flake8: noqa diff --git a/simpeg_drivers/potential_fields/magnetic_vector/constants.py b/simpeg_drivers/potential_fields/magnetic_vector/constants.py index 522d9998..bae72653 100644 --- a/simpeg_drivers/potential_fields/magnetic_vector/constants.py +++ b/simpeg_drivers/potential_fields/magnetic_vector/constants.py @@ -156,515 +156,6 @@ "distributed_workers": None, } -default_ui_json = { - "title": "Magnetic Vector (MVI) Inversion", - "documentation": "https://mirageoscience-simpeg-drivers.readthedocs-hosted.com/en/stable/intro.html", - "icon": "surveyairbornegravity", - "inversion_type": "magnetic vector", - "inducing_field_strength": { - "min": 0.1, - "max": 100000.0, - "precision": 2, - "lineEdit": False, - "main": True, - "group": "Inducing Field", - "label": "Strength (nT)", - "value": 50000.0, - }, - "inducing_field_inclination": { - "min": -90.0, - "max": 90.0, - "precision": 2, - "lineEdit": False, - "main": True, - "group": "Inducing Field", - "label": "Inclination (deg)", - "value": 90.0, - }, - "inducing_field_declination": { - "min": -180.0, - "max": 180.0, - "precision": 2, - "lineEdit": False, - "main": True, - "group": "Inducing Field", - "label": "Declination (deg)", - "value": 0.0, - }, - "data_object": { - "main": True, - "group": "Data", - "label": "Object", - "meshType": [ - "{202C5DB1-A56D-4004-9CAD-BAAFD8899406}", - "{6A057FDC-B355-11E3-95BE-FD84A7FFCB88}", - "{F26FEBA3-ADED-494B-B9E9-B2BBCBE298E1}", - "{48F5054A-1C5C-4CA4-9048-80F36DC60A06}", - "{b020a277-90e2-4cd7-84d6-612ee3f25051}", - "{4b99204c-d133-4579-a916-a9c8b98cfccb}", - "{028e4905-cc97-4dab-b1bf-d76f58b501b5}", - ], - "value": None, - }, - "tmi_channel_bool": { - "group": "Data", - "main": True, - "label": "TMI (nT)", - "value": False, - }, - "tmi_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "TMI (nT)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "tmi_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "tmi_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "bxx_channel_bool": { - "group": "Data", - "main": True, - "label": "Bxx (nT/m)", - "value": False, - }, - "bxx_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Bxx (nT/m)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "bxx_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "bxx_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "bxy_channel_bool": { - "group": "Data", - "main": True, - "label": "Bxy (nT/m)", - "value": False, - }, - "bxy_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Bxy (nT/m)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "bxy_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "bxy_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "bxz_channel_bool": { - "group": "Data", - "main": True, - "label": "Bxz (nT/m)", - "value": False, - }, - "bxz_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Bxz (nT/m)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "bxz_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "bxz_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "byy_channel_bool": { - "group": "Data", - "main": True, - "label": "Byy (nT/m)", - "value": False, - }, - "byy_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Byy (nT/m)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "byy_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "byy_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "byz_channel_bool": { - "group": "Data", - "main": True, - "label": "Byz (nT/m)", - "value": False, - }, - "byz_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Byz (nT/m)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "byz_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "byz_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "bzz_channel_bool": { - "group": "Data", - "main": True, - "label": "Bzz (nT/m)", - "value": False, - }, - "bzz_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Bzz (nT/m)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "bzz_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "bzz_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "bx_channel_bool": { - "group": "Data", - "main": True, - "label": "Bx (nT)", - "value": False, - }, - "bx_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Bx (nT)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "bx_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "bx_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "by_channel_bool": { - "group": "Data", - "main": True, - "label": "By (nT)", - "value": False, - }, - "by_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "By (nT)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "by_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "by_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "bz_channel_bool": { - "group": "Data", - "main": True, - "label": "Bz (nT)", - "value": False, - }, - "bz_channel": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "label": "Bz (nT)", - "parent": "data_object", - "optional": True, - "enabled": False, - "value": None, - }, - "bz_uncertainty": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Data", - "main": True, - "isValue": True, - "label": "Uncertainty", - "parent": "data_object", - "dependency": "bz_channel", - "dependencyType": "enabled", - "property": None, - "value": 1.0, - }, - "coolingRate": { - "group": "Optimization", - "label": "Iterations per beta", - "value": 1, - "min": 1, - "LineEdit": False, - "max": 10, - "precision": 1, - "verbose": 2, - "enabled": True, - }, - "starting_model": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": False, - "parent": "mesh", - "label": "Initial susceptibility (SI)", - "property": None, - "value": 1e-4, - }, - "starting_inclination": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": False, - "optional": True, - "enabled": False, - "parent": "mesh", - "label": "Initial inclination (deg)", - "property": None, - "value": 0.0, - }, - "starting_inclination_object": { - "group": "Mesh and models", - "main": True, - "meshType": [ - "{202C5DB1-A56D-4004-9CAD-BAAFD8899406}", - "{6A057FDC-B355-11E3-95BE-FD84A7FFCB88}", - "{F26FEBA3-ADED-494B-B9E9-B2BBCBE298E1}", - "{48F5054A-1C5C-4CA4-9048-80F36DC60A06}", - "{b020a277-90e2-4cd7-84d6-612ee3f25051}", - "{4ea87376-3ece-438b-bf12-3479733ded46}", - ], - "optional": True, - "enabled": False, - "label": "Object", - "value": None, - }, - "starting_declination": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": False, - "optional": True, - "enabled": False, - "parent": "mesh", - "label": "Initial declination (deg)", - "property": None, - "value": 0.0, - }, - "reference_model": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": True, - "optional": True, - "enabled": False, - "parent": "mesh", - "label": "Reference susceptibility (SI)", - "property": None, - "value": 0.0, - }, - "reference_inclination": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": False, - "optional": True, - "enabled": False, - "label": "Reference inclination (deg)", - "parent": "mesh", - "property": None, - "value": 0.0, - }, - "reference_declination": { - "association": ["Cell", "Vertex"], - "dataType": "Float", - "group": "Mesh and models", - "main": True, - "isValue": True, - "optional": True, - "enabled": False, - "label": "Reference declination (deg)", - "parent": "mesh", - "property": None, - "value": 0.0, - }, - "lower_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": False, - "parent": "mesh", - "label": "Lower bound (SI)", - "property": None, - "optional": True, - "value": 0.0, - "enabled": False, - }, - "upper_bound": { - "association": ["Cell", "Vertex"], - "main": True, - "dataType": "Float", - "group": "Mesh and models", - "isValue": False, - "parent": "mesh", - "label": "Upper bound (SI)", - "property": None, - "optional": True, - "value": 1.0, - "enabled": False, - }, -} -default_ui_json = dict(base_default_ui_json, **default_ui_json) -validations = { - "inversion_type": { - "required": True, - "values": ["magnetic vector"], - }, - "data_object": {"required": True, "types": [str, UUID, Points, Surface, Grid2D]}, - "tmi_channel": {"one_of": "data channel"}, - "tmi_uncertainty": {"one_of": "uncertainty channel"}, - "bxx_channel": {"one_of": "data channel"}, - "bxx_uncertainty": {"one_of": "uncertainty channel"}, - "bxy_channel": {"one_of": "data channel"}, - "bxy_uncertainty": {"one_of": "uncertainty channel"}, - "bxz_channel": {"one_of": "data channel"}, - "bxz_uncertainty": {"one_of": "uncertainty channel"}, - "byy_channel": {"one_of": "data channel"}, - "byy_uncertainty": {"one_of": "uncertainty channel"}, - "byz_channel": {"one_of": "data channel"}, - "byz_uncertainty": {"one_of": "uncertainty channel"}, - "bzz_channel": {"one_of": "data channel"}, - "bzz_uncertainty": {"one_of": "uncertainty channel"}, - "bx_channel": {"one_of": "data channel"}, - "bx_uncertainty": {"one_of": "uncertainty channel"}, - "by_channel": {"one_of": "data channel"}, - "by_uncertainty": {"one_of": "uncertainty channel"}, - "bz_channel": {"one_of": "data channel"}, - "bz_uncertainty": {"one_of": "uncertainty channel"}, -} -validations = dict(base_validations, **validations) app_initializer = { "geoh5": str(assets_path() / "FlinFlon.geoh5"), "monitoring_directory": str((assets_path() / "Temp").resolve()), diff --git a/simpeg_drivers/potential_fields/magnetic_vector/driver.py b/simpeg_drivers/potential_fields/magnetic_vector/driver.py index cf87f0ad..57d1a5ef 100644 --- a/simpeg_drivers/potential_fields/magnetic_vector/driver.py +++ b/simpeg_drivers/potential_fields/magnetic_vector/driver.py @@ -15,18 +15,21 @@ from simpeg_drivers.driver import InversionDriver -from .constants import validations -from .params import MagneticVectorForwardParams, MagneticVectorInversionParams +from .params import MVIForwardOptions, MVIInversionOptions -class MagneticVectorForwardDriver(InversionDriver): - _params_class = MagneticVectorForwardParams - _validations = validations +class MVIForwardDriver(InversionDriver): + """Magnetic Vector forward driver.""" + _params_class = MVIForwardOptions + _validations = {} -class MagneticVectorInversionDriver(InversionDriver): - _params_class = MagneticVectorInversionParams - _validations = validations + +class MVIInversionDriver(InversionDriver): + """Magnetic Vector inversion driver.""" + + _params_class = MVIInversionOptions + _validations = {} @property def mapping(self) -> list[maps.Projection] | None: diff --git a/simpeg_drivers/potential_fields/magnetic_vector/params.py b/simpeg_drivers/potential_fields/magnetic_vector/params.py index 40d49677..fe5f515f 100644 --- a/simpeg_drivers/potential_fields/magnetic_vector/params.py +++ b/simpeg_drivers/potential_fields/magnetic_vector/params.py @@ -17,12 +17,12 @@ from geoh5py.data import FloatData from simpeg_drivers import assets_path -from simpeg_drivers.params import BaseForwardData, BaseInversionData +from simpeg_drivers.params import BaseForwardOptions, BaseInversionOptions -class MagneticVectorForwardParams(BaseForwardData): +class MVIForwardOptions(BaseForwardOptions): """ - Magnetic vector forward parameters. + Magnetic Vector forward options. :param tmi_channel_bool: Total magnetic intensity channel boolean. :param bx_channel_bool: Bx channel boolean. @@ -57,9 +57,9 @@ class MagneticVectorForwardParams(BaseForwardData): bzz_channel_bool: bool = False -class MagneticVectorInversionParams(BaseInversionData): +class MVIInversionOptions(BaseInversionOptions): """ - Magnetic vector inversion parameters. + Magnetic Vector Inversion options. :param tmi_channel: Total magnetic intensity channel. :param bx_channel: Bx channel. diff --git a/simpeg_drivers/utils/surveys.py b/simpeg_drivers/utils/surveys.py index 7dce4bd6..992de52d 100644 --- a/simpeg_drivers/utils/surveys.py +++ b/simpeg_drivers/utils/surveys.py @@ -143,54 +143,3 @@ def get_unique_locations(survey: BaseSurvey) -> np.ndarray: locations = survey.receiver_locations return np.unique(locations, axis=0) - - -def is_outlier(population: list[float | int], value: float, n_std: int | float = 3): - """ - use a standard deviation threshold to determine if value is an outlier for the population. - - :param population: list of values. - :param value: single value to detect outlier status - :param n_std (optional): - - :return True if the deviation of value from the mean exceeds the standard deviation threshold. - """ - mean = np.mean(population) - std = np.std(population) - deviation = np.abs(mean - value) - return deviation > n_std * std - - -def next_neighbor(tree: cKDTree, point: list[float], nodes: list[int], n: int = 3): - """ - Returns smallest distance neighbor that has not yet been traversed. - - :param: tree: kd-tree computed for the point cloud of possible neighbors. - :param: point: Current point being traversed. - :param: nodes: Traversed point ids. - """ - distances, neighbors = tree.query(point, n) - new_ids = new_neighbors(distances, neighbors, nodes) - if any(new_ids): - distances = distances[new_ids] - neighbors = neighbors[new_ids] - next_id = np.argmin(distances) - return distances[next_id], neighbors[next_id] - - else: - return next_neighbor(tree, point, nodes, n + 3) - - -def new_neighbors(distances: np.ndarray, neighbors: np.ndarray, nodes: list[int]): - """ - Index into neighbor arrays excluding zero distance and past neighbors. - - :param: distances: previously computed distances - :param: neighbors: Possible neighbors - :param: nodes: Traversed point ids. - """ - ind = [ - i in nodes if distances[neighbors.tolist().index(i)] != 0 else False - for i in neighbors - ] - return np.where(ind)[0].tolist() diff --git a/simpeg_drivers/utils/write_default_uijson.py b/simpeg_drivers/utils/write_default_uijson.py index c97e2aa1..b442fb83 100644 --- a/simpeg_drivers/utils/write_default_uijson.py +++ b/simpeg_drivers/utils/write_default_uijson.py @@ -14,19 +14,8 @@ import argparse from pathlib import Path -from simpeg_drivers.electricals.direct_current.pseudo_three_dimensions.params import ( - DirectCurrentPseudo3DParams, -) -from simpeg_drivers.electricals.induced_polarization.pseudo_three_dimensions.params import ( - InducedPolarizationPseudo3DParams, -) -from simpeg_drivers.electromagnetics.frequency_domain import ( - FrequencyDomainElectromagneticsParams, -) -from simpeg_drivers.electromagnetics.time_domain import TimeDomainElectromagneticsParams from simpeg_drivers.joint.joint_cross_gradient import JointCrossGradientParams from simpeg_drivers.joint.joint_surveys import JointSurveysParams -from simpeg_drivers.natural_sources import MagnetotelluricsParams, TipperParams active_data_channels = [ @@ -52,38 +41,6 @@ def write_default_uijson(path: str | Path): filedict = { - "direct_current_inversion_pseudo3d.ui.json": DirectCurrentPseudo3DParams( - validate=False - ), - "direct_current_forward_pseudo3d.ui.json": DirectCurrentPseudo3DParams( - forward_only=True, validate=False - ), - "induced_polarization_inversion_pseudo3d.ui.json": InducedPolarizationPseudo3DParams( - validate=False - ), - "induced_polarization_forward_pseudo3d.ui.json": InducedPolarizationPseudo3DParams( - forward_only=True, validate=False - ), - "fem_inversion.ui.json": FrequencyDomainElectromagneticsParams( - forward_only=False, validate=False - ), - "fem_forward.ui.json": FrequencyDomainElectromagneticsParams( - forward_only=True, validate=False - ), - "tdem_inversion.ui.json": TimeDomainElectromagneticsParams( - forward_only=False, validate=False - ), - "tdem_forward.ui.json": TimeDomainElectromagneticsParams( - forward_only=True, validate=False - ), - "magnetotellurics_inversion.ui.json": MagnetotelluricsParams( - forward_only=False, validate=False - ), - "magnetotellurics_forward.ui.json": MagnetotelluricsParams( - forward_only=True, validate=False - ), - "tipper_inversion.ui.json": TipperParams(forward_only=False, validate=False), - "tipper_forward.ui.json": TipperParams(forward_only=True, validate=False), "joint_surveys_inversion.ui.json": JointSurveysParams( forward_only=False, validate=False ), diff --git a/tests/constants_test.py b/tests/constants_test.py deleted file mode 100644 index 991285a6..00000000 --- a/tests/constants_test.py +++ /dev/null @@ -1,44 +0,0 @@ -# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -# Copyright (c) 2024-2025 Mira Geoscience Ltd. ' -# ' -# This file is part of simpeg-drivers package. ' -# ' -# simpeg-drivers is distributed under the terms and conditions of the MIT License ' -# (see LICENSE file at the root of this source code package). ' -# ' -# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -from __future__ import annotations - -from simpeg_drivers.electricals.direct_current.three_dimensions import ( - constants as direct_current_constants, -) -from simpeg_drivers.electricals.induced_polarization.three_dimensions import ( - constants as induced_polarization_constants, -) -from simpeg_drivers.potential_fields.gravity import constants as gravity_constants -from simpeg_drivers.potential_fields.magnetic_scalar import ( - constants as magnetic_scalar_constants, -) -from simpeg_drivers.potential_fields.magnetic_vector import ( - constants as magnetic_vector_constants, -) - - -constants = [ - gravity_constants, - magnetic_scalar_constants, - magnetic_vector_constants, - direct_current_constants, - induced_polarization_constants, -] - - -def test_deprecated_uijson_fields(): - deprecated_fields = ["default"] - for constant in constants: - d_u_j = constant.default_ui_json - for value in d_u_j.values(): - if isinstance(value, dict): - for field in deprecated_fields: - assert field not in value.keys() diff --git a/tests/data_test.py b/tests/data_test.py index 953711bd..ae21bd22 100644 --- a/tests/data_test.py +++ b/tests/data_test.py @@ -22,17 +22,17 @@ from octree_creation_app.utils import treemesh_2_octree from simpeg_drivers.components import InversionData -from simpeg_drivers.params import ActiveCellsData +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.potential_fields.magnetic_vector.driver import ( - MagneticVectorInversionDriver, + MVIInversionDriver, ) from simpeg_drivers.potential_fields.magnetic_vector.params import ( - MagneticVectorInversionParams, + MVIInversionOptions, ) from simpeg_drivers.utils.testing import Geoh5Tester, setup_inversion_workspace -def get_mvi_params(tmp_path: Path, **kwargs) -> MagneticVectorInversionParams: +def get_mvi_params(tmp_path: Path, **kwargs) -> MVIInversionOptions: geoh5, entity, model, survey, topography = setup_inversion_workspace( tmp_path, background=0.0, @@ -45,11 +45,11 @@ def get_mvi_params(tmp_path: Path, **kwargs) -> MagneticVectorInversionParams: tmi_channel = survey.add_data( {"tmi": {"values": np.random.rand(survey.n_vertices)}} ) - params = MagneticVectorInversionParams( + params = MVIInversionOptions( geoh5=geoh5, data_object=survey, tmi_channel=tmi_channel, - active_cells=ActiveCellsData(topography_object=topography), + active_cells=ActiveCellsOptions(topography_object=topography), mesh=model.parent, starting_model=model, **kwargs, @@ -110,10 +110,10 @@ def test_survey_data(tmp_path: Path): ) mesh = treemesh_2_octree(workspace, mesh) - active_cells = ActiveCellsData( + active_cells = ActiveCellsOptions( topography_object=test_topo_object, topography=topo ) - params = MagneticVectorInversionParams( + params = MVIInversionOptions( geoh5=workspace, data_object=test_data_object, active_cells=active_cells, @@ -130,7 +130,7 @@ def test_survey_data(tmp_path: Path): resolution=0.0, ) - driver = MagneticVectorInversionDriver(params) + driver = MVIInversionDriver(params) assert driver.inversion is not None @@ -204,7 +204,7 @@ def test_get_uncertainty_component(tmp_path: Path): params = get_mvi_params(tmp_path, tmi_uncertainty=1.0) geoh5 = params.geoh5 data = InversionData(geoh5, params) - unc = data.get_data()[2]["tmi"] + unc = params.uncertainties["tmi"] assert len(np.unique(unc)) == 1 assert np.unique(unc)[0] == 1 assert len(unc) == data.entity.n_vertices @@ -214,23 +214,14 @@ def test_normalize(tmp_path: Path): params = get_mvi_params(tmp_path) geoh5 = params.geoh5 data = InversionData(geoh5, params) - len_data = len(data.observed["tmi"]) - data.observed = { - "tmi": np.arange(len_data, dtype=float), - "gz": np.arange(len_data, dtype=float), - } - data.components = list(data.observed.keys()) data.normalizations = data.get_normalizations() test_data = data.normalize(data.observed) - assert np.all( - np.hstack(list(data.normalizations[None].values())).tolist() - == np.repeat([1, -1], len_data) - ) - assert all(test_data["gz"] == (-1 * data.observed["gz"])) + assert all(test_data["tmi"] == params.data["tmi"]) + assert len(test_data) == 1 def test_get_survey(tmp_path: Path): - params = get_mvi_params(tmp_path) + params = get_mvi_params(tmp_path, tmi_uncertainty=1.0) geoh5 = params.geoh5 data = InversionData(geoh5, params) survey = data.create_survey() diff --git a/tests/driver_test.py b/tests/driver_test.py index 881f80ea..85fa7cb3 100644 --- a/tests/driver_test.py +++ b/tests/driver_test.py @@ -12,8 +12,8 @@ import numpy as np -from simpeg_drivers.params import ActiveCellsData -from simpeg_drivers.potential_fields import GravityInversionParams +from simpeg_drivers.params import ActiveCellsOptions +from simpeg_drivers.potential_fields import GravityInversionOptions from simpeg_drivers.potential_fields.gravity.driver import GravityInversionDriver from simpeg_drivers.utils.testing import setup_inversion_workspace @@ -34,8 +34,8 @@ def test_smallness_terms(tmp_path: Path): gz = survey.add_data({"gz": {"values": np.ones(survey.n_vertices)}}) mesh = model.parent - active_cells = ActiveCellsData(topography_object=topography) - params = GravityInversionParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = GravityInversionOptions( geoh5=geoh5, mesh=mesh, active_cells=active_cells, diff --git a/tests/locations_test.py b/tests/locations_test.py index 7f3bd70b..4a5cc5dd 100644 --- a/tests/locations_test.py +++ b/tests/locations_test.py @@ -17,12 +17,12 @@ from geoh5py.objects import Grid2D, Points from simpeg_drivers.components.locations import InversionLocations -from simpeg_drivers.params import ActiveCellsData -from simpeg_drivers.potential_fields import MagneticVectorInversionParams +from simpeg_drivers.params import ActiveCellsOptions +from simpeg_drivers.potential_fields import MVIInversionOptions from simpeg_drivers.utils.testing import Geoh5Tester, setup_inversion_workspace -def get_mvi_params(tmp_path: Path) -> MagneticVectorInversionParams: +def get_mvi_params(tmp_path: Path) -> MVIInversionOptions: geoh5, enitiy, model, survey, topography = setup_inversion_workspace( tmp_path, background=0.0, @@ -35,12 +35,12 @@ def get_mvi_params(tmp_path: Path) -> MagneticVectorInversionParams: tmi_channel = survey.add_data( {"tmi": {"values": np.random.rand(survey.n_vertices)}} ) - params = MagneticVectorInversionParams( + params = MVIInversionOptions( geoh5=geoh5, data_object=survey, tmi_channel=tmi_channel, tmi_uncertainty=1.0, - active_cells=ActiveCellsData(topography_object=topography), + active_cells=ActiveCellsOptions(topography_object=topography), mesh=model.parent, starting_model=model, ) diff --git a/tests/meshes_test.py b/tests/meshes_test.py index 523c8bbe..13c0af4e 100644 --- a/tests/meshes_test.py +++ b/tests/meshes_test.py @@ -20,12 +20,12 @@ from octree_creation_app.utils import treemesh_2_octree from simpeg_drivers.components import InversionMesh -from simpeg_drivers.params import ActiveCellsData -from simpeg_drivers.potential_fields import MagneticVectorInversionParams +from simpeg_drivers.params import ActiveCellsOptions +from simpeg_drivers.potential_fields import MVIInversionOptions from simpeg_drivers.utils.testing import Geoh5Tester, setup_inversion_workspace -def get_mvi_params(tmp_path: Path) -> MagneticVectorInversionParams: +def get_mvi_params(tmp_path: Path) -> MVIInversionOptions: geoh5, entity, model, survey, topography = setup_inversion_workspace( tmp_path, background=0.0, @@ -47,11 +47,11 @@ def get_mvi_params(tmp_path: Path) -> MagneticVectorInversionParams: {"elevation": {"values": topography.vertices[:, 2]}} ) elevation = topography.children[0] - params = MagneticVectorInversionParams( + params = MVIInversionOptions( geoh5=geoh5, data_object=survey, tmi_channel=tmi_channel, - active_cells=ActiveCellsData( + active_cells=ActiveCellsOptions( topography_object=topography, topography=elevation ), mesh=mesh, diff --git a/tests/models_test.py b/tests/models_test.py index 4211457e..9b0da4d9 100644 --- a/tests/models_test.py +++ b/tests/models_test.py @@ -20,15 +20,15 @@ InversionModel, InversionModelCollection, ) -from simpeg_drivers.params import ActiveCellsData -from simpeg_drivers.potential_fields import MagneticVectorInversionParams +from simpeg_drivers.params import ActiveCellsOptions +from simpeg_drivers.potential_fields import MVIInversionOptions from simpeg_drivers.potential_fields.magnetic_vector.driver import ( - MagneticVectorInversionDriver, + MVIInversionDriver, ) from simpeg_drivers.utils.testing import Geoh5Tester, setup_inversion_workspace -def get_mvi_params(tmp_path: Path) -> MagneticVectorInversionParams: +def get_mvi_params(tmp_path: Path) -> MVIInversionOptions: geoh5, entity, model, survey, topography = setup_inversion_workspace( tmp_path, background=0.0, @@ -48,12 +48,12 @@ def get_mvi_params(tmp_path: Path) -> MagneticVectorInversionParams: elevation = topography.add_data( {"elevation": {"values": topography.vertices[:, 2]}} ) - params = MagneticVectorInversionParams( + params = MVIInversionOptions( geoh5=geoh5, data_object=survey, tmi_channel=tmi_channel, mesh=mesh, - active_cells=ActiveCellsData( + active_cells=ActiveCellsOptions( topography_object=topography, topography=elevation ), starting_model=1e-04, @@ -70,7 +70,7 @@ def get_mvi_params(tmp_path: Path) -> MagneticVectorInversionParams: def test_zero_reference_model(tmp_path: Path): params = get_mvi_params(tmp_path) geoh5 = params.geoh5 - driver = MagneticVectorInversionDriver(params) + driver = MVIInversionDriver(params) _ = InversionModel(driver, "reference") incl = np.unique(geoh5.get_entity("reference_inclination")[0].values) decl = np.unique(geoh5.get_entity("reference_declination")[0].values) @@ -82,7 +82,7 @@ def test_zero_reference_model(tmp_path: Path): def test_collection(tmp_path: Path): params = get_mvi_params(tmp_path) - driver = MagneticVectorInversionDriver(params) + driver = MVIInversionDriver(params) models = InversionModelCollection(driver) models.remove_air(driver.models.active_cells) starting = InversionModel(driver, "starting") @@ -92,7 +92,7 @@ def test_collection(tmp_path: Path): def test_initialize(tmp_path: Path): params = get_mvi_params(tmp_path) - driver = MagneticVectorInversionDriver(params) + driver = MVIInversionDriver(params) starting_model = InversionModel(driver, "starting") assert len(starting_model.model) == 3 * driver.inversion_mesh.n_cells assert len(np.unique(starting_model.model)) == 3 @@ -102,7 +102,7 @@ def test_model_from_object(tmp_path: Path): # Test behaviour when loading model from Points object with non-matching mesh params = get_mvi_params(tmp_path) geoh5 = params.geoh5 - driver = MagneticVectorInversionDriver(params) + driver = MVIInversionDriver(params) inversion_mesh = InversionMesh(geoh5, params) cc = inversion_mesh.mesh.cell_centers diff --git a/tests/run_tests/driver_airborne_tem_test.py b/tests/run_tests/driver_airborne_tem_test.py index 2bfb0937..fb130728 100644 --- a/tests/run_tests/driver_airborne_tem_test.py +++ b/tests/run_tests/driver_airborne_tem_test.py @@ -17,10 +17,15 @@ from geoh5py.workspace import Workspace from pytest import raises -from simpeg_drivers.electromagnetics.time_domain import TimeDomainElectromagneticsParams +from simpeg_drivers.electromagnetics.time_domain import ( + TDEMForwardOptions, + TDEMInversionOptions, +) from simpeg_drivers.electromagnetics.time_domain.driver import ( - TimeDomainElectromagneticsDriver, + TDEMForwardDriver, + TDEMInversionDriver, ) +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -46,21 +51,19 @@ def test_bad_waveform(tmp_path: Path): padding_distance=400.0, flatten=False, ) - params = TimeDomainElectromagneticsParams( - forward_only=True, + params = TDEMForwardOptions( geoh5=geoh5, - mesh=model.parent.uid, - topography_object=topography.uid, - resolution=0.0, + mesh=model.parent, + active_cells=ActiveCellsOptions(topography_object=topography), z_from_topo=False, - data_object=survey.uid, - starting_model=model.uid, + data_object=survey, + starting_model=model, x_channel_bool=True, y_channel_bool=True, z_channel_bool=True, ) - params.workpath = tmp_path - fwr_driver = TimeDomainElectromagneticsDriver(params) + + fwr_driver = TDEMForwardDriver(params) survey.channels[-1] = 1000.0 @@ -88,21 +91,19 @@ def test_airborne_tem_fwr_run( padding_distance=400.0, flatten=False, ) - params = TimeDomainElectromagneticsParams( - forward_only=True, + params = TDEMForwardOptions( geoh5=geoh5, - mesh=model.parent.uid, - topography_object=topography.uid, - resolution=0.0, + mesh=model.parent, + active_cells=ActiveCellsOptions(topography_object=topography), z_from_topo=False, - data_object=survey.uid, - starting_model=model.uid, + data_object=survey, + starting_model=model, x_channel_bool=True, y_channel_bool=True, z_channel_bool=True, ) - params.workpath = tmp_path - fwr_driver = TimeDomainElectromagneticsDriver(params) + + fwr_driver = TDEMForwardDriver(params) fwr_driver.run() @@ -162,12 +163,11 @@ def test_airborne_tem_run(tmp_path: Path, max_iterations=1, pytest=True): orig_dBzdt = geoh5.get_entity("Iteration_0_z_[0]")[0].values # Run the inverse - params = TimeDomainElectromagneticsParams( + params = TDEMInversionOptions( geoh5=geoh5, - mesh=mesh.uid, - topography_object=topography.uid, - resolution=0.0, - data_object=survey.uid, + mesh=mesh, + active_cells=ActiveCellsOptions(topography_object=topography), + data_object=survey, starting_model=1e-3, reference_model=1e-3, chi_factor=1.0, @@ -185,12 +185,13 @@ def test_airborne_tem_run(tmp_path: Path, max_iterations=1, pytest=True): coolingRate=4, max_cg_iterations=200, prctile=5, + sens_wts_threshold=1.0, store_sensitivities="ram", **data_kwargs, ) - params.write_input_file(path=tmp_path, name="Inv_run") + params.write_ui_json(path=tmp_path / "Inv_run.ui.json") - driver = TimeDomainElectromagneticsDriver.start(str(tmp_path / "Inv_run.ui.json")) + driver = TDEMInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) with geoh5.open() as run_ws: output = get_inversion_output( diff --git a/tests/run_tests/driver_dc_2d_test.py b/tests/run_tests/driver_dc_2d_test.py index ef56e606..687cc093 100644 --- a/tests/run_tests/driver_dc_2d_test.py +++ b/tests/run_tests/driver_dc_2d_test.py @@ -18,15 +18,15 @@ from geoh5py.workspace import Workspace from simpeg_drivers.electricals.direct_current.two_dimensions.driver import ( - DirectCurrent2DForwardDriver, - DirectCurrent2DInversionDriver, + DC2DForwardDriver, + DC2DInversionDriver, ) from simpeg_drivers.electricals.direct_current.two_dimensions.params import ( - DirectCurrent2DForwardParams, - DirectCurrent2DInversionParams, + DC2DForwardOptions, + DC2DInversionOptions, ) -from simpeg_drivers.electricals.params import DrapeModelData, LineSelectionData -from simpeg_drivers.params import ActiveCellsData +from simpeg_drivers.electricals.params import DrapeModelOptions, LineSelectionOptions +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -59,15 +59,15 @@ def test_dc_2d_fwr_run( drape_height=0.0, flatten=False, ) - line_selection = LineSelectionData( + line_selection = LineSelectionOptions( line_object=geoh5.get_entity("line_ids")[0], line_id=101, ) - params = DirectCurrent2DForwardParams( + params = DC2DForwardOptions( geoh5=geoh5, data_object=survey, line_selection=line_selection, - drape_model=DrapeModelData( + drape_model=DrapeModelOptions( u_cell_size=5.0, v_cell_size=5.0, depth_core=100.0, @@ -76,11 +76,11 @@ def test_dc_2d_fwr_run( expansion_factor=1.1, ), starting_model=model, - active_cells=ActiveCellsData(topography_object=topography), + active_cells=ActiveCellsOptions(topography_object=topography), z_from_topo=False, ) - fwr_driver = DirectCurrent2DForwardDriver(params) + fwr_driver = DC2DForwardDriver(params) fwr_driver.run() @@ -94,9 +94,9 @@ def test_dc_2d_run(tmp_path: Path, max_iterations=1, pytest=True): topography = geoh5.get_entity("topography")[0] # Run the inverse - params = DirectCurrent2DInversionParams( + params = DC2DInversionOptions( geoh5=geoh5, - drape_model=DrapeModelData( + drape_model=DrapeModelOptions( u_cell_size=5.0, v_cell_size=5.0, depth_core=100.0, @@ -104,8 +104,8 @@ def test_dc_2d_run(tmp_path: Path, max_iterations=1, pytest=True): vertical_padding=100.0, expansion_factor=1.1, ), - active_cells=ActiveCellsData(topography_object=topography), - line_selection=LineSelectionData( + active_cells=ActiveCellsOptions(topography_object=topography), + line_selection=LineSelectionOptions( line_object=geoh5.get_entity("line_ids")[0], line_id=101, ), @@ -130,7 +130,7 @@ def test_dc_2d_run(tmp_path: Path, max_iterations=1, pytest=True): ) params.write_ui_json(path=tmp_path / "Inv_run.ui.json") - driver = DirectCurrent2DInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) + driver = DC2DInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) output = get_inversion_output( driver.params.geoh5.h5file, driver.params.out_group.uid diff --git a/tests/run_tests/driver_dc_p3d_test.py b/tests/run_tests/driver_dc_b2d_test.py similarity index 80% rename from tests/run_tests/driver_dc_p3d_test.py rename to tests/run_tests/driver_dc_b2d_test.py index 1bf2bcb0..52b838bb 100644 --- a/tests/run_tests/driver_dc_p3d_test.py +++ b/tests/run_tests/driver_dc_b2d_test.py @@ -18,19 +18,19 @@ from geoh5py.workspace import Workspace from simpeg_drivers.electricals.direct_current.pseudo_three_dimensions.driver import ( - DirectCurrentPseudo3DForwardDriver, - DirectCurrentPseudo3DInversionDriver, + DCBatch2DForwardDriver, + DCBatch2DInversionDriver, ) from simpeg_drivers.electricals.direct_current.pseudo_three_dimensions.params import ( - DirectCurrentPseudo3DForwardParams, - DirectCurrentPseudo3DInversionParams, + DCBatch2DForwardOptions, + DCBatch2DInversionOptions, ) from simpeg_drivers.electricals.params import ( - DrapeModelData, - FileControlData, - LineSelectionData, + DrapeModelOptions, + FileControlOptions, + LineSelectionOptions, ) -from simpeg_drivers.params import ActiveCellsData +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -59,10 +59,10 @@ def test_dc_p3d_fwr_run( drape_height=0.0, flatten=False, ) - params = DirectCurrentPseudo3DForwardParams( + params = DCBatch2DForwardOptions( geoh5=geoh5, mesh=model.parent, - drape_model=DrapeModelData( + drape_model=DrapeModelOptions( u_cell_size=5.0, v_cell_size=5.0, depth_core=100.0, @@ -70,14 +70,16 @@ def test_dc_p3d_fwr_run( horizontal_padding=1000.0, vertical_padding=1000.0, ), - active_cells=ActiveCellsData(topography_object=topography), + active_cells=ActiveCellsOptions(topography_object=topography), z_from_topo=False, data_object=survey, starting_model=model, - line_selection=LineSelectionData(line_object=geoh5.get_entity("line_ids")[0]), + line_selection=LineSelectionOptions( + line_object=geoh5.get_entity("line_ids")[0] + ), ) - fwr_driver = DirectCurrentPseudo3DForwardDriver(params) + fwr_driver = DCBatch2DForwardDriver(params) fwr_driver.run() @@ -97,10 +99,10 @@ def test_dc_p3d_run( topography = geoh5.get_entity("topography")[0] # Run the inverse - params = DirectCurrentPseudo3DInversionParams( + params = DCBatch2DInversionOptions( geoh5=geoh5, mesh=mesh, - drape_model=DrapeModelData( + drape_model=DrapeModelOptions( u_cell_size=5.0, v_cell_size=5.0, depth_core=100.0, @@ -108,11 +110,11 @@ def test_dc_p3d_run( horizontal_padding=1000.0, vertical_padding=1000.0, ), - active_cells=ActiveCellsData(topography_object=topography), + active_cells=ActiveCellsOptions(topography_object=topography), data_object=potential.parent, potential_channel=potential, potential_uncertainty=1e-3, - line_selection=LineSelectionData( + line_selection=LineSelectionOptions( line_object=geoh5.get_entity("line_ids")[0] ), starting_model=1e-2, @@ -128,13 +130,11 @@ def test_dc_p3d_run( prctile=100, upper_bound=10, coolingRate=1, - file_control=FileControlData(cleanup=False), + file_control=FileControlOptions(cleanup=False), ) params.write_ui_json(path=tmp_path / "Inv_run.ui.json") - driver = DirectCurrentPseudo3DInversionDriver.start( - str(tmp_path / "Inv_run.ui.json") - ) + driver = DCBatch2DInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) basepath = workpath.parent with open(basepath / "lookup.json", encoding="utf8") as f: @@ -147,11 +147,11 @@ def test_dc_p3d_run( ) filedata = middle_inversion_group.get_entity("SimPEG.out")[0] - with driver.pseudo3d_params.out_group.workspace.open(mode="r+"): - filedata.copy(parent=driver.pseudo3d_params.out_group) + with driver.batch2d_params.out_group.workspace.open(mode="r+"): + filedata.copy(parent=driver.batch2d_params.out_group) output = get_inversion_output( - driver.pseudo3d_params.geoh5.h5file, driver.pseudo3d_params.out_group.uid + driver.batch2d_params.geoh5.h5file, driver.batch2d_params.out_group.uid ) if geoh5.open(): output["data"] = potential.values diff --git a/tests/run_tests/driver_dc_test.py b/tests/run_tests/driver_dc_test.py index bf3d9674..2840adec 100644 --- a/tests/run_tests/driver_dc_test.py +++ b/tests/run_tests/driver_dc_test.py @@ -16,14 +16,14 @@ from geoh5py.workspace import Workspace from simpeg_drivers.electricals.direct_current.three_dimensions.driver import ( - DirectCurrent3DForwardDriver, - DirectCurrent3DInversionDriver, + DC3DForwardDriver, + DC3DInversionDriver, ) from simpeg_drivers.electricals.direct_current.three_dimensions.params import ( - DirectCurrent3DForwardParams, - DirectCurrent3DInversionParams, + DC3DForwardOptions, + DC3DInversionOptions, ) -from simpeg_drivers.params import ActiveCellsData +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -66,8 +66,8 @@ def test_dc_3d_fwr_run( geoh5.close() - active_cells = ActiveCellsData(topography_object=topography) - params = DirectCurrent3DForwardParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = DC3DForwardOptions( geoh5=geoh5, mesh=model.parent, active_cells=active_cells, @@ -76,7 +76,7 @@ def test_dc_3d_fwr_run( starting_model=model, resolution=None, ) - fwr_driver = DirectCurrent3DForwardDriver(params) + fwr_driver = DC3DForwardDriver(params) fwr_driver.run() @@ -96,8 +96,8 @@ def test_dc_3d_run( topography = geoh5.get_entity("topography")[0] # Run the inverse - active_cells = ActiveCellsData(topography_object=topography) - params = DirectCurrent3DInversionParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = DC3DInversionOptions( geoh5=geoh5, mesh=mesh, active_cells=active_cells, @@ -126,7 +126,7 @@ def test_dc_3d_run( ) params.write_ui_json(path=tmp_path / "Inv_run.ui.json") - driver = DirectCurrent3DInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) + driver = DC3DInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) # Should not be auto-scaling np.testing.assert_allclose(driver.data_misfit.multipliers, [1, 1, 1]) output = get_inversion_output( @@ -159,8 +159,8 @@ def test_dc_single_line_fwr_run( inversion_type="dcip", flatten=False, ) - active_cells = ActiveCellsData(topography_object=topography) - params = DirectCurrent3DForwardParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = DC3DForwardOptions( geoh5=geoh5, mesh=model.parent, active_cells=active_cells, @@ -170,7 +170,7 @@ def test_dc_single_line_fwr_run( resolution=None, ) - fwr_driver = DirectCurrent3DForwardDriver(params) + fwr_driver = DC3DForwardDriver(params) assert np.all(fwr_driver.window.window["size"] > 0) diff --git a/tests/run_tests/driver_fem_test.py b/tests/run_tests/driver_fem_test.py index c7a0a32e..d3144d2c 100644 --- a/tests/run_tests/driver_fem_test.py +++ b/tests/run_tests/driver_fem_test.py @@ -19,11 +19,14 @@ from geoh5py.groups import SimPEGGroup from simpeg_drivers.electromagnetics.frequency_domain.driver import ( - FrequencyDomainElectromagneticsDriver, + FDEMForwardDriver, + FDEMInversionDriver, ) from simpeg_drivers.electromagnetics.frequency_domain.params import ( - FrequencyDomainElectromagneticsParams, + FDEMForwardOptions, + FDEMInversionOptions, ) +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -54,20 +57,18 @@ def test_fem_fwr_run( inversion_type="fem", flatten=True, ) - params = FrequencyDomainElectromagneticsParams( - forward_only=True, + params = FDEMForwardOptions( geoh5=geoh5, - mesh=model.parent.uid, - topography_object=topography.uid, - resolution=0.0, + mesh=model.parent, + active_cells=ActiveCellsOptions(topography_object=topography), z_from_topo=False, - data_object=survey.uid, - starting_model=model.uid, + data_object=survey, + starting_model=model, z_real_channel_bool=True, z_imag_channel_bool=True, ) - params.workpath = tmp_path - fwr_driver = FrequencyDomainElectromagneticsDriver(params) + + fwr_driver = FDEMForwardDriver(params) fwr_driver.run() geoh5.close() @@ -121,18 +122,17 @@ def test_fem_run(tmp_path: Path, max_iterations=1, pytest=True): for comp, data_group, uncert_group in zip( components, data_groups, uncert_groups, strict=True ): - data_kwargs[f"{comp}_channel"] = data_group.uid - data_kwargs[f"{comp}_uncertainty"] = uncert_group.uid + data_kwargs[f"{comp}_channel"] = data_group + data_kwargs[f"{comp}_uncertainty"] = uncert_group orig_z_real_1 = geoh5.get_entity("Iteration_0_z_real_[0]")[0].values # Run the inverse - params = FrequencyDomainElectromagneticsParams( + params = FDEMInversionOptions( geoh5=geoh5, - mesh=mesh.uid, - topography_object=topography.uid, - resolution=0.0, - data_object=survey.uid, + mesh=mesh, + active_cells=ActiveCellsOptions(topography_object=topography), + data_object=survey, starting_model=1e-3, reference_model=1e-3, alpha_s=0.0, @@ -152,8 +152,8 @@ def test_fem_run(tmp_path: Path, max_iterations=1, pytest=True): sens_wts_threshold=1.0, **data_kwargs, ) - params.write_input_file(path=tmp_path, name="Inv_run") - driver = FrequencyDomainElectromagneticsDriver(params) + params.write_ui_json(path=tmp_path / "Inv_run.ui.json") + driver = FDEMInversionDriver(params) driver.run() with geoh5.open() as run_ws: diff --git a/tests/run_tests/driver_grav_test.py b/tests/run_tests/driver_grav_test.py index f5044cab..6d4dbf57 100644 --- a/tests/run_tests/driver_grav_test.py +++ b/tests/run_tests/driver_grav_test.py @@ -15,8 +15,11 @@ import numpy as np from geoh5py.workspace import Workspace -from simpeg_drivers.params import ActiveCellsData -from simpeg_drivers.potential_fields import GravityForwardParams, GravityInversionParams +from simpeg_drivers.params import ActiveCellsOptions +from simpeg_drivers.potential_fields import ( + GravityForwardOptions, + GravityInversionOptions, +) from simpeg_drivers.potential_fields.gravity.driver import ( GravityForwardDriver, GravityInversionDriver, @@ -47,8 +50,8 @@ def test_gravity_fwr_run( flatten=False, ) - active_cells = ActiveCellsData(topography_object=topography) - params = GravityForwardParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = GravityForwardOptions( geoh5=geoh5, mesh=model.parent, active_cells=active_cells, @@ -96,8 +99,8 @@ def test_gravity_run( gz.values = values # Run the inverse - active_cells = ActiveCellsData(topography_object=topography) - params = GravityInversionParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = GravityInversionOptions( geoh5=geoh5, mesh=mesh, active_cells=active_cells, diff --git a/tests/run_tests/driver_ground_tem_test.py b/tests/run_tests/driver_ground_tem_test.py index 0a95d65b..e90d57e1 100644 --- a/tests/run_tests/driver_ground_tem_test.py +++ b/tests/run_tests/driver_ground_tem_test.py @@ -16,10 +16,15 @@ import numpy as np from geoh5py.workspace import Workspace -from simpeg_drivers.electromagnetics.time_domain import TimeDomainElectromagneticsParams +from simpeg_drivers.electromagnetics.time_domain import ( + TDEMForwardOptions, + TDEMInversionOptions, +) from simpeg_drivers.electromagnetics.time_domain.driver import ( - TimeDomainElectromagneticsDriver, + TDEMForwardDriver, + TDEMInversionDriver, ) +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -54,21 +59,19 @@ def test_tiling_ground_tem( flatten=True, ) - params = TimeDomainElectromagneticsParams( - forward_only=True, + params = TDEMForwardOptions( geoh5=geoh5, - mesh=model.parent.uid, - topography_object=topography.uid, - resolution=0.0, + mesh=model.parent, + active_cells=ActiveCellsOptions(topography_object=topography), z_from_topo=False, - data_object=survey.uid, - starting_model=model.uid, + data_object=survey, + starting_model=model, x_channel_bool=True, y_channel_bool=True, z_channel_bool=True, tile_spatial=4, ) - fwr_driver = TimeDomainElectromagneticsDriver(params) + fwr_driver = TDEMForwardDriver(params) tiles = fwr_driver.get_tiles() @@ -104,21 +107,19 @@ def test_ground_tem_fwr_run( padding_distance=1000.0, flatten=True, ) - params = TimeDomainElectromagneticsParams( - forward_only=True, + params = TDEMForwardOptions( geoh5=geoh5, - mesh=model.parent.uid, - topography_object=topography.uid, - resolution=0.0, + mesh=model.parent, + active_cells=ActiveCellsOptions(topography_object=topography), z_from_topo=False, - data_object=survey.uid, - starting_model=model.uid, + data_object=survey, + starting_model=model, x_channel_bool=True, y_channel_bool=True, z_channel_bool=True, ) - params.workpath = tmp_path - fwr_driver = TimeDomainElectromagneticsDriver(params) + + fwr_driver = TDEMForwardDriver(params) survey.transmitters.remove_cells([15]) survey.tx_id_property.name = "tx_id" @@ -143,7 +144,7 @@ def test_ground_tem_run(tmp_path: Path, max_iterations=1, pytest=True): ) with Workspace(workpath) as geoh5: - simpeg_group = geoh5.get_entity("Tdem Forward")[0] + simpeg_group = geoh5.get_entity("Time-domain EM (TEM) Forward")[0] survey = simpeg_group.get_entity("Ground TEM Rx")[0] mesh = geoh5.get_entity("mesh")[0] topography = geoh5.get_entity("topography")[0] @@ -189,12 +190,11 @@ def test_ground_tem_run(tmp_path: Path, max_iterations=1, pytest=True): orig_dBzdt = geoh5.get_entity("Iteration_0_z_[0]")[0].values # Run the inverse - params = TimeDomainElectromagneticsParams( + params = TDEMInversionOptions( geoh5=geoh5, - mesh=mesh.uid, - topography_object=topography.uid, - resolution=0.0, - data_object=survey.uid, + mesh=mesh, + active_cells=ActiveCellsOptions(topography_object=topography), + data_object=survey, starting_model=1e-3, reference_model=1e-3, chi_factor=0.1, @@ -212,13 +212,13 @@ def test_ground_tem_run(tmp_path: Path, max_iterations=1, pytest=True): coolingRate=2, max_cg_iterations=200, prctile=100, - # sens_wts_threshold=1., + sens_wts_threshold=1.0, store_sensitivities="ram", **data_kwargs, ) - params.write_input_file(path=tmp_path, name="Inv_run") + params.write_ui_json(path=tmp_path / "Inv_run.ui.json") - driver = TimeDomainElectromagneticsDriver.start(str(tmp_path / "Inv_run.ui.json")) + driver = TDEMInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) with geoh5.open() as run_ws: output = get_inversion_output( diff --git a/tests/run_tests/driver_ip_2d_test.py b/tests/run_tests/driver_ip_2d_test.py index 0f3aba9b..80a43f49 100644 --- a/tests/run_tests/driver_ip_2d_test.py +++ b/tests/run_tests/driver_ip_2d_test.py @@ -16,15 +16,15 @@ from geoh5py.workspace import Workspace from simpeg_drivers.electricals.induced_polarization.two_dimensions import ( - InducedPolarization2DForwardParams, - InducedPolarization2DInversionParams, + IP2DForwardOptions, + IP2DInversionOptions, ) from simpeg_drivers.electricals.induced_polarization.two_dimensions.driver import ( - InducedPolarization2DForwardDriver, - InducedPolarization2DInversionDriver, + IP2DForwardDriver, + IP2DInversionDriver, ) -from simpeg_drivers.electricals.params import DrapeModelData, LineSelectionData -from simpeg_drivers.params import ActiveCellsData +from simpeg_drivers.electricals.params import DrapeModelOptions, LineSelectionOptions +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -53,21 +53,21 @@ def test_ip_2d_fwr_run( flatten=False, drape_height=0.0, ) - params = InducedPolarization2DForwardParams( + params = IP2DForwardOptions( geoh5=geoh5, data_object=survey, mesh=model.parent, - active_cells=ActiveCellsData(topography_object=topography), + active_cells=ActiveCellsOptions(topography_object=topography), z_from_topo=True, starting_model=model, conductivity_model=1e-2, - line_selection=LineSelectionData( + line_selection=LineSelectionOptions( line_object=geoh5.get_entity("line_ids")[0], line_id=101, ), ) - fwr_driver = InducedPolarization2DForwardDriver(params) + fwr_driver = IP2DForwardDriver(params) fwr_driver.run() @@ -86,14 +86,14 @@ def test_ip_2d_run( topography = geoh5.get_entity("topography")[0] # Run the inverse - params = InducedPolarization2DInversionParams( + params = IP2DInversionOptions( geoh5=geoh5, mesh=mesh, - active_cells=ActiveCellsData(topography_object=topography), + active_cells=ActiveCellsOptions(topography_object=topography), data_object=chargeability.parent, chargeability_channel=chargeability, chargeability_uncertainty=2e-4, - line_selection=LineSelectionData( + line_selection=LineSelectionOptions( line_object=geoh5.get_entity("line_ids")[0], line_id=101, ), @@ -115,9 +115,7 @@ def test_ip_2d_run( ) params.write_ui_json(path=tmp_path / "Inv_run.ui.json") - driver = InducedPolarization2DInversionDriver.start( - str(tmp_path / "Inv_run.ui.json") - ) + driver = IP2DInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) output = get_inversion_output( driver.params.geoh5.h5file, driver.params.out_group.uid diff --git a/tests/run_tests/driver_ip_p3d_test.py b/tests/run_tests/driver_ip_b2d_test.py similarity index 80% rename from tests/run_tests/driver_ip_p3d_test.py rename to tests/run_tests/driver_ip_b2d_test.py index 1f0e6819..6e26c0f1 100644 --- a/tests/run_tests/driver_ip_p3d_test.py +++ b/tests/run_tests/driver_ip_b2d_test.py @@ -17,19 +17,19 @@ from geoh5py.workspace import Workspace from simpeg_drivers.electricals.induced_polarization.pseudo_three_dimensions.driver import ( - InducedPolarizationPseudo3DForwardDriver, - InducedPolarizationPseudo3DInversionDriver, + IPBatch2DForwardDriver, + IPBatch2DInversionDriver, ) from simpeg_drivers.electricals.induced_polarization.pseudo_three_dimensions.params import ( - InducedPolarizationPseudo3DForwardParams, - InducedPolarizationPseudo3DInversionParams, + IPBatch2DForwardOptions, + IPBatch2DInversionOptions, ) from simpeg_drivers.electricals.params import ( - DrapeModelData, - FileControlData, - LineSelectionData, + DrapeModelOptions, + FileControlOptions, + LineSelectionOptions, ) -from simpeg_drivers.params import ActiveCellsData +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -59,10 +59,10 @@ def test_ip_p3d_fwr_run( flatten=False, ) - params = InducedPolarizationPseudo3DForwardParams( + params = IPBatch2DForwardOptions( geoh5=geoh5, mesh=model.parent, - drape_model=DrapeModelData( + drape_model=DrapeModelOptions( u_cell_size=5.0, v_cell_size=5.0, depth_core=100.0, @@ -70,17 +70,19 @@ def test_ip_p3d_fwr_run( horizontal_padding=100.0, vertical_padding=100.0, ), - active_cells=ActiveCellsData( + active_cells=ActiveCellsOptions( topography_object=topography, ), z_from_topo=True, data_object=survey, conductivity_model=1e-2, starting_model=model, - line_selection=LineSelectionData(line_object=geoh5.get_entity("line_ids")[0]), + line_selection=LineSelectionOptions( + line_object=geoh5.get_entity("line_ids")[0] + ), ) - fwr_driver = InducedPolarizationPseudo3DForwardDriver(params) + fwr_driver = IPBatch2DForwardDriver(params) fwr_driver.run() @@ -100,10 +102,10 @@ def test_ip_p3d_run( topography = geoh5.get_entity("topography")[0] # Run the inverse - params = InducedPolarizationPseudo3DInversionParams( + params = IPBatch2DInversionOptions( geoh5=geoh5, mesh=mesh, - drape_model=DrapeModelData( + drape_model=DrapeModelOptions( u_cell_size=5.0, v_cell_size=5.0, depth_core=100.0, @@ -111,11 +113,11 @@ def test_ip_p3d_run( horizontal_padding=1000.0, vertical_padding=1000.0, ), - active_cells=ActiveCellsData(topography_object=topography), + active_cells=ActiveCellsOptions(topography_object=topography), data_object=chargeability.parent, chargeability_channel=chargeability, chargeability_uncertainty=2e-4, - line_selection=LineSelectionData( + line_selection=LineSelectionOptions( line_object=geoh5.get_entity("line_ids")[0], ), conductivity_model=1e-2, @@ -135,13 +137,11 @@ def test_ip_p3d_run( prctile=100, upper_bound=0.1, coolingRate=1, - file_control=FileControlData(cleanup=False), + file_control=FileControlOptions(cleanup=False), ) params.write_ui_json(path=tmp_path / "Inv_run.ui.json") - driver = InducedPolarizationPseudo3DInversionDriver.start( - str(tmp_path / "Inv_run.ui.json") - ) + driver = IPBatch2DInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) basepath = workpath.parent with open(basepath / "lookup.json", encoding="utf8") as f: @@ -154,11 +154,11 @@ def test_ip_p3d_run( ) filedata = middle_inversion_group.get_entity("SimPEG.out")[0] - with driver.pseudo3d_params.out_group.workspace.open(mode="r+"): - filedata.copy(parent=driver.pseudo3d_params.out_group) + with driver.batch2d_params.out_group.workspace.open(mode="r+"): + filedata.copy(parent=driver.batch2d_params.out_group) output = get_inversion_output( - driver.pseudo3d_params.geoh5.h5file, driver.pseudo3d_params.out_group.uid + driver.batch2d_params.geoh5.h5file, driver.batch2d_params.out_group.uid ) if geoh5.open(): output["data"] = chargeability.values diff --git a/tests/run_tests/driver_ip_test.py b/tests/run_tests/driver_ip_test.py index 649f6bb7..e965e9ee 100644 --- a/tests/run_tests/driver_ip_test.py +++ b/tests/run_tests/driver_ip_test.py @@ -15,14 +15,14 @@ from geoh5py.workspace import Workspace from simpeg_drivers.electricals.induced_polarization.three_dimensions import ( - InducedPolarization3DForwardParams, - InducedPolarization3DInversionParams, + IP3DForwardOptions, + IP3DInversionOptions, ) from simpeg_drivers.electricals.induced_polarization.three_dimensions.driver import ( - InducedPolarization3DForwardDriver, - InducedPolarization3DInversionDriver, + IP3DForwardDriver, + IP3DInversionDriver, ) -from simpeg_drivers.params import ActiveCellsData +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -51,17 +51,17 @@ def test_ip_3d_fwr_run( inversion_type="dcip", flatten=False, ) - params = InducedPolarization3DForwardParams( + params = IP3DForwardOptions( geoh5=geoh5, mesh=model.parent, - active_cells=ActiveCellsData(topography_object=topography), + active_cells=ActiveCellsOptions(topography_object=topography), z_from_topo=True, data_object=survey, starting_model=model, conductivity_model=1e-2, ) - fwr_driver = InducedPolarization3DForwardDriver(params) + fwr_driver = IP3DForwardDriver(params) fwr_driver.run() @@ -81,10 +81,10 @@ def test_ip_3d_run( topography = geoh5.get_entity("topography")[0] # Run the inverse - params = InducedPolarization3DInversionParams( + params = IP3DInversionOptions( geoh5=geoh5, mesh=mesh, - active_cells=ActiveCellsData(topography_object=topography), + active_cells=ActiveCellsOptions(topography_object=topography), data_object=potential.parent, conductivity_model=1e-2, reference_model=1e-6, @@ -108,9 +108,7 @@ def test_ip_3d_run( ) params.write_ui_json(path=tmp_path / "Inv_run.ui.json") - driver = InducedPolarization3DInversionDriver.start( - str(tmp_path / "Inv_run.ui.json") - ) + driver = IP3DInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) output = get_inversion_output( driver.params.geoh5.h5file, driver.params.out_group.uid diff --git a/tests/run_tests/driver_joint_cross_gradient_test.py b/tests/run_tests/driver_joint_cross_gradient_test.py index fd6b1ae0..0c2d341c 100644 --- a/tests/run_tests/driver_joint_cross_gradient_test.py +++ b/tests/run_tests/driver_joint_cross_gradient_test.py @@ -16,29 +16,29 @@ from geoh5py.workspace import Workspace from simpeg_drivers.electricals.direct_current.three_dimensions import ( - DirectCurrent3DForwardParams, - DirectCurrent3DInversionParams, + DC3DForwardOptions, + DC3DInversionOptions, ) from simpeg_drivers.electricals.direct_current.three_dimensions.driver import ( - DirectCurrent3DForwardDriver, - DirectCurrent3DInversionDriver, + DC3DForwardDriver, + DC3DInversionDriver, ) from simpeg_drivers.joint.joint_cross_gradient import JointCrossGradientParams from simpeg_drivers.joint.joint_cross_gradient.driver import JointCrossGradientDriver -from simpeg_drivers.params import ActiveCellsData +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.potential_fields import ( - GravityForwardParams, - GravityInversionParams, - MagneticVectorForwardParams, - MagneticVectorInversionParams, + GravityForwardOptions, + GravityInversionOptions, + MVIForwardOptions, + MVIInversionOptions, ) from simpeg_drivers.potential_fields.gravity.driver import ( GravityForwardDriver, GravityInversionDriver, ) from simpeg_drivers.potential_fields.magnetic_vector.driver import ( - MagneticVectorForwardDriver, - MagneticVectorInversionDriver, + MVIForwardDriver, + MVIInversionDriver, ) from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -66,8 +66,8 @@ def test_joint_cross_gradient_fwr_run( n_electrodes=n_grid_points, n_lines=n_grid_points, ) - active_cells = ActiveCellsData(topography_object=topography) - params = GravityForwardParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = GravityForwardOptions( forward_only=True, geoh5=geoh5, mesh=model.parent, @@ -91,10 +91,10 @@ def test_joint_cross_gradient_fwr_run( flatten=False, ) inducing_field = (50000.0, 90.0, 0.0) - params = MagneticVectorForwardParams( + params = MVIForwardOptions( geoh5=geoh5, mesh=model.parent, - active_cells=ActiveCellsData(topography_object=topography), + active_cells=ActiveCellsOptions(topography_object=topography), inducing_field_strength=inducing_field[0], inducing_field_inclination=inducing_field[1], inducing_field_declination=inducing_field[2], @@ -104,7 +104,7 @@ def test_joint_cross_gradient_fwr_run( starting_model=model, ) # params.workpath = tmp_path - fwr_driver_b = MagneticVectorForwardDriver(params) + fwr_driver_b = MVIForwardDriver(params) _, _, model, survey, _ = setup_inversion_workspace( tmp_path, @@ -118,14 +118,14 @@ def test_joint_cross_gradient_fwr_run( inversion_type="dcip", flatten=False, ) - params = DirectCurrent3DForwardParams( + params = DC3DForwardOptions( geoh5=geoh5, mesh=model.parent, - active_cells=ActiveCellsData(topography_object=topography), + active_cells=ActiveCellsOptions(topography_object=topography), data_object=survey, starting_model=model, ) - fwr_driver_c = DirectCurrent3DForwardDriver(params) + fwr_driver_c = DC3DForwardDriver(params) fwr_driver_c.inversion_data.entity.name = "survey" # Force co-location of meshes @@ -182,8 +182,8 @@ def test_joint_cross_gradient_inv_run( if group.options["inversion_type"] == "gravity": data.values = data.values + np.random.randn(data.values.size) * 1e-2 - active_cells = ActiveCellsData(topography_object=topography) - params = GravityInversionParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = GravityInversionOptions( geoh5=geoh5, mesh=mesh, alpha_s=1.0, @@ -197,8 +197,8 @@ def test_joint_cross_gradient_inv_run( drivers.append(GravityInversionDriver(params)) elif group.options["inversion_type"] == "direct current 3d": data.values = data.values + np.random.randn(data.values.size) * 5e-4 - active_cells = ActiveCellsData(topography_object=topography) - params = DirectCurrent3DInversionParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = DC3DInversionOptions( geoh5=geoh5, mesh=mesh, alpha_s=1.0, @@ -212,14 +212,14 @@ def test_joint_cross_gradient_inv_run( reference_model=100.0, save_sensitivities=True, ) - drivers.append(DirectCurrent3DInversionDriver(params)) + drivers.append(DC3DInversionDriver(params)) else: data.values = data.values + np.random.randn(data.values.size) * 10.0 - params = MagneticVectorInversionParams( + params = MVIInversionOptions( geoh5=geoh5, mesh=mesh, alpha_s=1.0, - active_cells=ActiveCellsData(topography_object=topography), + active_cells=ActiveCellsOptions(topography_object=topography), inducing_field_strength=group.options["inducing_field_strength"][ "value" ], @@ -236,7 +236,7 @@ def test_joint_cross_gradient_inv_run( tmi_channel=data, tmi_uncertainty=1e1, ) - drivers.append(MagneticVectorInversionDriver(params)) + drivers.append(MVIInversionDriver(params)) # Run the inverse joint_params = JointCrossGradientParams( diff --git a/tests/run_tests/driver_joint_surveys_test.py b/tests/run_tests/driver_joint_surveys_test.py index 3e3035d8..ae95c4cb 100644 --- a/tests/run_tests/driver_joint_surveys_test.py +++ b/tests/run_tests/driver_joint_surveys_test.py @@ -16,8 +16,11 @@ from simpeg_drivers.joint.joint_surveys import JointSurveysParams from simpeg_drivers.joint.joint_surveys.driver import JointSurveyDriver -from simpeg_drivers.params import ActiveCellsData -from simpeg_drivers.potential_fields import GravityForwardParams, GravityInversionParams +from simpeg_drivers.params import ActiveCellsOptions +from simpeg_drivers.potential_fields import ( + GravityForwardOptions, + GravityInversionOptions, +) from simpeg_drivers.potential_fields.gravity.driver import GravityInversionDriver from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -43,8 +46,8 @@ def test_joint_surveys_fwr_run( n_electrodes=n_grid_points, n_lines=n_grid_points, ) - active_cells = ActiveCellsData(topography_object=topography) - params = GravityForwardParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = GravityForwardOptions( forward_only=True, geoh5=geoh5, mesh=model.parent, @@ -69,8 +72,8 @@ def test_joint_surveys_fwr_run( geoh5=geoh5, drape_height=10.0, ) - active_cells = ActiveCellsData(topography_object=topography) - params = GravityForwardParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = GravityForwardOptions( forward_only=True, geoh5=geoh5, mesh=model.parent, @@ -127,8 +130,8 @@ def test_joint_surveys_inv_run( active_model = mesh.get_entity("active_cells")[0] gz = survey.get_data("Iteration_0_gz")[0] orig_data.append(gz.values) - active_cells = ActiveCellsData(active_model=active_model) - params = GravityInversionParams( + active_cells = ActiveCellsOptions(active_model=active_model) + params = GravityInversionOptions( geoh5=geoh5, mesh=mesh, active_cells=active_cells, diff --git a/tests/run_tests/driver_mag_test.py b/tests/run_tests/driver_mag_test.py index f7e4477a..5427c52c 100644 --- a/tests/run_tests/driver_mag_test.py +++ b/tests/run_tests/driver_mag_test.py @@ -16,14 +16,14 @@ from dask.distributed import LocalCluster, performance_report from geoh5py.workspace import Workspace -from simpeg_drivers.params import ActiveCellsData +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.potential_fields import ( - MagneticScalarForwardParams, - MagneticScalarInversionParams, + MagneticForwardOptions, + MagneticInversionOptions, ) from simpeg_drivers.potential_fields.magnetic_scalar.driver import ( - MagneticScalarForwardDriver, - MagneticScalarInversionDriver, + MagneticForwardDriver, + MagneticInversionDriver, ) from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -51,8 +51,8 @@ def test_susceptibility_fwr_run( flatten=False, ) inducing_field = (49999.8, 90.0, 0.0) - active_cells = ActiveCellsData(topography_object=topography) - params = MagneticScalarForwardParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = MagneticForwardOptions( forward_only=True, geoh5=geoh5, mesh=model.parent, @@ -65,7 +65,7 @@ def test_susceptibility_fwr_run( starting_model=model, ) # params.workpath = tmp_path - fwr_driver = MagneticScalarForwardDriver(params) + fwr_driver = MagneticForwardDriver(params) fwr_driver.run() assert fwr_driver.inversion_data.survey.source_field.amplitude == inducing_field[0] @@ -93,8 +93,8 @@ def test_susceptibility_run( inducing_field = (50000.0, 90.0, 0.0) # Run the inverse - active_cells = ActiveCellsData(active_model=active_cells) - params = MagneticScalarInversionParams( + active_cells = ActiveCellsOptions(active_model=active_cells) + params = MagneticInversionOptions( geoh5=geoh5, mesh=mesh, active_cells=active_cells, @@ -119,7 +119,7 @@ def test_susceptibility_run( ) params.write_ui_json(path=tmp_path / "Inv_run.ui.json") - driver = MagneticScalarInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) + driver = MagneticInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) with Workspace(driver.params.geoh5.h5file) as run_ws: output = get_inversion_output( diff --git a/tests/run_tests/driver_mt_test.py b/tests/run_tests/driver_mt_test.py index a99501be..2626c4e9 100644 --- a/tests/run_tests/driver_mt_test.py +++ b/tests/run_tests/driver_mt_test.py @@ -19,11 +19,14 @@ from geoh5py.workspace import Workspace from simpeg_drivers.natural_sources.magnetotellurics.driver import ( - MagnetotelluricsDriver, + MTForwardDriver, + MTInversionDriver, ) from simpeg_drivers.natural_sources.magnetotellurics.params import ( - MagnetotelluricsParams, + MTForwardOptions, + MTInversionOptions, ) +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -53,15 +56,13 @@ def test_magnetotellurics_fwr_run( inversion_type="magnetotellurics", flatten=False, ) - params = MagnetotelluricsParams( - forward_only=True, + params = MTForwardOptions( geoh5=geoh5, - mesh=model.parent.uid, - topography_object=topography.uid, - resolution=0.0, + mesh=model.parent, + active_cells=ActiveCellsOptions(topography_object=topography), z_from_topo=False, - data_object=survey.uid, - starting_model=model.uid, + data_object=survey, + starting_model=model, background_conductivity=1e-2, zxx_real_channel_bool=True, zxx_imag_channel_bool=True, @@ -72,8 +73,8 @@ def test_magnetotellurics_fwr_run( zyy_real_channel_bool=True, zyy_imag_channel_bool=True, ) - params.workpath = tmp_path - fwr_driver = MagnetotelluricsDriver(params) + + fwr_driver = MTForwardDriver(params) fwr_driver.run() @@ -138,18 +139,17 @@ def test_magnetotellurics_run(tmp_path: Path, max_iterations=1, pytest=True): for comp, data_group, uncert_group in zip( components, data_groups, uncert_groups, strict=True ): - data_kwargs[f"{comp}_channel"] = data_group.uid - data_kwargs[f"{comp}_uncertainty"] = uncert_group.uid + data_kwargs[f"{comp}_channel"] = data_group + data_kwargs[f"{comp}_uncertainty"] = uncert_group orig_zyy_real_1 = geoh5.get_entity("Iteration_0_zyy_real_[0]")[0].values # Run the inverse - params = MagnetotelluricsParams( + params = MTInversionOptions( geoh5=geoh5, - mesh=mesh.uid, - topography_object=topography.uid, - resolution=0.0, - data_object=survey.uid, + mesh=mesh, + active_cells=ActiveCellsOptions(topography_object=topography), + data_object=survey, starting_model=100.0, reference_model=100.0, alpha_s=1.0, @@ -165,12 +165,13 @@ def test_magnetotellurics_run(tmp_path: Path, max_iterations=1, pytest=True): background_conductivity=100.0, max_global_iterations=max_iterations, initial_beta_ratio=1e3, + sens_wts_threshold=1.0, prctile=100, store_sensitivities="ram", **data_kwargs, ) - params.write_input_file(path=tmp_path, name="Inv_run") - driver = MagnetotelluricsDriver.start(str(tmp_path / "Inv_run.ui.json")) + params.write_ui_json(path=tmp_path / "Inv_run.ui.json") + driver = MTInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) with geoh5.open() as run_ws: output = get_inversion_output( @@ -186,18 +187,18 @@ def test_magnetotellurics_run(tmp_path: Path, max_iterations=1, pytest=True): # test that one channel works data_kwargs = {k: v for k, v in data_kwargs.items() if "zxx_real" in k} geoh5.open() - params = MagnetotelluricsParams( + params = MTInversionOptions( geoh5=geoh5, - mesh=geoh5.get_entity("mesh")[0].uid, - topography_object=topography.uid, - data_object=survey.uid, + mesh=geoh5.get_entity("mesh")[0], + active_cells=ActiveCellsOptions(topography_object=topography), + data_object=survey, starting_model=0.01, - conductivity_model=1e-2, + background_conductivity=1e-2, max_global_iterations=0, **data_kwargs, ) - params.write_input_file(path=tmp_path, name="Inv_run") - MagnetotelluricsDriver.start(str(tmp_path / "Inv_run.ui.json")) + params.write_ui_json(path=tmp_path / "Inv_run.ui.json") + MTInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) if __name__ == "__main__": diff --git a/tests/run_tests/driver_mvi_test.py b/tests/run_tests/driver_mvi_test.py index 4d991ad8..9bb3d646 100644 --- a/tests/run_tests/driver_mvi_test.py +++ b/tests/run_tests/driver_mvi_test.py @@ -17,14 +17,14 @@ from geoh5py.objects import Curve from geoh5py.workspace import Workspace -from simpeg_drivers.params import ActiveCellsData +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.potential_fields import ( - MagneticVectorForwardParams, - MagneticVectorInversionParams, + MVIForwardOptions, + MVIInversionOptions, ) from simpeg_drivers.potential_fields.magnetic_vector.driver import ( - MagneticVectorForwardDriver, - MagneticVectorInversionDriver, + MVIForwardDriver, + MVIInversionDriver, ) from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -59,8 +59,8 @@ def test_magnetic_vector_fwr_run( survey = Curve.create(geoh5, name=points.name, vertices=points.vertices) geoh5.remove_entity(points) inducing_field = (50000.0, 90.0, 0.0) - active_cells = ActiveCellsData(topography_object=topography) - params = MagneticVectorForwardParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = MVIForwardOptions( forward_only=True, geoh5=geoh5, mesh=model.parent, @@ -75,7 +75,7 @@ def test_magnetic_vector_fwr_run( starting_inclination=45, starting_declination=270, ) - fwr_driver = MagneticVectorForwardDriver(params) + fwr_driver = MVIForwardDriver(params) fwr_driver.run() @@ -100,8 +100,8 @@ def test_magnetic_vector_run( inducing_field = (50000.0, 90.0, 0.0) # Run the inverse - active_cells = ActiveCellsData(topography_object=topography) - params = MagneticVectorInversionParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = MVIInversionOptions( geoh5=geoh5, mesh=mesh, active_cells=active_cells, @@ -128,7 +128,7 @@ def test_magnetic_vector_run( ) params.write_ui_json(path=tmp_path / "Inv_run.ui.json") - driver = MagneticVectorInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) + driver = MVIInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) with Workspace(driver.params.geoh5.h5file) as run_ws: # Re-open the workspace and get iterations diff --git a/tests/run_tests/driver_tile_estimator_test.py b/tests/run_tests/driver_tile_estimator_test.py index 3102f5c2..5b4d10a3 100644 --- a/tests/run_tests/driver_tile_estimator_test.py +++ b/tests/run_tests/driver_tile_estimator_test.py @@ -14,10 +14,10 @@ import numpy as np -from simpeg_drivers.params import ActiveCellsData -from simpeg_drivers.potential_fields import MagneticScalarInversionParams +from simpeg_drivers.params import ActiveCellsOptions +from simpeg_drivers.potential_fields import MagneticInversionOptions from simpeg_drivers.potential_fields.magnetic_scalar.driver import ( - MagneticScalarInversionDriver, + MagneticInversionDriver, ) from simpeg_drivers.utils.testing import setup_inversion_workspace from simpeg_drivers.utils.tile_estimate import TileEstimator, TileParameters @@ -45,10 +45,10 @@ def test_tile_estimator_run( "tmi": {"values": np.random.rand(survey.n_vertices)}, } ) - params = MagneticScalarInversionParams( + params = MagneticInversionOptions( geoh5=geoh5, mesh=model.parent, - active_cells=ActiveCellsData(topography_object=topography), + active_cells=ActiveCellsOptions(topography_object=topography), inducing_field_strength=inducing_field[0], inducing_field_inclination=inducing_field[1], inducing_field_declination=inducing_field[2], @@ -58,7 +58,7 @@ def test_tile_estimator_run( starting_model=model, ) - driver = MagneticScalarInversionDriver(params) + driver = MagneticInversionDriver(params) tile_params = TileParameters(geoh5=geoh5, simulation=driver.out_group) estimator = TileEstimator(tile_params) diff --git a/tests/run_tests/driver_tipper_test.py b/tests/run_tests/driver_tipper_test.py index 7812ed57..ef96df87 100644 --- a/tests/run_tests/driver_tipper_test.py +++ b/tests/run_tests/driver_tipper_test.py @@ -16,8 +16,15 @@ from geoh5py.groups import SimPEGGroup from geoh5py.workspace import Workspace -from simpeg_drivers.natural_sources import TipperParams -from simpeg_drivers.natural_sources.tipper.driver import TipperDriver +from simpeg_drivers.natural_sources.tipper import ( + TipperForwardOptions, + TipperInversionOptions, +) +from simpeg_drivers.natural_sources.tipper.driver import ( + TipperForwardDriver, + TipperInversionDriver, +) +from simpeg_drivers.params import ActiveCellsOptions from simpeg_drivers.utils.testing import check_target, setup_inversion_workspace from simpeg_drivers.utils.utils import get_inversion_output @@ -48,15 +55,13 @@ def test_tipper_fwr_run( flatten=False, ) - params = TipperParams( - forward_only=True, + params = TipperForwardOptions( geoh5=geoh5, - mesh=model.parent.uid, - topography_object=topography.uid, - resolution=0.0, + mesh=model.parent, + active_cells=ActiveCellsOptions(topography_object=topography), z_from_topo=False, - data_object=survey.uid, - starting_model=model.uid, + data_object=survey, + starting_model=model, model_type="Resistivity (Ohm-m)", background_conductivity=1e2, txz_real_channel_bool=True, @@ -64,8 +69,8 @@ def test_tipper_fwr_run( tyz_real_channel_bool=True, tyz_imag_channel_bool=True, ) - params.workpath = tmp_path - fwr_driver = TipperDriver(params) + + fwr_driver = TipperForwardDriver(params) # Should always be returning conductivity for simpeg simulations assert not np.any(np.exp(fwr_driver.models.starting) > 1.01) @@ -121,18 +126,17 @@ def test_tipper_run(tmp_path: Path, max_iterations=1, pytest=True): for comp, data_group, uncert_group in zip( components, data_groups, uncert_groups, strict=True ): - data_kwargs[f"{comp}_channel"] = data_group.uid - data_kwargs[f"{comp}_uncertainty"] = uncert_group.uid + data_kwargs[f"{comp}_channel"] = data_group + data_kwargs[f"{comp}_uncertainty"] = uncert_group orig_tyz_real_1 = geoh5.get_entity("Iteration_0_tyz_real_[0]")[0].values # Run the inverse - params = TipperParams( + params = TipperInversionOptions( geoh5=geoh5, - mesh=mesh.uid, - topography_object=topography.uid, - resolution=0.0, - data_object=survey.uid, + mesh=mesh, + active_cells=ActiveCellsOptions(topography_object=topography), + data_object=survey, starting_model=1e2, reference_model=1e2, background_conductivity=1e2, @@ -155,8 +159,8 @@ def test_tipper_run(tmp_path: Path, max_iterations=1, pytest=True): store_sensitivities="ram", **data_kwargs, ) - params.write_input_file(path=tmp_path, name="Inv_run") - driver = TipperDriver.start(str(tmp_path / "Inv_run.ui.json")) + params.write_ui_json(path=tmp_path / "Inv_run.ui.json") + driver = TipperInversionDriver.start(str(tmp_path / "Inv_run.ui.json")) with geoh5.open() as run_ws: output = get_inversion_output( diff --git a/tests/run_tests/sensitivity_cutoff_test.py b/tests/run_tests/sensitivity_cutoff_test.py index 4a3fd754..f94ac8ca 100644 --- a/tests/run_tests/sensitivity_cutoff_test.py +++ b/tests/run_tests/sensitivity_cutoff_test.py @@ -21,8 +21,8 @@ from simpeg_drivers.depth_of_investigation.sensitivity_cutoff.params import ( SensitivityCutoffParams, ) -from simpeg_drivers.params import ActiveCellsData -from simpeg_drivers.potential_fields import GravityInversionParams +from simpeg_drivers.params import ActiveCellsOptions +from simpeg_drivers.potential_fields import GravityInversionOptions from simpeg_drivers.potential_fields.gravity.driver import GravityInversionDriver from simpeg_drivers.utils.testing import setup_inversion_workspace @@ -44,8 +44,8 @@ def setup_inversion_results( # Run the inverse with save_sensitivities=True gz = survey.add_data({"gz": {"values": np.random.randn(len(survey.vertices))}}) - active_cells = ActiveCellsData(topography_object=topography) - params = GravityInversionParams( + active_cells = ActiveCellsOptions(topography_object=topography) + params = GravityInversionOptions( geoh5=geoh5, mesh=mesh, active_cells=active_cells, diff --git a/tests/topography_test.py b/tests/topography_test.py index 1080964b..f25202a7 100644 --- a/tests/topography_test.py +++ b/tests/topography_test.py @@ -15,8 +15,8 @@ import numpy as np from simpeg_drivers.components import InversionTopography -from simpeg_drivers.params import ActiveCellsData -from simpeg_drivers.potential_fields import MagneticVectorInversionParams +from simpeg_drivers.params import ActiveCellsOptions +from simpeg_drivers.potential_fields import MVIInversionOptions from simpeg_drivers.utils.testing import Geoh5Tester, setup_inversion_workspace @@ -40,12 +40,12 @@ def test_get_locations(tmp_path: Path): elevation = topography.add_data( {"elevation": {"values": topography.vertices[:, 2]}} ) - params = MagneticVectorInversionParams( + params = MVIInversionOptions( geoh5=geoh5, mesh=mesh, data_object=survey, tmi_channel=tmi_channel, - active_cells=ActiveCellsData( + active_cells=ActiveCellsOptions( topography_object=topography, topography=elevation ), starting_model=1.0,