diff --git a/simpeg_drivers-assets/uijson/apparent_conductivity_forward.ui.json b/simpeg_drivers-assets/uijson/apparent_conductivity_forward.ui.json index 0007c916..b22c6220 100644 --- a/simpeg_drivers-assets/uijson/apparent_conductivity_forward.ui.json +++ b/simpeg_drivers-assets/uijson/apparent_conductivity_forward.ui.json @@ -129,9 +129,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/apparent_conductivity_inversion.ui.json b/simpeg_drivers-assets/uijson/apparent_conductivity_inversion.ui.json index 9bb5f5fe..442635e7 100644 --- a/simpeg_drivers-assets/uijson/apparent_conductivity_inversion.ui.json +++ b/simpeg_drivers-assets/uijson/apparent_conductivity_inversion.ui.json @@ -514,9 +514,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/direct_current_3d_forward.ui.json b/simpeg_drivers-assets/uijson/direct_current_3d_forward.ui.json index ce8f6673..d665b31d 100644 --- a/simpeg_drivers-assets/uijson/direct_current_3d_forward.ui.json +++ b/simpeg_drivers-assets/uijson/direct_current_3d_forward.ui.json @@ -123,9 +123,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/direct_current_3d_inversion.ui.json b/simpeg_drivers-assets/uijson/direct_current_3d_inversion.ui.json index b6c83cfd..e70dcb90 100644 --- a/simpeg_drivers-assets/uijson/direct_current_3d_inversion.ui.json +++ b/simpeg_drivers-assets/uijson/direct_current_3d_inversion.ui.json @@ -499,9 +499,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/fdem1d_forward.ui.json b/simpeg_drivers-assets/uijson/fdem1d_forward.ui.json index 11512518..e769de08 100644 --- a/simpeg_drivers-assets/uijson/fdem1d_forward.ui.json +++ b/simpeg_drivers-assets/uijson/fdem1d_forward.ui.json @@ -178,9 +178,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/fdem1d_inversion.ui.json b/simpeg_drivers-assets/uijson/fdem1d_inversion.ui.json index 88f68149..4189adfc 100644 --- a/simpeg_drivers-assets/uijson/fdem1d_inversion.ui.json +++ b/simpeg_drivers-assets/uijson/fdem1d_inversion.ui.json @@ -538,9 +538,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/fdem_forward.ui.json b/simpeg_drivers-assets/uijson/fdem_forward.ui.json index a60b92c8..7bfc2251 100644 --- a/simpeg_drivers-assets/uijson/fdem_forward.ui.json +++ b/simpeg_drivers-assets/uijson/fdem_forward.ui.json @@ -188,9 +188,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/fdem_inversion.ui.json b/simpeg_drivers-assets/uijson/fdem_inversion.ui.json index ca2cdc3f..b6c9ba17 100644 --- a/simpeg_drivers-assets/uijson/fdem_inversion.ui.json +++ b/simpeg_drivers-assets/uijson/fdem_inversion.ui.json @@ -697,9 +697,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/gravity_forward.ui.json b/simpeg_drivers-assets/uijson/gravity_forward.ui.json index b844d141..6b27f175 100644 --- a/simpeg_drivers-assets/uijson/gravity_forward.ui.json +++ b/simpeg_drivers-assets/uijson/gravity_forward.ui.json @@ -170,9 +170,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/gravity_inversion.ui.json b/simpeg_drivers-assets/uijson/gravity_inversion.ui.json index 8993ad5a..a5b1c119 100644 --- a/simpeg_drivers-assets/uijson/gravity_inversion.ui.json +++ b/simpeg_drivers-assets/uijson/gravity_inversion.ui.json @@ -16,7 +16,9 @@ "{6a057fdc-b355-11e3-95be-fd84a7ffcb88}", "{f26feba3-aded-494b-b9e9-b2bbcbe298e1}", "{48f5054a-1c5c-4ca4-9048-80f36dc60a06}", - "{b020a277-90e2-4cd7-84d6-612ee3f25051}" + "{b020a277-90e2-4cd7-84d6-612ee3f25051}", + "{b54f6be6-0eb5-4a4e-887a-ba9d276f9a83}", + "{5ffa3816-358d-4cdd-9b7d-e1f7f5543e05}" ], "value": "" }, @@ -758,14 +760,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", - "dataType": "Float", - "association": [ - "Vertex", - "Cell" - ], "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/induced_polarization_2d_inversion.ui.json b/simpeg_drivers-assets/uijson/induced_polarization_2d_inversion.ui.json index e8624d25..2e3ab944 100644 --- a/simpeg_drivers-assets/uijson/induced_polarization_2d_inversion.ui.json +++ b/simpeg_drivers-assets/uijson/induced_polarization_2d_inversion.ui.json @@ -537,7 +537,16 @@ "tooltip": "Direct solver to use for the forward calculations", "value": "Pardiso" }, - "tile_spatial": 1, + "tile_spatial": { + "group": "Compute", + "label": "Number of tiles", + "value": 1, + "min": 1, + "max": 1000, + "verbose": 2, + "visible": false, + "tooltip": "Splits the objective function into spatial tiles for distributed computation using the Dask library" + }, "store_sensitivities": { "choiceList": [ "disk", diff --git a/simpeg_drivers-assets/uijson/induced_polarization_3d_forward.ui.json b/simpeg_drivers-assets/uijson/induced_polarization_3d_forward.ui.json index d4da081f..0a5c387c 100644 --- a/simpeg_drivers-assets/uijson/induced_polarization_3d_forward.ui.json +++ b/simpeg_drivers-assets/uijson/induced_polarization_3d_forward.ui.json @@ -139,9 +139,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/induced_polarization_3d_inversion.ui.json b/simpeg_drivers-assets/uijson/induced_polarization_3d_inversion.ui.json index 1b337393..98f24f36 100644 --- a/simpeg_drivers-assets/uijson/induced_polarization_3d_inversion.ui.json +++ b/simpeg_drivers-assets/uijson/induced_polarization_3d_inversion.ui.json @@ -515,9 +515,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/magnetic_scalar_forward.ui.json b/simpeg_drivers-assets/uijson/magnetic_scalar_forward.ui.json index c4b5d03b..f480bae4 100644 --- a/simpeg_drivers-assets/uijson/magnetic_scalar_forward.ui.json +++ b/simpeg_drivers-assets/uijson/magnetic_scalar_forward.ui.json @@ -200,9 +200,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/magnetic_scalar_inversion.ui.json b/simpeg_drivers-assets/uijson/magnetic_scalar_inversion.ui.json index d3013771..2bd033de 100644 --- a/simpeg_drivers-assets/uijson/magnetic_scalar_inversion.ui.json +++ b/simpeg_drivers-assets/uijson/magnetic_scalar_inversion.ui.json @@ -791,9 +791,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/magnetic_vector_forward.ui.json b/simpeg_drivers-assets/uijson/magnetic_vector_forward.ui.json index 0020bbdc..f5950069 100644 --- a/simpeg_drivers-assets/uijson/magnetic_vector_forward.ui.json +++ b/simpeg_drivers-assets/uijson/magnetic_vector_forward.ui.json @@ -46,7 +46,9 @@ "{6a057fdc-b355-11e3-95be-fd84a7ffcb88}", "{f26feba3-aded-494b-b9e9-b2bbcbe298e1}", "{48f5054a-1c5c-4ca4-9048-80f36dc60a06}", - "{b020a277-90e2-4cd7-84d6-612ee3f25051}" + "{b020a277-90e2-4cd7-84d6-612ee3f25051}", + "{4b99204c-d133-4579-a916-a9c8b98cfccb}", + "{028e4905-cc97-4dab-b1bf-d76f58b501b5}" ], "value": "", "optional": true, @@ -98,8 +100,7 @@ "{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}" + "{4b99204c-d133-4579-a916-a9c8b98cfccb}" ], "value": "" }, @@ -232,9 +233,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/magnetic_vector_inversion.ui.json b/simpeg_drivers-assets/uijson/magnetic_vector_inversion.ui.json index 891be062..ea9cad09 100644 --- a/simpeg_drivers-assets/uijson/magnetic_vector_inversion.ui.json +++ b/simpeg_drivers-assets/uijson/magnetic_vector_inversion.ui.json @@ -839,9 +839,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/magnetic_vector_pde_forward.ui.json b/simpeg_drivers-assets/uijson/magnetic_vector_pde_forward.ui.json index 1405802b..d7d10023 100644 --- a/simpeg_drivers-assets/uijson/magnetic_vector_pde_forward.ui.json +++ b/simpeg_drivers-assets/uijson/magnetic_vector_pde_forward.ui.json @@ -46,7 +46,8 @@ "{6a057fdc-b355-11e3-95be-fd84a7ffcb88}", "{f26feba3-aded-494b-b9e9-b2bbcbe298e1}", "{48f5054a-1c5c-4ca4-9048-80f36dc60a06}", - "{b020a277-90e2-4cd7-84d6-612ee3f25051}" + "{b020a277-90e2-4cd7-84d6-612ee3f25051}", + "{028e4905-cc97-4dab-b1bf-d76f58b501b5}" ], "value": "", "optional": true, @@ -98,8 +99,7 @@ "{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}" + "{4b99204c-d133-4579-a916-a9c8b98cfccb}" ], "value": "" }, @@ -196,13 +196,11 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, "verbose": 2, + "visible": false, "tooltip": "Splits the objective function into spatial tiles for distributed computation using the Dask library" }, "max_chunk_size": { diff --git a/simpeg_drivers-assets/uijson/magnetic_vector_pde_inversion.ui.json b/simpeg_drivers-assets/uijson/magnetic_vector_pde_inversion.ui.json index 8ef6fbb8..a8cabc48 100644 --- a/simpeg_drivers-assets/uijson/magnetic_vector_pde_inversion.ui.json +++ b/simpeg_drivers-assets/uijson/magnetic_vector_pde_inversion.ui.json @@ -627,13 +627,11 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, "verbose": 2, + "visible": false, "tooltip": "Splits the objective function into spatial tiles for distributed computation using the Dask library" }, "out_group": { diff --git a/simpeg_drivers-assets/uijson/magnetotellurics_forward.ui.json b/simpeg_drivers-assets/uijson/magnetotellurics_forward.ui.json index 2790747c..4fe8895e 100644 --- a/simpeg_drivers-assets/uijson/magnetotellurics_forward.ui.json +++ b/simpeg_drivers-assets/uijson/magnetotellurics_forward.ui.json @@ -177,9 +177,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/magnetotellurics_inversion.ui.json b/simpeg_drivers-assets/uijson/magnetotellurics_inversion.ui.json index 72a4df81..4c16a597 100644 --- a/simpeg_drivers-assets/uijson/magnetotellurics_inversion.ui.json +++ b/simpeg_drivers-assets/uijson/magnetotellurics_inversion.ui.json @@ -728,9 +728,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/plate_sweep.ui.json b/simpeg_drivers-assets/uijson/plate_sweep.ui.json index ffe4c361..6673d41e 100644 --- a/simpeg_drivers-assets/uijson/plate_sweep.ui.json +++ b/simpeg_drivers-assets/uijson/plate_sweep.ui.json @@ -23,10 +23,9 @@ "main": true, "group": "Base", "label": "Output directory", - "directoryOnly": true, "enabled": false, "optional": true, - "tootip": "Directory to store simulation results, relative to the working geoh5.", + "tooltip": "Directory to store simulation results, relative to the working geoh5.", "value": "./simulations" }, "generate_summary": { @@ -34,7 +33,7 @@ "group": "Base", "label": "Generate summary file (.xlsx)", "enabled": true, - "tootip": "Create an xlsx file summarizing the parameters of all simulations found in the 'Output directory'.", + "tooltip": "Create an xlsx file summarizing the parameters of all simulations found in the 'Output directory'.", "value": true }, "background_start": { diff --git a/simpeg_drivers-assets/uijson/tdem1d_forward.ui.json b/simpeg_drivers-assets/uijson/tdem1d_forward.ui.json index a030eec2..c90c5e6d 100644 --- a/simpeg_drivers-assets/uijson/tdem1d_forward.ui.json +++ b/simpeg_drivers-assets/uijson/tdem1d_forward.ui.json @@ -34,7 +34,7 @@ "
Wire
Current * number of turns (NI).
", "" ], - "value": "dB/dt (T/s)" + "value": "Airborne dB/dt (V/Am^4)" }, "z_channel_bool": { "group": "Survey", @@ -192,9 +192,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/tdem1d_inversion.ui.json b/simpeg_drivers-assets/uijson/tdem1d_inversion.ui.json index 53ade0fd..694e9c6b 100644 --- a/simpeg_drivers-assets/uijson/tdem1d_inversion.ui.json +++ b/simpeg_drivers-assets/uijson/tdem1d_inversion.ui.json @@ -34,7 +34,7 @@ "
Wire
Current * number of turns (NI).
", "" ], - "value": "dB/dt (T/s)" + "value": "Airborne dB/dt (V/Am^4)" }, "z_channel": { "association": [ @@ -520,9 +520,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/tdem_forward.ui.json b/simpeg_drivers-assets/uijson/tdem_forward.ui.json index 5b85136e..dbc2d85f 100644 --- a/simpeg_drivers-assets/uijson/tdem_forward.ui.json +++ b/simpeg_drivers-assets/uijson/tdem_forward.ui.json @@ -56,7 +56,7 @@ "
Wire
Current * number of turns (NI).
", "" ], - "value": "dB/dt (T/s)" + "value": "Airborne dB/dt (V/Am^4)" }, "vertical_channel_bool": { "group": "Survey", @@ -187,9 +187,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/tdem_inversion.ui.json b/simpeg_drivers-assets/uijson/tdem_inversion.ui.json index 10d4fc85..340a04d3 100644 --- a/simpeg_drivers-assets/uijson/tdem_inversion.ui.json +++ b/simpeg_drivers-assets/uijson/tdem_inversion.ui.json @@ -56,7 +56,7 @@ "
Wire
Current * number of turns (NI).
", "" ], - "value": "dB/dt (T/s)" + "value": "Airborne dB/dt (V/Am^4)" }, "vertical_channel": { "association": [ @@ -604,9 +604,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/tipper_forward.ui.json b/simpeg_drivers-assets/uijson/tipper_forward.ui.json index 7794a830..76d5d7c0 100644 --- a/simpeg_drivers-assets/uijson/tipper_forward.ui.json +++ b/simpeg_drivers-assets/uijson/tipper_forward.ui.json @@ -153,9 +153,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers-assets/uijson/tipper_inversion.ui.json b/simpeg_drivers-assets/uijson/tipper_inversion.ui.json index 7e9c8be4..d0d22783 100644 --- a/simpeg_drivers-assets/uijson/tipper_inversion.ui.json +++ b/simpeg_drivers-assets/uijson/tipper_inversion.ui.json @@ -608,9 +608,6 @@ "tile_spatial": { "group": "Compute", "label": "Number of tiles", - "parent": "data_object", - "isValue": true, - "property": "", "value": 1, "min": 1, "max": 1000, diff --git a/simpeg_drivers/depth_of_investigation/sensitivity_cutoff/options.py b/simpeg_drivers/depth_of_investigation/sensitivity_cutoff/options.py index a284eb41..f70cec3e 100644 --- a/simpeg_drivers/depth_of_investigation/sensitivity_cutoff/options.py +++ b/simpeg_drivers/depth_of_investigation/sensitivity_cutoff/options.py @@ -37,6 +37,7 @@ class SensitivityCutoffOptions(Options): ) title: str = "Depth of Investigation: Sensitivity Cutoff" + icon: str = "grd" run_command: str = "simpeg_drivers.depth_of_investigation.sensitivity_cutoff.driver" conda_environment: str = "simpeg_drivers" diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 91e3df00..4fb1b058 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -14,7 +14,7 @@ from __future__ import annotations from abc import abstractmethod, ABC - +from typing import Self from copy import deepcopy import sys from datetime import datetime, timedelta @@ -29,9 +29,11 @@ from geoapps_utils.run import load_ui_json_as_dict from geoapps_utils.utils.importing import GeoAppsError +from geoh5py import Workspace from geoh5py.groups import SimPEGGroup from geoh5py.objects import FEMSurvey from geoh5py.shared.utils import fetch_active_workspace +from geoh5py.ui_json import BaseUIJson from simpeg import ( directives, @@ -68,6 +70,7 @@ BaseInversionOptions, ) from simpeg_drivers.joint.options import BaseJointOptions +from simpeg_drivers.uijson import SimPEGDriversUIJson from simpeg_drivers.utils.nested import tile_locations from simpeg_drivers.utils.regularization import cell_neighbors, set_rotated_operators from simpeg_drivers.utils.utils import ( @@ -489,6 +492,46 @@ def run(self): with fetch_active_workspace(self.workspace, mode="r+"): self.directives.save_iteration_log_files.write(1) + @classmethod + def start(cls, filepath: str | Path | BaseUIJson, mode="r+", **kwargs) -> Self: + """ + Run application specified by 'filepath' ui.json file. + + TODO: To be replaced by the base Driver class implementation on geoapps_utils + :param filepath: Path to valid ui.json file for the application driver. + :param mode: Mode to open the geoh5 file with. + :param kwargs: Additional keyword arguments for Options class. + + :return: Self object. + """ + + uijson = ( + SimPEGDriversUIJson.read(filepath) + if isinstance(filepath, str | Path) + else filepath + ) + + if not isinstance(uijson, BaseUIJson): + raise TypeError("Input file must be a string path or a BaseUIJson object.") + + if uijson.geoh5 is None: + raise GeoAppsError("The application needs a valid 'geoh5' file.") + + with Workspace(uijson.geoh5, mode=mode) as workspace: + try: + data = uijson.to_params(workspace) + kwargs.update(data) + params = cls._params_class.build(workspace=workspace, **kwargs) + driver = cls(params) + driver.run() + except GeoAppsError as error: + logging.getLogger(__name__).warning( + "\n\nApplicationError: %s\n\n", error + ) + sys.exit(1) + + return driver + @classmethod def start_dask_run( cls, json_path: Path, n_workers: int | None = None, n_threads: int | None = None diff --git a/simpeg_drivers/electricals/base_2d.py b/simpeg_drivers/electricals/base_2d.py index 3f0cf079..b5a4553b 100644 --- a/simpeg_drivers/electricals/base_2d.py +++ b/simpeg_drivers/electricals/base_2d.py @@ -14,9 +14,10 @@ from logging import getLogger import numpy as np +from geoh5py.data import FloatData from geoh5py.objects import DrapeModel, Octree, PotentialElectrode from geoh5py.ui_json.ui_json import fetch_active_workspace -from pydantic import field_validator, model_validator +from pydantic import AliasChoices, Field, field_validator, model_validator from simpeg_drivers.components.meshes import InversionMesh from simpeg_drivers.driver import BaseDriver @@ -24,6 +25,8 @@ CoreOptions, DrapeModelOptions, LineSelectionOptions, + ModelOptions, + ModelTypeEnum, ) from simpeg_drivers.utils.surveys import ( create_mesh_by_line_id, @@ -34,6 +37,26 @@ logger = getLogger(__name__) +class Conductivity2DModelOptions(ModelOptions): + """ + Options for the conductivity model of 2D inverse problems. + + :param conductivity_model: Conductivity model or background conductivity value. + :param model_type: Either a 'conductivity' or 'resistivity' model. The default is 'conductivity'. + :param length_scale_y: Overloads length scales in y direction since not used in 2D inversions. + :param y_norm: Overloads norm in the y direction since not used in 2D inversions. + """ + + model_type: ModelTypeEnum = ModelTypeEnum.conductivity + conductivity_model: float | FloatData | None = Field( + None, + validation_alias=AliasChoices("background_conductivity", "conductivity_model"), + ) + + length_scale_y: None = None + y_norm: None = None + + class Base2DOptions(CoreOptions): """ Base options for the Direct Current 2D forward and inverse driver. diff --git a/simpeg_drivers/electricals/direct_current/three_dimensions/options.py b/simpeg_drivers/electricals/direct_current/three_dimensions/options.py index 728fa663..259a4260 100644 --- a/simpeg_drivers/electricals/direct_current/three_dimensions/options.py +++ b/simpeg_drivers/electricals/direct_current/three_dimensions/options.py @@ -40,6 +40,7 @@ class DC3DForwardOptions(BaseForwardOptions): "simpeg_drivers.electricals.direct_current.three_dimensions.forward" ) title: str = "Direct Current 3D Forward" + icon: str = "PotentialElectrode" physical_property: str = "conductivity" inversion_type: str = "direct current 3d" @@ -64,6 +65,7 @@ class DC3DInversionOptions(BaseInversionOptions): "simpeg_drivers.electricals.direct_current.three_dimensions.inversion" ) title: str = "Direct Current 3D Inversion" + icon: str = "PotentialElectrode" physical_property: str = "conductivity" inversion_type: str = "direct current 3d" diff --git a/simpeg_drivers/electricals/direct_current/two_dimensions/options.py b/simpeg_drivers/electricals/direct_current/two_dimensions/options.py index d60b882a..5c2cf09c 100644 --- a/simpeg_drivers/electricals/direct_current/two_dimensions/options.py +++ b/simpeg_drivers/electricals/direct_current/two_dimensions/options.py @@ -17,12 +17,8 @@ from geoh5py.data import FloatData from simpeg_drivers import assets_path -from simpeg_drivers.electricals.base_2d import Base2DOptions -from simpeg_drivers.options import ( - BaseForwardOptions, - BaseInversionOptions, - ConductivityModelOptions, -) +from simpeg_drivers.electricals.base_2d import Base2DOptions, Conductivity2DModelOptions +from simpeg_drivers.options import BaseForwardOptions, BaseInversionOptions class DC2DForwardOptions(BaseForwardOptions, Base2DOptions): @@ -38,11 +34,12 @@ class DC2DForwardOptions(BaseForwardOptions, Base2DOptions): ) title: str = "Direct Current 2D Forward" + icon: str = "PotentialElectrode" physical_property: str = "conductivity" inversion_type: str = "direct current 2d" potential_channel_bool: bool = True - models: ConductivityModelOptions + models: Conductivity2DModelOptions class DC2DInversionOptions(BaseInversionOptions, Base2DOptions): @@ -59,11 +56,11 @@ class DC2DInversionOptions(BaseInversionOptions, Base2DOptions): default_ui_json: ClassVar[Path] = ( assets_path() / "uijson/direct_current_2d_inversion.ui.json" ) - + icon: str = "PotentialElectrode" title: str = "Direct Current 2D Inversion" physical_property: str = "conductivity" inversion_type: str = "direct current 2d" potential_channel: FloatData potential_uncertainty: float | FloatData | None = None - models: ConductivityModelOptions + models: Conductivity2DModelOptions diff --git a/simpeg_drivers/electricals/induced_polarization/three_dimensions/options.py b/simpeg_drivers/electricals/induced_polarization/three_dimensions/options.py index 780e256a..b9449a5d 100644 --- a/simpeg_drivers/electricals/induced_polarization/three_dimensions/options.py +++ b/simpeg_drivers/electricals/induced_polarization/three_dimensions/options.py @@ -36,8 +36,8 @@ class IP3DForwardOptions(BaseForwardOptions): default_ui_json: ClassVar[Path] = ( assets_path() / "uijson/induced_polarization_3d_forward.ui.json" ) - title: str = "Induced Polarization 3D Forward" + icon: str = "PotentialElectrode" physical_property: str = "chargeability" inversion_type: str = "induced polarization 3d" @@ -58,8 +58,8 @@ class IP3DInversionOptions(BaseInversionOptions): default_ui_json: ClassVar[Path] = ( assets_path() / "uijson/induced_polarization_3d_inversion.ui.json" ) - title: str = "Induced Polarization 3D Inversion" + icon: str = "PotentialElectrode" physical_property: str = "chargeability" inversion_type: str = "induced polarization 3d" diff --git a/simpeg_drivers/electricals/induced_polarization/two_dimensions/options.py b/simpeg_drivers/electricals/induced_polarization/two_dimensions/options.py index b92fcfcd..444caafe 100644 --- a/simpeg_drivers/electricals/induced_polarization/two_dimensions/options.py +++ b/simpeg_drivers/electricals/induced_polarization/two_dimensions/options.py @@ -39,6 +39,7 @@ class IP2DForwardOptions(BaseForwardOptions, Base2DOptions): ) title: str = "Induced Polarization 2D Forward" + icon: str = "PotentialElectrode" physical_property: str = "chargeability" inversion_type: str = "induced polarization 2d" @@ -61,6 +62,7 @@ class IP2DInversionOptions(BaseInversionOptions, Base2DOptions): ) title: str = "Induced Polarization 2D Inversion" + icon: str = "PotentialElectrode" physical_property: str = "chargeability" inversion_type: str = "induced polarization 2d" diff --git a/simpeg_drivers/electromagnetics/frequency_domain/options.py b/simpeg_drivers/electromagnetics/frequency_domain/options.py index b8cdaa15..19bd5a0a 100644 --- a/simpeg_drivers/electromagnetics/frequency_domain/options.py +++ b/simpeg_drivers/electromagnetics/frequency_domain/options.py @@ -99,6 +99,7 @@ class FDEMForwardOptions(BaseForwardOptions, BaseFDEMOptions): default_ui_json: ClassVar[Path] = assets_path() / "uijson/fdem_forward.ui.json" run_command: str = "simpeg_drivers.electromagnetics.frequency_domain.forward" title: str = "Frequency-domain EM (FEM) Forward" + icon: str = "surveyairborneem" physical_property: str = "conductivity" inversion_type: str = "fdem" @@ -170,6 +171,7 @@ class FDEMInversionOptions(BaseFDEMOptions, BaseInversionOptions): default_ui_json: ClassVar[Path] = assets_path() / "uijson/fdem_inversion.ui.json" run_command: str = "simpeg_drivers.electromagnetics.frequency_domain.inversion" title: str = "Frequency-domain EM (FEM) Inversion" + icon: str = "surveyairborneem" physical_property: str = "conductivity" inversion_type: str = "fdem" diff --git a/simpeg_drivers/electromagnetics/frequency_domain_1d/options.py b/simpeg_drivers/electromagnetics/frequency_domain_1d/options.py index c8ecc957..ddc2f34d 100644 --- a/simpeg_drivers/electromagnetics/frequency_domain_1d/options.py +++ b/simpeg_drivers/electromagnetics/frequency_domain_1d/options.py @@ -42,6 +42,7 @@ class FDEM1DForwardOptions(BaseForwardOptions, BaseFDEMOptions, Base1DOptions): default_ui_json: ClassVar[Path] = assets_path() / "uijson/fdem1d_forward.ui.json" run_command: str = "simpeg_drivers.electromagnetics.frequency_domain_1d.forward" title: str = "Frequency-domain EM-1D (FEM-1D) Forward" + icon: str = "surveyairborneem" physical_property: str = "conductivity" inversion_type: str = "fdem 1d" data_object: AirborneFEMReceivers @@ -75,6 +76,7 @@ class FDEM1DInversionOptions(BaseFDEMOptions, BaseInversionOptions, Base1DOption default_ui_json: ClassVar[Path] = assets_path() / "uijson/fdem1d_inversion.ui.json" run_command: str = "simpeg_drivers.electromagnetics.frequency_domain_1d.inversion" title: str = "Frequency-domain EM-1D (FEM-1D) Inversion" + icon: str = "surveyairborneem" physical_property: str = "conductivity" inversion_type: str = "fdem 1d" diff --git a/simpeg_drivers/electromagnetics/time_domain/options.py b/simpeg_drivers/electromagnetics/time_domain/options.py index 17776658..f3da99f1 100644 --- a/simpeg_drivers/electromagnetics/time_domain/options.py +++ b/simpeg_drivers/electromagnetics/time_domain/options.py @@ -87,6 +87,7 @@ class TDEMForwardOptions(BaseTDEMOptions, BaseForwardOptions): run_command: str = "simpeg_drivers.electromagnetics.time_domain.forward" title: str = "Time-domain EM (TEM) Forward" + icon: str = "surveyairborneem" physical_property: str = "conductivity" inversion_type: str = "tdem" @@ -124,6 +125,7 @@ class TDEMInversionOptions(BaseTDEMOptions, BaseInversionOptions): default_ui_json: ClassVar[Path] = assets_path() / "uijson/tdem_inversion.ui.json" run_command: str = "simpeg_drivers.electromagnetics.time_domain.inversion" title: str = "Time-domain EM (TEM) Inversion" + icon: str = "surveyairborneem" physical_property: str = "conductivity" inversion_type: str = "tdem" diff --git a/simpeg_drivers/electromagnetics/time_domain_1d/options.py b/simpeg_drivers/electromagnetics/time_domain_1d/options.py index f934ab83..37ce088a 100644 --- a/simpeg_drivers/electromagnetics/time_domain_1d/options.py +++ b/simpeg_drivers/electromagnetics/time_domain_1d/options.py @@ -40,6 +40,7 @@ class TDEM1DForwardOptions(TDEMForwardOptions, Base1DOptions): default_ui_json: ClassVar[Path] = assets_path() / "uijson/tdem1d_forward.ui.json" run_command: str = "simpeg_drivers.electromagnetics.time_domain_1d.forward" title: str = "Time-domain EM-1D (TEM-1D) Forward" + icon: str = "surveyairborneem" inversion_type: str = "tdem 1d" vertical_channel_bool: bool = Field( @@ -60,6 +61,7 @@ class TDEM1DInversionOptions(TDEMInversionOptions, Base1DOptions): default_ui_json: ClassVar[Path] = assets_path() / "uijson/tdem1d_inversion.ui.json" run_command: str = "simpeg_drivers.electromagnetics.time_domain_1d.inversion" title: str = "Time-domain EM-1D (TEM-1D) Inversion" + icon: str = "surveyairborneem" inversion_type: str = "tdem 1d" vertical_channel: PropertyGroup | None = Field( diff --git a/simpeg_drivers/joint/joint_cross_gradient/options.py b/simpeg_drivers/joint/joint_cross_gradient/options.py index f4f39698..3480ed58 100644 --- a/simpeg_drivers/joint/joint_cross_gradient/options.py +++ b/simpeg_drivers/joint/joint_cross_gradient/options.py @@ -38,6 +38,7 @@ class JointCrossGradientOptions(BaseJointOptions): ) run_command: str = "simpeg_drivers.joint.joint_cross_gradient.driver" title: str = "Joint Cross Gradient Inversion" + icon: str = "function" inversion_type: str = "joint cross gradient" mesh: Octree | None = None diff --git a/simpeg_drivers/joint/joint_petrophysics/options.py b/simpeg_drivers/joint/joint_petrophysics/options.py index 399abc86..2e1a2488 100644 --- a/simpeg_drivers/joint/joint_petrophysics/options.py +++ b/simpeg_drivers/joint/joint_petrophysics/options.py @@ -48,6 +48,7 @@ class JointPetrophysicsOptions(BaseJointOptions): ) run_command: str = "simpeg_drivers.joint.joint_petrophysics.driver" title: str = "Joint Petrophysically Guided Inversion (PGI)" + icon: str = "referencedata" inversion_type: str = "joint petrophysics" group_a_multiplier: float | None = None diff --git a/simpeg_drivers/joint/joint_surveys/options.py b/simpeg_drivers/joint/joint_surveys/options.py index 5acc7b21..4fc92c9d 100644 --- a/simpeg_drivers/joint/joint_surveys/options.py +++ b/simpeg_drivers/joint/joint_surveys/options.py @@ -45,6 +45,7 @@ class JointSurveysOptions(BaseJointOptions): ) run_command: str = "simpeg_drivers.joint.joint_surveys.driver" title: str = "Joint Surveys Inversion" + icon: str = "model" inversion_type: str = "joint surveys" models: JointSurveysModelOptions diff --git a/simpeg_drivers/natural_sources/apparent_conductivity/options.py b/simpeg_drivers/natural_sources/apparent_conductivity/options.py index 832f3b67..ad425291 100644 --- a/simpeg_drivers/natural_sources/apparent_conductivity/options.py +++ b/simpeg_drivers/natural_sources/apparent_conductivity/options.py @@ -38,6 +38,7 @@ class AppConForwardOptions(EMDataMixin, BaseForwardOptions): ) run_command: str = "simpeg_drivers.natural_sources.apparent_conductivity.forward" title: str = "Apparent Conductivity Forward" + icon: str = "surveyztem" physical_property: str = "conductivity" inversion_type: str = "apparent conductivity" app_con_channel_bool: bool = True @@ -59,6 +60,7 @@ class AppConInversionOptions(EMDataMixin, BaseInversionOptions): ) run_command: str = "simpeg_drivers.natural_sources.apparent_conductivity.inversion" title: str = "Apparent Conductivity Inversion" + icon: str = "surveyztem" physical_property: str = "conductivity" inversion_type: str = "apparent conductivity" diff --git a/simpeg_drivers/natural_sources/magnetotellurics/options.py b/simpeg_drivers/natural_sources/magnetotellurics/options.py index 60911bb1..3e1d64f0 100644 --- a/simpeg_drivers/natural_sources/magnetotellurics/options.py +++ b/simpeg_drivers/natural_sources/magnetotellurics/options.py @@ -49,6 +49,7 @@ class MTForwardOptions(EMDataMixin, BaseForwardOptions): ) run_command: str = "simpeg_drivers.natural_sources.magnetotellurics.forward" title: str = "Magnetotellurics Forward" + icon: str = "surveymagnetotellurics" physical_property: str = "conductivity" inversion_type: str = "magnetotellurics" @@ -96,6 +97,7 @@ class MTInversionOptions(EMDataMixin, BaseInversionOptions): ) run_command: str = "simpeg_drivers.natural_sources.magnetotellurics.inversion" title: str = "Magnetotellurics Inversion" + icon: str = "surveymagnetotellurics" physical_property: str = "conductivity" inversion_type: str = "magnetotellurics" diff --git a/simpeg_drivers/natural_sources/tipper/options.py b/simpeg_drivers/natural_sources/tipper/options.py index 5196b53c..7600614a 100644 --- a/simpeg_drivers/natural_sources/tipper/options.py +++ b/simpeg_drivers/natural_sources/tipper/options.py @@ -42,6 +42,7 @@ class TipperForwardOptions(EMDataMixin, BaseForwardOptions): default_ui_json: ClassVar[Path] = assets_path() / "uijson/tipper_forward.ui.json" run_command: str = "simpeg_drivers.natural_sources.tipper.forward" title: str = "Tipper Forward" + icon: str = "surveyztem" physical_property: str = "conductivity" inversion_type: str = "tipper" @@ -72,6 +73,7 @@ class TipperInversionOptions(EMDataMixin, BaseInversionOptions): default_ui_json: ClassVar[Path] = assets_path() / "uijson/tipper_inversion.ui.json" run_command: str = "simpeg_drivers.natural_sources.tipper.inversion" title: str = "Tipper Inversion" + icon: str = "surveyztem" physical_property: str = "conductivity" inversion_type: str = "tipper" diff --git a/simpeg_drivers/options.py b/simpeg_drivers/options.py index d1b35a10..446cf5e4 100644 --- a/simpeg_drivers/options.py +++ b/simpeg_drivers/options.py @@ -18,6 +18,7 @@ import numpy as np from geoapps_utils.base import Options +from geoapps_utils.utils.formatters import recursive_flatten from geoh5py.data import ( BooleanData, DataAssociationEnum, @@ -29,7 +30,7 @@ from geoh5py.groups import PropertyGroup, SimPEGGroup, UIJsonGroup from geoh5py.objects import DrapeModel, Grid2D, Octree, Points from geoh5py.objects.surveys.electromagnetics.base import BaseEMSurvey -from geoh5py.ui_json import InputFile +from geoh5py.ui_json import BaseUIJson from pydantic import ( AliasChoices, BaseModel, @@ -41,8 +42,10 @@ model_validator, ) +from simpeg_drivers.uijson import SimPEGDriversUIJson +from simpeg_drivers.utils.regularization import direction_and_dip + from . import public_version -from .utils.regularization import direction_and_dip logger = getLogger(__name__) @@ -235,10 +238,18 @@ def padding_cells(self) -> int: return 4 if self.inversion_type in ["fdem", "tdem"] else 6 - def _create_input_file_from_attributes(self) -> InputFile: - ifile = super()._create_input_file_from_attributes() - ifile.set_data_value("version", public_version()) - return ifile + def write_ui_json(self, path: Path) -> Path: + """ + Write UI JSON file. + + TODO: Replace in favor of base Options implementation + after geoapps_utils@feature/uijson is merged + """ + ui_json = SimPEGDriversUIJson.read(self.default_ui_json) + flatten = recursive_flatten(self.model_dump(exclude_unset=True)) + ui_json.set_values(**flatten) + + return ui_json.write(path) class ModelOptions(BaseModel): diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index 467fd50d..65f4cd3d 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -33,7 +33,6 @@ from geoh5py.groups import PropertyGroup, SimPEGGroup from geoh5py.objects import AirborneTEMReceivers, MaxwellPlate, Surface from geoh5py.objects.maxwell_plate import PlateGeometry -from geoh5py.ui_json import InputFile from scipy import ndimage, signal from scipy.sparse import csr_matrix from scipy.spatial import cKDTree @@ -42,6 +41,7 @@ from simpeg_drivers.electromagnetics.time_domain.options import CONVERSION from simpeg_drivers.plate_simulation.match.options import PlateMatchOptions from simpeg_drivers.plate_simulation.options import ModelOptions, PlateSimulationOptions +from simpeg_drivers.uijson import SimPEGDriversUIJson from simpeg_drivers.utils.utils import ( get_default_parallelization_params, start_dask_run, @@ -166,17 +166,17 @@ def start(cls, filepath: str | Path, mode="r+", **_) -> Self: filepath = Path(filepath).resolve() # TODO: Replace with UIJson when fully implemented - # uijson = PlateMatchUIJson.read(filepath) - uijson = InputFile.read_ui_json(filepath) + uijson = SimPEGDriversUIJson.read(filepath) - with uijson.geoh5.open(mode=mode): + with Workspace(uijson.geoh5, mode=mode) as workspace: try: - options = PlateMatchOptions.build(uijson) + data = uijson.to_params(workspace) + options = PlateMatchOptions.build(**data) logger.info("Initializing application . . .") driver = cls(options) logger.info("Running application . . .") driver.run() - logger.info("Results saved to %s", options.geoh5.h5file) + logger.info("Results saved to %s", uijson.geoh5) except GeoAppsError as error: logger.warning("\n\nApplicationError: %s\n\n", error) @@ -385,14 +385,13 @@ def run(self): with Workspace(self.params.simulation_files[best], mode="r") as ws: survey = fetch_survey(ws) - ui_json = survey.parent.parent.options - - ui_json["geoh5"] = ws - ifile = InputFile(ui_json=ui_json) + ui_json_dict = survey.parent.parent.options + ui_json_dict["geoh5"] = ws + uijson = SimPEGDriversUIJson.from_dict(ui_json_dict) # Avoid getting pydantic deprecation warnings from old PlateSimulations stored with suppress_logging(): - options = PlateSimulationOptions.build(ifile) + options = PlateSimulationOptions.build(**uijson.to_params(ws)) dir_correction = strike_angle[ii] + 180 if flip else strike_angle[ii] ind_center = int(centers[best]) diff --git a/simpeg_drivers/plate_simulation/match/options.py b/simpeg_drivers/plate_simulation/match/options.py index e589a7fe..f3690c24 100644 --- a/simpeg_drivers/plate_simulation/match/options.py +++ b/simpeg_drivers/plate_simulation/match/options.py @@ -39,6 +39,7 @@ class PlateMatchOptions(Options): name: ClassVar[str] = "plate_match" default_ui_json: ClassVar[Path] = assets_path() / "uijson/plate_match.ui.json" title: str = "Plate Match" + icon: str = "maxwellplate" run_command: str = "simpeg_drivers.plate_simulation.match.driver" out_group: SimPEGGroup | None = None diff --git a/simpeg_drivers/plate_simulation/options.py b/simpeg_drivers/plate_simulation/options.py index 0db21ce7..28d47ec0 100644 --- a/simpeg_drivers/plate_simulation/options.py +++ b/simpeg_drivers/plate_simulation/options.py @@ -14,10 +14,11 @@ from geoapps_utils.base import Options from geoh5py.groups import SimPEGGroup, UIJsonGroup -from geoh5py.ui_json import InputFile +from geoh5py.shared.utils import fetch_active_workspace from simpeg_drivers import assets_path from simpeg_drivers.options import BaseForwardOptions +from simpeg_drivers.uijson import SimPEGDriversUIJson from simpeg_drivers.utils.synthetics.meshes import MeshOptions from simpeg_drivers.utils.utils import driver_class_from_dict @@ -39,6 +40,7 @@ class PlateSimulationOptions(Options): name: ClassVar[str] = "plate_simulation" default_ui_json: ClassVar[Path] = assets_path() / "uijson/plate_simulation.ui.json" title: str = "Plate Simulation" + icon: str = "maxwellplate" run_command: str = "simpeg_drivers.plate_simulation.driver" out_group: SimPEGGroup | UIJsonGroup | None = None forward_only: bool = True @@ -58,15 +60,10 @@ def simulation_parameters(self) -> BaseForwardOptions: simulation_options = deepcopy(self.simulation.options) simulation_options["geoh5"] = self.geoh5 - input_file = InputFile(ui_json=simulation_options, validate=False) - if input_file.ui_json is None: - raise ValueError("Input file must have ui_json set.") + ui_json = SimPEGDriversUIJson.from_dict(simulation_options) - input_file.ui_json["mesh"]["value"] = None + with fetch_active_workspace(self.geoh5) as workspace: + data = ui_json.to_params(workspace=workspace, validate=False) + driver = driver_class_from_dict(data) - if input_file.data is None: - raise ValueError("Input file data must be set.") - - driver = driver_class_from_dict(input_file.data) - - return driver._params_class.build(input_file.data) # pylint: disable=protected-access + return driver._params_class.build(data) # pylint: disable=protected-access diff --git a/simpeg_drivers/plate_simulation/sweep/options.py b/simpeg_drivers/plate_simulation/sweep/options.py index ba6a9913..8165051e 100644 --- a/simpeg_drivers/plate_simulation/sweep/options.py +++ b/simpeg_drivers/plate_simulation/sweep/options.py @@ -14,12 +14,13 @@ import numpy as np from geoapps_utils.base import Options +from geoh5py import Workspace from geoh5py.groups import SimPEGGroup, UIJsonGroup -from geoh5py.shared.utils import stringify -from geoh5py.ui_json import InputFile +from geoh5py.shared.utils import fetch_active_workspace, stringify from pydantic import BaseModel, ConfigDict, field_serializer, field_validator from simpeg_drivers import assets_path +from simpeg_drivers.uijson import SimPEGDriversUIJson class ParamSweep(BaseModel): @@ -58,6 +59,7 @@ class SweepOptions(Options): name: ClassVar[str] = "plate_sweep" default_ui_json: ClassVar[Path] = assets_path() / "uijson/plate_sweep.ui.json" title: str = "Plate Sweep" + icon: str = "maxwellplate" run_command: str = "simpeg_drivers.plate_simulation.sweep.driver" out_group: SimPEGGroup | None = None forward_only: bool = True @@ -142,26 +144,36 @@ def trials(self) -> list[dict]: return trials @staticmethod - def all_hashable_options(options: dict) -> dict: - """Recurses through UIJson options to return flat dictionary of all key/values.""" + def all_hashable_options(options: dict, workspace: Workspace) -> dict: + """ + Recurses through UIJson options to return flat dictionary of all key/values. - # TODO: Use the base UIJson to read options and flatten instead of - # InputFile. Requires GEOPY-1875. + :param options: Options dictionary + :param workspace: Workspace to fetch objects from. - ifile = InputFile(ui_json=options, validate=False) - exceptions = list(Options.model_fields) + ["version", "icon", "documentation"] - # TODO: add these to the Options fields with empty string defaults. - out = {} - for k, v in ifile.data.items(): - if k in exceptions: - continue + :return: Flat dictionary of all key/values. + """ + ifile = SimPEGDriversUIJson.from_dict(options) + + with fetch_active_workspace(workspace, mode="r") as ws: + data = ifile.to_params(workspace=ws, validate=False) + exceptions = list(Options.model_fields) + [ + "version", + "icon", + "documentation", + ] + # TODO: add these to the Options fields with empty string defaults. + out = {} + for k, v in data.items(): + if k in exceptions: + continue - if isinstance(v, SimPEGGroup | UIJsonGroup): - opts = v.options - opts["geoh5"] = options["geoh5"] - out.update(SweepOptions.all_hashable_options(opts)) - else: - out[k] = v + if isinstance(v, SimPEGGroup | UIJsonGroup): + opts = v.options + opts["geoh5"] = ws + out.update(SweepOptions.all_hashable_options(opts, ws)) + else: + out[k] = v return out @@ -170,4 +182,7 @@ def template_options(self): """Return a flat version of the template.options dictionary.""" options = self.template.options options["geoh5"] = self.geoh5 - return stringify(SweepOptions.all_hashable_options(options)) + + with fetch_active_workspace(self.geoh5, mode="r") as workspace: + template = SweepOptions.all_hashable_options(options, workspace) + return stringify(template) diff --git a/simpeg_drivers/potential_fields/gravity/options.py b/simpeg_drivers/potential_fields/gravity/options.py index 763607ce..5333d90c 100644 --- a/simpeg_drivers/potential_fields/gravity/options.py +++ b/simpeg_drivers/potential_fields/gravity/options.py @@ -44,6 +44,7 @@ class GravityForwardOptions(BaseForwardOptions): run_command: str = "simpeg_drivers.potential_fields.gravity.forward" title: str = "Gravity Forward" + icon: str = "surveyairbornegravity" physical_property: str = "density" inversion_type: str = "gravity" @@ -88,6 +89,7 @@ class GravityInversionOptions(BaseInversionOptions): run_command: str = "simpeg_drivers.potential_fields.gravity.inversion" title: str = "Gravity Inversion" + icon: str = "surveyairbornegravity" physical_property: str = "density" inversion_type: str = "gravity" diff --git a/simpeg_drivers/potential_fields/magnetic_scalar/options.py b/simpeg_drivers/potential_fields/magnetic_scalar/options.py index 1e1839e7..7f422791 100644 --- a/simpeg_drivers/potential_fields/magnetic_scalar/options.py +++ b/simpeg_drivers/potential_fields/magnetic_scalar/options.py @@ -56,6 +56,7 @@ class MagneticForwardOptions(BaseForwardOptions): run_command: str = "simpeg_drivers.potential_fields.magnetic_scalar.forward" title: str = "Magnetic Scalar Forward" + icon: str = "surveyairbornemagnetics" physical_property: str = "susceptibility" inversion_type: str = "magnetic scalar" @@ -112,6 +113,7 @@ class MagneticInversionOptions(BaseInversionOptions): run_command: str = "simpeg_drivers.potential_fields.magnetic_scalar.inversion" title: str = "Magnetic Scalar Inversion" + icon: str = "surveyairbornemagnetics" physical_property: str = "susceptibility" inversion_type: str = "magnetic scalar" diff --git a/simpeg_drivers/potential_fields/magnetic_vector/options.py b/simpeg_drivers/potential_fields/magnetic_vector/options.py index 58e72ae9..70ab0bfe 100644 --- a/simpeg_drivers/potential_fields/magnetic_vector/options.py +++ b/simpeg_drivers/potential_fields/magnetic_vector/options.py @@ -60,6 +60,7 @@ class MagneticVectorForwardOptions(BaseForwardOptions): ) run_command: str = "simpeg_drivers.potential_fields.magnetic_vector.forward" title: str = "Magnetic Vector Forward" + icon: str = "surveyairbornemagnetics" physical_property: str = "susceptibility" inversion_type: str = "magnetic vector" @@ -114,6 +115,7 @@ class MagneticVectorInversionOptions(BaseInversionOptions): ) run_command: str = "simpeg_drivers.potential_fields.magnetic_vector.inversion" title: str = "Magnetic Vector Inversion" + icon: str = "surveyairbornemagnetics" physical_property: str = "susceptibility" inversion_type: str = "magnetic vector" diff --git a/simpeg_drivers/uijson.py b/simpeg_drivers/uijson.py index c9495195..809c0e1a 100644 --- a/simpeg_drivers/uijson.py +++ b/simpeg_drivers/uijson.py @@ -84,3 +84,27 @@ def write_default(cls): data = uijson.model_dump_json(indent=4, exclude_unset=False) with open(cls.default_ui_json, "w", encoding="utf-8") as file: file.write(data) + + @classmethod + def from_dict(cls, data: dict) -> BaseUIJson: + """ + Create a UIJson instance from a dictionary. + + Deal with known issues in legacy files + + :param data: Dictionary representing the ui json object. + + :returns: UIJson object. + """ + kwargs = {} + for key, item in data.items(): + if isinstance(item, dict) and key == "tile_spatial": + item.pop("isValue", None) + item.pop("property", None) + item.pop("parent", None) + + kwargs[key] = item if item != "" else None + + ui_json_class = cls.infer(**kwargs) + + return ui_json_class(**kwargs) diff --git a/simpeg_drivers/utils/tile_estimate.py b/simpeg_drivers/utils/tile_estimate.py index 18ef5296..f68ec2a4 100644 --- a/simpeg_drivers/utils/tile_estimate.py +++ b/simpeg_drivers/utils/tile_estimate.py @@ -41,6 +41,7 @@ class TileParameters(Options): """ default_ui_json: ClassVar[Path] = assets_path() / "uijson/tile_estimator.ui.json" + icon: str = "tilelist" simulation: SimPEGGroup render_plot: bool = True diff --git a/simpeg_drivers/utils/utils.py b/simpeg_drivers/utils/utils.py index 7b8810d5..bb488316 100644 --- a/simpeg_drivers/utils/utils.py +++ b/simpeg_drivers/utils/utils.py @@ -40,12 +40,12 @@ from geoh5py.objects.surveys.electromagnetics.base import LargeLoopGroundEMSurvey from geoh5py.shared import INTEGER_NDV from geoh5py.shared.utils import fetch_active_workspace, mask_by_extent, stringify -from geoh5py.ui_json import InputFile from grid_apps.utils import octree_2_treemesh from scipy.interpolate import interp1d from scipy.spatial import ConvexHull, cKDTree from simpeg_drivers import DRIVER_MAP +from simpeg_drivers.uijson import SimPEGDriversUIJson if TYPE_CHECKING: @@ -608,14 +608,14 @@ def simpeg_group_to_driver(group: SimPEGGroup, workspace: Workspace) -> Driver: :returns: InversionDriver object. """ + ui_json_dict = deepcopy(group.options) + ui_json_dict["geoh5"] = workspace + uijson = SimPEGDriversUIJson.from_dict(ui_json_dict) + data = uijson.to_params(workspace) + data["out_group"] = group - ui_json = deepcopy(group.options) - ui_json["geoh5"] = workspace - - ifile = InputFile(ui_json=ui_json) - inversion_driver = driver_class_from_dict(ifile.ui_json) - ifile.set_data_value("out_group", group) - params = inversion_driver._params_class.build(ifile) # pylint: disable=protected-access + inversion_driver = driver_class_from_dict(ui_json_dict) + params = inversion_driver._params_class.build(**data) # pylint: disable=protected-access return inversion_driver(params) diff --git a/tests/plate_simulation/runtest/driver_test.py b/tests/plate_simulation/runtest/driver_test.py index 297237c4..6b2f9432 100644 --- a/tests/plate_simulation/runtest/driver_test.py +++ b/tests/plate_simulation/runtest/driver_test.py @@ -11,7 +11,7 @@ import logging from geoh5py.groups import SimPEGGroup -from geoh5py.ui_json import InputFile +from geoh5py.ui_json import BaseUIJson from simpeg_drivers import assets_path from simpeg_drivers.plate_simulation.driver import ( @@ -31,6 +31,7 @@ SurveyOptions, SyntheticsComponentsOptions, ) +from simpeg_drivers.utils.utils import validate_out_group from tests.utils.targets import get_workspace @@ -45,52 +46,52 @@ def test_plate_simulation_params_from_input_file(tmp_path, caplog): with get_workspace(tmp_path / "inversion_test.ui.geoh5") as geoh5: components = SyntheticsComponents(geoh5, options=opts) - ifile = InputFile.read_ui_json( - assets_path() / "uijson" / "plate_simulation.ui.json", validate=False - ) - ifile.data["name"] = "test_gravity_plate_simulation" - ifile.data["geoh5"] = geoh5 - # Add simulation parameter - gravity_inversion = SimPEGGroup.create(geoh5) - options = GravityForwardOptions.model_construct() - fwr_ifile = InputFile.read_ui_json(options.default_ui_json) - options_dict = fwr_ifile.ui_json - options_dict["inversion_type"] = "gravity" - options_dict["forward_only"] = True - options_dict["geoh5"] = str(geoh5.h5file) - options_dict["topography_object"]["value"] = str(components.topography.uid) - options_dict["data_object"]["value"] = str(components.survey.uid) - gravity_inversion.options = options_dict - ifile.data["simulation"] = gravity_inversion - - # Add mesh parameters - ifile.data["u_cell_size"] = 10.0 - ifile.data["v_cell_size"] = 10.0 - ifile.data["w_cell_size"] = 10.0 - ifile.data["depth_core"] = 400.0 - ifile.data["minimum_level"] = 8 - ifile.data["max_distance"] = 200.0 - ifile.data["diagonal_balance"] = False - ifile.data["padding_distance"] = 1500.0 - - # Add model parameters - ifile.data["background"] = 1000.0 - ifile.data["overburden_property"] = 5.0 - ifile.data["thickness"] = 50.0 - ifile.data["plate_property"] = 2.0 - ifile.data["width"] = 100.0 - ifile.data["strike_length"] = 100.0 - ifile.data["dip_length"] = 100.0 - ifile.data["dip"] = 0.0 - ifile.data["dip_direction"] = 0.0 - ifile.data["number"] = 9 - ifile.data["spacing"] = 10.0 - ifile.data["elevation"] = 20 + fwr_ifile = BaseUIJson.read(options.default_ui_json) + options_dict = { + "inversion_type": "gravity", + "forward_only": True, + "topography_object": str(components.topography.uid), + "data_object": str(components.survey.uid), + "title": "gravity fwd", + } + fwr_ifile.set_values(**options_dict) + options_dict = fwr_ifile.to_params(workspace=geoh5) + options = GravityForwardOptions.build(options_dict) + gravity_inversion = validate_out_group(options) + + ifile = BaseUIJson.read(assets_path() / "uijson" / "plate_simulation.ui.json") + options_dict = { + "simulation": gravity_inversion, + # Add mesh parameters + "u_cell_size": 10.0, + "v_cell_size": 10.0, + "w_cell_size": 10.0, + "depth_core": 400.0, + "minimum_level": 8, + "max_distance": 200.0, + "diagonal_balance": False, + "padding_distance": 1500.0, + "name": "test_gravity_plate_simulation", + # Add model parameters + "background": 1000.0, + "overburden_property": 5.0, + "thickness": 50.0, + "plate_property": 2.0, + "width": 100.0, + "strike_length": 100.0, + "dip_length": 100.0, + "dip": 0.0, + "dip_direction": 0.0, + "number": 9, + "spacing": 10.0, + "elevation": 20, + } + ifile.set_values(**options_dict) with caplog.at_level(logging.WARNING): - params = PlateSimulationOptions.build(ifile) + params = PlateSimulationOptions.build(ifile.to_params(workspace=geoh5)) assert "Overburden thickness exceeds the plate depth" in caplog.text assert isinstance(params.simulation, SimPEGGroup) diff --git a/tests/plate_simulation/runtest/match_test.py b/tests/plate_simulation/runtest/match_test.py index 3841b267..2a6770ae 100644 --- a/tests/plate_simulation/runtest/match_test.py +++ b/tests/plate_simulation/runtest/match_test.py @@ -19,7 +19,7 @@ from geoh5py.data import FilenameData from geoh5py.groups import PropertyGroup, SimPEGGroup from geoh5py.objects import Points -from geoh5py.ui_json import InputFile +from geoh5py.ui_json import BaseUIJson from scipy import signal from simpeg_drivers import assets_path @@ -146,13 +146,10 @@ def test_matching_driver(tmp_path: Path): fwr_driver = TDEMForwardDriver(params) - ifile = InputFile.read_ui_json( - assets_path() / "uijson" / "plate_simulation.ui.json", validate=False - ) - ifile.data["geoh5"] = geoh5 - ifile.data["simulation"] = fwr_driver.out_group + ifile = BaseUIJson.read(assets_path() / "uijson" / "plate_simulation.ui.json") + ifile.set_values(simulation=fwr_driver.out_group) - plate_options = PlateSimulationOptions.build(ifile.data) + plate_options = PlateSimulationOptions.build(ifile.to_params(workspace=geoh5)) plate_options.model.overburden_options.thickness = 25.0 plate_options.model.overburden_options.overburden_property = 10000 plate_options.model.plate_options.geometry.dip_length = 300.0 @@ -222,13 +219,17 @@ def test_matching_driver(tmp_path: Path): topography_object=components.topography, simulations=new_dir, ) - match_driver = PlateMatchDriver(options) - results = match_driver.run() + json_file = options.write_ui_json(tmp_path / "match_options.ui.json") + + PlateMatchDriver.start(json_file) + with geoh5.open(): + out_group = geoh5.get_entity("Plate Match")[0] + results = out_group.get_entity("Points")[0] assert isinstance(results, Points) names = results.get_data("file")[0] - assert names.values[0] == file.stem + f"_[{1}].geoh5" + assert names.values == file.stem + f"_[{1}].geoh5" plate = geoh5.get_entity("Query [0]")[0] assert plate.geometry.dip_direction == 45.0 diff --git a/tests/plate_simulation/runtest/sweep_test.py b/tests/plate_simulation/runtest/sweep_test.py index 4484b6ae..58e52c6a 100644 --- a/tests/plate_simulation/runtest/sweep_test.py +++ b/tests/plate_simulation/runtest/sweep_test.py @@ -10,7 +10,7 @@ from geoh5py import Workspace from geoh5py.groups import SimPEGGroup -from geoh5py.ui_json import InputFile +from geoh5py.ui_json import BaseUIJson from pandas import read_excel from simpeg_drivers import assets_path @@ -27,38 +27,38 @@ def setup_plate_sweep(workspace) -> SimPEGGroup: data = get_survey(workspace, method="gravity", options=options.survey) topo = get_topography_surface(workspace, options) - gravity = SimPEGGroup.create(workspace, name="gravity fwd") options = GravityForwardOptions.model_construct() - fwr_ifile = InputFile.read_ui_json(options.default_ui_json) - options_dict = fwr_ifile.ui_json - options_dict["inversion_type"] = "gravity" - options_dict["forward_only"] = True - options_dict["geoh5"] = str(workspace.h5file) - options_dict["topography_object"]["value"] = str(topo.uid) - options_dict["data_object"]["value"] = str(data.uid) - options_dict["out_group"]["value"] = str(gravity.uid) - gravity.options = options_dict - - simulation = SimPEGGroup.create(workspace, name="plate simulation") + fwr_file = BaseUIJson.read(options.default_ui_json) + + fwr_file.inversion_type = "gravity" + fwr_file.forward_only = True + fwr_file.geoh5 = str(workspace.h5file) + fwr_file.topography_object.value = str(topo.uid) + fwr_file.data_object.value = str(data.uid) + + gravity = fwr_file.to_ui_json_group(workspace=workspace, name="gravity fwd") + options = PlateSimulationOptions.model_construct() - plate_ifile = InputFile.read_ui_json(options.default_ui_json) - options_dict = plate_ifile.ui_json - options_dict["simulation"]["value"] = str(gravity.uid) - options_dict["overburden_property"]["value"] = 100.0 - options_dict["thickness"]["value"] = 20.0 - options_dict["u_cell_size"]["value"] = 10.0 - options_dict["v_cell_size"]["value"] = 10.0 - options_dict["w_cell_size"]["value"] = 10.0 - options_dict["depth_core"]["value"] = 400.0 - options_dict["minimum_level"]["value"] = 8 - options_dict["max_distance"]["value"] = 200.0 - options_dict["diagonal_balance"]["value"] = False - options_dict["padding_distance"]["value"] = 1500.0 - options_dict["dip_direction"]["value"] = 0.0 - options_dict["number"]["value"] = 1 - options_dict["elevation"]["value"] = 100.0 - options_dict["out_group"]["value"] = str(simulation.uid) - simulation.options = options_dict + plate_ifile = BaseUIJson.read(options.default_ui_json) + + plate_ifile.simulation.value = str(gravity.uid) + plate_ifile.overburden_property.value = 100.0 + plate_ifile.thickness.value = 20.0 + plate_ifile.u_cell_size.value = 10.0 + plate_ifile.v_cell_size.value = 10.0 + plate_ifile.w_cell_size.value = 10.0 + plate_ifile.depth_core.value = 400.0 + plate_ifile.minimum_level.value = 8 + plate_ifile.max_distance.value = 200.0 + plate_ifile.diagonal_balance.value = False + plate_ifile.padding_distance.value = 1500.0 + plate_ifile.dip_direction.value = 0.0 + plate_ifile.number.value = 1 + plate_ifile.elevation.value = 100.0 + + simulation = plate_ifile.to_ui_json_group( + workspace=workspace, name="plate simulation" + ) return simulation @@ -69,30 +69,30 @@ def test_sweep(tmp_path): with Workspace.create(tmp_path / "test.geoh5") as ws: plate_simulation = setup_plate_sweep(ws) - ifile = InputFile.read_ui_json( - assets_path() / "uijson" / "plate_sweep.ui.json", validate=False - ) - ifile.data["name"] = "test_gravity_plate_simulation" - ifile.data["geoh5"] = ws - ifile.data["template"] = str(plate_simulation.uid) - ifile.data["workdir"] = str(workdir) - ifile.data["background_start"] = 0.0 - ifile.data["background_stop"] = 100.0 - ifile.data["background_count"] = 2 - ifile.data["plate_start"] = 500.0 - ifile.data["plate_stop"] = 1000.0 - ifile.data["plate_count"] = 2 - ifile.data["out_group"] = None - - ifile.write_ui_json(name="plate_sweep.ui.json", path=tmp_path) + ifile = BaseUIJson.read(assets_path() / "uijson" / "plate_sweep.ui.json") + data = { + "name": "test_gravity_plate_simulation", + "geoh5": ws, + "template": str(plate_simulation.uid), + "workdir": str(workdir), + "background_start": 0.0, + "background_stop": 100.0, + "background_count": 2, + "plate_start": 500.0, + "plate_stop": 1000.0, + "plate_count": 2, + "out_group": None, + } + ifile.set_values(**data) + ifile.write(tmp_path / "plate_sweep.ui.json") PlateSweepDriver.start(tmp_path / "plate_sweep.ui.json") assert workdir.exists() with Workspace(tmp_path / "test.geoh5"): - ifile = InputFile.read_ui_json(tmp_path / "plate_sweep.ui.json") - ifile.set_data_value("background_count", 3) - ifile.write_ui_json(path=tmp_path, name="plate_sweep_modified.ui.json") + ifile = BaseUIJson.read(tmp_path / "plate_sweep.ui.json") + ifile.set_values(background_count=3) + ifile.write(tmp_path / "plate_sweep_modified.ui.json") PlateSweepDriver.start(tmp_path / "plate_sweep_modified.ui.json") diff --git a/tests/run_tests/driver_grav_test.py b/tests/run_tests/driver_grav_test.py index 41e5400b..cb06f566 100644 --- a/tests/run_tests/driver_grav_test.py +++ b/tests/run_tests/driver_grav_test.py @@ -133,6 +133,7 @@ def test_gravity_run( starting_model=1e-4, topography_object=components.topography, reference_model=0.0, + sens_wts_threshold=1.0, save_sensitivities=True, ) params.write_ui_json(path=tmp_path / "Inv_run.ui.json") diff --git a/tests/run_tests/driver_joint_cross_gradient_test.py b/tests/run_tests/driver_joint_cross_gradient_test.py index 4b33ab32..3fbc085e 100644 --- a/tests/run_tests/driver_joint_cross_gradient_test.py +++ b/tests/run_tests/driver_joint_cross_gradient_test.py @@ -15,6 +15,7 @@ from geoh5py.groups import GroupTypeEnum, PropertyGroup from geoh5py.objects import CurrentElectrode, Octree, Points from geoh5py.workspace import Workspace +from simpeg.directives import UpdateIRLS from simpeg_drivers.electricals.direct_current.three_dimensions import ( DC3DForwardDriver, @@ -234,6 +235,7 @@ def test_joint_cross_gradient_inv_run( reference_model=0.0, upper_bound=1.0, tile_spatial=2, + x_norm=1.1, auto_scale_tiles=True, chi_factor=0.8, ) @@ -296,17 +298,19 @@ def test_joint_cross_gradient_inv_run( cross_gradient_weight_a_b=1e0, cross_gradient_weight_c_a=1e0, cross_gradient_weight_c_b=1e0, + sens_wts_threshold=1.0, percentile=100, ) - - driver = JointCrossGradientDriver(joint_params) - - # Check that chi factors set on the sub drivers are preserved forward - np.testing.assert_allclose( - driver.data_misfit.multipliers, [0.8, 0.8, 1.0, 1.0, 1.0], atol=1e-3 + file = joint_params.write_ui_json(tmp_path / "Joint_Inv_run.ui.json") + driver = JointCrossGradientDriver.start(file) + + # Check that the norm applied to the sub-driver is maintained + irls_directive = next( + directive + for directive in driver.directives.directive_list + if isinstance(directive, UpdateIRLS) ) - - driver.run() + np.testing.assert_almost_equal(irls_directive.metrics.input_norms[0][1], 1.1) if not pytest: return diff --git a/tests/run_tests/driver_rotated_gradients_test.py b/tests/run_tests/driver_rotated_gradients_test.py index 0b47de3e..dca72fa6 100644 --- a/tests/run_tests/driver_rotated_gradients_test.py +++ b/tests/run_tests/driver_rotated_gradients_test.py @@ -151,6 +151,7 @@ def test_rotated_grad_run( max_global_iterations=max_iterations, initial_beta_ratio=1e-1, percentile=95, + sens_wts_threshold=1.0, save_sensitivities=True, ) params.write_ui_json(path=tmp_path / "Inv_run.ui.json") diff --git a/tests/uijson_test.py b/tests/uijson_test.py index 8b686da6..f1eb88b9 100644 --- a/tests/uijson_test.py +++ b/tests/uijson_test.py @@ -18,7 +18,6 @@ from geoapps_utils.driver.data import BaseData from geoapps_utils.run import load_ui_json_as_dict from geoh5py import Workspace -from geoh5py.ui_json import InputFile from geoh5py.ui_json.annotations import Deprecated from packaging.version import Version from pydantic import AliasChoices, Field @@ -277,13 +276,13 @@ def test_legacy_uijson(tmp_path: Path, caplog): version_path = tmp_path / directory.name for file in directory.glob("*.ui.json"): - ifile = InputFile.read_ui_json(file, validate=False) - inversion_type = ifile.data.get("inversion_type", None) + ifile = SimPEGDriversUIJson.read(file) + inversion_type = ifile.inversion_type if inversion_type not in CHANNEL_NAME: continue - forward = ifile.data.get("forward_only", None) + forward = ifile.forward_only work_path = version_path / ( inversion_type + (" fwr" if forward else " inv") @@ -304,18 +303,19 @@ def test_legacy_uijson(tmp_path: Path, caplog): ) with Workspace.create(work_path / "inversion_test.ui.geoh5") as geoh5: components = SyntheticsComponents(geoh5, options=opts) - ifile.data["geoh5"] = geoh5 - ifile.data["mesh"] = components.mesh - ifile.data["starting_model"] = components.model - ifile.data["data_object"] = components.survey - ifile.data["topography_object"] = components.topography + options = ifile.to_params(workspace=geoh5, validate=False) + options["geoh5"] = geoh5 + options["mesh"] = components.mesh + options["starting_model"] = components.model + options["data_object"] = components.survey + options["topography_object"] = components.topography # Test deprecated name - ifile.data["coolingFactor"] = 4.0 + options["coolingFactor"] = 4.0 if "2d" in inversion_type or "pseudo 3d" in inversion_type: line_id = geoh5.get_entity("line_ids")[0] - ifile.data["line_object"] = line_id + options["line_object"] = line_id if not forward: n_vals = components.survey.n_vertices @@ -344,13 +344,13 @@ def test_legacy_uijson(tmp_path: Path, caplog): else: channel = data[0] - ifile.data[CHANNEL_NAME[inversion_type] + "_channel"] = channel - ifile.data[CHANNEL_NAME[inversion_type] + "_uncertainty"] = channel + options[CHANNEL_NAME[inversion_type] + "_channel"] = channel + options[CHANNEL_NAME[inversion_type] + "_uncertainty"] = channel - driver = driver_class_from_dict(ifile.data) + driver = driver_class_from_dict(options) with caplog.at_level(logging.WARNING): - params = driver._params_class.build(ifile) # pylint: disable=protected-access + params = driver._params_class.build(options) # pylint: disable=protected-access driver = driver(params) if "pseudo" in inversion_type: