From c796d33245e26fe96e926b6555554f1686449bc2 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 12 Jan 2026 14:44:29 -0800 Subject: [PATCH 01/24] Initial commit for match options and driver class. --- .../plate_simulation/match/__init__.py | 9 ++ .../plate_simulation/match/driver.py | 117 ++++++++++++++++++ .../plate_simulation/match/options.py | 51 ++++++++ 3 files changed, 177 insertions(+) create mode 100644 simpeg_drivers/plate_simulation/match/__init__.py create mode 100644 simpeg_drivers/plate_simulation/match/driver.py create mode 100644 simpeg_drivers/plate_simulation/match/options.py diff --git a/simpeg_drivers/plate_simulation/match/__init__.py b/simpeg_drivers/plate_simulation/match/__init__.py new file mode 100644 index 00000000..df32b204 --- /dev/null +++ b/simpeg_drivers/plate_simulation/match/__init__.py @@ -0,0 +1,9 @@ +# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +# Copyright (c) 2023-2026 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). ' +# ' +# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py new file mode 100644 index 00000000..07386167 --- /dev/null +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -0,0 +1,117 @@ +# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +# Copyright (c) 2023-2026 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 + +import sys +from pathlib import Path + +import numpy as np +from geoapps_utils.utils.importing import GeoAppsError +from geoapps_utils.utils.logger import get_logger +from geoh5py import Workspace +from geoh5py.groups import UIJsonGroup +from geoh5py.shared.utils import ( + dict_to_json_str, + fetch_active_workspace, + uuid_from_values, +) +from geoh5py.ui_json.ui_json import BaseUIJson +from geoh5py.ui_json.utils import flatten +from typing_extensions import Self + +from simpeg_drivers.driver import BaseDriver +from simpeg_drivers.plate_simulation.match.options import MatchOptions + + +logger = get_logger(name=__name__, level_name=False, propagate=False, add_name=False) + + +# TODO: Can we make this generic (PlateMatchDriver -> MatchDriver)? +class PlateMatchDriver(BaseDriver): + """Sets up and manages workers to run all combinations of swepts parameters.""" + + _params_class = MatchOptions + + def __init__(self, params: MatchOptions, workers: list[tuple[str]] | None = None): + super().__init__(params, workers=workers) + + self.out_group = self.validate_out_group(self.params.out_group) + + @property + def out_group(self) -> UIJsonGroup: + """ + Returns the output group for the simulation. + """ + return self._out_group + + @out_group.setter + def out_group(self, value: UIJsonGroup): + if not isinstance(value, UIJsonGroup): + raise TypeError("Output group must be a UIJsonGroup.") + + if self.params.out_group != value: + self.params.out_group = value + self.params.update_out_group_options() + + self._out_group = value + + def validate_out_group(self, out_group: UIJsonGroup | None) -> UIJsonGroup: + """ + Validate or create a UIJsonGroup to store results. + + :param value: Output group from selection. + """ + if isinstance(out_group, UIJsonGroup): + return out_group + + with fetch_active_workspace(self.params.geoh5, mode="r+"): + out_group = UIJsonGroup.create( + self.params.geoh5, + name=self.params.title, + ) + out_group.entity_type.name = self.params.title + + return out_group + + @classmethod + def start(cls, filepath: str | Path, mode="r", **_) -> Self: + """Start the parameter matching from a ui.json file.""" + logger.info("Loading input file . . .") + filepath = Path(filepath).resolve() + uijson = BaseUIJson.read(filepath) + + with Workspace(uijson.geoh5, mode=mode) as workspace: + try: + options = MatchOptions.build(uijson.to_params(workspace=workspace)) + logger.info("Initializing application . . .") + driver = cls(options) + logger.info("Running application . . .") + driver.run() + logger.info("Results saved to %s", options.geoh5.h5file) + + except GeoAppsError as error: + logger.warning("\n\nApplicationError: %s\n\n", error) + sys.exit(1) + + return driver + + def run(self): + """Loop over all trials and run a worker for each unique parameter set.""" + + logger.info( + "Running %s . . .", + self.params.template.options["title"], + ) + + +if __name__ == "__main__": + file = Path(sys.argv[1]) + PlateMatchDriver.start(file) diff --git a/simpeg_drivers/plate_simulation/match/options.py b/simpeg_drivers/plate_simulation/match/options.py new file mode 100644 index 00000000..abaabb3d --- /dev/null +++ b/simpeg_drivers/plate_simulation/match/options.py @@ -0,0 +1,51 @@ +# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +# Copyright (c) 2023-2026 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). ' +# ' +# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +import itertools +from pathlib import Path +from typing import ClassVar + +import numpy as np +from geoapps_utils.base import Options +from geoh5py.groups import PropertyGroup, UIJsonGroup +from geoh5py.objects import Points +from geoh5py.objects.surveys.electromagnetics.airborne_tem import AirborneTEMReceivers +from geoh5py.shared.utils import stringify +from geoh5py.ui_json import InputFile +from pydantic import BaseModel, ConfigDict, field_serializer + +from simpeg_drivers import assets_path + + +class MatchOptions(Options): + """ + Options for matching signal from a survey against a library of simulations. + + :param survey: A Time-Domain Airborne TEM survey object. + :param data: A property group containing observed data. + :param targets: A Points object containing the target locations. + :param strike_angles: An optional data array containing strike angles for each + target location. + :param simulations: Directory to store simulation files. + """ + + model_config = ConfigDict(frozen=False, arbitrary_types_allowed=True) + + name: ClassVar[str] = "plate_match" + default_ui_json: ClassVar[Path] = assets_path() / "uijson/plate_match.ui.json" + title: ClassVar[str] = "Plate Match" + run_command: ClassVar[str] = "simpeg_drivers.plate_simulation.match.driver" + out_group: UIJsonGroup | None = None + + survey: AirborneTEMReceivers + data: PropertyGroup + targets: Points + strike_angles: np.ndarray | None = None + simulations: ClassVar[Path] From ea56d4e774636cf0ab06e8131a0ac923ceac223f Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 13 Jan 2026 12:21:38 -0800 Subject: [PATCH 02/24] Continue work --- .../uijson/plate_match.ui.json | 111 ++++++++++++++++ .../plate_simulation/match/driver.py | 125 +++++++++++++++--- .../plate_simulation/match/options.py | 17 +-- .../plate_simulation/match/uijson.py | 26 ++++ 4 files changed, 256 insertions(+), 23 deletions(-) create mode 100644 simpeg_drivers-assets/uijson/plate_match.ui.json create mode 100644 simpeg_drivers/plate_simulation/match/uijson.py diff --git a/simpeg_drivers-assets/uijson/plate_match.ui.json b/simpeg_drivers-assets/uijson/plate_match.ui.json new file mode 100644 index 00000000..86ec9a2d --- /dev/null +++ b/simpeg_drivers-assets/uijson/plate_match.ui.json @@ -0,0 +1,111 @@ +{ + "version": "0.2.0-alpha.1", + "title": "Plate Match", + "icon": "maxwellplate", + "documentation": "https://mirageoscience-simpeg-drivers.readthedocs-hosted.com/en/latest/plate-simulation/", + "conda_environment": "simpeg_drivers", + "run_command": "simpeg_drivers.driver", + "geoh5": "", + "monitoring_directory": "", + "inversion_type": "plate match", + "survey": { + "main": true, + "label": "Survey", + "meshType": [ + "{6a057fdc-b355-11e3-95be-fd84a7ffcb88}", + "{19730589-fd28-4649-9de0-ad47249d9aba}" + ], + "tooltip": "Airborne TEM survey containing transmitter and receiver locations.", + "value": "" + }, + "data": { + "association": [ + "Cell", + "Vertex" + ], + "dataType": "Float", + "dataGroupType": "Multi-element", + "main": true, + "label": "EM Data", + "parent": "survey", + "tooltip": "Observed EM data to fit during plate matching.", + "value": "" + }, + "queries": { + "main": true, + "label": "Query Points", + "meshType": [ + "{6a057fdc-b355-11e3-95be-fd84a7ffcb88}", + "{202C5DB1-A56D-4004-9CAD-BAAFD8899406}" + ], + "tooltip": "Locations of EM anomalies on the survey to evaluate the match.", + "value": "" + }, + "max_distance": { + "main": true, + "label": "Query Max Distance (m)", + "value": 1000.0, + "tooltip": "Length on either side of the query points to evaluate the match." + }, + "strike_angles": { + "association": [ + "Cell", + "Vertex" + ], + "dataType": "Float", + "main": true, + "label": "Strike Angles (degrees)", + "parent": "queries", + "optional": true, + "enabled": false, + "tooltip": "Data containing the estimated angles between the flight path and dipping body.", + "value": "" + }, + "topography_object": { + "main": true, + "group": "Topography", + "label": "Topography", + "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}" + ], + "value": "", + "tooltip": "Select a topography object to define the drape height for the survey." + }, + "topography": { + "association": [ + "Vertex", + "Cell" + ], + "dataType": "Float", + "group": "Topography", + "main": true, + "optional": true, + "enabled": false, + "label": "Elevation channel", + "tooltip": "Set elevation from channel. If not set the topography will be set from the geometry of the selected 'topography' object", + "parent": "topography_object", + "dependency": "topography_object", + "dependencyType": "enabled", + "value": "", + "verbose": 2 + }, + "simulations": { + "main": true, + "label": "Simulations directory", + "directoryOnly": true, + "tootip": "Directory where pre-computed simulations are stored.", + "value": "./simulations" + }, + "out_group": { + "label": "UIJsonGroup", + "value": "", + "groupType": "{BB50AC61-A657-4926-9C82-067658E246A0}", + "visible": true, + "optional": true, + "enabled": false + } +} diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index 07386167..2ccb796c 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -15,16 +15,17 @@ import numpy as np from geoapps_utils.utils.importing import GeoAppsError +from geoapps_utils.utils.locations import topo_drape_elevation from geoapps_utils.utils.logger import get_logger +from geoapps_utils.utils.transformations import rotate_xyz from geoh5py import Workspace -from geoh5py.groups import UIJsonGroup +from geoh5py.groups import SimPEGGroup +from geoh5py.objects import AirborneTEMReceivers, Surface from geoh5py.shared.utils import ( - dict_to_json_str, fetch_active_workspace, - uuid_from_values, ) from geoh5py.ui_json.ui_json import BaseUIJson -from geoh5py.ui_json.utils import flatten +from scipy.spatial import cKDTree from typing_extensions import Self from simpeg_drivers.driver import BaseDriver @@ -34,7 +35,6 @@ logger = get_logger(name=__name__, level_name=False, propagate=False, add_name=False) -# TODO: Can we make this generic (PlateMatchDriver -> MatchDriver)? class PlateMatchDriver(BaseDriver): """Sets up and manages workers to run all combinations of swepts parameters.""" @@ -46,16 +46,16 @@ def __init__(self, params: MatchOptions, workers: list[tuple[str]] | None = None self.out_group = self.validate_out_group(self.params.out_group) @property - def out_group(self) -> UIJsonGroup: + def out_group(self) -> SimPEGGroup: """ Returns the output group for the simulation. """ return self._out_group @out_group.setter - def out_group(self, value: UIJsonGroup): - if not isinstance(value, UIJsonGroup): - raise TypeError("Output group must be a UIJsonGroup.") + def out_group(self, value: SimPEGGroup): + if not isinstance(value, SimPEGGroup): + raise TypeError("Output group must be a SimPEGGroup.") if self.params.out_group != value: self.params.out_group = value @@ -63,17 +63,17 @@ def out_group(self, value: UIJsonGroup): self._out_group = value - def validate_out_group(self, out_group: UIJsonGroup | None) -> UIJsonGroup: + def validate_out_group(self, out_group: SimPEGGroup | None) -> SimPEGGroup: """ - Validate or create a UIJsonGroup to store results. + Validate or create a SimPEGGroup to store results. - :param value: Output group from selection. + :param out_group: Output group from selection. """ - if isinstance(out_group, UIJsonGroup): + if isinstance(out_group, SimPEGGroup): return out_group with fetch_active_workspace(self.params.geoh5, mode="r+"): - out_group = UIJsonGroup.create( + out_group = SimPEGGroup.create( self.params.geoh5, name=self.params.title, ) @@ -111,7 +111,102 @@ def run(self): self.params.template.options["title"], ) + tree = cKDTree(self.params.survey.vertices[:, :2]) + + topo_z = ( + self.params.topography.values + if self.params.topography.values is not None + else self.params.topography_object.locations[:, 2] + ) + topo_drape_z = topo_drape_elevation( + self.params.survey.vertices, + self.params.topography_object.locations, + topo_z, + triangulation=self.params.topography_object.cells + if isinstance(self.params.topography_object, Surface) + else None, + ) + + for ii, query in enumerate(self.params.queries.vertices): + nearest = tree.query(query[:2], k=1)[0] + line_mask = np.where( + self.params.survey.parts == self.params.survey.parts[nearest] + )[0] + distances = np.linalg.norm( + self.params.survey.vertices[nearest, :2] + - self.params.survey.vertices[line_mask, :2], + axis=1, + ) + dist_mask = distances < self.params.max_distance + indices = line_mask[dist_mask] + + # Compute local coordinates for the current line segment + line_dist = distances[dist_mask] + line_dist[indices < nearest] *= -1.0 + local_xyz = np.c_[ + line_dist, + np.zeros_like(line_dist), + self.params.survey.vertices[indices, 2] - topo_drape_z[indices], + ] + + if self.params.strike_angles is not None: + angle = self.params.strike_angles[ii] + local_xyz = rotate_xyz( + local_xyz, [0, 0, 0], self.params.strike_angles[ii], 0 + ) + + # Convert to polar coordinates (distance, azimuth, height) + local_polar = np.c_[ + line_dist, + 90 - (np.rad2deg(np.arctan2(local_xyz[:, 0], local_xyz[:, 1])) % 180), + local_xyz[:, 2], + ] + + projection = None + data = {} + for file in self.params.simulations.iterdir(): + if Path(file).resolve().suffix == ".geoh5": + with Workspace(file, mode="r") as ws: + sim = next( + group + for group in ws.groups + if isinstance(group, SimPEGGroup) and "Plate" in group.name + ) + fwr = next( + child + for child in sim.children + if isinstance(child, SimPEGGroup) + ) + survey = next( + child + for child in fwr.children + if isinstance(child, AirborneTEMReceivers) + ) + group = survey.get_entity("Iteration_0_z")[0] + data[Path(file).stem] = group.table() + + # Create a projection matrix to interpolate simulated data to the observation locations + if projection is None: + dist = np.sign(survey.vertices[:, 0]) * np.linalg.norm( + survey.vertices[:, :2], axis=1 + ) + azm = ( + 90 + - np.rad2deg( + np.arctan2( + survey.vertices[:, 0], survey.vertices[:, 1] + ) + ) + % 180 + ).round(decimals=1) + height = (survey.vertices[:, 2]).round(decimals=1) + polar_coordinates = np.c_[dist, height, azm] + + shape = (-1, len(np.unique(azm)), len(np.unique(height))) + polar_coordinates.reshape(shape) + if __name__ == "__main__": - file = Path(sys.argv[1]) + # file = Path(sys.argv[1]) + file = Path(r"C:\Users\dominiquef\Documents\Workspace\Teck\RnD\plate_match.ui.json") PlateMatchDriver.start(file) diff --git a/simpeg_drivers/plate_simulation/match/options.py b/simpeg_drivers/plate_simulation/match/options.py index abaabb3d..ad0308a7 100644 --- a/simpeg_drivers/plate_simulation/match/options.py +++ b/simpeg_drivers/plate_simulation/match/options.py @@ -14,12 +14,10 @@ import numpy as np from geoapps_utils.base import Options -from geoh5py.groups import PropertyGroup, UIJsonGroup -from geoh5py.objects import Points +from geoh5py.groups import PropertyGroup, SimPEGGroup +from geoh5py.objects import Grid2D, Points from geoh5py.objects.surveys.electromagnetics.airborne_tem import AirborneTEMReceivers -from geoh5py.shared.utils import stringify -from geoh5py.ui_json import InputFile -from pydantic import BaseModel, ConfigDict, field_serializer +from pydantic import ConfigDict from simpeg_drivers import assets_path @@ -30,7 +28,7 @@ class MatchOptions(Options): :param survey: A Time-Domain Airborne TEM survey object. :param data: A property group containing observed data. - :param targets: A Points object containing the target locations. + :param queries: A Points object containing the target locations. :param strike_angles: An optional data array containing strike angles for each target location. :param simulations: Directory to store simulation files. @@ -42,10 +40,13 @@ class MatchOptions(Options): default_ui_json: ClassVar[Path] = assets_path() / "uijson/plate_match.ui.json" title: ClassVar[str] = "Plate Match" run_command: ClassVar[str] = "simpeg_drivers.plate_simulation.match.driver" - out_group: UIJsonGroup | None = None + out_group: SimPEGGroup | None = None survey: AirborneTEMReceivers data: PropertyGroup - targets: Points + queries: Points strike_angles: np.ndarray | None = None + max_distance: float = 1000.0 + topography_object: Points | Grid2D + topography: np.ndarray | None = None simulations: ClassVar[Path] diff --git a/simpeg_drivers/plate_simulation/match/uijson.py b/simpeg_drivers/plate_simulation/match/uijson.py new file mode 100644 index 00000000..e2fc3c23 --- /dev/null +++ b/simpeg_drivers/plate_simulation/match/uijson.py @@ -0,0 +1,26 @@ +# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +# Copyright (c) 2023-2026 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 geoh5py.ui_json.forms import DataForm, FloatForm, ObjectForm, StringForm +from geoh5py.ui_json.ui_json import BaseUIJson +from pydantic import ConfigDict + + +class PlateMatchUIJson(BaseUIJson): + model_config = ConfigDict(arbitrary_types_allowed=True) + + survey: ObjectForm + data: DataForm + queries: ObjectForm + strike_angles: DataForm + max_distance: FloatForm + topography_object: ObjectForm + topography: DataForm + simulations: StringForm From afd31c4061f946e8b5382bb8977a3c1d7df9cd58 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Thu, 15 Jan 2026 20:29:15 -0800 Subject: [PATCH 03/24] First full run --- .../uijson/plate_match.ui.json | 4 +- .../plate_simulation/match/driver.py | 346 +++++++++++++----- .../plate_simulation/match/options.py | 18 +- 3 files changed, 268 insertions(+), 100 deletions(-) diff --git a/simpeg_drivers-assets/uijson/plate_match.ui.json b/simpeg_drivers-assets/uijson/plate_match.ui.json index 86ec9a2d..04a42d51 100644 --- a/simpeg_drivers-assets/uijson/plate_match.ui.json +++ b/simpeg_drivers-assets/uijson/plate_match.ui.json @@ -4,7 +4,7 @@ "icon": "maxwellplate", "documentation": "https://mirageoscience-simpeg-drivers.readthedocs-hosted.com/en/latest/plate-simulation/", "conda_environment": "simpeg_drivers", - "run_command": "simpeg_drivers.driver", + "run_command": "simpeg_drivers.plate_simulation.match.driver", "geoh5": "", "monitoring_directory": "", "inversion_type": "plate match", @@ -103,7 +103,7 @@ "out_group": { "label": "UIJsonGroup", "value": "", - "groupType": "{BB50AC61-A657-4926-9C82-067658E246A0}", + "groupType": "{55ed3daf-c192-4d4b-a439-60fa987fe2b8}", "visible": true, "optional": true, "enabled": false diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index 2ccb796c..797a0743 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -17,21 +17,28 @@ from geoapps_utils.utils.importing import GeoAppsError from geoapps_utils.utils.locations import topo_drape_elevation from geoapps_utils.utils.logger import get_logger -from geoapps_utils.utils.transformations import rotate_xyz +from geoapps_utils.utils.plotting import symlog from geoh5py import Workspace -from geoh5py.groups import SimPEGGroup +from geoh5py.groups import PropertyGroup, SimPEGGroup from geoh5py.objects import AirborneTEMReceivers, Surface from geoh5py.shared.utils import ( fetch_active_workspace, ) +from geoh5py.ui_json import InputFile from geoh5py.ui_json.ui_json import BaseUIJson +from scipy import signal +from scipy.sparse import csr_matrix, diags from scipy.spatial import cKDTree +from tqdm import tqdm from typing_extensions import Self from simpeg_drivers.driver import BaseDriver from simpeg_drivers.plate_simulation.match.options import MatchOptions +from simpeg_drivers.plate_simulation.options import PlateSimulationOptions +# import matplotlib.pyplot as plt + logger = get_logger(name=__name__, level_name=False, propagate=False, add_name=False) @@ -43,6 +50,8 @@ class PlateMatchDriver(BaseDriver): def __init__(self, params: MatchOptions, workers: list[tuple[str]] | None = None): super().__init__(params, workers=workers) + self._drape_heights = self.set_drape_height() + self.out_group = self.validate_out_group(self.params.out_group) @property @@ -82,15 +91,16 @@ def validate_out_group(self, out_group: SimPEGGroup | None) -> SimPEGGroup: return out_group @classmethod - def start(cls, filepath: str | Path, mode="r", **_) -> Self: + def start(cls, filepath: str | Path, mode="r+", **_) -> Self: """Start the parameter matching from a ui.json file.""" logger.info("Loading input file . . .") filepath = Path(filepath).resolve() - uijson = BaseUIJson.read(filepath) + # uijson = BaseUIJson.read(filepath) + uijson = InputFile.read_ui_json(filepath) - with Workspace(uijson.geoh5, mode=mode) as workspace: + with uijson.geoh5.open(mode=mode): try: - options = MatchOptions.build(uijson.to_params(workspace=workspace)) + options = MatchOptions.build(uijson) logger.info("Initializing application . . .") driver = cls(options) logger.info("Running application . . .") @@ -103,110 +113,256 @@ def start(cls, filepath: str | Path, mode="r", **_) -> Self: return driver - def run(self): - """Loop over all trials and run a worker for each unique parameter set.""" + def set_drape_height(self) -> np.ndarray: + """Set drape heights based on topography object and optional topography data.""" - logger.info( - "Running %s . . .", - self.params.template.options["title"], - ) + topo = self.params.topography_object.locations - tree = cKDTree(self.params.survey.vertices[:, :2]) + if self.params.topography is not None: + topo[:, 2] = self.params.topography.values - topo_z = ( - self.params.topography.values - if self.params.topography.values is not None - else self.params.topography_object.locations[:, 2] - ) topo_drape_z = topo_drape_elevation( self.params.survey.vertices, - self.params.topography_object.locations, - topo_z, + topo, triangulation=self.params.topography_object.cells if isinstance(self.params.topography_object, Surface) else None, ) + return topo_drape_z[:, 2] + + def normalized_data(self, property_group: PropertyGroup, threshold=5) -> np.ndarray: + """ + Return data from a property group with symlog scaling and zero mean. + + :param property_group: Property group containing data channels. + :param threshold: Percentile threshold for symlog normalization. + + :return: Normalized data array. + """ + table = property_group.table() + data_array = np.vstack([table[name] for name in table.dtype.names]) + thresh = np.percentile(np.abs(data_array), threshold) + log_data = symlog(data_array, thresh) + return log_data - np.mean(log_data, axis=1)[:, None] + + def fetch_survey(self, workspace: Workspace) -> AirborneTEMReceivers | None: + """Fetch the survey from the workspace.""" + for group in workspace.groups: + if isinstance(group, SimPEGGroup): + for child in group.children: + if isinstance(child, AirborneTEMReceivers): + return child + + return None + + def spatial_interpolation( + self, + indices: np.ndarray, + locations: np.ndarray, + strike_angle: float | None = None, + ) -> csr_matrix: + """ + Create a spatial interpolation matrix from simulation to observation locations. + + :param indices: Indices for the line segment of the observation locations. + :param locations: Positions to interpolate from. + :param strike_angle: Optional strike angle to correct azimuths. + + :return: Spatial interpolation matrix. + """ + # Compute local coordinates for the current line segment + local_polar = self.xyz_to_polar(self.params.survey.vertices[indices, :]) + local_polar[:, 1] = ( + 0.0 if strike_angle is None else strike_angle + ) # Align azimuths to zero + + # Convert to polar coordinates (distance, azimuth, height) + query_polar = self.xyz_to_polar(locations) + + # Get the 8 nearest neighbors in the simulation to each observation point + sim_tree = cKDTree(query_polar) + rad, inds = sim_tree.query(local_polar, k=8) + + weights = (rad**2.0 + 1e-1) ** -1 + row_ids = np.kron(np.arange(local_polar.shape[0]), np.ones(8)) + inv_dist_op = csr_matrix( + (weights.flatten(), (row_ids, np.hstack(inds.flatten()))), + shape=(local_polar.shape[0], locations.shape[0]), + ) + + # Normalize the rows + row_sum = np.asarray(inv_dist_op.sum(axis=1)).flatten() ** -1.0 + return diags(row_sum) @ inv_dist_op + + @staticmethod + def xyz_to_polar(xyz: np.ndarray) -> np.ndarray: + """ + Convert Cartesian coordinates to polar coordinates defined as + (distance, azimuth, height), where distance is signed based on the + x-coordinate relative to the mean location. + + :param xyz: Cartesian coordinates. + + :return: Polar coordinates (distance, azimuth, height). + """ + mean_loc = np.mean(xyz, axis=0) + distances = np.sign(xyz[:, 0] - mean_loc[0]) * np.linalg.norm( + xyz[:, :2] - mean_loc[:2], axis=1 + ) + azimuths = 90 - (np.rad2deg(np.arctan2(xyz[:, 0], xyz[:, 1])) % 180) + return np.c_[distances, azimuths, xyz[:, 2]] + + @staticmethod + def time_interpolation( + query_times: np.ndarray, sim_times: np.ndarray + ) -> csr_matrix: + """ + Create a time interpolation matrix from simulation to observation times. + + :param query_times: Observation times. + :param sim_times: Simulation times. + + :return: Time interpolation matrix. + """ + right = np.searchsorted(sim_times, query_times) + + inds = np.r_[right - 1, right] + + row_ids = np.tile(np.arange(len(query_times)), 2) + weights = (np.abs(query_times[row_ids] - sim_times[inds]) + 1e-12) ** -1 + + time_projection = csr_matrix( + (weights.flatten(), (row_ids, np.hstack(inds.flatten()))), + shape=(len(query_times), len(sim_times)), + ) + row_sum = np.asarray(time_projection.sum(axis=1)).flatten() ** -1.0 + return diags(row_sum) @ time_projection + + def get_segment_indices(self, nearest: int) -> np.ndarray: + """ + Get indices of line segment for a given nearest vertex. + + :param nearest: Nearest vertex index. + """ + line_mask = np.where( + self.params.survey.parts == self.params.survey.parts[nearest] + )[0] + distances = np.linalg.norm( + self.params.survey.vertices[nearest, :2] + - self.params.survey.vertices[line_mask, :2], + axis=1, + ) + dist_mask = distances < self.params.max_distance + indices = line_mask[dist_mask] + return indices + + def run(self): + """Loop over all trials and run a worker for each unique parameter set.""" + + logger.info( + "Running %s . . .", + self.params.title, + ) + observed = self.normalized_data(self.params.data) + + scores = [] + files_id = [] + tree = cKDTree(self.params.survey.vertices[:, :2]) + spatial_projection = None + time_projection = None for ii, query in enumerate(self.params.queries.vertices): - nearest = tree.query(query[:2], k=1)[0] - line_mask = np.where( - self.params.survey.parts == self.params.survey.parts[nearest] - )[0] - distances = np.linalg.norm( - self.params.survey.vertices[nearest, :2] - - self.params.survey.vertices[line_mask, :2], - axis=1, - ) - dist_mask = distances < self.params.max_distance - indices = line_mask[dist_mask] - - # Compute local coordinates for the current line segment - line_dist = distances[dist_mask] - line_dist[indices < nearest] *= -1.0 - local_xyz = np.c_[ - line_dist, - np.zeros_like(line_dist), - self.params.survey.vertices[indices, 2] - topo_drape_z[indices], - ] - - if self.params.strike_angles is not None: - angle = self.params.strike_angles[ii] - local_xyz = rotate_xyz( - local_xyz, [0, 0, 0], self.params.strike_angles[ii], 0 - ) - - # Convert to polar coordinates (distance, azimuth, height) - local_polar = np.c_[ - line_dist, - 90 - (np.rad2deg(np.arctan2(local_xyz[:, 0], local_xyz[:, 1])) % 180), - local_xyz[:, 2], - ] - - projection = None - data = {} - for file in self.params.simulations.iterdir(): - if Path(file).resolve().suffix == ".geoh5": - with Workspace(file, mode="r") as ws: - sim = next( - group - for group in ws.groups - if isinstance(group, SimPEGGroup) and "Plate" in group.name + for sim_file in tqdm(self.params.simulation_files): + with Workspace(sim_file, mode="r") as ws: + survey = self.fetch_survey(ws) + + if survey is None: + logger.warning("No survey found in %s, skipping.", sim_file) + continue + + simulated = self.normalized_data( + survey.get_entity("Iteration_0_z")[0] + ) + + # Create a projection matrix to interpolate simulated data to the observation locations + # Assume that lines of simulations are centered at origin + if spatial_projection is None: + nearest = tree.query(query[:2], k=1)[1] + indices = self.get_segment_indices(nearest) + spatial_projection = self.spatial_interpolation( + indices, + survey.vertices, + self.params.strike_angles.values[ii], ) - fwr = next( - child - for child in sim.children - if isinstance(child, SimPEGGroup) + + if time_projection is None: + query_times = np.asarray(self.params.survey.channels) + simulated_times = np.asarray(survey.channels) + + # Only interpolate for times within the simulated range + time_mask = (query_times > simulated_times.min()) & ( + query_times < simulated_times.max() ) - survey = next( - child - for child in fwr.children - if isinstance(child, AirborneTEMReceivers) + time_projection = self.time_interpolation( + query_times[time_mask], simulated_times ) - group = survey.get_entity("Iteration_0_z")[0] - data[Path(file).stem] = group.table() - - # Create a projection matrix to interpolate simulated data to the observation locations - if projection is None: - dist = np.sign(survey.vertices[:, 0]) * np.linalg.norm( - survey.vertices[:, :2], axis=1 - ) - azm = ( - 90 - - np.rad2deg( - np.arctan2( - survey.vertices[:, 0], survey.vertices[:, 1] - ) - ) - % 180 - ).round(decimals=1) - height = (survey.vertices[:, 2]).round(decimals=1) - polar_coordinates = np.c_[dist, height, azm] - - shape = (-1, len(np.unique(azm)), len(np.unique(height))) - polar_coordinates.reshape(shape) + observed = observed[time_mask, :] + + pred = time_projection @ (spatial_projection @ simulated.T).T + + score = 0.0 + + # if sim_file.stem == "0e50d2da-7ab0-5484-9ffd-365f076cce98": + # + # fig, ax = plt.figure(), plt.subplot() + + # Metric: normalized cross-correlation + for obs, pre in zip(observed[:, indices], pred, strict=True): + # Full cross-correlation + corr = signal.correlate( + obs, pre, mode="full" + ) # corr[k] ~ sum_t y[t] * x[t - k] + # Normalize by energy to get correlation coefficient in [-1, 1] + denom = np.linalg.norm(pre) * np.linalg.norm(obs) + if denom == 0: + corr_norm = np.zeros_like(corr) + else: + corr_norm = corr / denom + + score += np.max(corr_norm) + # if sim_file.stem == "0e50d2da-7ab0-5484-9ffd-365f076cce98": + # ax.plot(obs , 'r') + # ax.plot(pre, 'k') + + # if sim_file.stem == "0e50d2da-7ab0-5484-9ffd-365f076cce98": + # plt.show() + + scores.append(score) + files_id.append(sim_file) + + spatial_projection = None + time_projection = None + + ranked = np.argsort(scores) + print("Top 3 matches:") + for rank in ranked[-1:][::-1]: + print(f"File: {files_id[rank].stem:30s} Score: {scores[rank]:.4f}") + with Workspace(files_id[rank], mode="r") as ws: + survey = self.fetch_survey(ws) + ui_json = survey.parent.parent.options + ui_json["geoh5"] = ws + ifile = InputFile(ui_json=ui_json) + options = PlateSimulationOptions.build(ifile) + + plate = survey.parent.parent.get_entity("plate")[0].copy( + parent=self.params.out_group + ) + plate.vertices = plate.vertices + query + + print(f"Best parameters:{options.model.model_dump_json(indent=2)}") if __name__ == "__main__": - # file = Path(sys.argv[1]) - file = Path(r"C:\Users\dominiquef\Documents\Workspace\Teck\RnD\plate_match.ui.json") + file = Path(sys.argv[1]) + # file = Path(r"C:\Users\dominiquef\Documents\Workspace\Teck\RnD\plate_match_v2.ui.json") PlateMatchDriver.start(file) diff --git a/simpeg_drivers/plate_simulation/match/options.py b/simpeg_drivers/plate_simulation/match/options.py index ad0308a7..2d5a32c8 100644 --- a/simpeg_drivers/plate_simulation/match/options.py +++ b/simpeg_drivers/plate_simulation/match/options.py @@ -14,6 +14,7 @@ import numpy as np from geoapps_utils.base import Options +from geoh5py.data import FloatData from geoh5py.groups import PropertyGroup, SimPEGGroup from geoh5py.objects import Grid2D, Points from geoh5py.objects.surveys.electromagnetics.airborne_tem import AirborneTEMReceivers @@ -45,8 +46,19 @@ class MatchOptions(Options): survey: AirborneTEMReceivers data: PropertyGroup queries: Points - strike_angles: np.ndarray | None = None + strike_angles: FloatData | None = None max_distance: float = 1000.0 topography_object: Points | Grid2D - topography: np.ndarray | None = None - simulations: ClassVar[Path] + topography: FloatData | None = None + simulations: str + + @property + def simulation_files(self) -> list[Path]: + """Path to simulation files directory.""" + sim_dir = self.geoh5.h5file.parent / self.simulations + simulation_files = [] + for file in sim_dir.iterdir(): + if Path(file).resolve().suffix == ".geoh5": + simulation_files.append(Path(file)) + + return simulation_files From 5bea23ca37de507d76bf5e92f2c6947aa105b19c Mon Sep 17 00:00:00 2001 From: dominiquef Date: Thu, 15 Jan 2026 20:36:41 -0800 Subject: [PATCH 04/24] Fix to run from main driver --- simpeg_drivers-assets/uijson/plate_match.ui.json | 1 + simpeg_drivers/__init__.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/simpeg_drivers-assets/uijson/plate_match.ui.json b/simpeg_drivers-assets/uijson/plate_match.ui.json index 04a42d51..e536f3fd 100644 --- a/simpeg_drivers-assets/uijson/plate_match.ui.json +++ b/simpeg_drivers-assets/uijson/plate_match.ui.json @@ -8,6 +8,7 @@ "geoh5": "", "monitoring_directory": "", "inversion_type": "plate match", + "forward_only": true, "survey": { "main": true, "label": "Survey", diff --git a/simpeg_drivers/__init__.py b/simpeg_drivers/__init__.py index 09790b88..a2aefb59 100644 --- a/simpeg_drivers/__init__.py +++ b/simpeg_drivers/__init__.py @@ -176,4 +176,8 @@ def assets_path() -> Path: "simpeg_drivers.plate_simulation.sweep.driver", {"forward": "PlateSweepDriver"}, ), + "plate match": ( + "simpeg_drivers.plate_simulation.match.driver", + {"forward": "PlateMatchDriver"}, + ), } From 66c0e3fc66f5ee1c906de5f1a4d0d7b49051c7b1 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Thu, 15 Jan 2026 20:39:00 -0800 Subject: [PATCH 05/24] Attach plate simulation params to plate surface --- simpeg_drivers/plate_simulation/match/driver.py | 1 + 1 file changed, 1 insertion(+) diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index 797a0743..e443734f 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -358,6 +358,7 @@ def run(self): parent=self.params.out_group ) plate.vertices = plate.vertices + query + plate.metadata = options.model.model_dump() print(f"Best parameters:{options.model.model_dump_json(indent=2)}") From 65c4c9d751ea679b3b303c3410064a2861e87224 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 16 Jan 2026 12:44:07 -0800 Subject: [PATCH 06/24] Re jig dask setup on base class. Parallel run on plate_sim.match --- simpeg_drivers/driver.py | 133 ++++--- .../electromagnetics/base_1d_driver.py | 24 ++ .../plate_simulation/match/driver.py | 337 ++++++++++-------- 3 files changed, 282 insertions(+), 212 deletions(-) diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 8867a5d5..90978e0a 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -16,21 +16,17 @@ import cProfile import pstats -import multiprocessing import contextlib from copy import deepcopy import sys from datetime import datetime, timedelta import logging -from multiprocessing.pool import ThreadPool from pathlib import Path from time import time from typing_extensions import Self import numpy as np -from dask import config as dconf - from dask.distributed import get_client, Client, LocalCluster, performance_report from geoapps_utils.base import Driver, Options @@ -41,7 +37,6 @@ from geoh5py.groups import SimPEGGroup from geoh5py.objects import FEMSurvey from geoh5py.shared.utils import fetch_active_workspace -from geoh5py.shared.exceptions import Geoh5FileClosedError from geoh5py.ui_json import InputFile from simpeg import ( @@ -158,6 +153,62 @@ def validate_workers(self, workers: list[tuple[str]] | None) -> list[tuple[str]] return workers + @classmethod + def start_dask_run( + cls, + ifile, + n_workers: int | None = None, + n_threads: int | None = None, + save_report: bool = True, + ): + """ + Sets Dask config settings. + + :param ifile: Input file path. + :param n_workers: Number of Dask workers. + :param n_threads: Number of threads per Dask worker. + :param save_report: Whether to save a performance report. + """ + distributed_process = ( + n_workers is not None and n_workers > 1 + ) or n_threads is not None + + cluster = ( + LocalCluster( + processes=True, + n_workers=n_workers, + threads_per_worker=n_threads, + ) + if distributed_process + else None + ) + profiler = cProfile.Profile() + profiler.enable() + + with ( + cluster.get_client() + if cluster is not None + else contextlib.nullcontext() as context_client + ): + # Full run + with ( + performance_report(filename=ifile.parent / "dask_profile.html") + if (save_report and isinstance(context_client, Client)) + else contextlib.nullcontext() + ): + cls.start(ifile) + sys.stdout.close() + + profiler.disable() + + if save_report: + with open( + ifile.parent / "runtime_profile.txt", encoding="utf-8", mode="w" + ) as s: + ps = pstats.Stats(profiler, stream=s) + ps.sort_stats("cumulative") + ps.print_stats() + class InversionDriver(BaseDriver): _params_class = BaseForwardOptions | BaseInversionOptions @@ -485,8 +536,6 @@ def run(self): sys.stdout = self.logger self.logger.start() - self.configure_dask() - with fetch_active_workspace(self.workspace, mode="r+"): simpeg_inversion = self.inversion @@ -728,18 +777,6 @@ def get_tiles(self): sorting=self.simulation.survey.sorting, ) - def configure_dask(self): - """Sets Dask config settings.""" - - if self.client: - dconf.set(scheduler=self.client) - else: - n_cpu = self.params.compute.n_cpu - if n_cpu is None: - n_cpu = int(multiprocessing.cpu_count()) - - dconf.set(scheduler="threads", pool=ThreadPool(n_cpu)) - @classmethod def start(cls, filepath: str | Path | InputFile, **kwargs) -> Self: """ @@ -840,57 +877,11 @@ def get_path(self, filepath: str | Path) -> str: if __name__ == "__main__": file = Path(sys.argv[1]).resolve() input_file = load_ui_json_as_dict(file) - n_workers = input_file.get("n_workers", None) - n_threads = input_file.get("n_threads", None) - save_report = input_file.get("performance_report", False) - - # Force distributed on 1D problems - if "1D" in input_file.get("title") and n_workers is None: - cpu_count = multiprocessing.cpu_count() - - if cpu_count < 16: - n_threads = n_threads or 2 - else: - n_threads = n_threads or 4 - - n_workers = cpu_count // n_threads - - distributed_process = ( - n_workers is not None and n_workers > 1 - ) or n_threads is not None - + # Need to know the driver class before starting dask driver_class = InversionDriver.from_input_file(input_file) - - cluster = ( - LocalCluster( - processes=True, - n_workers=n_workers, - threads_per_worker=n_threads, - ) - if distributed_process - else None + driver_class.start_dask_run( + file, + n_workers=input_file.get("n_workers", None), + n_threads=input_file.get("n_threads", None), + save_report=input_file.get("performance_report", False), ) - profiler = cProfile.Profile() - profiler.enable() - - with ( - cluster.get_client() - if cluster is not None - else contextlib.nullcontext() as context_client - ): - # Full run - with ( - performance_report(filename=file.parent / "dask_profile.html") - if (save_report and isinstance(context_client, Client)) - else contextlib.nullcontext() - ): - driver_class.start(file) - sys.stdout.close() - - profiler.disable() - - if save_report: - with open(file.parent / "runtime_profile.txt", encoding="utf-8", mode="w") as s: - ps = pstats.Stats(profiler, stream=s) - ps.sort_stats("cumulative") - ps.print_stats() diff --git a/simpeg_drivers/electromagnetics/base_1d_driver.py b/simpeg_drivers/electromagnetics/base_1d_driver.py index 7d5bed8f..c0c95771 100644 --- a/simpeg_drivers/electromagnetics/base_1d_driver.py +++ b/simpeg_drivers/electromagnetics/base_1d_driver.py @@ -125,3 +125,27 @@ def workers(self): else: self._workers = np.arange(multiprocessing.cpu_count()).tolist() return self._workers + + @classmethod + def start_dask_run( + cls, + ifile, + n_workers: int | None = None, + n_threads: int | None = None, + save_report: bool = True, + ): + """Overload configurations of BaseDriver Dask config settings.""" + # Force distributed on 1D problems + if n_workers is None: + cpu_count = multiprocessing.cpu_count() + + if cpu_count < 16: + n_threads = n_threads or 2 + else: + n_threads = n_threads or 4 + + n_workers = cpu_count // n_threads + + super().start_dask_run( + ifile, n_workers=n_workers, n_threads=n_threads, save_report=save_report + ) diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index e443734f..bd6820ba 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -10,10 +10,13 @@ from __future__ import annotations +import multiprocessing import sys from pathlib import Path +from time import time import numpy as np +from geoapps_utils.run import load_ui_json_as_dict from geoapps_utils.utils.importing import GeoAppsError from geoapps_utils.utils.locations import topo_drape_elevation from geoapps_utils.utils.logger import get_logger @@ -25,15 +28,15 @@ fetch_active_workspace, ) from geoh5py.ui_json import InputFile -from geoh5py.ui_json.ui_json import BaseUIJson from scipy import signal from scipy.sparse import csr_matrix, diags from scipy.spatial import cKDTree -from tqdm import tqdm from typing_extensions import Self from simpeg_drivers.driver import BaseDriver from simpeg_drivers.plate_simulation.match.options import MatchOptions + +# from simpeg_drivers.plate_simulation.match.uijson import PlateMatchUIJson from simpeg_drivers.plate_simulation.options import PlateSimulationOptions @@ -51,9 +54,60 @@ def __init__(self, params: MatchOptions, workers: list[tuple[str]] | None = None super().__init__(params, workers=workers) self._drape_heights = self.set_drape_height() - + self._template = self.get_template() + self._time_mask, self._time_projection = self.time_mask_and_projection() self.out_group = self.validate_out_group(self.params.out_group) + def get_template(self): + """ + Get a template simulation to extract time sampling. + """ + with Workspace(self.params.simulation_files[0], mode="r") as ws: + survey = fetch_survey(ws) + if survey.channels is None: + raise GeoAppsError( + f"No time channels found in survey of {self.params.simulation_files[0]}" + ) + + if survey.vertices is None: + raise GeoAppsError( + f"No receiver locations found in survey of {self.params.simulation_files[0]}" + ) + + return survey + + def time_mask_and_projection(self) -> tuple[np.ndarray, csr_matrix]: + """ + Create a time mask and interpolation matrix from simulation to observation times. + + Assumes that all simulations in the directory have the same time sampling. + + :return: Time mask and time interpolation matrix. + """ + + simulated_times = np.asarray(self._template.channels) + + query_times = np.asarray(self.params.survey.channels) + # Only interpolate for times within the simulated range + time_mask = (query_times > simulated_times.min()) & ( + query_times < simulated_times.max() + ) + query_times = query_times[time_mask] + right = np.searchsorted(simulated_times, query_times) + inds = np.r_[right - 1, right] + row_ids = np.tile(np.arange(len(query_times)), 2) + + # Create inverse distance weighting matrix + weights = (np.abs(query_times[row_ids] - simulated_times[inds]) + 1e-12) ** -1 + time_projection = csr_matrix( + (weights.flatten(), (row_ids, np.hstack(inds.flatten()))), + shape=(len(query_times), len(simulated_times)), + ) + row_sum = np.asarray(time_projection.sum(axis=1)).flatten() ** -1.0 + time_projection = diags(row_sum) @ time_projection + + return time_mask, time_projection + @property def out_group(self) -> SimPEGGroup: """ @@ -95,7 +149,9 @@ def start(cls, filepath: str | Path, mode="r+", **_) -> Self: """Start the parameter matching from a ui.json file.""" logger.info("Loading input file . . .") filepath = Path(filepath).resolve() - # uijson = BaseUIJson.read(filepath) + + # TODO: Replace with UIJson when fully implemented + # uijson = PlateMatchUIJson.read(filepath) uijson = InputFile.read_ui_json(filepath) with uijson.geoh5.open(mode=mode): @@ -130,42 +186,15 @@ def set_drape_height(self) -> np.ndarray: ) return topo_drape_z[:, 2] - def normalized_data(self, property_group: PropertyGroup, threshold=5) -> np.ndarray: - """ - Return data from a property group with symlog scaling and zero mean. - - :param property_group: Property group containing data channels. - :param threshold: Percentile threshold for symlog normalization. - - :return: Normalized data array. - """ - table = property_group.table() - data_array = np.vstack([table[name] for name in table.dtype.names]) - thresh = np.percentile(np.abs(data_array), threshold) - log_data = symlog(data_array, thresh) - return log_data - np.mean(log_data, axis=1)[:, None] - - def fetch_survey(self, workspace: Workspace) -> AirborneTEMReceivers | None: - """Fetch the survey from the workspace.""" - for group in workspace.groups: - if isinstance(group, SimPEGGroup): - for child in group.children: - if isinstance(child, AirborneTEMReceivers): - return child - - return None - def spatial_interpolation( self, indices: np.ndarray, - locations: np.ndarray, strike_angle: float | None = None, ) -> csr_matrix: """ Create a spatial interpolation matrix from simulation to observation locations. :param indices: Indices for the line segment of the observation locations. - :param locations: Positions to interpolate from. :param strike_angle: Optional strike angle to correct azimuths. :return: Spatial interpolation matrix. @@ -177,7 +206,7 @@ def spatial_interpolation( ) # Align azimuths to zero # Convert to polar coordinates (distance, azimuth, height) - query_polar = self.xyz_to_polar(locations) + query_polar = self.xyz_to_polar(self._template.vertices) # Get the 8 nearest neighbors in the simulation to each observation point sim_tree = cKDTree(query_polar) @@ -187,7 +216,7 @@ def spatial_interpolation( row_ids = np.kron(np.arange(local_polar.shape[0]), np.ones(8)) inv_dist_op = csr_matrix( (weights.flatten(), (row_ids, np.hstack(inds.flatten()))), - shape=(local_polar.shape[0], locations.shape[0]), + shape=(local_polar.shape[0], self._template.vertices.shape[0]), ) # Normalize the rows @@ -213,32 +242,6 @@ def xyz_to_polar(xyz: np.ndarray) -> np.ndarray: azimuths = 90 - (np.rad2deg(np.arctan2(xyz[:, 0], xyz[:, 1])) % 180) return np.c_[distances, azimuths, xyz[:, 2]] - @staticmethod - def time_interpolation( - query_times: np.ndarray, sim_times: np.ndarray - ) -> csr_matrix: - """ - Create a time interpolation matrix from simulation to observation times. - - :param query_times: Observation times. - :param sim_times: Simulation times. - - :return: Time interpolation matrix. - """ - right = np.searchsorted(sim_times, query_times) - - inds = np.r_[right - 1, right] - - row_ids = np.tile(np.arange(len(query_times)), 2) - weights = (np.abs(query_times[row_ids] - sim_times[inds]) + 1e-12) ** -1 - - time_projection = csr_matrix( - (weights.flatten(), (row_ids, np.hstack(inds.flatten()))), - shape=(len(query_times), len(sim_times)), - ) - row_sum = np.asarray(time_projection.sum(axis=1)).flatten() ** -1.0 - return diags(row_sum) @ time_projection - def get_segment_indices(self, nearest: int) -> np.ndarray: """ Get indices of line segment for a given nearest vertex. @@ -259,96 +262,49 @@ def get_segment_indices(self, nearest: int) -> np.ndarray: def run(self): """Loop over all trials and run a worker for each unique parameter set.""" - logger.info( "Running %s . . .", self.params.title, ) - observed = self.normalized_data(self.params.data) - - scores = [] - files_id = [] + observed = normalized_data(self.params.data)[self._time_mask, :] tree = cKDTree(self.params.survey.vertices[:, :2]) - spatial_projection = None - time_projection = None - for ii, query in enumerate(self.params.queries.vertices): - for sim_file in tqdm(self.params.simulation_files): - with Workspace(sim_file, mode="r") as ws: - survey = self.fetch_survey(ws) - if survey is None: - logger.warning("No survey found in %s, skipping.", sim_file) - continue + for ii, query in enumerate(self.params.queries.vertices): + tasks = [] + nearest = tree.query(query[:2], k=1)[1] + indices = self.get_segment_indices(nearest) + spatial_projection = self.spatial_interpolation( + indices, + self.params.strike_angles.values[ii], + ) - simulated = self.normalized_data( - survey.get_entity("Iteration_0_z")[0] + file_split = np.array_split(self.params.simulation_files, len(self.workers)) + + ct = time() + for file_batch in file_split: + tasks.append( + self.client.submit( + process_files_batch, + file_batch, + spatial_projection, + self._time_projection, + observed[:, indices], ) + ) - # Create a projection matrix to interpolate simulated data to the observation locations - # Assume that lines of simulations are centered at origin - if spatial_projection is None: - nearest = tree.query(query[:2], k=1)[1] - indices = self.get_segment_indices(nearest) - spatial_projection = self.spatial_interpolation( - indices, - survey.vertices, - self.params.strike_angles.values[ii], - ) - - if time_projection is None: - query_times = np.asarray(self.params.survey.channels) - simulated_times = np.asarray(survey.channels) - - # Only interpolate for times within the simulated range - time_mask = (query_times > simulated_times.min()) & ( - query_times < simulated_times.max() - ) - time_projection = self.time_interpolation( - query_times[time_mask], simulated_times - ) - observed = observed[time_mask, :] - - pred = time_projection @ (spatial_projection @ simulated.T).T - - score = 0.0 - - # if sim_file.stem == "0e50d2da-7ab0-5484-9ffd-365f076cce98": - # - # fig, ax = plt.figure(), plt.subplot() - - # Metric: normalized cross-correlation - for obs, pre in zip(observed[:, indices], pred, strict=True): - # Full cross-correlation - corr = signal.correlate( - obs, pre, mode="full" - ) # corr[k] ~ sum_t y[t] * x[t - k] - # Normalize by energy to get correlation coefficient in [-1, 1] - denom = np.linalg.norm(pre) * np.linalg.norm(obs) - if denom == 0: - corr_norm = np.zeros_like(corr) - else: - corr_norm = corr / denom - - score += np.max(corr_norm) - # if sim_file.stem == "0e50d2da-7ab0-5484-9ffd-365f076cce98": - # ax.plot(obs , 'r') - # ax.plot(pre, 'k') - - # if sim_file.stem == "0e50d2da-7ab0-5484-9ffd-365f076cce98": - # plt.show() - - scores.append(score) - files_id.append(sim_file) - - spatial_projection = None - time_projection = None + scores = np.hstack(self.client.gather(tasks)) + print(f"Processing time: {time() - ct:.1f} seconds") ranked = np.argsort(scores) - print("Top 3 matches:") + for rank in ranked[-1:][::-1]: - print(f"File: {files_id[rank].stem:30s} Score: {scores[rank]:.4f}") - with Workspace(files_id[rank], mode="r") as ws: - survey = self.fetch_survey(ws) + logger.info( + "File: %s \nScore: %.4f", + self.params.simulation_files[rank].name, + scores[rank], + ) + with Workspace(self.params.simulation_files[rank], mode="r") as ws: + survey = fetch_survey(ws) ui_json = survey.parent.parent.options ui_json["geoh5"] = ws ifile = InputFile(ui_json=ui_json) @@ -357,13 +313,112 @@ def run(self): plate = survey.parent.parent.get_entity("plate")[0].copy( parent=self.params.out_group ) - plate.vertices = plate.vertices + query + + # Set position of plate to query location + center = self.params.survey.vertices[nearest] + center[2] = self._drape_heights[nearest] + plate.vertices = plate.vertices + center plate.metadata = options.model.model_dump() print(f"Best parameters:{options.model.model_dump_json(indent=2)}") + @classmethod + def start_dask_run( + cls, + ifile, + n_workers: int | None = None, + n_threads: int | None = None, + save_report: bool = True, + ): + """Overload configurations of BaseDriver Dask config settings.""" + # Force distributed on 1D problems + if n_workers is None: + cpu_count = multiprocessing.cpu_count() + + if cpu_count < 16: + n_threads = n_threads or 2 + else: + n_threads = n_threads or 4 + + n_workers = cpu_count // n_threads + + super().start_dask_run( + ifile, n_workers=n_workers, n_threads=n_threads, save_report=save_report + ) + + +def normalized_data(property_group: PropertyGroup, threshold=5) -> np.ndarray: + """ + Return data from a property group with symlog scaling and zero mean. + + :param property_group: Property group containing data channels. + :param threshold: Percentile threshold for symlog normalization. + + :return: Normalized data array. + """ + table = property_group.table() + data_array = np.vstack([table[name] for name in table.dtype.names]) + thresh = np.percentile(np.abs(data_array), threshold) + log_data = symlog(data_array, thresh) + return log_data - np.mean(log_data, axis=1)[:, None] + + +def fetch_survey(workspace: Workspace) -> AirborneTEMReceivers | None: + """Fetch the survey from the workspace.""" + for group in workspace.groups: + if isinstance(group, SimPEGGroup): + for child in group.children: + if isinstance(child, AirborneTEMReceivers): + return child + + return None + + +def process_files_batch( + files: Path | list[Path], spatial_projection, time_projection, observed +): + scores = [] + + if isinstance(files, Path): + files = [files] + + for sim_file in files: + with Workspace(sim_file, mode="r") as ws: + survey = fetch_survey(ws) + + if survey is None: + logger.warning("No survey found in %s, skipping.", sim_file) + continue + + simulated = normalized_data(survey.get_entity("Iteration_0_z")[0]) + + pred = time_projection @ (spatial_projection @ simulated.T).T + score = 0.0 + + # Metric: normalized cross-correlation + for obs, pre in zip(observed, pred, strict=True): + # Full cross-correlation + corr = signal.correlate(obs, pre, mode="full") + # Normalize by energy to get correlation coefficient in [-1, 1] + denom = np.linalg.norm(pre) * np.linalg.norm(obs) + if denom == 0: + corr_norm = np.zeros_like(corr) + else: + corr_norm = corr / denom + + score += np.max(corr_norm) + + scores.append(score) + + return scores + if __name__ == "__main__": - file = Path(sys.argv[1]) - # file = Path(r"C:\Users\dominiquef\Documents\Workspace\Teck\RnD\plate_match_v2.ui.json") - PlateMatchDriver.start(file) + file = Path(sys.argv[1]).resolve() + input_file = load_ui_json_as_dict(file) + PlateMatchDriver.start_dask_run( + file, + n_workers=input_file.get("n_workers", None), + n_threads=input_file.get("n_threads", None), + save_report=input_file.get("performance_report", False), + ) From 12c5416256ccc8ef466e8540e95768ede2af8b76 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 16 Jan 2026 12:56:36 -0800 Subject: [PATCH 07/24] Add progress bar --- simpeg_drivers/plate_simulation/match/driver.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index bd6820ba..fece2d6b 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -13,9 +13,9 @@ import multiprocessing import sys from pathlib import Path -from time import time import numpy as np +from dask.distributed import progress from geoapps_utils.run import load_ui_json_as_dict from geoapps_utils.utils.importing import GeoAppsError from geoapps_utils.utils.locations import topo_drape_elevation @@ -278,9 +278,10 @@ def run(self): self.params.strike_angles.values[ii], ) - file_split = np.array_split(self.params.simulation_files, len(self.workers)) + file_split = np.array_split( + self.params.simulation_files, len(self.workers) * 10 + ) - ct = time() for file_batch in file_split: tasks.append( self.client.submit( @@ -291,10 +292,9 @@ def run(self): observed[:, indices], ) ) - + # Display progress bar + progress(tasks) scores = np.hstack(self.client.gather(tasks)) - - print(f"Processing time: {time() - ct:.1f} seconds") ranked = np.argsort(scores) for rank in ranked[-1:][::-1]: From 6741a6668338afba1434981c1e068b9fb5636831 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 16 Jan 2026 14:58:25 -0800 Subject: [PATCH 08/24] Refactor code to create sparse inv interpolation --- .../plate_simulation/match/driver.py | 100 ++++++++---------- 1 file changed, 43 insertions(+), 57 deletions(-) diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index fece2d6b..4e98199e 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -56,7 +56,6 @@ def __init__(self, params: MatchOptions, workers: list[tuple[str]] | None = None self._drape_heights = self.set_drape_height() self._template = self.get_template() self._time_mask, self._time_projection = self.time_mask_and_projection() - self.out_group = self.validate_out_group(self.params.out_group) def get_template(self): """ @@ -84,9 +83,7 @@ def time_mask_and_projection(self) -> tuple[np.ndarray, csr_matrix]: :return: Time mask and time interpolation matrix. """ - simulated_times = np.asarray(self._template.channels) - query_times = np.asarray(self.params.survey.channels) # Only interpolate for times within the simulated range time_mask = (query_times > simulated_times.min()) & ( @@ -94,56 +91,16 @@ def time_mask_and_projection(self) -> tuple[np.ndarray, csr_matrix]: ) query_times = query_times[time_mask] right = np.searchsorted(simulated_times, query_times) - inds = np.r_[right - 1, right] - row_ids = np.tile(np.arange(len(query_times)), 2) - - # Create inverse distance weighting matrix - weights = (np.abs(query_times[row_ids] - simulated_times[inds]) + 1e-12) ** -1 - time_projection = csr_matrix( - (weights.flatten(), (row_ids, np.hstack(inds.flatten()))), - shape=(len(query_times), len(simulated_times)), - ) - row_sum = np.asarray(time_projection.sum(axis=1)).flatten() ** -1.0 - time_projection = diags(row_sum) @ time_projection + inds = np.c_[right - 1, right].flatten() + row_ids = np.repeat(np.arange(len(query_times)), 2) + # Create inverse distance weighting matrix based on time difference + time_diff = np.abs(query_times[row_ids] - simulated_times[inds]) + time_projection = self.inverse_weighted_operator( + time_diff, inds, (len(query_times), len(simulated_times)), 1.0, 1e-12 + ) return time_mask, time_projection - @property - def out_group(self) -> SimPEGGroup: - """ - Returns the output group for the simulation. - """ - return self._out_group - - @out_group.setter - def out_group(self, value: SimPEGGroup): - if not isinstance(value, SimPEGGroup): - raise TypeError("Output group must be a SimPEGGroup.") - - if self.params.out_group != value: - self.params.out_group = value - self.params.update_out_group_options() - - self._out_group = value - - def validate_out_group(self, out_group: SimPEGGroup | None) -> SimPEGGroup: - """ - Validate or create a SimPEGGroup to store results. - - :param out_group: Output group from selection. - """ - if isinstance(out_group, SimPEGGroup): - return out_group - - with fetch_active_workspace(self.params.geoh5, mode="r+"): - out_group = SimPEGGroup.create( - self.params.geoh5, - name=self.params.title, - ) - out_group.entity_type.name = self.params.title - - return out_group - @classmethod def start(cls, filepath: str | Path, mode="r+", **_) -> Self: """Start the parameter matching from a ui.json file.""" @@ -212,13 +169,40 @@ def spatial_interpolation( sim_tree = cKDTree(query_polar) rad, inds = sim_tree.query(local_polar, k=8) - weights = (rad**2.0 + 1e-1) ** -1 - row_ids = np.kron(np.arange(local_polar.shape[0]), np.ones(8)) - inv_dist_op = csr_matrix( - (weights.flatten(), (row_ids, np.hstack(inds.flatten()))), - shape=(local_polar.shape[0], self._template.vertices.shape[0]), + return self.inverse_weighted_operator( + rad.flatten(), + inds.flatten(), + (local_polar.shape[0], self._template.vertices.shape[0]), + 2.0, + 1e-1, ) + @staticmethod + def inverse_weighted_operator( + values: np.ndarray, + col_indices: np.ndarray, + shape: tuple, + power: float, + threshold: float, + ) -> csr_matrix: + """ + Create an inverse distance weighted sparse matrix. + + :param values: Distance values. + :param col_indices: Column indices for the sparse matrix. + :param shape: Shape of the sparse matrix. + :param power: Power for the inverse distance weighting. + :param threshold: Threshold to avoid singularities. + + :return: Inverse distance weighted sparse matrix. + """ + weights = (values**power + threshold) ** -1 + n_vals_row = weights.shape[0] // shape[0] + row_ids = np.repeat(np.arange(shape[0]), n_vals_row) + inv_dist_op = csr_matrix( + (weights, (row_ids, col_indices)), + shape=shape, + ) # Normalize the rows row_sum = np.asarray(inv_dist_op.sum(axis=1)).flatten() ** -1.0 return diags(row_sum) @ inv_dist_op @@ -391,7 +375,6 @@ def process_files_batch( continue simulated = normalized_data(survey.get_entity("Iteration_0_z")[0]) - pred = time_projection @ (spatial_projection @ simulated.T).T score = 0.0 @@ -414,7 +397,10 @@ def process_files_batch( if __name__ == "__main__": - file = Path(sys.argv[1]).resolve() + # file = Path(sys.argv[1]).resolve() + file = Path( + r"C:\Users\dominiquef\Documents\Workspace\Teck\RnD\plate_match_v2.ui.json" + ) input_file = load_ui_json_as_dict(file) PlateMatchDriver.start_dask_run( file, From 6396a83846f5a8cfe4f5f81f9d127198834bb251 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 16 Jan 2026 15:01:46 -0800 Subject: [PATCH 09/24] Move out_group setter to BaseDriver. Remove duplicate sub-class setters --- simpeg_drivers/driver.py | 68 ++++++++++--------- simpeg_drivers/plate_simulation/driver.py | 8 --- .../plate_simulation/sweep/driver.py | 36 ---------- 3 files changed, 37 insertions(+), 75 deletions(-) diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 90978e0a..84245c87 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -95,6 +95,7 @@ def __init__( workers: list[str] | None = None, ): super().__init__(params) + self.out_group = self.validate_out_group(self.params.out_group) self._client: Client | bool = self.validate_client(client) if getattr(self.params, "store_sensitivities", None) == "disk" and self.client: @@ -104,6 +105,42 @@ def __init__( self._workers: list[tuple[str]] | None = self.validate_workers(workers) + @property + def out_group(self) -> SimPEGGroup: + """ + Returns the output group for the simulation. + """ + return self._out_group + + @out_group.setter + def out_group(self, value: SimPEGGroup): + if not isinstance(value, SimPEGGroup): + raise TypeError("Output group must be a SimPEGGroup.") + + if self.params.out_group != value: + self.params.out_group = value + self.params.update_out_group_options() + + self._out_group = value + + def validate_out_group(self, out_group: SimPEGGroup | None) -> SimPEGGroup: + """ + Validate or create a SimPEGGroup to store results. + + :param out_group: Output group from selection. + """ + if isinstance(out_group, SimPEGGroup): + return out_group + + with fetch_active_workspace(self.params.geoh5, mode="r+"): + out_group = SimPEGGroup.create( + self.params.geoh5, + name=self.params.title, + ) + out_group.entity_type.name = self.params.title + + return out_group + @property def client(self) -> Client | bool | None: """ @@ -224,7 +261,6 @@ def __init__( super().__init__(params, client=client, workers=workers) self.inversion_type = self.params.inversion_type - self.out_group = self.validate_out_group(self.params.out_group) self._data_misfit: objective_function.ComboObjectiveFunction | None = None self._directives: list[directives.InversionDirective] | None = None self._inverse_problem: inverse_problem.BaseInvProblem | None = None @@ -432,36 +468,6 @@ def ordering(self): """List of ordering of the data.""" return self.inversion_data.survey.ordering - @property - def out_group(self) -> SimPEGGroup: - """ - Returns the output group for the simulation. - """ - return self._out_group - - @out_group.setter - def out_group(self, value: SimPEGGroup): - if not isinstance(value, SimPEGGroup): - raise TypeError("Output group must be a SimPEGGroup.") - - self.params.out_group = value - self.params.update_out_group_options() - self._out_group = value - - def validate_out_group(self, out_group: SimPEGGroup | None) -> SimPEGGroup: - """ - Validate or create a SimPEGGroup to store results. - - :param out_group: Output group from selection. - """ - if isinstance(out_group, SimPEGGroup): - return out_group - - with fetch_active_workspace(self.workspace, mode="r+"): - out_group = SimPEGGroup.create(self.workspace, name=self.params.title) - - return out_group - @property def params(self) -> BaseForwardOptions | BaseInversionOptions: """Application parameters.""" diff --git a/simpeg_drivers/plate_simulation/driver.py b/simpeg_drivers/plate_simulation/driver.py index 0b8fd40c..d30ef5c1 100644 --- a/simpeg_drivers/plate_simulation/driver.py +++ b/simpeg_drivers/plate_simulation/driver.py @@ -62,7 +62,6 @@ def __init__( self._model: FloatData | None = None self._simulation_parameters: BaseForwardOptions | None = None self._simulation_driver: InversionDriver | None = None - self._out_group = self.validate_out_group(self.params.out_group) def run(self) -> InversionDriver: """Create octree mesh, fill model, and simulate.""" @@ -77,13 +76,6 @@ def run(self) -> InversionDriver: return self.simulation_driver - @property - def out_group(self) -> SimPEGGroup: - """ - Returns the output group for the simulation. - """ - return self._out_group - def validate_out_group(self, out_group: SimPEGGroup | None) -> SimPEGGroup: """ Validate or create a SimPEGGroup to store results. diff --git a/simpeg_drivers/plate_simulation/sweep/driver.py b/simpeg_drivers/plate_simulation/sweep/driver.py index f1cee0c9..2ca7921c 100644 --- a/simpeg_drivers/plate_simulation/sweep/driver.py +++ b/simpeg_drivers/plate_simulation/sweep/driver.py @@ -48,42 +48,6 @@ def __init__(self, params: SweepOptions, workers: list[tuple[str]] | None = None self.out_group = self.validate_out_group(self.params.out_group) - @property - def out_group(self) -> SimPEGGroup: - """ - Returns the output group for the simulation. - """ - return self._out_group - - @out_group.setter - def out_group(self, value: SimPEGGroup): - if not isinstance(value, SimPEGGroup): - raise TypeError("Output group must be a SimPEGGroup.") - - if self.params.out_group != value: - self.params.out_group = value - self.params.update_out_group_options() - - self._out_group = value - - def validate_out_group(self, out_group: SimPEGGroup | None) -> SimPEGGroup: - """ - Validate or create a UIJsonGroup to store results. - - :param value: Output group from selection. - """ - if isinstance(out_group, SimPEGGroup): - return out_group - - with fetch_active_workspace(self.params.geoh5, mode="r+"): - out_group = SimPEGGroup.create( - self.params.geoh5, - name=self.params.title, - ) - out_group.entity_type.name = self.params.title - - return out_group - @classmethod def start(cls, filepath: str | Path, mode="r", **_) -> Self: """Start the parameter sweep from a ui.json file.""" From 3c25bf14761a5a77934ee9d35afb5719cd40cad9 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 19 Jan 2026 11:01:42 -0800 Subject: [PATCH 10/24] Move basic functions to utils. Start adding unitests --- simpeg_drivers/plate_simulation/driver.py | 8 +- .../plate_simulation/match/driver.py | 74 +++--------------- .../plate_simulation/match/options.py | 8 +- simpeg_drivers/utils/utils.py | 48 ++++++++++++ .../plate_simulation/runtest/gravity_test.py | 1 - tests/plate_simulation/runtest/match_test.py | 77 +++++++++++++++++++ tests/utils_test.py | 57 ++++++++++++++ 7 files changed, 201 insertions(+), 72 deletions(-) create mode 100644 tests/plate_simulation/runtest/match_test.py create mode 100644 tests/utils_test.py diff --git a/simpeg_drivers/plate_simulation/driver.py b/simpeg_drivers/plate_simulation/driver.py index d30ef5c1..0ba111bf 100644 --- a/simpeg_drivers/plate_simulation/driver.py +++ b/simpeg_drivers/plate_simulation/driver.py @@ -15,7 +15,7 @@ import numpy as np from dask.distributed import Client -from geoapps_utils.base import Driver, get_logger +from geoapps_utils.base import get_logger from geoapps_utils.utils.transformations import azimuth_to_unit_vector from geoh5py.data import FloatData, ReferencedData from geoh5py.groups import SimPEGGroup @@ -40,10 +40,8 @@ class PlateSimulationDriver(BaseDriver): :param params: Parameters for plate simulation (mesh, model and series). - :param plate: Plate object used to add anomaly to the model. - :param mesh: Octree mesh in which model is built for the simulation. - :param model: Model to simulate. - :param survey: Survey object for the simulation + :param client: Dask client for parallel processing. + :param workers: List of worker addresses for Dask client. """ _params_class = PlateSimulationOptions diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index 4e98199e..e961031f 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -29,28 +29,27 @@ ) from geoh5py.ui_json import InputFile from scipy import signal -from scipy.sparse import csr_matrix, diags +from scipy.sparse import csr_matrix from scipy.spatial import cKDTree from typing_extensions import Self from simpeg_drivers.driver import BaseDriver -from simpeg_drivers.plate_simulation.match.options import MatchOptions - -# from simpeg_drivers.plate_simulation.match.uijson import PlateMatchUIJson +from simpeg_drivers.plate_simulation.match.options import PlateMatchOptions from simpeg_drivers.plate_simulation.options import PlateSimulationOptions +from simpeg_drivers.utils.utils import inverse_weighted_operator, xyz_to_polar -# import matplotlib.pyplot as plt - logger = get_logger(name=__name__, level_name=False, propagate=False, add_name=False) class PlateMatchDriver(BaseDriver): """Sets up and manages workers to run all combinations of swepts parameters.""" - _params_class = MatchOptions + _params_class = PlateMatchOptions - def __init__(self, params: MatchOptions, workers: list[tuple[str]] | None = None): + def __init__( + self, params: PlateMatchOptions, workers: list[tuple[str]] | None = None + ): super().__init__(params, workers=workers) self._drape_heights = self.set_drape_height() @@ -96,7 +95,7 @@ def time_mask_and_projection(self) -> tuple[np.ndarray, csr_matrix]: # Create inverse distance weighting matrix based on time difference time_diff = np.abs(query_times[row_ids] - simulated_times[inds]) - time_projection = self.inverse_weighted_operator( + time_projection = inverse_weighted_operator( time_diff, inds, (len(query_times), len(simulated_times)), 1.0, 1e-12 ) return time_mask, time_projection @@ -113,7 +112,7 @@ def start(cls, filepath: str | Path, mode="r+", **_) -> Self: with uijson.geoh5.open(mode=mode): try: - options = MatchOptions.build(uijson) + options = PlateMatchOptions.build(uijson) logger.info("Initializing application . . .") driver = cls(options) logger.info("Running application . . .") @@ -157,19 +156,19 @@ def spatial_interpolation( :return: Spatial interpolation matrix. """ # Compute local coordinates for the current line segment - local_polar = self.xyz_to_polar(self.params.survey.vertices[indices, :]) + local_polar = xyz_to_polar(self.params.survey.vertices[indices, :]) local_polar[:, 1] = ( 0.0 if strike_angle is None else strike_angle ) # Align azimuths to zero # Convert to polar coordinates (distance, azimuth, height) - query_polar = self.xyz_to_polar(self._template.vertices) + query_polar = xyz_to_polar(self._template.vertices) # Get the 8 nearest neighbors in the simulation to each observation point sim_tree = cKDTree(query_polar) rad, inds = sim_tree.query(local_polar, k=8) - return self.inverse_weighted_operator( + return inverse_weighted_operator( rad.flatten(), inds.flatten(), (local_polar.shape[0], self._template.vertices.shape[0]), @@ -177,55 +176,6 @@ def spatial_interpolation( 1e-1, ) - @staticmethod - def inverse_weighted_operator( - values: np.ndarray, - col_indices: np.ndarray, - shape: tuple, - power: float, - threshold: float, - ) -> csr_matrix: - """ - Create an inverse distance weighted sparse matrix. - - :param values: Distance values. - :param col_indices: Column indices for the sparse matrix. - :param shape: Shape of the sparse matrix. - :param power: Power for the inverse distance weighting. - :param threshold: Threshold to avoid singularities. - - :return: Inverse distance weighted sparse matrix. - """ - weights = (values**power + threshold) ** -1 - n_vals_row = weights.shape[0] // shape[0] - row_ids = np.repeat(np.arange(shape[0]), n_vals_row) - inv_dist_op = csr_matrix( - (weights, (row_ids, col_indices)), - shape=shape, - ) - # Normalize the rows - row_sum = np.asarray(inv_dist_op.sum(axis=1)).flatten() ** -1.0 - return diags(row_sum) @ inv_dist_op - - @staticmethod - def xyz_to_polar(xyz: np.ndarray) -> np.ndarray: - """ - Convert Cartesian coordinates to polar coordinates defined as - (distance, azimuth, height), where distance is signed based on the - x-coordinate relative to the mean location. - - :param xyz: Cartesian coordinates. - - :return: Polar coordinates (distance, azimuth, height). - """ - mean_loc = np.mean(xyz, axis=0) - distances = np.sign(xyz[:, 0] - mean_loc[0]) * np.linalg.norm( - xyz[:, :2] - mean_loc[:2], axis=1 - ) - - azimuths = 90 - (np.rad2deg(np.arctan2(xyz[:, 0], xyz[:, 1])) % 180) - return np.c_[distances, azimuths, xyz[:, 2]] - def get_segment_indices(self, nearest: int) -> np.ndarray: """ Get indices of line segment for a given nearest vertex. diff --git a/simpeg_drivers/plate_simulation/match/options.py b/simpeg_drivers/plate_simulation/match/options.py index 2d5a32c8..90a655ff 100644 --- a/simpeg_drivers/plate_simulation/match/options.py +++ b/simpeg_drivers/plate_simulation/match/options.py @@ -23,7 +23,7 @@ from simpeg_drivers import assets_path -class MatchOptions(Options): +class PlateMatchOptions(Options): """ Options for matching signal from a survey against a library of simulations. @@ -39,8 +39,8 @@ class MatchOptions(Options): name: ClassVar[str] = "plate_match" default_ui_json: ClassVar[Path] = assets_path() / "uijson/plate_match.ui.json" - title: ClassVar[str] = "Plate Match" - run_command: ClassVar[str] = "simpeg_drivers.plate_simulation.match.driver" + title: str = "Plate Match" + run_command: str = "simpeg_drivers.plate_simulation.match.driver" out_group: SimPEGGroup | None = None survey: AirborneTEMReceivers @@ -50,7 +50,7 @@ class MatchOptions(Options): max_distance: float = 1000.0 topography_object: Points | Grid2D topography: FloatData | None = None - simulations: str + simulations: str | Path @property def simulation_files(self) -> list[Path]: diff --git a/simpeg_drivers/utils/utils.py b/simpeg_drivers/utils/utils.py index e79e52e4..7e5ab46f 100644 --- a/simpeg_drivers/utils/utils.py +++ b/simpeg_drivers/utils/utils.py @@ -29,6 +29,7 @@ from geoh5py.ui_json import InputFile from grid_apps.utils import octree_2_treemesh from scipy.interpolate import LinearNDInterpolator, NearestNDInterpolator, interp1d +from scipy.sparse import csr_matrix, diags from scipy.spatial import ConvexHull, Delaunay, cKDTree from simpeg_drivers import DRIVER_MAP @@ -572,3 +573,50 @@ def simpeg_group_to_driver(group: SimPEGGroup, workspace: Workspace) -> Inversio params = inversion_driver._params_class.build(ifile) # pylint: disable=protected-access return inversion_driver(params) + + +def xyz_to_polar(locations: np.ndarray) -> np.ndarray: + """ + Convert Cartesian coordinates to polar coordinates defined as + (distance, azimuth, height), where distance is signed based on the + x-coordinate relative to the mean location. + + :param locations: Cartesian coordinates. + + :return: Polar coordinates (distance, azimuth, height). + """ + xyz = locations - np.mean(locations, axis=0) + distances = np.sign(xyz[:, 0]) * np.linalg.norm(xyz[:, :2], axis=1) + + azimuths = 90 - (np.rad2deg(np.arctan2(xyz[:, 0], xyz[:, 1])) % 180) + return np.c_[distances, azimuths, locations[:, 2]] + + +def inverse_weighted_operator( + values: np.ndarray, + col_indices: np.ndarray, + shape: tuple, + power: float, + threshold: float, +) -> csr_matrix: + """ + Create an inverse distance weighted sparse matrix. + + :param values: Distance values. + :param col_indices: Column indices for the sparse matrix. + :param shape: Shape of the sparse matrix. + :param power: Power for the inverse distance weighting. + :param threshold: Threshold to avoid singularities. + + :return: Inverse distance weighted sparse matrix. + """ + weights = (values**power + threshold) ** -1 + n_vals_row = weights.shape[0] // shape[0] + row_ids = np.repeat(np.arange(shape[0]), n_vals_row) + inv_dist_op = csr_matrix( + (weights, (row_ids, col_indices)), + shape=shape, + ) + # Normalize the rows + row_sum = np.asarray(inv_dist_op.sum(axis=1)).flatten() ** -1.0 + return diags(row_sum) @ inv_dist_op diff --git a/tests/plate_simulation/runtest/gravity_test.py b/tests/plate_simulation/runtest/gravity_test.py index 3c702d4b..130517bb 100644 --- a/tests/plate_simulation/runtest/gravity_test.py +++ b/tests/plate_simulation/runtest/gravity_test.py @@ -9,7 +9,6 @@ # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' import numpy as np -from geoh5py import Workspace from geoh5py.groups import SimPEGGroup from simpeg_drivers.plate_simulation.driver import PlateSimulationDriver diff --git a/tests/plate_simulation/runtest/match_test.py b/tests/plate_simulation/runtest/match_test.py new file mode 100644 index 00000000..d8c3082f --- /dev/null +++ b/tests/plate_simulation/runtest/match_test.py @@ -0,0 +1,77 @@ +# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +# Copyright (c) 2023-2026 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 pathlib import Path + +import numpy as np +from geoh5py import Workspace +from geoh5py.groups import PropertyGroup +from geoh5py.objects import Points + +from simpeg_drivers.plate_simulation.match.options import PlateMatchOptions +from simpeg_drivers.utils.synthetics.driver import ( + SyntheticsComponents, +) +from simpeg_drivers.utils.synthetics.options import ( + MeshOptions, + ModelOptions, + SurveyOptions, + SyntheticsComponentsOptions, +) +from tests.utils.targets import get_workspace + + +def generate_example(geoh5: Workspace, n_grid_points: int, refinement: tuple[int]): + opts = SyntheticsComponentsOptions( + method="airborne tdem", + survey=SurveyOptions( + n_stations=n_grid_points, n_lines=n_grid_points, drape=10.0 + ), + mesh=MeshOptions(refinement=refinement, padding_distance=400.0), + model=ModelOptions(background=0.001), + ) + components = SyntheticsComponents(geoh5, options=opts) + vals = components.survey.add_data( + {"observed_data": {"values": np.random.randn(components.survey.n_vertices)}}, + ) + components.property_group = PropertyGroup(components.survey, properties=vals) + components.queries = Points.create(geoh5, vertices=np.random.randn(1, 3)) + + return components + + +def test_file_parsing(tmp_path: Path): + """ + Generate a few files and test the + plate_simulation.match.Options.simulation_files() method. + """ + filenames = [ + "sim_001.txt", + "sim_002.txt", + "sim_010.txt", + "sim_011.txt", + ] + for fname in filenames: + (tmp_path / fname).touch() + + with get_workspace(tmp_path / f"{__name__}.geoh5") as geoh5: + components = generate_example(geoh5, n_grid_points=3, refinement=(2,)) + options = PlateMatchOptions( + geoh5=geoh5, + survey=components.survey, + data=components.property_group, + queries=components.queries, + topography_object=components.topography, + simulations=tmp_path, + ) + + sim_files = options.simulation_files + assert len(sim_files) == 1 + assert sim_files[0].name == f"{__name__}.geoh5" diff --git a/tests/utils_test.py b/tests/utils_test.py new file mode 100644 index 00000000..13888682 --- /dev/null +++ b/tests/utils_test.py @@ -0,0 +1,57 @@ +# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +# Copyright (c) 2023-2026 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). ' +# ' +# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +import numpy as np + +from simpeg_drivers.utils.utils import inverse_weighted_operator, xyz_to_polar + + +def test_xyz_to_polar(): + """ + Test the xyz_to_polar utility function. + """ + for _ in range(100): + rad = np.abs(np.random.randn()) + azm = np.random.randn() + + # Create x, y, z coordinates + x = rad * np.cos(azm) + y = rad * np.sin(azm) + z = np.random.randn() + + polar = xyz_to_polar(np.vstack([[[0, 0, 0]], [[x, y, z]]])) + np.testing.assert_almost_equal( + polar[0, 0], -polar[1, 0] + ) # Opposite side of center + np.testing.assert_almost_equal(polar[0, 1], polar[1, 1]) # Same azimuth + np.testing.assert_allclose([0, z], polar[:, 2]) # Preserves z + + +def test_inverse_weighted_operator(): + """ + Test the inverse_weighted_operator utility function. + + For a constant input, the output should be the same constant. + """ + power = 2.0 + threshold = 1e-12 + shape = (100, 1000) + values = np.random.randn(shape[0] * 2) + indices = np.c_[ + np.random.randint(0, shape[1] - 1, shape[0]), + np.random.randint(0, shape[1] - 1, shape[0]), + ].flatten() + + opt = inverse_weighted_operator(values, indices, shape, power, threshold) + test_val = np.random.randn() + interp = opt * np.full(shape[1], test_val) + + assert opt.shape == shape + np.testing.assert_allclose(interp, test_val, rtol=1e-3) From dc43052ead263a90051e1d7663a1da5736d1b973 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 19 Jan 2026 11:18:09 -0800 Subject: [PATCH 11/24] Remove dprecated configure_dask in joint. Rename opt options --- simpeg_drivers/driver.py | 8 ++++---- simpeg_drivers/joint/driver.py | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 84245c87..c156d919 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -448,16 +448,16 @@ def n_values(self): def optimization(self): if getattr(self, "_optimization", None) is None: if self.params.forward_only: - return optimization.ProjectedGNCG() + return optimization.ProjectedGNCG(cg_rtol=1.0) self._optimization = optimization.ProjectedGNCG( maxIter=self.params.optimization.max_global_iterations, lower=self.models.lower_bound, upper=self.models.upper_bound, maxIterLS=self.params.optimization.max_line_search_iterations, - maxIterCG=self.params.optimization.max_cg_iterations, - tolCG=self.params.optimization.tol_cg, - stepOffBoundsFact=1e-8, + cg_maxiter=self.params.optimization.max_cg_iterations, + cg_rtol=self.params.optimization.tol_cg, + active_set_grad_scale=1e-8, LSshorten=0.25, require_decrease=False, ) diff --git a/simpeg_drivers/joint/driver.py b/simpeg_drivers/joint/driver.py index 07d5e30f..cd945bfa 100644 --- a/simpeg_drivers/joint/driver.py +++ b/simpeg_drivers/joint/driver.py @@ -234,7 +234,6 @@ def run(self): if self.logger: sys.stdout = self.logger self.logger.start() - self.configure_dask() if Path(self.params.input_file.path_name).is_file(): with fetch_active_workspace(self.workspace, mode="r+"): From 7062d7b7e9f07f46d0b44f93029f3ac647cb4340 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 19 Jan 2026 16:56:50 -0800 Subject: [PATCH 12/24] Move utils to geoh5py and geoapps_driver. Add unitest --- .../plate_simulation/match/driver.py | 138 +++++++++--------- simpeg_drivers/utils/utils.py | 47 ------ tests/plate_simulation/runtest/match_test.py | 85 ++++++++++- tests/utils_test.py | 57 -------- 4 files changed, 152 insertions(+), 175 deletions(-) delete mode 100644 tests/utils_test.py diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index e961031f..16c0cf37 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -15,12 +15,14 @@ from pathlib import Path import numpy as np -from dask.distributed import progress +from dask.distributed import Future, progress from geoapps_utils.run import load_ui_json_as_dict from geoapps_utils.utils.importing import GeoAppsError from geoapps_utils.utils.locations import topo_drape_elevation from geoapps_utils.utils.logger import get_logger +from geoapps_utils.utils.numerical import inverse_weighted_operator from geoapps_utils.utils.plotting import symlog +from geoapps_utils.utils.transformations import xyz_to_polar from geoh5py import Workspace from geoh5py.groups import PropertyGroup, SimPEGGroup from geoh5py.objects import AirborneTEMReceivers, Surface @@ -36,7 +38,6 @@ from simpeg_drivers.driver import BaseDriver from simpeg_drivers.plate_simulation.match.options import PlateMatchOptions from simpeg_drivers.plate_simulation.options import PlateSimulationOptions -from simpeg_drivers.utils.utils import inverse_weighted_operator, xyz_to_polar logger = get_logger(name=__name__, level_name=False, propagate=False, add_name=False) @@ -52,7 +53,7 @@ def __init__( ): super().__init__(params, workers=workers) - self._drape_heights = self.set_drape_height() + self._drape_heights = self._get_drape_heights() self._template = self.get_template() self._time_mask, self._time_projection = self.time_mask_and_projection() @@ -85,12 +86,12 @@ def time_mask_and_projection(self) -> tuple[np.ndarray, csr_matrix]: simulated_times = np.asarray(self._template.channels) query_times = np.asarray(self.params.survey.channels) # Only interpolate for times within the simulated range - time_mask = (query_times > simulated_times.min()) & ( - query_times < simulated_times.max() + time_mask = (query_times >= simulated_times.min()) & ( + query_times <= simulated_times.max() ) query_times = query_times[time_mask] right = np.searchsorted(simulated_times, query_times) - inds = np.c_[right - 1, right].flatten() + inds = np.c_[np.maximum(0, right - 1), right].flatten() row_ids = np.repeat(np.arange(len(query_times)), 2) # Create inverse distance weighting matrix based on time difference @@ -125,7 +126,7 @@ def start(cls, filepath: str | Path, mode="r+", **_) -> Self: return driver - def set_drape_height(self) -> np.ndarray: + def _get_drape_heights(self) -> np.ndarray: """Set drape heights based on topography object and optional topography data.""" topo = self.params.topography_object.locations @@ -156,18 +157,24 @@ def spatial_interpolation( :return: Spatial interpolation matrix. """ # Compute local coordinates for the current line segment - local_polar = xyz_to_polar(self.params.survey.vertices[indices, :]) + local_polar = xyz_to_polar( + self.params.survey.vertices[indices] + - np.r_[self.params.survey.vertices[indices, :2].mean(axis=0), 0] + ) + local_polar[local_polar[:, 1] >= 180, 0] *= -1 # Wrap azimuths local_polar[:, 1] = ( 0.0 if strike_angle is None else strike_angle ) # Align azimuths to zero # Convert to polar coordinates (distance, azimuth, height) query_polar = xyz_to_polar(self._template.vertices) + query_polar[query_polar[:, 1] >= 180, 0] *= -1 + query_polar[:, 1] = query_polar[:, 1] % 180 # Wrap azimuths # Get the 8 nearest neighbors in the simulation to each observation point sim_tree = cKDTree(query_polar) rad, inds = sim_tree.query(local_polar, k=8) - + inds = np.minimum(query_polar.shape[0] - 1, inds) return inverse_weighted_operator( rad.flatten(), inds.flatten(), @@ -176,24 +183,6 @@ def spatial_interpolation( 1e-1, ) - def get_segment_indices(self, nearest: int) -> np.ndarray: - """ - Get indices of line segment for a given nearest vertex. - - :param nearest: Nearest vertex index. - """ - line_mask = np.where( - self.params.survey.parts == self.params.survey.parts[nearest] - )[0] - distances = np.linalg.norm( - self.params.survey.vertices[nearest, :2] - - self.params.survey.vertices[line_mask, :2], - axis=1, - ) - dist_mask = distances < self.params.max_distance - indices = line_mask[dist_mask] - return indices - def run(self): """Loop over all trials and run a worker for each unique parameter set.""" logger.info( @@ -202,59 +191,74 @@ def run(self): ) observed = normalized_data(self.params.data)[self._time_mask, :] tree = cKDTree(self.params.survey.vertices[:, :2]) - + results = [] for ii, query in enumerate(self.params.queries.vertices): - tasks = [] + # Find the nearest survey location to the query point nearest = tree.query(query[:2], k=1)[1] - indices = self.get_segment_indices(nearest) + indices = self.params.survey.get_segment_indices( + nearest, self.params.max_distance + ) spatial_projection = self.spatial_interpolation( indices, - self.params.strike_angles.values[ii], + 0 + if self.params.strike_angles is None + else self.params.strike_angles.values[ii], ) - file_split = np.array_split( - self.params.simulation_files, len(self.workers) * 10 + self.params.simulation_files, np.maximum(1, len(self.workers) * 10) ) + tasks = [] for file_batch in file_split: + args = ( + file_batch, + spatial_projection, + self._time_projection, + observed[:, indices], + ) + tasks.append( - self.client.submit( - process_files_batch, - file_batch, - spatial_projection, - self._time_projection, - observed[:, indices], - ) + self.client.submit(process_files_batch, *args) + if self.client + else process_files_batch(*args) ) + # Display progress bar - progress(tasks) - scores = np.hstack(self.client.gather(tasks)) - ranked = np.argsort(scores) - - for rank in ranked[-1:][::-1]: - logger.info( - "File: %s \nScore: %.4f", - self.params.simulation_files[rank].name, - scores[rank], + if isinstance(tasks[0], Future): + progress(tasks) + self.client.gather(tasks) + + scores = np.hstack(tasks) + ranked = np.argsort(scores)[::-1] + + # TODO: Return top N matches + # for rank in ranked[-1:][::-1]: + logger.info( + "File: %s \nScore: %.4f", + self.params.simulation_files[ranked[0]].name, + scores[ranked[0]], + ) + with Workspace(self.params.simulation_files[ranked[0]], mode="r") as ws: + survey = fetch_survey(ws) + ui_json = survey.parent.parent.options + ui_json["geoh5"] = ws + ifile = InputFile(ui_json=ui_json) + options = PlateSimulationOptions.build(ifile) + + plate = survey.parent.parent.get_entity("plate")[0].copy( + parent=self.params.out_group ) - with Workspace(self.params.simulation_files[rank], mode="r") as ws: - survey = fetch_survey(ws) - ui_json = survey.parent.parent.options - ui_json["geoh5"] = ws - ifile = InputFile(ui_json=ui_json) - options = PlateSimulationOptions.build(ifile) - - plate = survey.parent.parent.get_entity("plate")[0].copy( - parent=self.params.out_group - ) - - # Set position of plate to query location - center = self.params.survey.vertices[nearest] - center[2] = self._drape_heights[nearest] - plate.vertices = plate.vertices + center - plate.metadata = options.model.model_dump() - - print(f"Best parameters:{options.model.model_dump_json(indent=2)}") + + # Set position of plate to query location + center = self.params.survey.vertices[nearest] + center[2] = self._drape_heights[nearest] + plate.vertices = plate.vertices + center + plate.metadata = options.model.model_dump() + + print(f"Best parameters:{options.model.model_dump_json(indent=2)}") + results.append(self.params.simulation_files[ranked[0]].name) + + return results @classmethod def start_dask_run( diff --git a/simpeg_drivers/utils/utils.py b/simpeg_drivers/utils/utils.py index 7e5ab46f..64bb1cd9 100644 --- a/simpeg_drivers/utils/utils.py +++ b/simpeg_drivers/utils/utils.py @@ -573,50 +573,3 @@ def simpeg_group_to_driver(group: SimPEGGroup, workspace: Workspace) -> Inversio params = inversion_driver._params_class.build(ifile) # pylint: disable=protected-access return inversion_driver(params) - - -def xyz_to_polar(locations: np.ndarray) -> np.ndarray: - """ - Convert Cartesian coordinates to polar coordinates defined as - (distance, azimuth, height), where distance is signed based on the - x-coordinate relative to the mean location. - - :param locations: Cartesian coordinates. - - :return: Polar coordinates (distance, azimuth, height). - """ - xyz = locations - np.mean(locations, axis=0) - distances = np.sign(xyz[:, 0]) * np.linalg.norm(xyz[:, :2], axis=1) - - azimuths = 90 - (np.rad2deg(np.arctan2(xyz[:, 0], xyz[:, 1])) % 180) - return np.c_[distances, azimuths, locations[:, 2]] - - -def inverse_weighted_operator( - values: np.ndarray, - col_indices: np.ndarray, - shape: tuple, - power: float, - threshold: float, -) -> csr_matrix: - """ - Create an inverse distance weighted sparse matrix. - - :param values: Distance values. - :param col_indices: Column indices for the sparse matrix. - :param shape: Shape of the sparse matrix. - :param power: Power for the inverse distance weighting. - :param threshold: Threshold to avoid singularities. - - :return: Inverse distance weighted sparse matrix. - """ - weights = (values**power + threshold) ** -1 - n_vals_row = weights.shape[0] // shape[0] - row_ids = np.repeat(np.arange(shape[0]), n_vals_row) - inv_dist_op = csr_matrix( - (weights, (row_ids, col_indices)), - shape=shape, - ) - # Normalize the rows - row_sum = np.asarray(inv_dist_op.sum(axis=1)).flatten() ** -1.0 - return diags(row_sum) @ inv_dist_op diff --git a/tests/plate_simulation/runtest/match_test.py b/tests/plate_simulation/runtest/match_test.py index d8c3082f..c2d116d2 100644 --- a/tests/plate_simulation/runtest/match_test.py +++ b/tests/plate_simulation/runtest/match_test.py @@ -7,15 +7,22 @@ # (see LICENSE file at the root of this source code package). ' # ' # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - +import shutil from pathlib import Path import numpy as np from geoh5py import Workspace from geoh5py.groups import PropertyGroup from geoh5py.objects import Points +from geoh5py.ui_json import InputFile +from simpeg_drivers import assets_path +from simpeg_drivers.electromagnetics.time_domain.driver import TDEMForwardDriver +from simpeg_drivers.electromagnetics.time_domain.options import TDEMForwardOptions +from simpeg_drivers.plate_simulation.driver import PlateSimulationDriver +from simpeg_drivers.plate_simulation.match.driver import PlateMatchDriver, fetch_survey from simpeg_drivers.plate_simulation.match.options import PlateMatchOptions +from simpeg_drivers.plate_simulation.options import PlateSimulationOptions from simpeg_drivers.utils.synthetics.driver import ( SyntheticsComponents, ) @@ -31,9 +38,7 @@ def generate_example(geoh5: Workspace, n_grid_points: int, refinement: tuple[int]): opts = SyntheticsComponentsOptions( method="airborne tdem", - survey=SurveyOptions( - n_stations=n_grid_points, n_lines=n_grid_points, drape=10.0 - ), + survey=SurveyOptions(n_stations=n_grid_points, n_lines=1, drape=10.0), mesh=MeshOptions(refinement=refinement, padding_distance=400.0), model=ModelOptions(background=0.001), ) @@ -41,6 +46,9 @@ def generate_example(geoh5: Workspace, n_grid_points: int, refinement: tuple[int vals = components.survey.add_data( {"observed_data": {"values": np.random.randn(components.survey.n_vertices)}}, ) + + # Shift survey up (for single line) + components.survey.vertices = components.survey.vertices + np.r_[0, 100, 0] components.property_group = PropertyGroup(components.survey, properties=vals) components.queries = Points.create(geoh5, vertices=np.random.randn(1, 3)) @@ -75,3 +83,72 @@ def test_file_parsing(tmp_path: Path): sim_files = options.simulation_files assert len(sim_files) == 1 assert sim_files[0].name == f"{__name__}.geoh5" + + +def test_matching_driver(tmp_path: Path): + """ + Generate a few files and test the + plate_simulation.match.Options.simulation_files() method. + """ + + # Generate simulation files + with get_workspace(tmp_path / f"{__name__}.geoh5") as geoh5: + components = generate_example(geoh5, n_grid_points=5, refinement=(2,)) + + params = TDEMForwardOptions.build( + geoh5=geoh5, + mesh=components.mesh, + topography_object=components.topography, + data_object=components.survey, + starting_model=components.model, + x_channel_bool=True, + y_channel_bool=True, + z_channel_bool=True, + ) + + 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 + + plate_options = PlateSimulationOptions.build(ifile.data) + driver = PlateSimulationDriver(plate_options) + driver.run() + + # Make copies of the generated simulation file to emulate a sweep + file = tmp_path / f"{__name__}.geoh5" + new_dir = tmp_path / "simulations" + new_dir.mkdir(parents=True, exist_ok=True) + + for ii in range(1, 5): + new_file = new_dir / (file.stem + f"_[{ii}].geoh5") + shutil.copy(file, new_file) + + # Modify the data slightly + with Workspace(new_file) as sim_geoh5: + survey = fetch_survey(sim_geoh5) + prop_group = survey.get_entity("Iteration_0_z")[0] + scale = np.cos(np.linspace(-np.pi / ii, np.pi / ii, survey.n_vertices)) + + for uid in prop_group.properties: + child = survey.get_entity(uid)[0] + child.values = child.values * scale + + # Random choice of file + with geoh5.open(): + survey = fetch_survey(geoh5) + options = PlateMatchOptions( + geoh5=geoh5, + survey=survey, + data=survey.get_entity("Iteration_0_z")[0], + queries=components.queries, + topography_object=components.topography, + simulations=new_dir, + ) + match_driver = PlateMatchDriver(options) + results = match_driver.run() + + assert results[0] == file.stem + f"_[{4}].geoh5" diff --git a/tests/utils_test.py b/tests/utils_test.py deleted file mode 100644 index 13888682..00000000 --- a/tests/utils_test.py +++ /dev/null @@ -1,57 +0,0 @@ -# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -# Copyright (c) 2023-2026 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). ' -# ' -# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -import numpy as np - -from simpeg_drivers.utils.utils import inverse_weighted_operator, xyz_to_polar - - -def test_xyz_to_polar(): - """ - Test the xyz_to_polar utility function. - """ - for _ in range(100): - rad = np.abs(np.random.randn()) - azm = np.random.randn() - - # Create x, y, z coordinates - x = rad * np.cos(azm) - y = rad * np.sin(azm) - z = np.random.randn() - - polar = xyz_to_polar(np.vstack([[[0, 0, 0]], [[x, y, z]]])) - np.testing.assert_almost_equal( - polar[0, 0], -polar[1, 0] - ) # Opposite side of center - np.testing.assert_almost_equal(polar[0, 1], polar[1, 1]) # Same azimuth - np.testing.assert_allclose([0, z], polar[:, 2]) # Preserves z - - -def test_inverse_weighted_operator(): - """ - Test the inverse_weighted_operator utility function. - - For a constant input, the output should be the same constant. - """ - power = 2.0 - threshold = 1e-12 - shape = (100, 1000) - values = np.random.randn(shape[0] * 2) - indices = np.c_[ - np.random.randint(0, shape[1] - 1, shape[0]), - np.random.randint(0, shape[1] - 1, shape[0]), - ].flatten() - - opt = inverse_weighted_operator(values, indices, shape, power, threshold) - test_val = np.random.randn() - interp = opt * np.full(shape[1], test_val) - - assert opt.shape == shape - np.testing.assert_allclose(interp, test_val, rtol=1e-3) From 23f703933ef3aa615e70ce98f2cde0de4ee67d1d Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 20 Jan 2026 09:42:06 -0800 Subject: [PATCH 13/24] Adjust changes to geoapps_utils --- simpeg_drivers/plate_simulation/match/driver.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index 16c0cf37..ee7d78bd 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -22,7 +22,7 @@ from geoapps_utils.utils.logger import get_logger from geoapps_utils.utils.numerical import inverse_weighted_operator from geoapps_utils.utils.plotting import symlog -from geoapps_utils.utils.transformations import xyz_to_polar +from geoapps_utils.utils.transformations import cartesian_to_polar from geoh5py import Workspace from geoh5py.groups import PropertyGroup, SimPEGGroup from geoh5py.objects import AirborneTEMReceivers, Surface @@ -157,9 +157,9 @@ def spatial_interpolation( :return: Spatial interpolation matrix. """ # Compute local coordinates for the current line segment - local_polar = xyz_to_polar( - self.params.survey.vertices[indices] - - np.r_[self.params.survey.vertices[indices, :2].mean(axis=0), 0] + local_polar = cartesian_to_polar( + self.params.survey.vertices[indices], + origin=np.r_[self.params.survey.vertices[indices, :2].mean(axis=0), 0], ) local_polar[local_polar[:, 1] >= 180, 0] *= -1 # Wrap azimuths local_polar[:, 1] = ( @@ -167,7 +167,7 @@ def spatial_interpolation( ) # Align azimuths to zero # Convert to polar coordinates (distance, azimuth, height) - query_polar = xyz_to_polar(self._template.vertices) + query_polar = cartesian_to_polar(self._template.vertices) query_polar[query_polar[:, 1] >= 180, 0] *= -1 query_polar[:, 1] = query_polar[:, 1] % 180 # Wrap azimuths From 2c09b2f6ecafcec2487191f26802fd03e88384b0 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 20 Jan 2026 10:53:31 -0800 Subject: [PATCH 14/24] Point to branches of 2449 --- pyproject.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a7298709..3dc5cbcc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,16 +94,16 @@ python-mumps = "0.0.3.*" ## Pip dependencies from Git repositories #---------------------------------------- #geoh5py = {version = ">=0.13.0a, 0.13.*", source = "pypi", allow-prereleases = true} -geoh5py = {git = "https://github.com/MiraGeoscience/geoh5py.git", rev = "develop"} +geoh5py = {git = "https://github.com/MiraGeoscience/geoh5py.git", rev = "GEOPY-2449"} #grid-apps = {version = ">=0.2.0a, 0.2.*", source = "pypi", allow-prereleases = true} grid-apps = {git = "https://github.com/MiraGeoscience/grid-apps.git", rev = "develop"} #geoapps-utils = {version = ">=0.7.0a, 0.7.*", source = "pypi", allow-prereleases = true} -geoapps-utils = {git = "https://github.com/MiraGeoscience/geoapps-utils.git", rev = "develop"} +geoapps-utils = {git = "https://github.com/MiraGeoscience/geoapps-utils.git", rev = "GEOPY-2449"} #mira-simpeg = {version = ">=0.23.0.3a, 0.23.0.*", source="pypi", allow-prereleases = true, extras = ["dask"]} -mira-simpeg = {git = "https://github.com/MiraGeoscience/simpeg.git", rev = "GEOPY-2522", extras = ["dask"]} +mira-simpeg = {git = "https://github.com/MiraGeoscience/simpeg.git", rev = "develop", extras = ["dask"]} ## about pip dependencies # to be specified to work with conda-lock From f263fa40c1fa421508a3e650fbb2599572602af8 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Wed, 21 Jan 2026 13:26:08 -0800 Subject: [PATCH 15/24] Re-lock --- .../py-3.10-linux-64-dev.conda.lock.yml | 46 +- environments/py-3.10-linux-64.conda.lock.yml | 24 +- .../py-3.10-win-64-dev.conda.lock.yml | 46 +- environments/py-3.10-win-64.conda.lock.yml | 24 +- .../py-3.11-linux-64-dev.conda.lock.yml | 50 +- environments/py-3.11-linux-64.conda.lock.yml | 28 +- .../py-3.11-win-64-dev.conda.lock.yml | 50 +- environments/py-3.11-win-64.conda.lock.yml | 28 +- .../py-3.12-linux-64-dev.conda.lock.yml | 50 +- environments/py-3.12-linux-64.conda.lock.yml | 28 +- .../py-3.12-win-64-dev.conda.lock.yml | 50 +- environments/py-3.12-win-64.conda.lock.yml | 28 +- py-3.10.conda-lock.yml | 406 ++++++++-------- py-3.11.conda-lock.yml | 440 +++++++++--------- py-3.12.conda-lock.yml | 440 +++++++++--------- pyproject.toml | 4 +- 16 files changed, 871 insertions(+), 871 deletions(-) diff --git a/environments/py-3.10-linux-64-dev.conda.lock.yml b/environments/py-3.10-linux-64-dev.conda.lock.yml index d4634df7..4aef5f41 100644 --- a/environments/py-3.10-linux-64-dev.conda.lock.yml +++ b/environments/py-3.10-linux-64-dev.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 2b50544cb4f1d5b69b9b4ae438e854dd769e9447f4d1f6f37b9c8332259e2f13 +# input_hash: 56acf844153236bc0bae9c73a9c7a6769bafd992ebe223ac3fa1ee1ba32d25ef channels: - conda-forge @@ -16,7 +16,7 @@ dependencies: - asciitree=0.3.3=py_2 - astroid=4.0.3=py310hff52083_0 - asttokens=3.0.1=pyhd8ed1ab_0 - - async-lru=2.0.5=pyh29332c3_0 + - async-lru=2.1.0=pyhcf101f3_0 - attrs=25.4.0=pyhcf101f3_1 - babel=2.17.0=pyhd8ed1ab_0 - backports.zstd=1.3.0=py310h69bd2ac_0 @@ -47,7 +47,7 @@ dependencies: - debugpy=1.8.18=py310h25320af_0 - decorator=5.2.1=pyhd8ed1ab_0 - defusedxml=0.7.1=pyhd8ed1ab_0 - - dill=0.4.0=pyhcf101f3_1 + - dill=0.4.1=pyhcf101f3_0 - discretize=0.11.3=py310hc563356_1 - distributed=2025.3.0=pyhd8ed1ab_0 - docutils=0.19=py310hff52083_1 @@ -57,12 +57,12 @@ dependencies: - fonttools=4.61.1=py310h3406613_0 - fqdn=1.5.1=pyhd8ed1ab_1 - freetype=2.14.1=ha770c72_0 - - fsspec=2025.12.0=pyhd8ed1ab_0 + - fsspec=2026.1.0=pyhd8ed1ab_0 - geoana=0.7.2=py310hc563356_1 - h11=0.16.0=pyhcf101f3_1 - h2=4.3.0=pyhcf101f3_0 - h5py=3.15.1=nompi_py310h4aa865e_101 - - hdf5=1.14.6=nompi_h1b119a7_104 + - hdf5=1.14.6=nompi_h1b119a7_105 - hpack=4.1.0=pyhd8ed1ab_0 - httpcore=1.0.9=pyh29332c3_0 - httpx=0.28.1=pyhd8ed1ab_0 @@ -93,17 +93,17 @@ dependencies: - jupyter_core=5.9.1=pyhc90fa1f_0 - jupyter_events=0.12.0=pyh29332c3_0 - jupyter_server=2.17.0=pyhcf101f3_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_1 - - jupyterlab=4.5.1=pyhd8ed1ab_0 + - jupyter_server_terminals=0.5.4=pyhcf101f3_0 + - jupyterlab=4.5.2=pyhd8ed1ab_0 - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_server=2.28.0=pyhcf101f3_0 - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 - - jupytext=1.18.1=pyh80e38bb_0 + - jupytext=1.19.0=pyh0398c0e_0 - keyutils=1.6.3=hb9d3cd8_0 - kiwisolver=1.4.9=py310haaf941d_2 - krb5=1.21.3=h659f571_0 - lark=1.3.1=pyhd8ed1ab_0 - - lcms2=2.17=h717163a_0 + - lcms2=2.18=h0c24ade_0 - ld_impl_linux-64=2.45=default_hbd61a6d_105 - lerc=4.0.0=h0aef613_1 - libaec=1.1.4=h3f801dc_0 @@ -129,14 +129,14 @@ dependencies: - libiconv=1.18=h3b78370_2 - libjpeg-turbo=3.1.2=hb03c661_0 - liblapack=3.9.0=37_h5e43f62_mkl - - liblzma=5.8.1=hb9d3cd8_2 + - liblzma=5.8.2=hb03c661_0 - libnghttp2=1.67.0=had1ee68_0 - libnsl=2.0.1=hb9d3cd8_1 - - libpng=1.6.53=h421ea60_0 + - libpng=1.6.54=h421ea60_0 - libscotch=7.0.6=hea33c07_1 - libsodium=1.0.20=h4ab18f5_0 - libspatialindex=2.0.0=he02047a_0 - - libsqlite=3.51.1=h0c1763c_1 + - libsqlite=3.51.2=h0c1763c_0 - libssh2=1.11.1=hcf80075_0 - libstdcxx=15.2.0=h934c35e_16 - libstdcxx-ng=15.2.0=hdf11a46_16 @@ -173,7 +173,7 @@ dependencies: - ncurses=6.5=h2d0b736_3 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - nodejs=22.6.0=hc19f0b3_1 - - notebook=7.5.1=pyhcf101f3_0 + - notebook=7.5.2=pyhcf101f3_0 - notebook-shim=0.2.4=pyhd8ed1ab_1 - numcodecs=0.13.1=py310h5eaa309_0 - numpy=1.26.4=py310hb13e2d6_0 @@ -192,7 +192,7 @@ dependencies: - pip=25.3=pyh8b19718_0 - platformdirs=4.5.1=pyhcf101f3_0 - pluggy=1.6.0=pyhf9edf01_1 - - prometheus_client=0.23.1=pyhd8ed1ab_0 + - prometheus_client=0.24.1=pyhd8ed1ab_0 - prompt-toolkit=3.0.52=pyha770c72_0 - psutil=7.2.1=py310h139afa4_0 - pthread-stubs=0.4=hb9d3cd8_1002 @@ -205,7 +205,7 @@ dependencies: - pygments=2.19.2=pyhd8ed1ab_0 - pylint=4.0.4=pyhcf101f3_0 - pymatsolver=0.3.1=pyh48887ae_201 - - pyparsing=3.3.1=pyhcf101f3_0 + - pyparsing=3.3.2=pyhcf101f3_0 - pysocks=1.7.1=pyha55dd90_7 - pytest=9.0.2=pyhcf101f3_0 - pytest-cov=7.0.0=pyhcf101f3_1 @@ -230,13 +230,13 @@ dependencies: - rtree=1.2.0=py310haf1e407_1 - scikit-learn=1.6.1=py310h27f47ee_0 - scipy=1.14.1=py310hfcf56fc_2 - - send2trash=2.0.0=pyha191276_0 - - setuptools=80.9.0=pyhff2d567_0 + - send2trash=2.1.0=pyha191276_0 + - setuptools=80.10.1=pyh332efcf_0 - six=1.17.0=pyhe01879c_1 - sniffio=1.3.1=pyhd8ed1ab_2 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - sortedcontainers=2.4.0=pyhd8ed1ab_1 - - soupsieve=2.8.1=pyhd8ed1ab_0 + - soupsieve=2.8.2=pyhd8ed1ab_0 - sphinx=5.3.0=pyhd8ed1ab_0 - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 @@ -251,8 +251,8 @@ dependencies: - threadpoolctl=3.6.0=pyhecae5ae_0 - tinycss2=1.5.1=pyhcf101f3_0 - tk=8.6.13=noxft_ha0e22de_103 - - tomli=2.3.0=pyhcf101f3_0 - - tomlkit=0.13.3=pyha770c72_0 + - tomli=2.4.0=pyhcf101f3_0 + - tomlkit=0.14.0=pyha770c72_0 - toolz=1.1.0=pyhd8ed1ab_1 - tornado=6.5.3=py310h7c4b9e2_0 - tqdm=4.67.1=pyhd8ed1ab_1 @@ -283,10 +283,10 @@ dependencies: - zlib=1.3.1=hb9d3cd8_2 - zstd=1.5.7=hb78ec9c_6 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc - grid-apps @ git+https://github.com/MiraGeoscience/grid-apps.git@99e51cbe794114ce08ab3bb16efcc6749b14914a - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae variables: KMP_WARNINGS: 0 diff --git a/environments/py-3.10-linux-64.conda.lock.yml b/environments/py-3.10-linux-64.conda.lock.yml index 366ab5b8..acbe02bf 100644 --- a/environments/py-3.10-linux-64.conda.lock.yml +++ b/environments/py-3.10-linux-64.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 2b50544cb4f1d5b69b9b4ae438e854dd769e9447f4d1f6f37b9c8332259e2f13 +# input_hash: 56acf844153236bc0bae9c73a9c7a6769bafd992ebe223ac3fa1ee1ba32d25ef channels: - conda-forge @@ -32,11 +32,11 @@ dependencies: - fasteners=0.19=pyhd8ed1ab_1 - fonttools=4.61.1=py310h3406613_0 - freetype=2.14.1=ha770c72_0 - - fsspec=2025.12.0=pyhd8ed1ab_0 + - fsspec=2026.1.0=pyhd8ed1ab_0 - geoana=0.7.2=py310hc563356_1 - h2=4.3.0=pyhcf101f3_0 - h5py=3.15.1=nompi_py310h4aa865e_101 - - hdf5=1.14.6=nompi_h1b119a7_104 + - hdf5=1.14.6=nompi_h1b119a7_105 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=75.1=he02047a_0 @@ -46,7 +46,7 @@ dependencies: - keyutils=1.6.3=hb9d3cd8_0 - kiwisolver=1.4.9=py310haaf941d_2 - krb5=1.21.3=h659f571_0 - - lcms2=2.17=h717163a_0 + - lcms2=2.18=h0c24ade_0 - ld_impl_linux-64=2.45=default_hbd61a6d_105 - lerc=4.0.0=h0aef613_1 - libaec=1.1.4=h3f801dc_0 @@ -72,13 +72,13 @@ dependencies: - libiconv=1.18=h3b78370_2 - libjpeg-turbo=3.1.2=hb03c661_0 - liblapack=3.9.0=37_h5e43f62_mkl - - liblzma=5.8.1=hb9d3cd8_2 + - liblzma=5.8.2=hb03c661_0 - libnghttp2=1.67.0=had1ee68_0 - libnsl=2.0.1=hb9d3cd8_1 - - libpng=1.6.53=h421ea60_0 + - libpng=1.6.54=h421ea60_0 - libscotch=7.0.6=hea33c07_1 - libspatialindex=2.0.0=he02047a_0 - - libsqlite=3.51.1=h0c1763c_1 + - libsqlite=3.51.2=h0c1763c_0 - libssh2=1.11.1=hcf80075_0 - libstdcxx=15.2.0=h934c35e_16 - libstdcxx-ng=15.2.0=hdf11a46_16 @@ -116,7 +116,7 @@ dependencies: - pydantic-core=2.41.5=py310hd8f68c5_1 - pydiso=0.1.2=py310h4b187eb_1 - pymatsolver=0.3.1=pyh48887ae_201 - - pyparsing=3.3.1=pyhcf101f3_0 + - pyparsing=3.3.2=pyhcf101f3_0 - pysocks=1.7.1=pyha55dd90_7 - python=3.10.19=h3c07f61_2_cpython - python-dateutil=2.9.0.post0=pyhe01879c_2 @@ -129,7 +129,7 @@ dependencies: - rtree=1.2.0=py310haf1e407_1 - scikit-learn=1.6.1=py310h27f47ee_0 - scipy=1.14.1=py310hfcf56fc_2 - - setuptools=80.9.0=pyhff2d567_0 + - setuptools=80.10.1=pyh332efcf_0 - six=1.17.0=pyhe01879c_1 - sortedcontainers=2.4.0=pyhd8ed1ab_1 - tbb=2021.13.0=hb700be7_5 @@ -156,10 +156,10 @@ dependencies: - zipp=3.23.0=pyhcf101f3_1 - zstd=1.5.7=hb78ec9c_6 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc - grid-apps @ git+https://github.com/MiraGeoscience/grid-apps.git@99e51cbe794114ce08ab3bb16efcc6749b14914a - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae variables: KMP_WARNINGS: 0 diff --git a/environments/py-3.10-win-64-dev.conda.lock.yml b/environments/py-3.10-win-64-dev.conda.lock.yml index 6b994403..cdbec403 100644 --- a/environments/py-3.10-win-64-dev.conda.lock.yml +++ b/environments/py-3.10-win-64-dev.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: win-64 -# input_hash: ade6f8568a23d600ae9ce846ee88765a4745040016210637a40b1410b32073fe +# input_hash: 4095d8c1a6c5ba4facb54b1eef593eaa3c13a1bb5dba5638b7d7103f84795d37 channels: - conda-forge @@ -16,7 +16,7 @@ dependencies: - asciitree=0.3.3=py_2 - astroid=4.0.3=py310h5588dad_0 - asttokens=3.0.1=pyhd8ed1ab_0 - - async-lru=2.0.5=pyh29332c3_0 + - async-lru=2.1.0=pyhcf101f3_0 - attrs=25.4.0=pyhcf101f3_1 - babel=2.17.0=pyhd8ed1ab_0 - backports.zstd=1.3.0=py310h458dff3_0 @@ -46,7 +46,7 @@ dependencies: - debugpy=1.8.19=py310h699e580_0 - decorator=5.2.1=pyhd8ed1ab_0 - defusedxml=0.7.1=pyhd8ed1ab_0 - - dill=0.4.0=pyhcf101f3_1 + - dill=0.4.1=pyhcf101f3_0 - discretize=0.11.3=py310hfb7dd09_1 - distributed=2025.3.0=pyhd8ed1ab_0 - docutils=0.19=py310h5588dad_1 @@ -56,12 +56,12 @@ dependencies: - fonttools=4.61.1=py310hdb0e946_0 - fqdn=1.5.1=pyhd8ed1ab_1 - freetype=2.14.1=h57928b3_0 - - fsspec=2025.12.0=pyhd8ed1ab_0 + - fsspec=2026.1.0=pyhd8ed1ab_0 - geoana=0.7.2=py310hfb7dd09_1 - h11=0.16.0=pyhcf101f3_1 - h2=4.3.0=pyhcf101f3_0 - h5py=3.15.1=nompi_py310hb7e4da9_101 - - hdf5=1.14.6=nompi_h89f0904_104 + - hdf5=1.14.6=nompi_h89f0904_105 - hpack=4.1.0=pyhd8ed1ab_0 - httpcore=1.0.9=pyh29332c3_0 - httpx=0.28.1=pyhd8ed1ab_0 @@ -92,16 +92,16 @@ dependencies: - jupyter_core=5.9.1=pyh6dadd2b_0 - jupyter_events=0.12.0=pyh29332c3_0 - jupyter_server=2.17.0=pyhcf101f3_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_1 - - jupyterlab=4.5.1=pyhd8ed1ab_0 + - jupyter_server_terminals=0.5.4=pyhcf101f3_0 + - jupyterlab=4.5.2=pyhd8ed1ab_0 - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_server=2.28.0=pyhcf101f3_0 - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 - - jupytext=1.18.1=pyh80e38bb_0 + - jupytext=1.19.0=pyh0398c0e_0 - kiwisolver=1.4.9=py310h1e1005b_2 - krb5=1.21.3=hdf4eb48_0 - lark=1.3.1=pyhd8ed1ab_0 - - lcms2=2.17=hbcf6048_0 + - lcms2=2.18=hf2c6c5f_0 - lerc=4.0.0=h6470a55_1 - libaec=1.1.4=h20038f6_0 - libblas=3.9.0=35_h5709861_mkl @@ -122,11 +122,11 @@ dependencies: - libiconv=1.18=hc1393d2_2 - libjpeg-turbo=3.1.2=hfd05255_0 - liblapack=3.9.0=35_hf9ab0e9_mkl - - liblzma=5.8.1=h2466b09_2 - - libpng=1.6.53=h7351971_0 + - liblzma=5.8.2=hfd05255_0 + - libpng=1.6.54=h7351971_0 - libsodium=1.0.20=hc70643c_0 - libspatialindex=2.0.0=h5a68840_0 - - libsqlite=3.51.1=hf5d6505_1 + - libsqlite=3.51.2=hf5d6505_0 - libssh2=1.11.1=h9aa295b_0 - libtiff=4.7.1=h8f73337_1 - libwebp-base=1.6.0=h4d5522a_0 @@ -156,7 +156,7 @@ dependencies: - nbformat=5.10.4=pyhd8ed1ab_1 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - nodejs=25.2.1=he453025_1 - - notebook=7.5.1=pyhcf101f3_0 + - notebook=7.5.2=pyhcf101f3_0 - notebook-shim=0.2.4=pyhd8ed1ab_1 - numcodecs=0.13.1=py310hb4db72f_0 - numpy=1.26.4=py310hf667824_0 @@ -174,7 +174,7 @@ dependencies: - pip=25.3=pyh8b19718_0 - platformdirs=4.5.1=pyhcf101f3_0 - pluggy=1.6.0=pyhf9edf01_1 - - prometheus_client=0.23.1=pyhd8ed1ab_0 + - prometheus_client=0.24.1=pyhd8ed1ab_0 - prompt-toolkit=3.0.52=pyha770c72_0 - psutil=7.2.1=py310h1637853_0 - pthread-stubs=0.4=h0e40799_1002 @@ -186,7 +186,7 @@ dependencies: - pygments=2.19.2=pyhd8ed1ab_0 - pylint=4.0.4=pyhcf101f3_0 - pymatsolver=0.3.1=pyh48887ae_201 - - pyparsing=3.3.1=pyhcf101f3_0 + - pyparsing=3.3.2=pyhcf101f3_0 - pysocks=1.7.1=pyh09c184e_7 - pytest=9.0.2=pyhcf101f3_0 - pytest-cov=7.0.0=pyhcf101f3_1 @@ -212,13 +212,13 @@ dependencies: - rtree=1.2.0=py310h08d5ad2_1 - scikit-learn=1.6.1=py310hf2a6c47_0 - scipy=1.14.1=py310hbd0dde3_2 - - send2trash=2.0.0=pyh6dadd2b_0 - - setuptools=80.9.0=pyhff2d567_0 + - send2trash=2.1.0=pyh6dadd2b_0 + - setuptools=80.10.1=pyh332efcf_0 - six=1.17.0=pyhe01879c_1 - sniffio=1.3.1=pyhd8ed1ab_2 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - sortedcontainers=2.4.0=pyhd8ed1ab_1 - - soupsieve=2.8.1=pyhd8ed1ab_0 + - soupsieve=2.8.2=pyhd8ed1ab_0 - sphinx=5.3.0=pyhd8ed1ab_0 - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 @@ -233,8 +233,8 @@ dependencies: - threadpoolctl=3.6.0=pyhecae5ae_0 - tinycss2=1.5.1=pyhcf101f3_0 - tk=8.6.13=h2c6b04d_3 - - tomli=2.3.0=pyhcf101f3_0 - - tomlkit=0.13.3=pyha770c72_0 + - tomli=2.4.0=pyhcf101f3_0 + - tomlkit=0.14.0=pyha770c72_0 - toolz=1.1.0=pyhd8ed1ab_1 - tornado=6.5.4=py310h29418f3_0 - tqdm=4.67.1=pyhd8ed1ab_1 @@ -270,10 +270,10 @@ dependencies: - zipp=3.23.0=pyhcf101f3_1 - zstd=1.5.7=h534d264_6 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc - grid-apps @ git+https://github.com/MiraGeoscience/grid-apps.git@99e51cbe794114ce08ab3bb16efcc6749b14914a - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae variables: KMP_WARNINGS: 0 diff --git a/environments/py-3.10-win-64.conda.lock.yml b/environments/py-3.10-win-64.conda.lock.yml index 2eb23b9d..003e79a6 100644 --- a/environments/py-3.10-win-64.conda.lock.yml +++ b/environments/py-3.10-win-64.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: win-64 -# input_hash: ade6f8568a23d600ae9ce846ee88765a4745040016210637a40b1410b32073fe +# input_hash: 4095d8c1a6c5ba4facb54b1eef593eaa3c13a1bb5dba5638b7d7103f84795d37 channels: - conda-forge @@ -31,11 +31,11 @@ dependencies: - fasteners=0.19=pyhd8ed1ab_1 - fonttools=4.61.1=py310hdb0e946_0 - freetype=2.14.1=h57928b3_0 - - fsspec=2025.12.0=pyhd8ed1ab_0 + - fsspec=2026.1.0=pyhd8ed1ab_0 - geoana=0.7.2=py310hfb7dd09_1 - h2=4.3.0=pyhcf101f3_0 - h5py=3.15.1=nompi_py310hb7e4da9_101 - - hdf5=1.14.6=nompi_h89f0904_104 + - hdf5=1.14.6=nompi_h89f0904_105 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=78.2=h637d24d_0 @@ -44,7 +44,7 @@ dependencies: - joblib=1.5.3=pyhd8ed1ab_0 - kiwisolver=1.4.9=py310h1e1005b_2 - krb5=1.21.3=hdf4eb48_0 - - lcms2=2.17=hbcf6048_0 + - lcms2=2.18=hf2c6c5f_0 - lerc=4.0.0=h6470a55_1 - libaec=1.1.4=h20038f6_0 - libblas=3.9.0=35_h5709861_mkl @@ -65,10 +65,10 @@ dependencies: - libiconv=1.18=hc1393d2_2 - libjpeg-turbo=3.1.2=hfd05255_0 - liblapack=3.9.0=35_hf9ab0e9_mkl - - liblzma=5.8.1=h2466b09_2 - - libpng=1.6.53=h7351971_0 + - liblzma=5.8.2=hfd05255_0 + - libpng=1.6.54=h7351971_0 - libspatialindex=2.0.0=h5a68840_0 - - libsqlite=3.51.1=hf5d6505_1 + - libsqlite=3.51.2=hf5d6505_0 - libssh2=1.11.1=h9aa295b_0 - libtiff=4.7.1=h8f73337_1 - libwebp-base=1.6.0=h4d5522a_0 @@ -100,7 +100,7 @@ dependencies: - pydantic-core=2.41.5=py310h034784e_1 - pydiso=0.1.2=py310h3dbbb0c_1 - pymatsolver=0.3.1=pyh48887ae_201 - - pyparsing=3.3.1=pyhcf101f3_0 + - pyparsing=3.3.2=pyhcf101f3_0 - pysocks=1.7.1=pyh09c184e_7 - python=3.10.19=hc20f281_2_cpython - python-dateutil=2.9.0.post0=pyhe01879c_2 @@ -112,7 +112,7 @@ dependencies: - rtree=1.2.0=py310h08d5ad2_1 - scikit-learn=1.6.1=py310hf2a6c47_0 - scipy=1.14.1=py310hbd0dde3_2 - - setuptools=80.9.0=pyhff2d567_0 + - setuptools=80.10.1=pyh332efcf_0 - six=1.17.0=pyhe01879c_1 - sortedcontainers=2.4.0=pyhd8ed1ab_1 - tbb=2021.13.0=h3155e25_5 @@ -144,10 +144,10 @@ dependencies: - zipp=3.23.0=pyhcf101f3_1 - zstd=1.5.7=h534d264_6 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc - grid-apps @ git+https://github.com/MiraGeoscience/grid-apps.git@99e51cbe794114ce08ab3bb16efcc6749b14914a - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae variables: KMP_WARNINGS: 0 diff --git a/environments/py-3.11-linux-64-dev.conda.lock.yml b/environments/py-3.11-linux-64-dev.conda.lock.yml index 4f7f9c4a..d0406864 100644 --- a/environments/py-3.11-linux-64-dev.conda.lock.yml +++ b/environments/py-3.11-linux-64-dev.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 5a4516dfb4e65db8f49436fab37d54a6b4d11c5554b1596d650b342d1875c5e0 +# input_hash: 63b54937a5485c2342c949498a43e2a0c19090b2df7a941558e7f5f979673863 channels: - conda-forge @@ -16,7 +16,7 @@ dependencies: - asciitree=0.3.3=py_2 - astroid=4.0.3=py311h38be061_0 - asttokens=3.0.1=pyhd8ed1ab_0 - - async-lru=2.0.5=pyh29332c3_0 + - async-lru=2.1.0=pyhcf101f3_0 - attrs=25.4.0=pyhcf101f3_1 - babel=2.17.0=pyhd8ed1ab_0 - backports.zstd=1.3.0=py311h6b1f9c4_0 @@ -47,8 +47,8 @@ dependencies: - debugpy=1.8.18=py311hc665b79_0 - decorator=5.2.1=pyhd8ed1ab_0 - defusedxml=0.7.1=pyhd8ed1ab_0 - - deprecated=1.3.1=pyhd8ed1ab_0 - - dill=0.4.0=pyhcf101f3_1 + - deprecated=1.3.1=pyhd8ed1ab_1 + - dill=0.4.1=pyhcf101f3_0 - discretize=0.11.3=py311h1d5f577_1 - distributed=2025.3.0=pyhd8ed1ab_0 - docutils=0.19=py311h38be061_1 @@ -58,12 +58,12 @@ dependencies: - fonttools=4.61.1=py311h3778330_0 - fqdn=1.5.1=pyhd8ed1ab_1 - freetype=2.14.1=ha770c72_0 - - fsspec=2025.12.0=pyhd8ed1ab_0 + - fsspec=2026.1.0=pyhd8ed1ab_0 - geoana=0.7.2=py311h1d5f577_1 - h11=0.16.0=pyhcf101f3_1 - h2=4.3.0=pyhcf101f3_0 - h5py=3.15.1=nompi_py311h0b2f468_101 - - hdf5=1.14.6=nompi_h1b119a7_104 + - hdf5=1.14.6=nompi_h1b119a7_105 - hpack=4.1.0=pyhd8ed1ab_0 - httpcore=1.0.9=pyh29332c3_0 - httpx=0.28.1=pyhd8ed1ab_0 @@ -95,17 +95,17 @@ dependencies: - jupyter_core=5.9.1=pyhc90fa1f_0 - jupyter_events=0.12.0=pyh29332c3_0 - jupyter_server=2.17.0=pyhcf101f3_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_1 - - jupyterlab=4.5.1=pyhd8ed1ab_0 + - jupyter_server_terminals=0.5.4=pyhcf101f3_0 + - jupyterlab=4.5.2=pyhd8ed1ab_0 - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_server=2.28.0=pyhcf101f3_0 - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 - - jupytext=1.18.1=pyh80e38bb_0 + - jupytext=1.19.0=pyh0398c0e_0 - keyutils=1.6.3=hb9d3cd8_0 - kiwisolver=1.4.9=py311h724c32c_2 - krb5=1.21.3=h659f571_0 - lark=1.3.1=pyhd8ed1ab_0 - - lcms2=2.17=h717163a_0 + - lcms2=2.18=h0c24ade_0 - ld_impl_linux-64=2.45=default_hbd61a6d_105 - lerc=4.0.0=h0aef613_1 - libaec=1.1.4=h3f801dc_0 @@ -131,14 +131,14 @@ dependencies: - libiconv=1.18=h3b78370_2 - libjpeg-turbo=3.1.2=hb03c661_0 - liblapack=3.9.0=37_h5e43f62_mkl - - liblzma=5.8.1=hb9d3cd8_2 + - liblzma=5.8.2=hb03c661_0 - libnghttp2=1.67.0=had1ee68_0 - libnsl=2.0.1=hb9d3cd8_1 - - libpng=1.6.53=h421ea60_0 + - libpng=1.6.54=h421ea60_0 - libscotch=7.0.6=hea33c07_1 - libsodium=1.0.20=h4ab18f5_0 - libspatialindex=2.0.0=he02047a_0 - - libsqlite=3.51.1=h0c1763c_1 + - libsqlite=3.51.2=h0c1763c_0 - libssh2=1.11.1=hcf80075_0 - libstdcxx=15.2.0=h934c35e_16 - libstdcxx-ng=15.2.0=hdf11a46_16 @@ -175,7 +175,7 @@ dependencies: - ncurses=6.5=h2d0b736_3 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - nodejs=22.6.0=hc19f0b3_1 - - notebook=7.5.1=pyhcf101f3_0 + - notebook=7.5.2=pyhcf101f3_0 - notebook-shim=0.2.4=pyhd8ed1ab_1 - numcodecs=0.15.1=py311hed34c8f_1 - numpy=1.26.4=py311h64a7726_0 @@ -193,7 +193,7 @@ dependencies: - pip=25.3=pyh8b19718_0 - platformdirs=4.5.1=pyhcf101f3_0 - pluggy=1.6.0=pyhf9edf01_1 - - prometheus_client=0.23.1=pyhd8ed1ab_0 + - prometheus_client=0.24.1=pyhd8ed1ab_0 - prompt-toolkit=3.0.52=pyha770c72_0 - psutil=7.2.1=py311haee01d2_0 - pthread-stubs=0.4=hb9d3cd8_1002 @@ -206,7 +206,7 @@ dependencies: - pygments=2.19.2=pyhd8ed1ab_0 - pylint=4.0.4=pyhcf101f3_0 - pymatsolver=0.3.1=pyh48887ae_201 - - pyparsing=3.3.1=pyhcf101f3_0 + - pyparsing=3.3.2=pyhcf101f3_0 - pysocks=1.7.1=pyha55dd90_7 - pytest=9.0.2=pyhcf101f3_0 - pytest-cov=7.0.0=pyhcf101f3_1 @@ -231,13 +231,13 @@ dependencies: - rtree=1.2.0=py311ha1603b9_1 - scikit-learn=1.6.1=py311h57cc02b_0 - scipy=1.14.1=py311he9a78e4_2 - - send2trash=2.0.0=pyha191276_0 - - setuptools=80.9.0=pyhff2d567_0 + - send2trash=2.1.0=pyha191276_0 + - setuptools=80.10.1=pyh332efcf_0 - six=1.17.0=pyhe01879c_1 - sniffio=1.3.1=pyhd8ed1ab_2 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - sortedcontainers=2.4.0=pyhd8ed1ab_1 - - soupsieve=2.8.1=pyhd8ed1ab_0 + - soupsieve=2.8.2=pyhd8ed1ab_0 - sphinx=5.3.0=pyhd8ed1ab_0 - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 @@ -252,8 +252,8 @@ dependencies: - threadpoolctl=3.6.0=pyhecae5ae_0 - tinycss2=1.5.1=pyhcf101f3_0 - tk=8.6.13=noxft_ha0e22de_103 - - tomli=2.3.0=pyhcf101f3_0 - - tomlkit=0.13.3=pyha770c72_0 + - tomli=2.4.0=pyhcf101f3_0 + - tomlkit=0.14.0=pyha770c72_0 - toolz=1.1.0=pyhd8ed1ab_1 - tornado=6.5.3=py311h49ec1c0_0 - tqdm=4.67.1=pyhd8ed1ab_1 @@ -273,7 +273,7 @@ dependencies: - websocket-client=1.9.0=pyhd8ed1ab_0 - wheel=0.45.1=pyhd8ed1ab_1 - widgetsnbextension=3.6.10=pyhd8ed1ab_0 - - wrapt=1.17.3=py311h49ec1c0_1 + - wrapt=2.0.1=py311h49ec1c0_1 - xorg-libxau=1.0.12=hb03c661_1 - xorg-libxdmcp=1.1.5=hb03c661_1 - xyzservices=2025.11.0=pyhd8ed1ab_0 @@ -285,10 +285,10 @@ dependencies: - zlib=1.3.1=hb9d3cd8_2 - zstd=1.5.7=hb78ec9c_6 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc - grid-apps @ git+https://github.com/MiraGeoscience/grid-apps.git@99e51cbe794114ce08ab3bb16efcc6749b14914a - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae variables: KMP_WARNINGS: 0 diff --git a/environments/py-3.11-linux-64.conda.lock.yml b/environments/py-3.11-linux-64.conda.lock.yml index 4de597cb..7d52271e 100644 --- a/environments/py-3.11-linux-64.conda.lock.yml +++ b/environments/py-3.11-linux-64.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 5a4516dfb4e65db8f49436fab37d54a6b4d11c5554b1596d650b342d1875c5e0 +# input_hash: 63b54937a5485c2342c949498a43e2a0c19090b2df7a941558e7f5f979673863 channels: - conda-forge @@ -27,17 +27,17 @@ dependencies: - cycler=0.12.1=pyhcf101f3_2 - cytoolz=1.1.0=py311h49ec1c0_1 - dask-core=2025.3.0=pyhd8ed1ab_0 - - deprecated=1.3.1=pyhd8ed1ab_0 + - deprecated=1.3.1=pyhd8ed1ab_1 - discretize=0.11.3=py311h1d5f577_1 - distributed=2025.3.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - fonttools=4.61.1=py311h3778330_0 - freetype=2.14.1=ha770c72_0 - - fsspec=2025.12.0=pyhd8ed1ab_0 + - fsspec=2026.1.0=pyhd8ed1ab_0 - geoana=0.7.2=py311h1d5f577_1 - h2=4.3.0=pyhcf101f3_0 - h5py=3.15.1=nompi_py311h0b2f468_101 - - hdf5=1.14.6=nompi_h1b119a7_104 + - hdf5=1.14.6=nompi_h1b119a7_105 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=75.1=he02047a_0 @@ -47,7 +47,7 @@ dependencies: - keyutils=1.6.3=hb9d3cd8_0 - kiwisolver=1.4.9=py311h724c32c_2 - krb5=1.21.3=h659f571_0 - - lcms2=2.17=h717163a_0 + - lcms2=2.18=h0c24ade_0 - ld_impl_linux-64=2.45=default_hbd61a6d_105 - lerc=4.0.0=h0aef613_1 - libaec=1.1.4=h3f801dc_0 @@ -73,13 +73,13 @@ dependencies: - libiconv=1.18=h3b78370_2 - libjpeg-turbo=3.1.2=hb03c661_0 - liblapack=3.9.0=37_h5e43f62_mkl - - liblzma=5.8.1=hb9d3cd8_2 + - liblzma=5.8.2=hb03c661_0 - libnghttp2=1.67.0=had1ee68_0 - libnsl=2.0.1=hb9d3cd8_1 - - libpng=1.6.53=h421ea60_0 + - libpng=1.6.54=h421ea60_0 - libscotch=7.0.6=hea33c07_1 - libspatialindex=2.0.0=he02047a_0 - - libsqlite=3.51.1=h0c1763c_1 + - libsqlite=3.51.2=h0c1763c_0 - libssh2=1.11.1=hcf80075_0 - libstdcxx=15.2.0=h934c35e_16 - libstdcxx-ng=15.2.0=hdf11a46_16 @@ -117,7 +117,7 @@ dependencies: - pydantic-core=2.41.5=py311h902ca64_1 - pydiso=0.1.2=py311h6070e36_1 - pymatsolver=0.3.1=pyh48887ae_201 - - pyparsing=3.3.1=pyhcf101f3_0 + - pyparsing=3.3.2=pyhcf101f3_0 - pysocks=1.7.1=pyha55dd90_7 - python=3.11.14=hd63d673_2_cpython - python-dateutil=2.9.0.post0=pyhe01879c_2 @@ -130,7 +130,7 @@ dependencies: - rtree=1.2.0=py311ha1603b9_1 - scikit-learn=1.6.1=py311h57cc02b_0 - scipy=1.14.1=py311he9a78e4_2 - - setuptools=80.9.0=pyhff2d567_0 + - setuptools=80.10.1=pyh332efcf_0 - six=1.17.0=pyhe01879c_1 - sortedcontainers=2.4.0=pyhd8ed1ab_1 - tbb=2021.13.0=hb700be7_5 @@ -148,7 +148,7 @@ dependencies: - unicodedata2=17.0.0=py311h49ec1c0_1 - urllib3=2.6.3=pyhd8ed1ab_0 - wheel=0.45.1=pyhd8ed1ab_1 - - wrapt=1.17.3=py311h49ec1c0_1 + - wrapt=2.0.1=py311h49ec1c0_1 - xorg-libxau=1.0.12=hb03c661_1 - xorg-libxdmcp=1.1.5=hb03c661_1 - xyzservices=2025.11.0=pyhd8ed1ab_0 @@ -158,10 +158,10 @@ dependencies: - zipp=3.23.0=pyhcf101f3_1 - zstd=1.5.7=hb78ec9c_6 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc - grid-apps @ git+https://github.com/MiraGeoscience/grid-apps.git@99e51cbe794114ce08ab3bb16efcc6749b14914a - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae variables: KMP_WARNINGS: 0 diff --git a/environments/py-3.11-win-64-dev.conda.lock.yml b/environments/py-3.11-win-64-dev.conda.lock.yml index 3f5f1a87..cdd25ffb 100644 --- a/environments/py-3.11-win-64-dev.conda.lock.yml +++ b/environments/py-3.11-win-64-dev.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: win-64 -# input_hash: 18951a7399038507897a2e4d2ce4f98c2560b388e41fad171b805dd135d64300 +# input_hash: fb18dd8c88b4986ce881481f4f4c756520898dda00e4f5006f10cc99878f79e0 channels: - conda-forge @@ -16,7 +16,7 @@ dependencies: - asciitree=0.3.3=py_2 - astroid=4.0.3=py311h1ea47a8_0 - asttokens=3.0.1=pyhd8ed1ab_0 - - async-lru=2.0.5=pyh29332c3_0 + - async-lru=2.1.0=pyhcf101f3_0 - attrs=25.4.0=pyhcf101f3_1 - babel=2.17.0=pyhd8ed1ab_0 - backports.zstd=1.3.0=py311h71c1bcc_0 @@ -46,8 +46,8 @@ dependencies: - debugpy=1.8.19=py311h5dfdfe8_0 - decorator=5.2.1=pyhd8ed1ab_0 - defusedxml=0.7.1=pyhd8ed1ab_0 - - deprecated=1.3.1=pyhd8ed1ab_0 - - dill=0.4.0=pyhcf101f3_1 + - deprecated=1.3.1=pyhd8ed1ab_1 + - dill=0.4.1=pyhcf101f3_0 - discretize=0.11.3=py311h05ac4f6_1 - distributed=2025.3.0=pyhd8ed1ab_0 - docutils=0.19=py311h1ea47a8_1 @@ -57,12 +57,12 @@ dependencies: - fonttools=4.61.1=py311h3f79411_0 - fqdn=1.5.1=pyhd8ed1ab_1 - freetype=2.14.1=h57928b3_0 - - fsspec=2025.12.0=pyhd8ed1ab_0 + - fsspec=2026.1.0=pyhd8ed1ab_0 - geoana=0.7.2=py311h05ac4f6_1 - h11=0.16.0=pyhcf101f3_1 - h2=4.3.0=pyhcf101f3_0 - h5py=3.15.1=nompi_py311hc40ba4b_101 - - hdf5=1.14.6=nompi_h89f0904_104 + - hdf5=1.14.6=nompi_h89f0904_105 - hpack=4.1.0=pyhd8ed1ab_0 - httpcore=1.0.9=pyh29332c3_0 - httpx=0.28.1=pyhd8ed1ab_0 @@ -94,16 +94,16 @@ dependencies: - jupyter_core=5.9.1=pyh6dadd2b_0 - jupyter_events=0.12.0=pyh29332c3_0 - jupyter_server=2.17.0=pyhcf101f3_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_1 - - jupyterlab=4.5.1=pyhd8ed1ab_0 + - jupyter_server_terminals=0.5.4=pyhcf101f3_0 + - jupyterlab=4.5.2=pyhd8ed1ab_0 - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_server=2.28.0=pyhcf101f3_0 - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 - - jupytext=1.18.1=pyh80e38bb_0 + - jupytext=1.19.0=pyh0398c0e_0 - kiwisolver=1.4.9=py311h275cad7_2 - krb5=1.21.3=hdf4eb48_0 - lark=1.3.1=pyhd8ed1ab_0 - - lcms2=2.17=hbcf6048_0 + - lcms2=2.18=hf2c6c5f_0 - lerc=4.0.0=h6470a55_1 - libaec=1.1.4=h20038f6_0 - libblas=3.9.0=35_h5709861_mkl @@ -124,11 +124,11 @@ dependencies: - libiconv=1.18=hc1393d2_2 - libjpeg-turbo=3.1.2=hfd05255_0 - liblapack=3.9.0=35_hf9ab0e9_mkl - - liblzma=5.8.1=h2466b09_2 - - libpng=1.6.53=h7351971_0 + - liblzma=5.8.2=hfd05255_0 + - libpng=1.6.54=h7351971_0 - libsodium=1.0.20=hc70643c_0 - libspatialindex=2.0.0=h5a68840_0 - - libsqlite=3.51.1=hf5d6505_1 + - libsqlite=3.51.2=hf5d6505_0 - libssh2=1.11.1=h9aa295b_0 - libtiff=4.7.1=h8f73337_1 - libwebp-base=1.6.0=h4d5522a_0 @@ -158,7 +158,7 @@ dependencies: - nbformat=5.10.4=pyhd8ed1ab_1 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - nodejs=25.2.1=he453025_1 - - notebook=7.5.1=pyhcf101f3_0 + - notebook=7.5.2=pyhcf101f3_0 - notebook-shim=0.2.4=pyhd8ed1ab_1 - numcodecs=0.15.1=py311h11fd7f3_1 - numpy=1.26.4=py311h0b4df5a_0 @@ -175,7 +175,7 @@ dependencies: - pip=25.3=pyh8b19718_0 - platformdirs=4.5.1=pyhcf101f3_0 - pluggy=1.6.0=pyhf9edf01_1 - - prometheus_client=0.23.1=pyhd8ed1ab_0 + - prometheus_client=0.24.1=pyhd8ed1ab_0 - prompt-toolkit=3.0.52=pyha770c72_0 - psutil=7.2.1=py311hf893f09_0 - pthread-stubs=0.4=h0e40799_1002 @@ -187,7 +187,7 @@ dependencies: - pygments=2.19.2=pyhd8ed1ab_0 - pylint=4.0.4=pyhcf101f3_0 - pymatsolver=0.3.1=pyh48887ae_201 - - pyparsing=3.3.1=pyhcf101f3_0 + - pyparsing=3.3.2=pyhcf101f3_0 - pysocks=1.7.1=pyh09c184e_7 - pytest=9.0.2=pyhcf101f3_0 - pytest-cov=7.0.0=pyhcf101f3_1 @@ -213,13 +213,13 @@ dependencies: - rtree=1.2.0=py311h44d53c4_1 - scikit-learn=1.6.1=py311hdcb8d17_0 - scipy=1.14.1=py311hf16d85f_2 - - send2trash=2.0.0=pyh6dadd2b_0 - - setuptools=80.9.0=pyhff2d567_0 + - send2trash=2.1.0=pyh6dadd2b_0 + - setuptools=80.10.1=pyh332efcf_0 - six=1.17.0=pyhe01879c_1 - sniffio=1.3.1=pyhd8ed1ab_2 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - sortedcontainers=2.4.0=pyhd8ed1ab_1 - - soupsieve=2.8.1=pyhd8ed1ab_0 + - soupsieve=2.8.2=pyhd8ed1ab_0 - sphinx=5.3.0=pyhd8ed1ab_0 - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 @@ -234,8 +234,8 @@ dependencies: - threadpoolctl=3.6.0=pyhecae5ae_0 - tinycss2=1.5.1=pyhcf101f3_0 - tk=8.6.13=h2c6b04d_3 - - tomli=2.3.0=pyhcf101f3_0 - - tomlkit=0.13.3=pyha770c72_0 + - tomli=2.4.0=pyhcf101f3_0 + - tomlkit=0.14.0=pyha770c72_0 - toolz=1.1.0=pyhd8ed1ab_1 - tornado=6.5.4=py311h3485c13_0 - tqdm=4.67.1=pyhd8ed1ab_1 @@ -261,7 +261,7 @@ dependencies: - widgetsnbextension=3.6.10=pyhd8ed1ab_0 - win_inet_pton=1.1.0=pyh7428d3b_8 - winpty=0.4.3=4 - - wrapt=1.17.3=py311h3485c13_1 + - wrapt=2.0.1=py311h3485c13_1 - xorg-libxau=1.0.12=hba3369d_1 - xorg-libxdmcp=1.1.5=hba3369d_1 - xyzservices=2025.11.0=pyhd8ed1ab_0 @@ -272,10 +272,10 @@ dependencies: - zipp=3.23.0=pyhcf101f3_1 - zstd=1.5.7=h534d264_6 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc - grid-apps @ git+https://github.com/MiraGeoscience/grid-apps.git@99e51cbe794114ce08ab3bb16efcc6749b14914a - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae variables: KMP_WARNINGS: 0 diff --git a/environments/py-3.11-win-64.conda.lock.yml b/environments/py-3.11-win-64.conda.lock.yml index bbe138cb..f61346e9 100644 --- a/environments/py-3.11-win-64.conda.lock.yml +++ b/environments/py-3.11-win-64.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: win-64 -# input_hash: 18951a7399038507897a2e4d2ce4f98c2560b388e41fad171b805dd135d64300 +# input_hash: fb18dd8c88b4986ce881481f4f4c756520898dda00e4f5006f10cc99878f79e0 channels: - conda-forge @@ -26,17 +26,17 @@ dependencies: - cycler=0.12.1=pyhcf101f3_2 - cytoolz=1.1.0=py311h3485c13_1 - dask-core=2025.3.0=pyhd8ed1ab_0 - - deprecated=1.3.1=pyhd8ed1ab_0 + - deprecated=1.3.1=pyhd8ed1ab_1 - discretize=0.11.3=py311h05ac4f6_1 - distributed=2025.3.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - fonttools=4.61.1=py311h3f79411_0 - freetype=2.14.1=h57928b3_0 - - fsspec=2025.12.0=pyhd8ed1ab_0 + - fsspec=2026.1.0=pyhd8ed1ab_0 - geoana=0.7.2=py311h05ac4f6_1 - h2=4.3.0=pyhcf101f3_0 - h5py=3.15.1=nompi_py311hc40ba4b_101 - - hdf5=1.14.6=nompi_h89f0904_104 + - hdf5=1.14.6=nompi_h89f0904_105 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=78.2=h637d24d_0 @@ -45,7 +45,7 @@ dependencies: - joblib=1.5.3=pyhd8ed1ab_0 - kiwisolver=1.4.9=py311h275cad7_2 - krb5=1.21.3=hdf4eb48_0 - - lcms2=2.17=hbcf6048_0 + - lcms2=2.18=hf2c6c5f_0 - lerc=4.0.0=h6470a55_1 - libaec=1.1.4=h20038f6_0 - libblas=3.9.0=35_h5709861_mkl @@ -66,10 +66,10 @@ dependencies: - libiconv=1.18=hc1393d2_2 - libjpeg-turbo=3.1.2=hfd05255_0 - liblapack=3.9.0=35_hf9ab0e9_mkl - - liblzma=5.8.1=h2466b09_2 - - libpng=1.6.53=h7351971_0 + - liblzma=5.8.2=hfd05255_0 + - libpng=1.6.54=h7351971_0 - libspatialindex=2.0.0=h5a68840_0 - - libsqlite=3.51.1=hf5d6505_1 + - libsqlite=3.51.2=hf5d6505_0 - libssh2=1.11.1=h9aa295b_0 - libtiff=4.7.1=h8f73337_1 - libwebp-base=1.6.0=h4d5522a_0 @@ -101,7 +101,7 @@ dependencies: - pydantic-core=2.41.5=py311hf51aa87_1 - pydiso=0.1.2=py311h1c8cef1_1 - pymatsolver=0.3.1=pyh48887ae_201 - - pyparsing=3.3.1=pyhcf101f3_0 + - pyparsing=3.3.2=pyhcf101f3_0 - pysocks=1.7.1=pyh09c184e_7 - python=3.11.14=h0159041_2_cpython - python-dateutil=2.9.0.post0=pyhe01879c_2 @@ -113,7 +113,7 @@ dependencies: - rtree=1.2.0=py311h44d53c4_1 - scikit-learn=1.6.1=py311hdcb8d17_0 - scipy=1.14.1=py311hf16d85f_2 - - setuptools=80.9.0=pyhff2d567_0 + - setuptools=80.10.1=pyh332efcf_0 - six=1.17.0=pyhe01879c_1 - sortedcontainers=2.4.0=pyhd8ed1ab_1 - tbb=2021.13.0=h3155e25_5 @@ -136,7 +136,7 @@ dependencies: - vcomp14=14.44.35208=h818238b_34 - wheel=0.45.1=pyhd8ed1ab_1 - win_inet_pton=1.1.0=pyh7428d3b_8 - - wrapt=1.17.3=py311h3485c13_1 + - wrapt=2.0.1=py311h3485c13_1 - xorg-libxau=1.0.12=hba3369d_1 - xorg-libxdmcp=1.1.5=hba3369d_1 - xyzservices=2025.11.0=pyhd8ed1ab_0 @@ -146,10 +146,10 @@ dependencies: - zipp=3.23.0=pyhcf101f3_1 - zstd=1.5.7=h534d264_6 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc - grid-apps @ git+https://github.com/MiraGeoscience/grid-apps.git@99e51cbe794114ce08ab3bb16efcc6749b14914a - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae variables: KMP_WARNINGS: 0 diff --git a/environments/py-3.12-linux-64-dev.conda.lock.yml b/environments/py-3.12-linux-64-dev.conda.lock.yml index 64811ec4..0dc4fead 100644 --- a/environments/py-3.12-linux-64-dev.conda.lock.yml +++ b/environments/py-3.12-linux-64-dev.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: f08dbe12eaba84788a1b865c9d12288c14f6e9a11eeecf419706ee2305b09559 +# input_hash: 8d2ec2f5bff152c0b1a90962f693656e4ddb9e44ed5c8117e1ca290243cc3f6e channels: - conda-forge @@ -17,7 +17,7 @@ dependencies: - asciitree=0.3.3=py_2 - astroid=4.0.3=py312h7900ff3_0 - asttokens=3.0.1=pyhd8ed1ab_0 - - async-lru=2.0.5=pyh29332c3_0 + - async-lru=2.1.0=pyhcf101f3_0 - attrs=25.4.0=pyhcf101f3_1 - babel=2.17.0=pyhd8ed1ab_0 - backports.zstd=1.3.0=py312h90b7ffd_0 @@ -49,8 +49,8 @@ dependencies: - debugpy=1.8.18=py312h8285ef7_0 - decorator=5.2.1=pyhd8ed1ab_0 - defusedxml=0.7.1=pyhd8ed1ab_0 - - deprecated=1.3.1=pyhd8ed1ab_0 - - dill=0.4.0=pyhcf101f3_1 + - deprecated=1.3.1=pyhd8ed1ab_1 + - dill=0.4.1=pyhcf101f3_0 - discretize=0.11.3=py312hf890105_1 - distributed=2025.3.0=pyhd8ed1ab_0 - docutils=0.18.1=py312h7900ff3_1 @@ -60,12 +60,12 @@ dependencies: - fonttools=4.61.1=py312h8a5da7c_0 - fqdn=1.5.1=pyhd8ed1ab_1 - freetype=2.14.1=ha770c72_0 - - fsspec=2025.12.0=pyhd8ed1ab_0 + - fsspec=2026.1.0=pyhd8ed1ab_0 - geoana=0.7.2=py312hf890105_1 - h11=0.16.0=pyhcf101f3_1 - h2=4.3.0=pyhcf101f3_0 - h5py=3.15.1=nompi_py312ha4f8f14_101 - - hdf5=1.14.6=nompi_h1b119a7_104 + - hdf5=1.14.6=nompi_h1b119a7_105 - hpack=4.1.0=pyhd8ed1ab_0 - httpcore=1.0.9=pyh29332c3_0 - httpx=0.28.1=pyhd8ed1ab_0 @@ -97,17 +97,17 @@ dependencies: - jupyter_core=5.9.1=pyhc90fa1f_0 - jupyter_events=0.12.0=pyh29332c3_0 - jupyter_server=2.17.0=pyhcf101f3_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_1 - - jupyterlab=4.5.1=pyhd8ed1ab_0 + - jupyter_server_terminals=0.5.4=pyhcf101f3_0 + - jupyterlab=4.5.2=pyhd8ed1ab_0 - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_server=2.28.0=pyhcf101f3_0 - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 - - jupytext=1.18.1=pyh80e38bb_0 + - jupytext=1.19.0=pyh0398c0e_0 - keyutils=1.6.3=hb9d3cd8_0 - kiwisolver=1.4.9=py312h0a2e395_2 - krb5=1.21.3=h659f571_0 - lark=1.3.1=pyhd8ed1ab_0 - - lcms2=2.17=h717163a_0 + - lcms2=2.18=h0c24ade_0 - ld_impl_linux-64=2.45=default_hbd61a6d_105 - lerc=4.0.0=h0aef613_1 - libaec=1.1.4=h3f801dc_0 @@ -133,14 +133,14 @@ dependencies: - libiconv=1.18=h3b78370_2 - libjpeg-turbo=3.1.2=hb03c661_0 - liblapack=3.9.0=37_h5e43f62_mkl - - liblzma=5.8.1=hb9d3cd8_2 + - liblzma=5.8.2=hb03c661_0 - libnghttp2=1.67.0=had1ee68_0 - libnsl=2.0.1=hb9d3cd8_1 - - libpng=1.6.53=h421ea60_0 + - libpng=1.6.54=h421ea60_0 - libscotch=7.0.6=hea33c07_1 - libsodium=1.0.20=h4ab18f5_0 - libspatialindex=2.0.0=he02047a_0 - - libsqlite=3.51.1=h0c1763c_1 + - libsqlite=3.51.2=h0c1763c_0 - libssh2=1.11.1=hcf80075_0 - libstdcxx=15.2.0=h934c35e_16 - libstdcxx-ng=15.2.0=hdf11a46_16 @@ -177,7 +177,7 @@ dependencies: - ncurses=6.5=h2d0b736_3 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - nodejs=22.6.0=hc19f0b3_1 - - notebook=7.5.1=pyhcf101f3_0 + - notebook=7.5.2=pyhcf101f3_0 - notebook-shim=0.2.4=pyhd8ed1ab_1 - numcodecs=0.15.1=py312hf79963d_1 - numpy=1.26.4=py312heda63a1_0 @@ -195,7 +195,7 @@ dependencies: - pip=25.3=pyh8b19718_0 - platformdirs=4.5.1=pyhcf101f3_0 - pluggy=1.6.0=pyhf9edf01_1 - - prometheus_client=0.23.1=pyhd8ed1ab_0 + - prometheus_client=0.24.1=pyhd8ed1ab_0 - prompt-toolkit=3.0.52=pyha770c72_0 - psutil=7.2.1=py312h5253ce2_0 - pthread-stubs=0.4=hb9d3cd8_1002 @@ -208,7 +208,7 @@ dependencies: - pygments=2.19.2=pyhd8ed1ab_0 - pylint=4.0.4=pyhcf101f3_0 - pymatsolver=0.3.1=pyh48887ae_201 - - pyparsing=3.3.1=pyhcf101f3_0 + - pyparsing=3.3.2=pyhcf101f3_0 - pysocks=1.7.1=pyha55dd90_7 - pytest=9.0.2=pyhcf101f3_0 - pytest-cov=7.0.0=pyhcf101f3_1 @@ -234,13 +234,13 @@ dependencies: - rtree=1.2.0=py312h3ed4c40_1 - scikit-learn=1.6.1=py312h7a48858_0 - scipy=1.14.1=py312h62794b6_2 - - send2trash=2.0.0=pyha191276_0 - - setuptools=80.9.0=pyhff2d567_0 + - send2trash=2.1.0=pyha191276_0 + - setuptools=80.10.1=pyh332efcf_0 - six=1.17.0=pyhe01879c_1 - sniffio=1.3.1=pyhd8ed1ab_2 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - sortedcontainers=2.4.0=pyhd8ed1ab_1 - - soupsieve=2.8.1=pyhd8ed1ab_0 + - soupsieve=2.8.2=pyhd8ed1ab_0 - sphinx=5.3.0=pyhd8ed1ab_0 - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 @@ -255,8 +255,8 @@ dependencies: - threadpoolctl=3.6.0=pyhecae5ae_0 - tinycss2=1.5.1=pyhcf101f3_0 - tk=8.6.13=noxft_ha0e22de_103 - - tomli=2.3.0=pyhcf101f3_0 - - tomlkit=0.13.3=pyha770c72_0 + - tomli=2.4.0=pyhcf101f3_0 + - tomlkit=0.14.0=pyha770c72_0 - toolz=1.1.0=pyhd8ed1ab_1 - tornado=6.5.3=py312h4c3975b_0 - tqdm=4.67.1=pyhd8ed1ab_1 @@ -276,7 +276,7 @@ dependencies: - websocket-client=1.9.0=pyhd8ed1ab_0 - wheel=0.45.1=pyhd8ed1ab_1 - widgetsnbextension=3.6.10=pyhd8ed1ab_0 - - wrapt=1.17.3=py312h4c3975b_1 + - wrapt=2.0.1=py312h4c3975b_1 - xorg-libxau=1.0.12=hb03c661_1 - xorg-libxdmcp=1.1.5=hb03c661_1 - xyzservices=2025.11.0=pyhd8ed1ab_0 @@ -288,10 +288,10 @@ dependencies: - zlib=1.3.1=hb9d3cd8_2 - zstd=1.5.7=hb78ec9c_6 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc - grid-apps @ git+https://github.com/MiraGeoscience/grid-apps.git@99e51cbe794114ce08ab3bb16efcc6749b14914a - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae variables: KMP_WARNINGS: 0 diff --git a/environments/py-3.12-linux-64.conda.lock.yml b/environments/py-3.12-linux-64.conda.lock.yml index 498e810c..cf2896e0 100644 --- a/environments/py-3.12-linux-64.conda.lock.yml +++ b/environments/py-3.12-linux-64.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: f08dbe12eaba84788a1b865c9d12288c14f6e9a11eeecf419706ee2305b09559 +# input_hash: 8d2ec2f5bff152c0b1a90962f693656e4ddb9e44ed5c8117e1ca290243cc3f6e channels: - conda-forge @@ -27,17 +27,17 @@ dependencies: - cycler=0.12.1=pyhcf101f3_2 - cytoolz=1.1.0=py312h4c3975b_1 - dask-core=2025.3.0=pyhd8ed1ab_0 - - deprecated=1.3.1=pyhd8ed1ab_0 + - deprecated=1.3.1=pyhd8ed1ab_1 - discretize=0.11.3=py312hf890105_1 - distributed=2025.3.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - fonttools=4.61.1=py312h8a5da7c_0 - freetype=2.14.1=ha770c72_0 - - fsspec=2025.12.0=pyhd8ed1ab_0 + - fsspec=2026.1.0=pyhd8ed1ab_0 - geoana=0.7.2=py312hf890105_1 - h2=4.3.0=pyhcf101f3_0 - h5py=3.15.1=nompi_py312ha4f8f14_101 - - hdf5=1.14.6=nompi_h1b119a7_104 + - hdf5=1.14.6=nompi_h1b119a7_105 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=75.1=he02047a_0 @@ -47,7 +47,7 @@ dependencies: - keyutils=1.6.3=hb9d3cd8_0 - kiwisolver=1.4.9=py312h0a2e395_2 - krb5=1.21.3=h659f571_0 - - lcms2=2.17=h717163a_0 + - lcms2=2.18=h0c24ade_0 - ld_impl_linux-64=2.45=default_hbd61a6d_105 - lerc=4.0.0=h0aef613_1 - libaec=1.1.4=h3f801dc_0 @@ -73,13 +73,13 @@ dependencies: - libiconv=1.18=h3b78370_2 - libjpeg-turbo=3.1.2=hb03c661_0 - liblapack=3.9.0=37_h5e43f62_mkl - - liblzma=5.8.1=hb9d3cd8_2 + - liblzma=5.8.2=hb03c661_0 - libnghttp2=1.67.0=had1ee68_0 - libnsl=2.0.1=hb9d3cd8_1 - - libpng=1.6.53=h421ea60_0 + - libpng=1.6.54=h421ea60_0 - libscotch=7.0.6=hea33c07_1 - libspatialindex=2.0.0=he02047a_0 - - libsqlite=3.51.1=h0c1763c_1 + - libsqlite=3.51.2=h0c1763c_0 - libssh2=1.11.1=hcf80075_0 - libstdcxx=15.2.0=h934c35e_16 - libstdcxx-ng=15.2.0=hdf11a46_16 @@ -117,7 +117,7 @@ dependencies: - pydantic-core=2.41.5=py312h868fb18_1 - pydiso=0.1.2=py312h686354e_1 - pymatsolver=0.3.1=pyh48887ae_201 - - pyparsing=3.3.1=pyhcf101f3_0 + - pyparsing=3.3.2=pyhcf101f3_0 - pysocks=1.7.1=pyha55dd90_7 - python=3.12.12=hd63d673_1_cpython - python-dateutil=2.9.0.post0=pyhe01879c_2 @@ -130,7 +130,7 @@ dependencies: - rtree=1.2.0=py312h3ed4c40_1 - scikit-learn=1.6.1=py312h7a48858_0 - scipy=1.14.1=py312h62794b6_2 - - setuptools=80.9.0=pyhff2d567_0 + - setuptools=80.10.1=pyh332efcf_0 - six=1.17.0=pyhe01879c_1 - sortedcontainers=2.4.0=pyhd8ed1ab_1 - tbb=2021.13.0=hb700be7_5 @@ -148,7 +148,7 @@ dependencies: - unicodedata2=17.0.0=py312h4c3975b_1 - urllib3=2.6.3=pyhd8ed1ab_0 - wheel=0.45.1=pyhd8ed1ab_1 - - wrapt=1.17.3=py312h4c3975b_1 + - wrapt=2.0.1=py312h4c3975b_1 - xorg-libxau=1.0.12=hb03c661_1 - xorg-libxdmcp=1.1.5=hb03c661_1 - xyzservices=2025.11.0=pyhd8ed1ab_0 @@ -158,10 +158,10 @@ dependencies: - zipp=3.23.0=pyhcf101f3_1 - zstd=1.5.7=hb78ec9c_6 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc - grid-apps @ git+https://github.com/MiraGeoscience/grid-apps.git@99e51cbe794114ce08ab3bb16efcc6749b14914a - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae variables: KMP_WARNINGS: 0 diff --git a/environments/py-3.12-win-64-dev.conda.lock.yml b/environments/py-3.12-win-64-dev.conda.lock.yml index ce117f01..48692c88 100644 --- a/environments/py-3.12-win-64-dev.conda.lock.yml +++ b/environments/py-3.12-win-64-dev.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: win-64 -# input_hash: 75f9dfef05ce45a19001c219a5a5624930d16cb508f9743ae44859e7a2ed2328 +# input_hash: a78d91fa3dc4c95c661cb43f744570c4cbf3dc04b7182fba46b68958c9f38e93 channels: - conda-forge @@ -17,7 +17,7 @@ dependencies: - asciitree=0.3.3=py_2 - astroid=4.0.3=py312h2e8e312_0 - asttokens=3.0.1=pyhd8ed1ab_0 - - async-lru=2.0.5=pyh29332c3_0 + - async-lru=2.1.0=pyhcf101f3_0 - attrs=25.4.0=pyhcf101f3_1 - babel=2.17.0=pyhd8ed1ab_0 - backports.zstd=1.3.0=py312h06d0912_0 @@ -48,8 +48,8 @@ dependencies: - debugpy=1.8.19=py312ha1a9051_0 - decorator=5.2.1=pyhd8ed1ab_0 - defusedxml=0.7.1=pyhd8ed1ab_0 - - deprecated=1.3.1=pyhd8ed1ab_0 - - dill=0.4.0=pyhcf101f3_1 + - deprecated=1.3.1=pyhd8ed1ab_1 + - dill=0.4.1=pyhcf101f3_0 - discretize=0.11.3=py312h9b46583_1 - distributed=2025.3.0=pyhd8ed1ab_0 - docutils=0.18.1=py312h2e8e312_1 @@ -59,12 +59,12 @@ dependencies: - fonttools=4.61.1=py312h05f76fc_0 - fqdn=1.5.1=pyhd8ed1ab_1 - freetype=2.14.1=h57928b3_0 - - fsspec=2025.12.0=pyhd8ed1ab_0 + - fsspec=2026.1.0=pyhd8ed1ab_0 - geoana=0.7.2=py312h9b46583_1 - h11=0.16.0=pyhcf101f3_1 - h2=4.3.0=pyhcf101f3_0 - h5py=3.15.1=nompi_py312h03cd2ba_101 - - hdf5=1.14.6=nompi_h89f0904_104 + - hdf5=1.14.6=nompi_h89f0904_105 - hpack=4.1.0=pyhd8ed1ab_0 - httpcore=1.0.9=pyh29332c3_0 - httpx=0.28.1=pyhd8ed1ab_0 @@ -96,16 +96,16 @@ dependencies: - jupyter_core=5.9.1=pyh6dadd2b_0 - jupyter_events=0.12.0=pyh29332c3_0 - jupyter_server=2.17.0=pyhcf101f3_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_1 - - jupyterlab=4.5.1=pyhd8ed1ab_0 + - jupyter_server_terminals=0.5.4=pyhcf101f3_0 + - jupyterlab=4.5.2=pyhd8ed1ab_0 - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_server=2.28.0=pyhcf101f3_0 - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 - - jupytext=1.18.1=pyh80e38bb_0 + - jupytext=1.19.0=pyh0398c0e_0 - kiwisolver=1.4.9=py312h78d62e6_2 - krb5=1.21.3=hdf4eb48_0 - lark=1.3.1=pyhd8ed1ab_0 - - lcms2=2.17=hbcf6048_0 + - lcms2=2.18=hf2c6c5f_0 - lerc=4.0.0=h6470a55_1 - libaec=1.1.4=h20038f6_0 - libblas=3.9.0=35_h5709861_mkl @@ -126,11 +126,11 @@ dependencies: - libiconv=1.18=hc1393d2_2 - libjpeg-turbo=3.1.2=hfd05255_0 - liblapack=3.9.0=35_hf9ab0e9_mkl - - liblzma=5.8.1=h2466b09_2 - - libpng=1.6.53=h7351971_0 + - liblzma=5.8.2=hfd05255_0 + - libpng=1.6.54=h7351971_0 - libsodium=1.0.20=hc70643c_0 - libspatialindex=2.0.0=h5a68840_0 - - libsqlite=3.51.1=hf5d6505_1 + - libsqlite=3.51.2=hf5d6505_0 - libssh2=1.11.1=h9aa295b_0 - libtiff=4.7.1=h8f73337_1 - libwebp-base=1.6.0=h4d5522a_0 @@ -160,7 +160,7 @@ dependencies: - nbformat=5.10.4=pyhd8ed1ab_1 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - nodejs=25.2.1=he453025_1 - - notebook=7.5.1=pyhcf101f3_0 + - notebook=7.5.2=pyhcf101f3_0 - notebook-shim=0.2.4=pyhd8ed1ab_1 - numcodecs=0.15.1=py312hc128f0a_1 - numpy=1.26.4=py312h8753938_0 @@ -177,7 +177,7 @@ dependencies: - pip=25.3=pyh8b19718_0 - platformdirs=4.5.1=pyhcf101f3_0 - pluggy=1.6.0=pyhf9edf01_1 - - prometheus_client=0.23.1=pyhd8ed1ab_0 + - prometheus_client=0.24.1=pyhd8ed1ab_0 - prompt-toolkit=3.0.52=pyha770c72_0 - psutil=7.2.1=py312he5662c2_0 - pthread-stubs=0.4=h0e40799_1002 @@ -189,7 +189,7 @@ dependencies: - pygments=2.19.2=pyhd8ed1ab_0 - pylint=4.0.4=pyhcf101f3_0 - pymatsolver=0.3.1=pyh48887ae_201 - - pyparsing=3.3.1=pyhcf101f3_0 + - pyparsing=3.3.2=pyhcf101f3_0 - pysocks=1.7.1=pyh09c184e_7 - pytest=9.0.2=pyhcf101f3_0 - pytest-cov=7.0.0=pyhcf101f3_1 @@ -216,13 +216,13 @@ dependencies: - rtree=1.2.0=py312h50e5f8f_1 - scikit-learn=1.6.1=py312h816cc57_0 - scipy=1.14.1=py312h337df96_2 - - send2trash=2.0.0=pyh6dadd2b_0 - - setuptools=80.9.0=pyhff2d567_0 + - send2trash=2.1.0=pyh6dadd2b_0 + - setuptools=80.10.1=pyh332efcf_0 - six=1.17.0=pyhe01879c_1 - sniffio=1.3.1=pyhd8ed1ab_2 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - sortedcontainers=2.4.0=pyhd8ed1ab_1 - - soupsieve=2.8.1=pyhd8ed1ab_0 + - soupsieve=2.8.2=pyhd8ed1ab_0 - sphinx=5.3.0=pyhd8ed1ab_0 - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 @@ -237,8 +237,8 @@ dependencies: - threadpoolctl=3.6.0=pyhecae5ae_0 - tinycss2=1.5.1=pyhcf101f3_0 - tk=8.6.13=h2c6b04d_3 - - tomli=2.3.0=pyhcf101f3_0 - - tomlkit=0.13.3=pyha770c72_0 + - tomli=2.4.0=pyhcf101f3_0 + - tomlkit=0.14.0=pyha770c72_0 - toolz=1.1.0=pyhd8ed1ab_1 - tornado=6.5.4=py312he06e257_0 - tqdm=4.67.1=pyhd8ed1ab_1 @@ -264,7 +264,7 @@ dependencies: - widgetsnbextension=3.6.10=pyhd8ed1ab_0 - win_inet_pton=1.1.0=pyh7428d3b_8 - winpty=0.4.3=4 - - wrapt=1.17.3=py312he06e257_1 + - wrapt=2.0.1=py312he06e257_1 - xorg-libxau=1.0.12=hba3369d_1 - xorg-libxdmcp=1.1.5=hba3369d_1 - xyzservices=2025.11.0=pyhd8ed1ab_0 @@ -275,10 +275,10 @@ dependencies: - zipp=3.23.0=pyhcf101f3_1 - zstd=1.5.7=h534d264_6 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc - grid-apps @ git+https://github.com/MiraGeoscience/grid-apps.git@99e51cbe794114ce08ab3bb16efcc6749b14914a - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae variables: KMP_WARNINGS: 0 diff --git a/environments/py-3.12-win-64.conda.lock.yml b/environments/py-3.12-win-64.conda.lock.yml index 1986d356..50313854 100644 --- a/environments/py-3.12-win-64.conda.lock.yml +++ b/environments/py-3.12-win-64.conda.lock.yml @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: win-64 -# input_hash: 75f9dfef05ce45a19001c219a5a5624930d16cb508f9743ae44859e7a2ed2328 +# input_hash: a78d91fa3dc4c95c661cb43f744570c4cbf3dc04b7182fba46b68958c9f38e93 channels: - conda-forge @@ -26,17 +26,17 @@ dependencies: - cycler=0.12.1=pyhcf101f3_2 - cytoolz=1.1.0=py312he06e257_1 - dask-core=2025.3.0=pyhd8ed1ab_0 - - deprecated=1.3.1=pyhd8ed1ab_0 + - deprecated=1.3.1=pyhd8ed1ab_1 - discretize=0.11.3=py312h9b46583_1 - distributed=2025.3.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - fonttools=4.61.1=py312h05f76fc_0 - freetype=2.14.1=h57928b3_0 - - fsspec=2025.12.0=pyhd8ed1ab_0 + - fsspec=2026.1.0=pyhd8ed1ab_0 - geoana=0.7.2=py312h9b46583_1 - h2=4.3.0=pyhcf101f3_0 - h5py=3.15.1=nompi_py312h03cd2ba_101 - - hdf5=1.14.6=nompi_h89f0904_104 + - hdf5=1.14.6=nompi_h89f0904_105 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=78.2=h637d24d_0 @@ -45,7 +45,7 @@ dependencies: - joblib=1.5.3=pyhd8ed1ab_0 - kiwisolver=1.4.9=py312h78d62e6_2 - krb5=1.21.3=hdf4eb48_0 - - lcms2=2.17=hbcf6048_0 + - lcms2=2.18=hf2c6c5f_0 - lerc=4.0.0=h6470a55_1 - libaec=1.1.4=h20038f6_0 - libblas=3.9.0=35_h5709861_mkl @@ -66,10 +66,10 @@ dependencies: - libiconv=1.18=hc1393d2_2 - libjpeg-turbo=3.1.2=hfd05255_0 - liblapack=3.9.0=35_hf9ab0e9_mkl - - liblzma=5.8.1=h2466b09_2 - - libpng=1.6.53=h7351971_0 + - liblzma=5.8.2=hfd05255_0 + - libpng=1.6.54=h7351971_0 - libspatialindex=2.0.0=h5a68840_0 - - libsqlite=3.51.1=hf5d6505_1 + - libsqlite=3.51.2=hf5d6505_0 - libssh2=1.11.1=h9aa295b_0 - libtiff=4.7.1=h8f73337_1 - libwebp-base=1.6.0=h4d5522a_0 @@ -101,7 +101,7 @@ dependencies: - pydantic-core=2.41.5=py312hdabe01f_1 - pydiso=0.1.2=py312h3fe0e52_1 - pymatsolver=0.3.1=pyh48887ae_201 - - pyparsing=3.3.1=pyhcf101f3_0 + - pyparsing=3.3.2=pyhcf101f3_0 - pysocks=1.7.1=pyh09c184e_7 - python=3.12.12=h0159041_1_cpython - python-dateutil=2.9.0.post0=pyhe01879c_2 @@ -113,7 +113,7 @@ dependencies: - rtree=1.2.0=py312h50e5f8f_1 - scikit-learn=1.6.1=py312h816cc57_0 - scipy=1.14.1=py312h337df96_2 - - setuptools=80.9.0=pyhff2d567_0 + - setuptools=80.10.1=pyh332efcf_0 - six=1.17.0=pyhe01879c_1 - sortedcontainers=2.4.0=pyhd8ed1ab_1 - tbb=2021.13.0=h3155e25_5 @@ -136,7 +136,7 @@ dependencies: - vcomp14=14.44.35208=h818238b_34 - wheel=0.45.1=pyhd8ed1ab_1 - win_inet_pton=1.1.0=pyh7428d3b_8 - - wrapt=1.17.3=py312he06e257_1 + - wrapt=2.0.1=py312he06e257_1 - xorg-libxau=1.0.12=hba3369d_1 - xorg-libxdmcp=1.1.5=hba3369d_1 - xyzservices=2025.11.0=pyhd8ed1ab_0 @@ -146,10 +146,10 @@ dependencies: - zipp=3.23.0=pyhcf101f3_1 - zstd=1.5.7=h534d264_6 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc - grid-apps @ git+https://github.com/MiraGeoscience/grid-apps.git@99e51cbe794114ce08ab3bb16efcc6749b14914a - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae variables: KMP_WARNINGS: 0 diff --git a/py-3.10.conda-lock.yml b/py-3.10.conda-lock.yml index ec94b8b6..cebcb39c 100644 --- a/py-3.10.conda-lock.yml +++ b/py-3.10.conda-lock.yml @@ -15,8 +15,8 @@ version: 1 metadata: content_hash: - win-64: ade6f8568a23d600ae9ce846ee88765a4745040016210637a40b1410b32073fe - linux-64: 2b50544cb4f1d5b69b9b4ae438e854dd769e9447f4d1f6f37b9c8332259e2f13 + win-64: 4095d8c1a6c5ba4facb54b1eef593eaa3c13a1bb5dba5638b7d7103f84795d37 + linux-64: 56acf844153236bc0bae9c73a9c7a6769bafd992ebe223ac3fa1ee1ba32d25ef channels: - url: conda-forge used_env_vars: [] @@ -300,29 +300,29 @@ package: category: dev optional: true - name: async-lru - version: 2.0.5 + version: 2.1.0 manager: conda platform: linux-64 dependencies: python: '' typing_extensions: '>=4.0.0' - url: https://repo.prefix.dev/conda-forge/noarch/async-lru-2.0.5-pyh29332c3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/async-lru-2.1.0-pyhcf101f3_0.conda hash: - md5: d9d0f99095a9bb7e3641bca8c6ad2ac7 - sha256: 3b7233041e462d9eeb93ea1dfe7b18aca9c358832517072054bb8761df0c324b + md5: 04d2e5fba67e5a1ecec8e25d6c769004 + sha256: fb09cb9bfe4da1586d0ad3bf80bb65e70acfd5fe0f76df384250a1c0587d6acc category: dev optional: true - name: async-lru - version: 2.0.5 + version: 2.1.0 manager: conda platform: win-64 dependencies: - python: '>=3.9' + python: '>=3.10' typing_extensions: '>=4.0.0' - url: https://repo.prefix.dev/conda-forge/noarch/async-lru-2.0.5-pyh29332c3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/async-lru-2.1.0-pyhcf101f3_0.conda hash: - md5: d9d0f99095a9bb7e3641bca8c6ad2ac7 - sha256: 3b7233041e462d9eeb93ea1dfe7b18aca9c358832517072054bb8761df0c324b + md5: 04d2e5fba67e5a1ecec8e25d6c769004 + sha256: fb09cb9bfe4da1586d0ad3bf80bb65e70acfd5fe0f76df384250a1c0587d6acc category: dev optional: true - name: attrs @@ -1164,27 +1164,27 @@ package: category: dev optional: true - name: dill - version: 0.4.0 + version: 0.4.1 manager: conda platform: linux-64 dependencies: python: '' - url: https://repo.prefix.dev/conda-forge/noarch/dill-0.4.0-pyhcf101f3_1.conda + url: https://repo.prefix.dev/conda-forge/noarch/dill-0.4.1-pyhcf101f3_0.conda hash: - md5: eec5b361dbbaa69dba05050977a414b0 - sha256: c0c91bd91e59940091cec1760db51a82a58e9c64edf4b808bd2da94201ccfdb4 + md5: 080a808fce955026bf82107d955d32da + sha256: 1ef84c0cc4efd0c2d58c3cb365945edbd9ee42a1c54514d1ccba4b641005f757 category: dev optional: true - name: dill - version: 0.4.0 + version: 0.4.1 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/dill-0.4.0-pyhcf101f3_1.conda + url: https://repo.prefix.dev/conda-forge/noarch/dill-0.4.1-pyhcf101f3_0.conda hash: - md5: eec5b361dbbaa69dba05050977a414b0 - sha256: c0c91bd91e59940091cec1760db51a82a58e9c64edf4b808bd2da94201ccfdb4 + md5: 080a808fce955026bf82107d955d32da + sha256: 1ef84c0cc4efd0c2d58c3cb365945edbd9ee42a1c54514d1ccba4b641005f757 category: dev optional: true - name: discretize @@ -1469,27 +1469,27 @@ package: category: main optional: false - name: fsspec - version: 2025.12.0 + version: 2026.1.0 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/fsspec-2025.12.0-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/fsspec-2026.1.0-pyhd8ed1ab_0.conda hash: - md5: a3b9510e2491c20c7fc0f5e730227fbb - sha256: 64a4ed910e39d96cd590d297982b229c57a08e70450d489faa34fd2bec36dbcc + md5: 1daaf94a304a27ba3446a306235a37ea + sha256: bfba6c280366f48b00a6a7036988fc2bc3fea5ac1d8303152c9da69d72a22936 category: main optional: false - name: fsspec - version: 2025.12.0 + version: 2026.1.0 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/fsspec-2025.12.0-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/fsspec-2026.1.0-pyhd8ed1ab_0.conda hash: - md5: a3b9510e2491c20c7fc0f5e730227fbb - sha256: 64a4ed910e39d96cd590d297982b229c57a08e70450d489faa34fd2bec36dbcc + md5: 1daaf94a304a27ba3446a306235a37ea + sha256: bfba6c280366f48b00a6a7036988fc2bc3fea5ac1d8303152c9da69d72a22936 category: main optional: false - name: geoana @@ -1628,17 +1628,17 @@ package: dependencies: __glibc: '>=2.17,<3.0.a0' libaec: '>=1.1.4,<2.0a0' - libcurl: '>=8.17.0,<9.0a0' + libcurl: '>=8.18.0,<9.0a0' libgcc: '>=14' libgfortran: '' libgfortran5: '>=14.3.0' libstdcxx: '>=14' libzlib: '>=1.3.1,<2.0a0' openssl: '>=3.5.4,<4.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/hdf5-1.14.6-nompi_h1b119a7_104.conda + url: https://repo.prefix.dev/conda-forge/linux-64/hdf5-1.14.6-nompi_h1b119a7_105.conda hash: - md5: 0857f4d157820dcd5625f61fdfefb780 - sha256: 454e9724b322cee277abd7acf4f8d688e9c4ded006b6d5bc9fcc2a1ff907d27a + md5: d58cd79121dd51128f2a5dab44edf1ea + sha256: aa85acd07b8f60d1760c6b3fa91dd8402572766e763f3989c759ecd266ed8e9f category: main optional: false - name: hdf5 @@ -1647,16 +1647,16 @@ package: platform: win-64 dependencies: libaec: '>=1.1.4,<2.0a0' - libcurl: '>=8.17.0,<9.0a0' + libcurl: '>=8.18.0,<9.0a0' libzlib: '>=1.3.1,<2.0a0' openssl: '>=3.5.4,<4.0a0' ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/hdf5-1.14.6-nompi_h89f0904_104.conda + url: https://repo.prefix.dev/conda-forge/win-64/hdf5-1.14.6-nompi_h89f0904_105.conda hash: - md5: 9cc4a5567d46c7fcde99563e86522882 - sha256: cc948149f700033ff85ce4a1854edf6adcb5881391a3df5c40cbe2a793dd9f81 + md5: c1caaf8a28c0eb3be85566e63a5fcb5a + sha256: 52e5eb039289946a32aee305e6af777d77376dc0adcb2bdcc31633dcc48d21a5 category: main optional: false - name: hpack @@ -2589,33 +2589,33 @@ package: category: dev optional: true - name: jupyter_server_terminals - version: 0.5.3 + version: 0.5.4 manager: conda platform: linux-64 dependencies: - python: '>=3.9' + python: '' terminado: '>=0.8.3' - url: https://repo.prefix.dev/conda-forge/noarch/jupyter_server_terminals-0.5.3-pyhd8ed1ab_1.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyter_server_terminals-0.5.4-pyhcf101f3_0.conda hash: - md5: 2d983ff1b82a1ccb6f2e9d8784bdd6bd - sha256: 0890fc79422191bc29edf17d7b42cff44ba254aa225d31eb30819f8772b775b8 + md5: 7b8bace4943e0dc345fc45938826f2b8 + sha256: 5eda79ed9f53f590031d29346abd183051263227dd9ee667b5ca1133ce297654 category: dev optional: true - name: jupyter_server_terminals - version: 0.5.3 + version: 0.5.4 manager: conda platform: win-64 dependencies: - python: '>=3.9' + python: '>=3.10' terminado: '>=0.8.3' - url: https://repo.prefix.dev/conda-forge/noarch/jupyter_server_terminals-0.5.3-pyhd8ed1ab_1.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyter_server_terminals-0.5.4-pyhcf101f3_0.conda hash: - md5: 2d983ff1b82a1ccb6f2e9d8784bdd6bd - sha256: 0890fc79422191bc29edf17d7b42cff44ba254aa225d31eb30819f8772b775b8 + md5: 7b8bace4943e0dc345fc45938826f2b8 + sha256: 5eda79ed9f53f590031d29346abd183051263227dd9ee667b5ca1133ce297654 category: dev optional: true - name: jupyterlab - version: 4.5.1 + version: 4.5.2 manager: conda platform: linux-64 dependencies: @@ -2634,14 +2634,14 @@ package: tomli: '>=1.2.2' tornado: '>=6.2.0' traitlets: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.5.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.5.2-pyhd8ed1ab_0.conda hash: - md5: f8e8f8db45e1a946ce9b20b0f60b3111 - sha256: ac31a517238173eb565ba9f517b1f9437fba48035f1276a9c1190c145657cafd + md5: 513e7fcc06c82b24c84ff88ece13ac9f + sha256: 4e277cee7fc4b403c954960476375e5a51babd06f3ac46a04bd9fff5971aa569 category: dev optional: true - name: jupyterlab - version: 4.5.1 + version: 4.5.2 manager: conda platform: win-64 dependencies: @@ -2660,10 +2660,10 @@ package: tomli: '>=1.2.2' tornado: '>=6.2.0' traitlets: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.5.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.5.2-pyhd8ed1ab_0.conda hash: - md5: f8e8f8db45e1a946ce9b20b0f60b3111 - sha256: ac31a517238173eb565ba9f517b1f9437fba48035f1276a9c1190c145657cafd + md5: 513e7fcc06c82b24c84ff88ece13ac9f + sha256: 4e277cee7fc4b403c954960476375e5a51babd06f3ac46a04bd9fff5971aa569 category: dev optional: true - name: jupyterlab_pygments @@ -2755,7 +2755,7 @@ package: category: dev optional: true - name: jupytext - version: 1.18.1 + version: 1.19.0 manager: conda platform: linux-64 dependencies: @@ -2766,14 +2766,14 @@ package: python: '>=3.10' pyyaml: '' tomli: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupytext-1.18.1-pyh80e38bb_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupytext-1.19.0-pyh0398c0e_0.conda hash: - md5: 3c85f79f1debe2d2c82ac08f1c1126e1 - sha256: 07063dad3019455d786dc3b5174731eb0ef53eb699df25e21571c2b7cdcf0fd0 + md5: 1831f8fcb080707636343f5e1d8994f1 + sha256: 76f1c795088c7ad8b899ee388aafe69d3412ff11d5ca628fff0b655fbb31de05 category: dev optional: true - name: jupytext - version: 1.18.1 + version: 1.19.0 manager: conda platform: win-64 dependencies: @@ -2784,10 +2784,10 @@ package: python: '>=3.10' pyyaml: '' tomli: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupytext-1.18.1-pyh80e38bb_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupytext-1.19.0-pyh0398c0e_0.conda hash: - md5: 3c85f79f1debe2d2c82ac08f1c1126e1 - sha256: 07063dad3019455d786dc3b5174731eb0ef53eb699df25e21571c2b7cdcf0fd0 + md5: 1831f8fcb080707636343f5e1d8994f1 + sha256: 76f1c795088c7ad8b899ee388aafe69d3412ff11d5ca628fff0b655fbb31de05 category: dev optional: true - name: keyutils @@ -2891,34 +2891,34 @@ package: category: dev optional: true - name: lcms2 - version: '2.17' + version: '2.18' manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - libgcc: '>=13' - libjpeg-turbo: '>=3.0.0,<4.0a0' - libtiff: '>=4.7.0,<4.8.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/lcms2-2.17-h717163a_0.conda + libgcc: '>=14' + libjpeg-turbo: '>=3.1.2,<4.0a0' + libtiff: '>=4.7.1,<4.8.0a0' + url: https://repo.prefix.dev/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda hash: - md5: 000e85703f0fd9594c81710dd5066471 - sha256: d6a61830a354da022eae93fa896d0991385a875c6bba53c82263a289deda9db8 + md5: 6f2e2c8f58160147c4d1c6f4c14cbac4 + sha256: 836ec4b895352110335b9fdcfa83a8dcdbe6c5fb7c06c4929130600caea91c0a category: main optional: false - name: lcms2 - version: '2.17' + version: '2.18' manager: conda platform: win-64 dependencies: - libjpeg-turbo: '>=3.0.0,<4.0a0' - libtiff: '>=4.7.0,<4.8.0a0' + libjpeg-turbo: '>=3.1.2,<4.0a0' + libtiff: '>=4.7.1,<4.8.0a0' ucrt: '>=10.0.20348.0' - vc: '>=14.2,<15' - vc14_runtime: '>=14.29.30139' - url: https://repo.prefix.dev/conda-forge/win-64/lcms2-2.17-hbcf6048_0.conda + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/lcms2-2.18-hf2c6c5f_0.conda hash: - md5: 3538827f77b82a837fa681a4579e37a1 - sha256: 7712eab5f1a35ca3ea6db48ead49e0d6ac7f96f8560da8023e61b3dbe4f3b25d + md5: b6c68d6b829b044cd17a41e0a8a23ca1 + sha256: 7eeb18c5c86db146b62da66d9e8b0e753a52987f9134a494309588bbeceddf28 category: main optional: false - name: ld_impl_linux-64 @@ -3534,30 +3534,30 @@ package: category: main optional: false - name: liblzma - version: 5.8.1 + version: 5.8.2 manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - libgcc: '>=13' - url: https://repo.prefix.dev/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda + libgcc: '>=14' + url: https://repo.prefix.dev/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda hash: - md5: 1a580f7796c7bf6393fddb8bbbde58dc - sha256: f2591c0069447bbe28d4d696b7fcb0c5bd0b4ac582769b89addbcf26fb3430d8 + md5: c7c83eecbb72d88b940c249af56c8b17 + sha256: 755c55ebab181d678c12e49cced893598f2bab22d582fbbf4d8b83c18be207eb category: main optional: false - name: liblzma - version: 5.8.1 + version: 5.8.2 manager: conda platform: win-64 dependencies: ucrt: '>=10.0.20348.0' - vc: '>=14.2,<15' - vc14_runtime: '>=14.29.30139' - url: https://repo.prefix.dev/conda-forge/win-64/liblzma-5.8.1-h2466b09_2.conda + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/liblzma-5.8.2-hfd05255_0.conda hash: - md5: c15148b2e18da456f5108ccb5e411446 - sha256: 55764956eb9179b98de7cc0e55696f2eff8f7b83fc3ebff5e696ca358bca28cc + md5: ba0bfd4c3cf73f299ffe46ff0eaeb8e3 + sha256: f25bf293f550c8ed2e0c7145eb404324611cfccff37660869d97abf526eb957c category: main optional: false - name: libnghttp2 @@ -3592,21 +3592,21 @@ package: category: main optional: false - name: libpng - version: 1.6.53 + version: 1.6.54 manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' libgcc: '>=14' libzlib: '>=1.3.1,<2.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/libpng-1.6.53-h421ea60_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/libpng-1.6.54-h421ea60_0.conda hash: - md5: 00d4e66b1f746cb14944cad23fffb405 - sha256: 8acdeb9a7e3d2630176ba8e947caf6bf4985a5148dec69b801e5eb797856688b + md5: d361fa2a59e53b61c2675bfa073e5b7e + sha256: 5de60d34aac848a9991a09fcdea7c0e783d00024aefec279d55e87c0c44742cd category: main optional: false - name: libpng - version: 1.6.53 + version: 1.6.54 manager: conda platform: win-64 dependencies: @@ -3614,10 +3614,10 @@ package: ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/libpng-1.6.53-h7351971_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/libpng-1.6.54-h7351971_0.conda hash: - md5: fb6f43f6f08ca100cb24cff125ab0d9e - sha256: e5d061e7bdb2b97227b6955d1aa700a58a5703b5150ab0467cc37de609f277b6 + md5: 638ecb69e44b6a588afd5633e81f9e61 + sha256: 6e269361aa18a57bd2e593e480d83d93fc5f839d33d3bfc31b4ffe10edf6751c category: main optional: false - name: libscotch @@ -3693,31 +3693,31 @@ package: category: main optional: false - name: libsqlite - version: 3.51.1 + version: 3.51.2 manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' libgcc: '>=14' libzlib: '>=1.3.1,<2.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/libsqlite-3.51.1-h0c1763c_1.conda + url: https://repo.prefix.dev/conda-forge/linux-64/libsqlite-3.51.2-h0c1763c_0.conda hash: - md5: ad1fd565aff83b543d726382c0ab0af2 - sha256: 5ef162b2a1390d1495a759734afe2312a358a58441cf8f378be651903646f3b7 + md5: f7d30045eccb83f2bb8053041f42db3c + sha256: c1ff4589b48d32ca0a2628970d869fa9f7b2c2d00269a3761edc7e9e4c1ab7b8 category: main optional: false - name: libsqlite - version: 3.51.1 + version: 3.51.2 manager: conda platform: win-64 dependencies: ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/libsqlite-3.51.1-hf5d6505_1.conda + url: https://repo.prefix.dev/conda-forge/win-64/libsqlite-3.51.2-hf5d6505_0.conda hash: - md5: be65be5f758709fc01b01626152e96b0 - sha256: d6d86715a1afe11f626b7509935e9d2e14a4946632c0ac474526e20fc6c55f99 + md5: 903979414b47d777d548e5f0165e6cd8 + sha256: 756478128e3e104bd7e7c3ce6c1b0efad7e08c7320c69fdc726e039323c63fbb category: main optional: false - name: libssh2 @@ -4697,39 +4697,39 @@ package: category: dev optional: true - name: notebook - version: 7.5.1 + version: 7.5.2 manager: conda platform: linux-64 dependencies: importlib_resources: '>=5.0' jupyter_server: '>=2.4.0,<3' - jupyterlab: '>=4.5.1,<4.6' + jupyterlab: '>=4.5.2,<4.6' jupyterlab_server: '>=2.28.0,<3' notebook-shim: '>=0.2,<0.3' python: '' tornado: '>=6.2.0' - url: https://repo.prefix.dev/conda-forge/noarch/notebook-7.5.1-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/notebook-7.5.2-pyhcf101f3_0.conda hash: - md5: c984a8b773a34e38f5cf399b6d582e5c - sha256: 672ec7db73c8bfbacf9227c0c2287effdeded77b4d06373f2e498a310ce76a8c + md5: 47b58fa741a608dac785b71b8083bdb7 + sha256: 05bda90b7a980593c5e955dec5c556ff4dabf56e6ff45a3fb6c670f5f20b11e6 category: dev optional: true - name: notebook - version: 7.5.1 + version: 7.5.2 manager: conda platform: win-64 dependencies: importlib_resources: '>=5.0' jupyter_server: '>=2.4.0,<3' - jupyterlab: '>=4.5.1,<4.6' + jupyterlab: '>=4.5.2,<4.6' jupyterlab_server: '>=2.28.0,<3' notebook-shim: '>=0.2,<0.3' python: '>=3.10' tornado: '>=6.2.0' - url: https://repo.prefix.dev/conda-forge/noarch/notebook-7.5.1-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/notebook-7.5.2-pyhcf101f3_0.conda hash: - md5: c984a8b773a34e38f5cf399b6d582e5c - sha256: 672ec7db73c8bfbacf9227c0c2287effdeded77b4d06373f2e498a310ce76a8c + md5: 47b58fa741a608dac785b71b8083bdb7 + sha256: 05bda90b7a980593c5e955dec5c556ff4dabf56e6ff45a3fb6c670f5f20b11e6 category: dev optional: true - name: notebook-shim @@ -5244,27 +5244,27 @@ package: category: dev optional: true - name: prometheus_client - version: 0.23.1 + version: 0.24.1 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/prometheus_client-0.23.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/prometheus_client-0.24.1-pyhd8ed1ab_0.conda hash: - md5: a1e91db2d17fd258c64921cb38e6745a - sha256: 13dc67de68db151ff909f2c1d2486fa7e2d51355b25cee08d26ede1b62d48d40 + md5: 7526d20621b53440b0aae45d4797847e + sha256: 75b2589159d04b3fb92db16d9970b396b9124652c784ab05b66f584edc97f283 category: dev optional: true - name: prometheus_client - version: 0.23.1 + version: 0.24.1 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/prometheus_client-0.23.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/prometheus_client-0.24.1-pyhd8ed1ab_0.conda hash: - md5: a1e91db2d17fd258c64921cb38e6745a - sha256: 13dc67de68db151ff909f2c1d2486fa7e2d51355b25cee08d26ede1b62d48d40 + md5: 7526d20621b53440b0aae45d4797847e + sha256: 75b2589159d04b3fb92db16d9970b396b9124652c784ab05b66f584edc97f283 category: dev optional: true - name: prompt-toolkit @@ -5612,27 +5612,27 @@ package: category: main optional: false - name: pyparsing - version: 3.3.1 + version: 3.3.2 manager: conda platform: linux-64 dependencies: python: '' - url: https://repo.prefix.dev/conda-forge/noarch/pyparsing-3.3.1-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda hash: - md5: d837065e4e0de4962c3462079c23f969 - sha256: 0c70bc577f5efa87501bdc841b88f594f4d3f3a992dfb851e2130fa5c817835b + md5: 3687cc0b82a8b4c17e1f0eb7e47163d5 + sha256: 417fba4783e528ee732afa82999300859b065dc59927344b4859c64aae7182de category: main optional: false - name: pyparsing - version: 3.3.1 + version: 3.3.2 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/pyparsing-3.3.1-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda hash: - md5: d837065e4e0de4962c3462079c23f969 - sha256: 0c70bc577f5efa87501bdc841b88f594f4d3f3a992dfb851e2130fa5c817835b + md5: 3687cc0b82a8b4c17e1f0eb7e47163d5 + sha256: 417fba4783e528ee732afa82999300859b065dc59927344b4859c64aae7182de category: main optional: false - name: pysocks @@ -6389,54 +6389,54 @@ package: category: main optional: false - name: send2trash - version: 2.0.0 + version: 2.1.0 manager: conda platform: linux-64 dependencies: __linux: '' python: '' - url: https://repo.prefix.dev/conda-forge/noarch/send2trash-2.0.0-pyha191276_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/send2trash-2.1.0-pyha191276_0.conda hash: - md5: f2cc28627a451a28ddd5ef5ab0bf579d - sha256: 27cd93b4f848a1c8193a7b1b8e6e6d03321462e96997ce95ea1a39305f7ac7cb + md5: 645026465469ecd4989188e1c4e24953 + sha256: b25d573874fe39cb8e4cf6ed0279acb9a94fedce5c5ae885da11566d595035ad category: dev optional: true - name: send2trash - version: 2.0.0 + version: 2.1.0 manager: conda platform: win-64 dependencies: __win: '' python: '>=3.10' pywin32: '' - url: https://repo.prefix.dev/conda-forge/noarch/send2trash-2.0.0-pyh6dadd2b_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/send2trash-2.1.0-pyh6dadd2b_0.conda hash: - md5: 40df72e963d80a403c1861ae9428b13c - sha256: f154f702baf550de9c1e3517f110bb71a056df5645027c8d15b37f3ea33722cc + md5: 69ba308f1356f39901f5654d82405df3 + sha256: b64e5cdb66f5d31fcef05b6ed95b8be3e80796528aa8a165428496c0dda3383f category: dev optional: true - name: setuptools - version: 80.9.0 + version: 80.10.1 manager: conda platform: linux-64 dependencies: - python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda + python: '>=3.10' + url: https://repo.prefix.dev/conda-forge/noarch/setuptools-80.10.1-pyh332efcf_0.conda hash: - md5: 4de79c071274a53dcaf2a8c749d1499e - sha256: 972560fcf9657058e3e1f97186cc94389144b46dbdf58c807ce62e83f977e863 + md5: cb72cedd94dd923c6a9405a3d3b1c018 + sha256: 89d5bb48047e7e27aa52a3a71d6ebf386e5ee4bdbd7ca91d653df9977eca8253 category: main optional: false - name: setuptools - version: 80.9.0 + version: 80.10.1 manager: conda platform: win-64 dependencies: - python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda + python: '>=3.10' + url: https://repo.prefix.dev/conda-forge/noarch/setuptools-80.10.1-pyh332efcf_0.conda hash: - md5: 4de79c071274a53dcaf2a8c749d1499e - sha256: 972560fcf9657058e3e1f97186cc94389144b46dbdf58c807ce62e83f977e863 + md5: cb72cedd94dd923c6a9405a3d3b1c018 + sha256: 89d5bb48047e7e27aa52a3a71d6ebf386e5ee4bdbd7ca91d653df9977eca8253 category: main optional: false - name: six @@ -6536,27 +6536,27 @@ package: category: main optional: false - name: soupsieve - version: 2.8.1 + version: 2.8.2 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/soupsieve-2.8.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/soupsieve-2.8.2-pyhd8ed1ab_0.conda hash: - md5: 7de28c27fe620a4f7dbfaea137c6232b - sha256: 4ba9b8c45862e54d05ed9a04cc6aab5a17756ab9865f57cbf2836e47144153d2 + md5: fcbe3971b6017792e9b24ff451daa7f5 + sha256: aacc87d88795ef887b89fe9401d1092312c43371d1ba92340d8924da1a982b6a category: dev optional: true - name: soupsieve - version: 2.8.1 + version: 2.8.2 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/soupsieve-2.8.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/soupsieve-2.8.2-pyhd8ed1ab_0.conda hash: - md5: 7de28c27fe620a4f7dbfaea137c6232b - sha256: 4ba9b8c45862e54d05ed9a04cc6aab5a17756ab9865f57cbf2836e47144153d2 + md5: fcbe3971b6017792e9b24ff451daa7f5 + sha256: aacc87d88795ef887b89fe9401d1092312c43371d1ba92340d8924da1a982b6a category: dev optional: true - name: sphinx @@ -6964,51 +6964,51 @@ package: category: main optional: false - name: tomli - version: 2.3.0 + version: 2.4.0 manager: conda platform: linux-64 dependencies: python: '' - url: https://repo.prefix.dev/conda-forge/noarch/tomli-2.3.0-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda hash: - md5: d2732eb636c264dc9aa4cbee404b1a53 - sha256: cb77c660b646c00a48ef942a9e1721ee46e90230c7c570cdeb5a893b5cce9bff + md5: 72e780e9aa2d0a3295f59b1874e3768b + sha256: 62940c563de45790ba0f076b9f2085a842a65662268b02dd136a8e9b1eaf47a8 category: dev optional: true - name: tomli - version: 2.3.0 + version: 2.4.0 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/tomli-2.3.0-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda hash: - md5: d2732eb636c264dc9aa4cbee404b1a53 - sha256: cb77c660b646c00a48ef942a9e1721ee46e90230c7c570cdeb5a893b5cce9bff + md5: 72e780e9aa2d0a3295f59b1874e3768b + sha256: 62940c563de45790ba0f076b9f2085a842a65662268b02dd136a8e9b1eaf47a8 category: dev optional: true - name: tomlkit - version: 0.13.3 + version: 0.14.0 manager: conda platform: linux-64 dependencies: - python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/tomlkit-0.13.3-pyha770c72_0.conda + python: '>=3.10' + url: https://repo.prefix.dev/conda-forge/noarch/tomlkit-0.14.0-pyha770c72_0.conda hash: - md5: 146402bf0f11cbeb8f781fa4309a95d3 - sha256: f8d3b49c084831a20923f66826f30ecfc55a4cd951e544b7213c692887343222 + md5: 385dca77a8b0ec6fa9b92cb62d09b43b + sha256: b35082091c8efd084e51bc3a4a2d3b07897eff232aaf58cbc0f959b6291a6a93 category: dev optional: true - name: tomlkit - version: 0.13.3 + version: 0.14.0 manager: conda platform: win-64 dependencies: - python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/tomlkit-0.13.3-pyha770c72_0.conda + python: '>=3.10' + url: https://repo.prefix.dev/conda-forge/noarch/tomlkit-0.14.0-pyha770c72_0.conda hash: - md5: 146402bf0f11cbeb8f781fa4309a95d3 - sha256: f8d3b49c084831a20923f66826f30ecfc55a4cd951e544b7213c692887343222 + md5: 385dca77a8b0ec6fa9b92cb62d09b43b + sha256: b35082091c8efd084e51bc3a4a2d3b07897eff232aaf58cbc0f959b6291a6a93 category: dev optional: true - name: toolz @@ -7827,43 +7827,43 @@ package: category: main optional: false - name: geoapps-utils - version: 0.7.0a2.dev1+3a0ee39 + version: 0.7.0a2.dev11+3f02228 manager: pip platform: linux-64 dependencies: - geoh5py: 0.13.0a2.dev34+872fd38e + geoh5py: 0.13.0a2.dev52+fda60c22 matplotlib: '>=3.8.4,<3.9.0' numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.12.0,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a hash: - sha256: 3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + sha256: 3f02228742b4837bd456438081d0a128fc3e1b3a source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a category: main optional: false - name: geoapps-utils - version: 0.7.0a2.dev1+3a0ee39 + version: 0.7.0a2.dev11+3f02228 manager: pip platform: win-64 dependencies: - geoh5py: 0.13.0a2.dev34+872fd38e + geoh5py: 0.13.0a2.dev52+fda60c22 matplotlib: '>=3.8.4,<3.9.0' numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.12.0,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a hash: - sha256: 3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + sha256: 3f02228742b4837bd456438081d0a128fc3e1b3a source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a category: main optional: false - name: geoh5py - version: 0.13.0a2.dev34+872fd38e + version: 0.13.0a2.dev52+fda60c22 manager: pip platform: linux-64 dependencies: @@ -7871,16 +7871,16 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.12.0,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + url: git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc hash: - sha256: 872fd38e1f3a73fad567de7825e5e2bb0aadab72 + sha256: fda60c226dafdcdcb0bbe312be4c1622451479dc source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + url: git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc category: main optional: false - name: geoh5py - version: 0.13.0a2.dev34+872fd38e + version: 0.13.0a2.dev52+fda60c22 manager: pip platform: win-64 dependencies: @@ -7888,12 +7888,12 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.12.0,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + url: git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc hash: - sha256: 872fd38e1f3a73fad567de7825e5e2bb0aadab72 + sha256: fda60c226dafdcdcb0bbe312be4c1622451479dc source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + url: git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc category: main optional: false - name: grid-apps @@ -7902,8 +7902,8 @@ package: platform: linux-64 dependencies: discretize: '>=0.11.0,<0.12.dev' - geoapps-utils: 0.7.0a2.dev1+3a0ee39 - geoh5py: 0.13.0a2.dev34+872fd38e + geoapps-utils: 0.7.0a2.dev11+3f02228 + geoh5py: 0.13.0a2.dev52+fda60c22 numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.12.0,<3.0.0' scipy: '>=1.14.0,<1.15.0' @@ -7921,8 +7921,8 @@ package: platform: win-64 dependencies: discretize: '>=0.11.0,<0.12.dev' - geoapps-utils: 0.7.0a2.dev1+3a0ee39 - geoh5py: 0.13.0a2.dev34+872fd38e + geoapps-utils: 0.7.0a2.dev11+3f02228 + geoh5py: 0.13.0a2.dev52+fda60c22 numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.12.0,<3.0.0' scipy: '>=1.14.0,<1.15.0' @@ -7935,7 +7935,7 @@ package: category: main optional: false - name: mira-simpeg - version: 0.23.0.3a1.dev105+g7d744e889 + version: 0.23.0.3a1.dev107+g1cf096ddf manager: pip platform: linux-64 dependencies: @@ -7948,16 +7948,16 @@ package: pymatsolver: '>=0.3' scipy: '>=1.8' typing-extensions: '*' - url: git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + url: git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae hash: - sha256: 7d744e889c77fa74ab5addcd26b7c709f395eb77 + sha256: 1cf096ddfe44da149fecbb53d6f6e97fae3c23ae source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + url: git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae category: main optional: false - name: mira-simpeg - version: 0.23.0.3a1.dev105+g7d744e889 + version: 0.23.0.3a1.dev107+g1cf096ddf manager: pip platform: win-64 dependencies: @@ -7970,11 +7970,11 @@ package: pymatsolver: '>=0.3' scipy: '>=1.8' typing-extensions: '*' - url: git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + url: git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae hash: - sha256: 7d744e889c77fa74ab5addcd26b7c709f395eb77 + sha256: 1cf096ddfe44da149fecbb53d6f6e97fae3c23ae source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + url: git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae category: main optional: false diff --git a/py-3.11.conda-lock.yml b/py-3.11.conda-lock.yml index 39bfe0c2..7a1ac887 100644 --- a/py-3.11.conda-lock.yml +++ b/py-3.11.conda-lock.yml @@ -15,8 +15,8 @@ version: 1 metadata: content_hash: - win-64: 18951a7399038507897a2e4d2ce4f98c2560b388e41fad171b805dd135d64300 - linux-64: 5a4516dfb4e65db8f49436fab37d54a6b4d11c5554b1596d650b342d1875c5e0 + win-64: fb18dd8c88b4986ce881481f4f4c756520898dda00e4f5006f10cc99878f79e0 + linux-64: 63b54937a5485c2342c949498a43e2a0c19090b2df7a941558e7f5f979673863 channels: - url: conda-forge used_env_vars: [] @@ -298,29 +298,29 @@ package: category: dev optional: true - name: async-lru - version: 2.0.5 + version: 2.1.0 manager: conda platform: linux-64 dependencies: - python: '>=3.9' + python: '>=3.10' typing_extensions: '>=4.0.0' - url: https://repo.prefix.dev/conda-forge/noarch/async-lru-2.0.5-pyh29332c3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/async-lru-2.1.0-pyhcf101f3_0.conda hash: - md5: d9d0f99095a9bb7e3641bca8c6ad2ac7 - sha256: 3b7233041e462d9eeb93ea1dfe7b18aca9c358832517072054bb8761df0c324b + md5: 04d2e5fba67e5a1ecec8e25d6c769004 + sha256: fb09cb9bfe4da1586d0ad3bf80bb65e70acfd5fe0f76df384250a1c0587d6acc category: dev optional: true - name: async-lru - version: 2.0.5 + version: 2.1.0 manager: conda platform: win-64 dependencies: - python: '>=3.9' + python: '>=3.10' typing_extensions: '>=4.0.0' - url: https://repo.prefix.dev/conda-forge/noarch/async-lru-2.0.5-pyh29332c3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/async-lru-2.1.0-pyhcf101f3_0.conda hash: - md5: d9d0f99095a9bb7e3641bca8c6ad2ac7 - sha256: 3b7233041e462d9eeb93ea1dfe7b18aca9c358832517072054bb8761df0c324b + md5: 04d2e5fba67e5a1ecec8e25d6c769004 + sha256: fb09cb9bfe4da1586d0ad3bf80bb65e70acfd5fe0f76df384250a1c0587d6acc category: dev optional: true - name: attrs @@ -1167,11 +1167,11 @@ package: platform: linux-64 dependencies: python: '>=3.10' - wrapt: <2,>=1.10 - url: https://repo.prefix.dev/conda-forge/noarch/deprecated-1.3.1-pyhd8ed1ab_0.conda + wrapt: <3,>=1.10 + url: https://repo.prefix.dev/conda-forge/noarch/deprecated-1.3.1-pyhd8ed1ab_1.conda hash: - md5: bf74a83f7a0f2a21b5d709997402cac4 - sha256: c994a70449d548dd388768090c71c1da81e1e128a281547ab9022908d46878c5 + md5: 5498feb783ab29db6ca8845f68fa0f03 + sha256: 7d57a7b8266043ffb99d092ebc25e89a0a2490bed4146b9432c83c2c476fa94d category: main optional: false - name: deprecated @@ -1180,35 +1180,35 @@ package: platform: win-64 dependencies: python: '>=3.10' - wrapt: <2,>=1.10 - url: https://repo.prefix.dev/conda-forge/noarch/deprecated-1.3.1-pyhd8ed1ab_0.conda + wrapt: <3,>=1.10 + url: https://repo.prefix.dev/conda-forge/noarch/deprecated-1.3.1-pyhd8ed1ab_1.conda hash: - md5: bf74a83f7a0f2a21b5d709997402cac4 - sha256: c994a70449d548dd388768090c71c1da81e1e128a281547ab9022908d46878c5 + md5: 5498feb783ab29db6ca8845f68fa0f03 + sha256: 7d57a7b8266043ffb99d092ebc25e89a0a2490bed4146b9432c83c2c476fa94d category: main optional: false - name: dill - version: 0.4.0 + version: 0.4.1 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/dill-0.4.0-pyhcf101f3_1.conda + url: https://repo.prefix.dev/conda-forge/noarch/dill-0.4.1-pyhcf101f3_0.conda hash: - md5: eec5b361dbbaa69dba05050977a414b0 - sha256: c0c91bd91e59940091cec1760db51a82a58e9c64edf4b808bd2da94201ccfdb4 + md5: 080a808fce955026bf82107d955d32da + sha256: 1ef84c0cc4efd0c2d58c3cb365945edbd9ee42a1c54514d1ccba4b641005f757 category: dev optional: true - name: dill - version: 0.4.0 + version: 0.4.1 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/dill-0.4.0-pyhcf101f3_1.conda + url: https://repo.prefix.dev/conda-forge/noarch/dill-0.4.1-pyhcf101f3_0.conda hash: - md5: eec5b361dbbaa69dba05050977a414b0 - sha256: c0c91bd91e59940091cec1760db51a82a58e9c64edf4b808bd2da94201ccfdb4 + md5: 080a808fce955026bf82107d955d32da + sha256: 1ef84c0cc4efd0c2d58c3cb365945edbd9ee42a1c54514d1ccba4b641005f757 category: dev optional: true - name: discretize @@ -1493,27 +1493,27 @@ package: category: main optional: false - name: fsspec - version: 2025.12.0 + version: 2026.1.0 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/fsspec-2025.12.0-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/fsspec-2026.1.0-pyhd8ed1ab_0.conda hash: - md5: a3b9510e2491c20c7fc0f5e730227fbb - sha256: 64a4ed910e39d96cd590d297982b229c57a08e70450d489faa34fd2bec36dbcc + md5: 1daaf94a304a27ba3446a306235a37ea + sha256: bfba6c280366f48b00a6a7036988fc2bc3fea5ac1d8303152c9da69d72a22936 category: main optional: false - name: fsspec - version: 2025.12.0 + version: 2026.1.0 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/fsspec-2025.12.0-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/fsspec-2026.1.0-pyhd8ed1ab_0.conda hash: - md5: a3b9510e2491c20c7fc0f5e730227fbb - sha256: 64a4ed910e39d96cd590d297982b229c57a08e70450d489faa34fd2bec36dbcc + md5: 1daaf94a304a27ba3446a306235a37ea + sha256: bfba6c280366f48b00a6a7036988fc2bc3fea5ac1d8303152c9da69d72a22936 category: main optional: false - name: geoana @@ -1652,17 +1652,17 @@ package: dependencies: __glibc: '>=2.17,<3.0.a0' libaec: '>=1.1.4,<2.0a0' - libcurl: '>=8.17.0,<9.0a0' + libcurl: '>=8.18.0,<9.0a0' libgcc: '>=14' libgfortran: '' libgfortran5: '>=14.3.0' libstdcxx: '>=14' libzlib: '>=1.3.1,<2.0a0' openssl: '>=3.5.4,<4.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/hdf5-1.14.6-nompi_h1b119a7_104.conda + url: https://repo.prefix.dev/conda-forge/linux-64/hdf5-1.14.6-nompi_h1b119a7_105.conda hash: - md5: 0857f4d157820dcd5625f61fdfefb780 - sha256: 454e9724b322cee277abd7acf4f8d688e9c4ded006b6d5bc9fcc2a1ff907d27a + md5: d58cd79121dd51128f2a5dab44edf1ea + sha256: aa85acd07b8f60d1760c6b3fa91dd8402572766e763f3989c759ecd266ed8e9f category: main optional: false - name: hdf5 @@ -1671,16 +1671,16 @@ package: platform: win-64 dependencies: libaec: '>=1.1.4,<2.0a0' - libcurl: '>=8.17.0,<9.0a0' + libcurl: '>=8.18.0,<9.0a0' libzlib: '>=1.3.1,<2.0a0' openssl: '>=3.5.4,<4.0a0' ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/hdf5-1.14.6-nompi_h89f0904_104.conda + url: https://repo.prefix.dev/conda-forge/win-64/hdf5-1.14.6-nompi_h89f0904_105.conda hash: - md5: 9cc4a5567d46c7fcde99563e86522882 - sha256: cc948149f700033ff85ce4a1854edf6adcb5881391a3df5c40cbe2a793dd9f81 + md5: c1caaf8a28c0eb3be85566e63a5fcb5a + sha256: 52e5eb039289946a32aee305e6af777d77376dc0adcb2bdcc31633dcc48d21a5 category: main optional: false - name: hpack @@ -2637,33 +2637,33 @@ package: category: dev optional: true - name: jupyter_server_terminals - version: 0.5.3 + version: 0.5.4 manager: conda platform: linux-64 dependencies: - python: '>=3.9' + python: '>=3.10' terminado: '>=0.8.3' - url: https://repo.prefix.dev/conda-forge/noarch/jupyter_server_terminals-0.5.3-pyhd8ed1ab_1.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyter_server_terminals-0.5.4-pyhcf101f3_0.conda hash: - md5: 2d983ff1b82a1ccb6f2e9d8784bdd6bd - sha256: 0890fc79422191bc29edf17d7b42cff44ba254aa225d31eb30819f8772b775b8 + md5: 7b8bace4943e0dc345fc45938826f2b8 + sha256: 5eda79ed9f53f590031d29346abd183051263227dd9ee667b5ca1133ce297654 category: dev optional: true - name: jupyter_server_terminals - version: 0.5.3 + version: 0.5.4 manager: conda platform: win-64 dependencies: - python: '>=3.9' + python: '>=3.10' terminado: '>=0.8.3' - url: https://repo.prefix.dev/conda-forge/noarch/jupyter_server_terminals-0.5.3-pyhd8ed1ab_1.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyter_server_terminals-0.5.4-pyhcf101f3_0.conda hash: - md5: 2d983ff1b82a1ccb6f2e9d8784bdd6bd - sha256: 0890fc79422191bc29edf17d7b42cff44ba254aa225d31eb30819f8772b775b8 + md5: 7b8bace4943e0dc345fc45938826f2b8 + sha256: 5eda79ed9f53f590031d29346abd183051263227dd9ee667b5ca1133ce297654 category: dev optional: true - name: jupyterlab - version: 4.5.1 + version: 4.5.2 manager: conda platform: linux-64 dependencies: @@ -2682,14 +2682,14 @@ package: tomli: '>=1.2.2' tornado: '>=6.2.0' traitlets: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.5.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.5.2-pyhd8ed1ab_0.conda hash: - md5: f8e8f8db45e1a946ce9b20b0f60b3111 - sha256: ac31a517238173eb565ba9f517b1f9437fba48035f1276a9c1190c145657cafd + md5: 513e7fcc06c82b24c84ff88ece13ac9f + sha256: 4e277cee7fc4b403c954960476375e5a51babd06f3ac46a04bd9fff5971aa569 category: dev optional: true - name: jupyterlab - version: 4.5.1 + version: 4.5.2 manager: conda platform: win-64 dependencies: @@ -2708,10 +2708,10 @@ package: tomli: '>=1.2.2' tornado: '>=6.2.0' traitlets: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.5.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.5.2-pyhd8ed1ab_0.conda hash: - md5: f8e8f8db45e1a946ce9b20b0f60b3111 - sha256: ac31a517238173eb565ba9f517b1f9437fba48035f1276a9c1190c145657cafd + md5: 513e7fcc06c82b24c84ff88ece13ac9f + sha256: 4e277cee7fc4b403c954960476375e5a51babd06f3ac46a04bd9fff5971aa569 category: dev optional: true - name: jupyterlab_pygments @@ -2803,7 +2803,7 @@ package: category: dev optional: true - name: jupytext - version: 1.18.1 + version: 1.19.0 manager: conda platform: linux-64 dependencies: @@ -2814,14 +2814,14 @@ package: python: '>=3.10' pyyaml: '' tomli: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupytext-1.18.1-pyh80e38bb_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupytext-1.19.0-pyh0398c0e_0.conda hash: - md5: 3c85f79f1debe2d2c82ac08f1c1126e1 - sha256: 07063dad3019455d786dc3b5174731eb0ef53eb699df25e21571c2b7cdcf0fd0 + md5: 1831f8fcb080707636343f5e1d8994f1 + sha256: 76f1c795088c7ad8b899ee388aafe69d3412ff11d5ca628fff0b655fbb31de05 category: dev optional: true - name: jupytext - version: 1.18.1 + version: 1.19.0 manager: conda platform: win-64 dependencies: @@ -2832,10 +2832,10 @@ package: python: '>=3.10' pyyaml: '' tomli: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupytext-1.18.1-pyh80e38bb_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupytext-1.19.0-pyh0398c0e_0.conda hash: - md5: 3c85f79f1debe2d2c82ac08f1c1126e1 - sha256: 07063dad3019455d786dc3b5174731eb0ef53eb699df25e21571c2b7cdcf0fd0 + md5: 1831f8fcb080707636343f5e1d8994f1 + sha256: 76f1c795088c7ad8b899ee388aafe69d3412ff11d5ca628fff0b655fbb31de05 category: dev optional: true - name: keyutils @@ -2939,34 +2939,34 @@ package: category: dev optional: true - name: lcms2 - version: '2.17' + version: '2.18' manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - libgcc: '>=13' - libjpeg-turbo: '>=3.0.0,<4.0a0' - libtiff: '>=4.7.0,<4.8.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/lcms2-2.17-h717163a_0.conda + libgcc: '>=14' + libjpeg-turbo: '>=3.1.2,<4.0a0' + libtiff: '>=4.7.1,<4.8.0a0' + url: https://repo.prefix.dev/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda hash: - md5: 000e85703f0fd9594c81710dd5066471 - sha256: d6a61830a354da022eae93fa896d0991385a875c6bba53c82263a289deda9db8 + md5: 6f2e2c8f58160147c4d1c6f4c14cbac4 + sha256: 836ec4b895352110335b9fdcfa83a8dcdbe6c5fb7c06c4929130600caea91c0a category: main optional: false - name: lcms2 - version: '2.17' + version: '2.18' manager: conda platform: win-64 dependencies: - libjpeg-turbo: '>=3.0.0,<4.0a0' - libtiff: '>=4.7.0,<4.8.0a0' + libjpeg-turbo: '>=3.1.2,<4.0a0' + libtiff: '>=4.7.1,<4.8.0a0' ucrt: '>=10.0.20348.0' - vc: '>=14.2,<15' - vc14_runtime: '>=14.29.30139' - url: https://repo.prefix.dev/conda-forge/win-64/lcms2-2.17-hbcf6048_0.conda + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/lcms2-2.18-hf2c6c5f_0.conda hash: - md5: 3538827f77b82a837fa681a4579e37a1 - sha256: 7712eab5f1a35ca3ea6db48ead49e0d6ac7f96f8560da8023e61b3dbe4f3b25d + md5: b6c68d6b829b044cd17a41e0a8a23ca1 + sha256: 7eeb18c5c86db146b62da66d9e8b0e753a52987f9134a494309588bbeceddf28 category: main optional: false - name: ld_impl_linux-64 @@ -3582,30 +3582,30 @@ package: category: main optional: false - name: liblzma - version: 5.8.1 + version: 5.8.2 manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - libgcc: '>=13' - url: https://repo.prefix.dev/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda + libgcc: '>=14' + url: https://repo.prefix.dev/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda hash: - md5: 1a580f7796c7bf6393fddb8bbbde58dc - sha256: f2591c0069447bbe28d4d696b7fcb0c5bd0b4ac582769b89addbcf26fb3430d8 + md5: c7c83eecbb72d88b940c249af56c8b17 + sha256: 755c55ebab181d678c12e49cced893598f2bab22d582fbbf4d8b83c18be207eb category: main optional: false - name: liblzma - version: 5.8.1 + version: 5.8.2 manager: conda platform: win-64 dependencies: ucrt: '>=10.0.20348.0' - vc: '>=14.2,<15' - vc14_runtime: '>=14.29.30139' - url: https://repo.prefix.dev/conda-forge/win-64/liblzma-5.8.1-h2466b09_2.conda + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/liblzma-5.8.2-hfd05255_0.conda hash: - md5: c15148b2e18da456f5108ccb5e411446 - sha256: 55764956eb9179b98de7cc0e55696f2eff8f7b83fc3ebff5e696ca358bca28cc + md5: ba0bfd4c3cf73f299ffe46ff0eaeb8e3 + sha256: f25bf293f550c8ed2e0c7145eb404324611cfccff37660869d97abf526eb957c category: main optional: false - name: libnghttp2 @@ -3640,21 +3640,21 @@ package: category: main optional: false - name: libpng - version: 1.6.53 + version: 1.6.54 manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' libgcc: '>=14' libzlib: '>=1.3.1,<2.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/libpng-1.6.53-h421ea60_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/libpng-1.6.54-h421ea60_0.conda hash: - md5: 00d4e66b1f746cb14944cad23fffb405 - sha256: 8acdeb9a7e3d2630176ba8e947caf6bf4985a5148dec69b801e5eb797856688b + md5: d361fa2a59e53b61c2675bfa073e5b7e + sha256: 5de60d34aac848a9991a09fcdea7c0e783d00024aefec279d55e87c0c44742cd category: main optional: false - name: libpng - version: 1.6.53 + version: 1.6.54 manager: conda platform: win-64 dependencies: @@ -3662,10 +3662,10 @@ package: ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/libpng-1.6.53-h7351971_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/libpng-1.6.54-h7351971_0.conda hash: - md5: fb6f43f6f08ca100cb24cff125ab0d9e - sha256: e5d061e7bdb2b97227b6955d1aa700a58a5703b5150ab0467cc37de609f277b6 + md5: 638ecb69e44b6a588afd5633e81f9e61 + sha256: 6e269361aa18a57bd2e593e480d83d93fc5f839d33d3bfc31b4ffe10edf6751c category: main optional: false - name: libscotch @@ -3741,31 +3741,31 @@ package: category: main optional: false - name: libsqlite - version: 3.51.1 + version: 3.51.2 manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' libgcc: '>=14' libzlib: '>=1.3.1,<2.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/libsqlite-3.51.1-h0c1763c_1.conda + url: https://repo.prefix.dev/conda-forge/linux-64/libsqlite-3.51.2-h0c1763c_0.conda hash: - md5: ad1fd565aff83b543d726382c0ab0af2 - sha256: 5ef162b2a1390d1495a759734afe2312a358a58441cf8f378be651903646f3b7 + md5: f7d30045eccb83f2bb8053041f42db3c + sha256: c1ff4589b48d32ca0a2628970d869fa9f7b2c2d00269a3761edc7e9e4c1ab7b8 category: main optional: false - name: libsqlite - version: 3.51.1 + version: 3.51.2 manager: conda platform: win-64 dependencies: ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/libsqlite-3.51.1-hf5d6505_1.conda + url: https://repo.prefix.dev/conda-forge/win-64/libsqlite-3.51.2-hf5d6505_0.conda hash: - md5: be65be5f758709fc01b01626152e96b0 - sha256: d6d86715a1afe11f626b7509935e9d2e14a4946632c0ac474526e20fc6c55f99 + md5: 903979414b47d777d548e5f0165e6cd8 + sha256: 756478128e3e104bd7e7c3ce6c1b0efad7e08c7320c69fdc726e039323c63fbb category: main optional: false - name: libssh2 @@ -4745,39 +4745,39 @@ package: category: dev optional: true - name: notebook - version: 7.5.1 + version: 7.5.2 manager: conda platform: linux-64 dependencies: importlib_resources: '>=5.0' jupyter_server: '>=2.4.0,<3' - jupyterlab: '>=4.5.1,<4.6' + jupyterlab: '>=4.5.2,<4.6' jupyterlab_server: '>=2.28.0,<3' notebook-shim: '>=0.2,<0.3' python: '>=3.10' tornado: '>=6.2.0' - url: https://repo.prefix.dev/conda-forge/noarch/notebook-7.5.1-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/notebook-7.5.2-pyhcf101f3_0.conda hash: - md5: c984a8b773a34e38f5cf399b6d582e5c - sha256: 672ec7db73c8bfbacf9227c0c2287effdeded77b4d06373f2e498a310ce76a8c + md5: 47b58fa741a608dac785b71b8083bdb7 + sha256: 05bda90b7a980593c5e955dec5c556ff4dabf56e6ff45a3fb6c670f5f20b11e6 category: dev optional: true - name: notebook - version: 7.5.1 + version: 7.5.2 manager: conda platform: win-64 dependencies: importlib_resources: '>=5.0' jupyter_server: '>=2.4.0,<3' - jupyterlab: '>=4.5.1,<4.6' + jupyterlab: '>=4.5.2,<4.6' jupyterlab_server: '>=2.28.0,<3' notebook-shim: '>=0.2,<0.3' python: '>=3.10' tornado: '>=6.2.0' - url: https://repo.prefix.dev/conda-forge/noarch/notebook-7.5.1-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/notebook-7.5.2-pyhcf101f3_0.conda hash: - md5: c984a8b773a34e38f5cf399b6d582e5c - sha256: 672ec7db73c8bfbacf9227c0c2287effdeded77b4d06373f2e498a310ce76a8c + md5: 47b58fa741a608dac785b71b8083bdb7 + sha256: 05bda90b7a980593c5e955dec5c556ff4dabf56e6ff45a3fb6c670f5f20b11e6 category: dev optional: true - name: notebook-shim @@ -5272,27 +5272,27 @@ package: category: dev optional: true - name: prometheus_client - version: 0.23.1 + version: 0.24.1 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/prometheus_client-0.23.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/prometheus_client-0.24.1-pyhd8ed1ab_0.conda hash: - md5: a1e91db2d17fd258c64921cb38e6745a - sha256: 13dc67de68db151ff909f2c1d2486fa7e2d51355b25cee08d26ede1b62d48d40 + md5: 7526d20621b53440b0aae45d4797847e + sha256: 75b2589159d04b3fb92db16d9970b396b9124652c784ab05b66f584edc97f283 category: dev optional: true - name: prometheus_client - version: 0.23.1 + version: 0.24.1 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/prometheus_client-0.23.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/prometheus_client-0.24.1-pyhd8ed1ab_0.conda hash: - md5: a1e91db2d17fd258c64921cb38e6745a - sha256: 13dc67de68db151ff909f2c1d2486fa7e2d51355b25cee08d26ede1b62d48d40 + md5: 7526d20621b53440b0aae45d4797847e + sha256: 75b2589159d04b3fb92db16d9970b396b9124652c784ab05b66f584edc97f283 category: dev optional: true - name: prompt-toolkit @@ -5640,27 +5640,27 @@ package: category: main optional: false - name: pyparsing - version: 3.3.1 + version: 3.3.2 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/pyparsing-3.3.1-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda hash: - md5: d837065e4e0de4962c3462079c23f969 - sha256: 0c70bc577f5efa87501bdc841b88f594f4d3f3a992dfb851e2130fa5c817835b + md5: 3687cc0b82a8b4c17e1f0eb7e47163d5 + sha256: 417fba4783e528ee732afa82999300859b065dc59927344b4859c64aae7182de category: main optional: false - name: pyparsing - version: 3.3.1 + version: 3.3.2 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/pyparsing-3.3.1-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda hash: - md5: d837065e4e0de4962c3462079c23f969 - sha256: 0c70bc577f5efa87501bdc841b88f594f4d3f3a992dfb851e2130fa5c817835b + md5: 3687cc0b82a8b4c17e1f0eb7e47163d5 + sha256: 417fba4783e528ee732afa82999300859b065dc59927344b4859c64aae7182de category: main optional: false - name: pysocks @@ -6417,54 +6417,54 @@ package: category: main optional: false - name: send2trash - version: 2.0.0 + version: 2.1.0 manager: conda platform: linux-64 dependencies: __linux: '' python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/send2trash-2.0.0-pyha191276_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/send2trash-2.1.0-pyha191276_0.conda hash: - md5: f2cc28627a451a28ddd5ef5ab0bf579d - sha256: 27cd93b4f848a1c8193a7b1b8e6e6d03321462e96997ce95ea1a39305f7ac7cb + md5: 645026465469ecd4989188e1c4e24953 + sha256: b25d573874fe39cb8e4cf6ed0279acb9a94fedce5c5ae885da11566d595035ad category: dev optional: true - name: send2trash - version: 2.0.0 + version: 2.1.0 manager: conda platform: win-64 dependencies: __win: '' python: '>=3.10' pywin32: '' - url: https://repo.prefix.dev/conda-forge/noarch/send2trash-2.0.0-pyh6dadd2b_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/send2trash-2.1.0-pyh6dadd2b_0.conda hash: - md5: 40df72e963d80a403c1861ae9428b13c - sha256: f154f702baf550de9c1e3517f110bb71a056df5645027c8d15b37f3ea33722cc + md5: 69ba308f1356f39901f5654d82405df3 + sha256: b64e5cdb66f5d31fcef05b6ed95b8be3e80796528aa8a165428496c0dda3383f category: dev optional: true - name: setuptools - version: 80.9.0 + version: 80.10.1 manager: conda platform: linux-64 dependencies: - python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda + python: '>=3.10' + url: https://repo.prefix.dev/conda-forge/noarch/setuptools-80.10.1-pyh332efcf_0.conda hash: - md5: 4de79c071274a53dcaf2a8c749d1499e - sha256: 972560fcf9657058e3e1f97186cc94389144b46dbdf58c807ce62e83f977e863 + md5: cb72cedd94dd923c6a9405a3d3b1c018 + sha256: 89d5bb48047e7e27aa52a3a71d6ebf386e5ee4bdbd7ca91d653df9977eca8253 category: main optional: false - name: setuptools - version: 80.9.0 + version: 80.10.1 manager: conda platform: win-64 dependencies: - python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda + python: '>=3.10' + url: https://repo.prefix.dev/conda-forge/noarch/setuptools-80.10.1-pyh332efcf_0.conda hash: - md5: 4de79c071274a53dcaf2a8c749d1499e - sha256: 972560fcf9657058e3e1f97186cc94389144b46dbdf58c807ce62e83f977e863 + md5: cb72cedd94dd923c6a9405a3d3b1c018 + sha256: 89d5bb48047e7e27aa52a3a71d6ebf386e5ee4bdbd7ca91d653df9977eca8253 category: main optional: false - name: six @@ -6564,27 +6564,27 @@ package: category: main optional: false - name: soupsieve - version: 2.8.1 + version: 2.8.2 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/soupsieve-2.8.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/soupsieve-2.8.2-pyhd8ed1ab_0.conda hash: - md5: 7de28c27fe620a4f7dbfaea137c6232b - sha256: 4ba9b8c45862e54d05ed9a04cc6aab5a17756ab9865f57cbf2836e47144153d2 + md5: fcbe3971b6017792e9b24ff451daa7f5 + sha256: aacc87d88795ef887b89fe9401d1092312c43371d1ba92340d8924da1a982b6a category: dev optional: true - name: soupsieve - version: 2.8.1 + version: 2.8.2 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/soupsieve-2.8.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/soupsieve-2.8.2-pyhd8ed1ab_0.conda hash: - md5: 7de28c27fe620a4f7dbfaea137c6232b - sha256: 4ba9b8c45862e54d05ed9a04cc6aab5a17756ab9865f57cbf2836e47144153d2 + md5: fcbe3971b6017792e9b24ff451daa7f5 + sha256: aacc87d88795ef887b89fe9401d1092312c43371d1ba92340d8924da1a982b6a category: dev optional: true - name: sphinx @@ -6992,51 +6992,51 @@ package: category: main optional: false - name: tomli - version: 2.3.0 + version: 2.4.0 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/tomli-2.3.0-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda hash: - md5: d2732eb636c264dc9aa4cbee404b1a53 - sha256: cb77c660b646c00a48ef942a9e1721ee46e90230c7c570cdeb5a893b5cce9bff + md5: 72e780e9aa2d0a3295f59b1874e3768b + sha256: 62940c563de45790ba0f076b9f2085a842a65662268b02dd136a8e9b1eaf47a8 category: dev optional: true - name: tomli - version: 2.3.0 + version: 2.4.0 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/tomli-2.3.0-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda hash: - md5: d2732eb636c264dc9aa4cbee404b1a53 - sha256: cb77c660b646c00a48ef942a9e1721ee46e90230c7c570cdeb5a893b5cce9bff + md5: 72e780e9aa2d0a3295f59b1874e3768b + sha256: 62940c563de45790ba0f076b9f2085a842a65662268b02dd136a8e9b1eaf47a8 category: dev optional: true - name: tomlkit - version: 0.13.3 + version: 0.14.0 manager: conda platform: linux-64 dependencies: - python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/tomlkit-0.13.3-pyha770c72_0.conda + python: '>=3.10' + url: https://repo.prefix.dev/conda-forge/noarch/tomlkit-0.14.0-pyha770c72_0.conda hash: - md5: 146402bf0f11cbeb8f781fa4309a95d3 - sha256: f8d3b49c084831a20923f66826f30ecfc55a4cd951e544b7213c692887343222 + md5: 385dca77a8b0ec6fa9b92cb62d09b43b + sha256: b35082091c8efd084e51bc3a4a2d3b07897eff232aaf58cbc0f959b6291a6a93 category: dev optional: true - name: tomlkit - version: 0.13.3 + version: 0.14.0 manager: conda platform: win-64 dependencies: - python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/tomlkit-0.13.3-pyha770c72_0.conda + python: '>=3.10' + url: https://repo.prefix.dev/conda-forge/noarch/tomlkit-0.14.0-pyha770c72_0.conda hash: - md5: 146402bf0f11cbeb8f781fa4309a95d3 - sha256: f8d3b49c084831a20923f66826f30ecfc55a4cd951e544b7213c692887343222 + md5: 385dca77a8b0ec6fa9b92cb62d09b43b + sha256: b35082091c8efd084e51bc3a4a2d3b07897eff232aaf58cbc0f959b6291a6a93 category: dev optional: true - name: toolz @@ -7596,7 +7596,7 @@ package: category: dev optional: true - name: wrapt - version: 1.17.3 + version: 2.0.1 manager: conda platform: linux-64 dependencies: @@ -7604,14 +7604,14 @@ package: libgcc: '>=14' python: '>=3.11,<3.12.0a0' python_abi: 3.11.* - url: https://repo.prefix.dev/conda-forge/linux-64/wrapt-1.17.3-py311h49ec1c0_1.conda + url: https://repo.prefix.dev/conda-forge/linux-64/wrapt-2.0.1-py311h49ec1c0_1.conda hash: - md5: 47c1c27dee6c31bf8eefbdbdde817d83 - sha256: efcb41a300b58624790d2ce1c6ac9c1da7d23dd91c3d329bd22853866f8f8533 + md5: e8442f5d358d1449deaf4ba76f5e212c + sha256: 81327871ef18cbdd095e1e7650a198fd13f02355a39f23f1e377aa6d899f8ce0 category: main optional: false - name: wrapt - version: 1.17.3 + version: 2.0.1 manager: conda platform: win-64 dependencies: @@ -7620,10 +7620,10 @@ package: ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/wrapt-1.17.3-py311h3485c13_1.conda + url: https://repo.prefix.dev/conda-forge/win-64/wrapt-2.0.1-py311h3485c13_1.conda hash: - md5: fbf91bcdeeb11de218edce103104e353 - sha256: 96f1ea03084a6deeb0630372319a03d7774f982d24e9ad7394941efd5779591c + md5: 6984e251174331af4da961ac6d859188 + sha256: 1bc7cbb700f44f68aa5935de8cf111a08019b47f05dfbb1af95e74da2052590f category: main optional: false - name: xorg-libxau @@ -7886,43 +7886,43 @@ package: category: main optional: false - name: geoapps-utils - version: 0.7.0a2.dev1+3a0ee39 + version: 0.7.0a2.dev11+3f02228 manager: pip platform: linux-64 dependencies: - geoh5py: 0.13.0a2.dev34+872fd38e + geoh5py: 0.13.0a2.dev52+fda60c22 matplotlib: '>=3.8.4,<3.9.0' numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.12.0,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a hash: - sha256: 3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + sha256: 3f02228742b4837bd456438081d0a128fc3e1b3a source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a category: main optional: false - name: geoapps-utils - version: 0.7.0a2.dev1+3a0ee39 + version: 0.7.0a2.dev11+3f02228 manager: pip platform: win-64 dependencies: - geoh5py: 0.13.0a2.dev34+872fd38e + geoh5py: 0.13.0a2.dev52+fda60c22 matplotlib: '>=3.8.4,<3.9.0' numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.12.0,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a hash: - sha256: 3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + sha256: 3f02228742b4837bd456438081d0a128fc3e1b3a source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a category: main optional: false - name: geoh5py - version: 0.13.0a2.dev34+872fd38e + version: 0.13.0a2.dev52+fda60c22 manager: pip platform: linux-64 dependencies: @@ -7930,16 +7930,16 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.12.0,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + url: git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc hash: - sha256: 872fd38e1f3a73fad567de7825e5e2bb0aadab72 + sha256: fda60c226dafdcdcb0bbe312be4c1622451479dc source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + url: git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc category: main optional: false - name: geoh5py - version: 0.13.0a2.dev34+872fd38e + version: 0.13.0a2.dev52+fda60c22 manager: pip platform: win-64 dependencies: @@ -7947,12 +7947,12 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.12.0,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + url: git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc hash: - sha256: 872fd38e1f3a73fad567de7825e5e2bb0aadab72 + sha256: fda60c226dafdcdcb0bbe312be4c1622451479dc source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + url: git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc category: main optional: false - name: grid-apps @@ -7961,8 +7961,8 @@ package: platform: linux-64 dependencies: discretize: '>=0.11.0,<0.12.dev' - geoapps-utils: 0.7.0a2.dev1+3a0ee39 - geoh5py: 0.13.0a2.dev34+872fd38e + geoapps-utils: 0.7.0a2.dev11+3f02228 + geoh5py: 0.13.0a2.dev52+fda60c22 numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.12.0,<3.0.0' scipy: '>=1.14.0,<1.15.0' @@ -7980,8 +7980,8 @@ package: platform: win-64 dependencies: discretize: '>=0.11.0,<0.12.dev' - geoapps-utils: 0.7.0a2.dev1+3a0ee39 - geoh5py: 0.13.0a2.dev34+872fd38e + geoapps-utils: 0.7.0a2.dev11+3f02228 + geoh5py: 0.13.0a2.dev52+fda60c22 numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.12.0,<3.0.0' scipy: '>=1.14.0,<1.15.0' @@ -7994,7 +7994,7 @@ package: category: main optional: false - name: mira-simpeg - version: 0.23.0.3a1.dev105+g7d744e889 + version: 0.23.0.3a1.dev107+g1cf096ddf manager: pip platform: linux-64 dependencies: @@ -8007,16 +8007,16 @@ package: pymatsolver: '>=0.3' scipy: '>=1.8' typing-extensions: '*' - url: git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + url: git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae hash: - sha256: 7d744e889c77fa74ab5addcd26b7c709f395eb77 + sha256: 1cf096ddfe44da149fecbb53d6f6e97fae3c23ae source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + url: git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae category: main optional: false - name: mira-simpeg - version: 0.23.0.3a1.dev105+g7d744e889 + version: 0.23.0.3a1.dev107+g1cf096ddf manager: pip platform: win-64 dependencies: @@ -8029,11 +8029,11 @@ package: pymatsolver: '>=0.3' scipy: '>=1.8' typing-extensions: '*' - url: git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + url: git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae hash: - sha256: 7d744e889c77fa74ab5addcd26b7c709f395eb77 + sha256: 1cf096ddfe44da149fecbb53d6f6e97fae3c23ae source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + url: git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae category: main optional: false diff --git a/py-3.12.conda-lock.yml b/py-3.12.conda-lock.yml index d093ef3d..aa9625ae 100644 --- a/py-3.12.conda-lock.yml +++ b/py-3.12.conda-lock.yml @@ -15,8 +15,8 @@ version: 1 metadata: content_hash: - win-64: 75f9dfef05ce45a19001c219a5a5624930d16cb508f9743ae44859e7a2ed2328 - linux-64: f08dbe12eaba84788a1b865c9d12288c14f6e9a11eeecf419706ee2305b09559 + win-64: a78d91fa3dc4c95c661cb43f744570c4cbf3dc04b7182fba46b68958c9f38e93 + linux-64: 8d2ec2f5bff152c0b1a90962f693656e4ddb9e44ed5c8117e1ca290243cc3f6e channels: - url: conda-forge used_env_vars: [] @@ -324,29 +324,29 @@ package: category: dev optional: true - name: async-lru - version: 2.0.5 + version: 2.1.0 manager: conda platform: linux-64 dependencies: - python: '>=3.9' + python: '>=3.10' typing_extensions: '>=4.0.0' - url: https://repo.prefix.dev/conda-forge/noarch/async-lru-2.0.5-pyh29332c3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/async-lru-2.1.0-pyhcf101f3_0.conda hash: - md5: d9d0f99095a9bb7e3641bca8c6ad2ac7 - sha256: 3b7233041e462d9eeb93ea1dfe7b18aca9c358832517072054bb8761df0c324b + md5: 04d2e5fba67e5a1ecec8e25d6c769004 + sha256: fb09cb9bfe4da1586d0ad3bf80bb65e70acfd5fe0f76df384250a1c0587d6acc category: dev optional: true - name: async-lru - version: 2.0.5 + version: 2.1.0 manager: conda platform: win-64 dependencies: - python: '>=3.9' + python: '>=3.10' typing_extensions: '>=4.0.0' - url: https://repo.prefix.dev/conda-forge/noarch/async-lru-2.0.5-pyh29332c3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/async-lru-2.1.0-pyhcf101f3_0.conda hash: - md5: d9d0f99095a9bb7e3641bca8c6ad2ac7 - sha256: 3b7233041e462d9eeb93ea1dfe7b18aca9c358832517072054bb8761df0c324b + md5: 04d2e5fba67e5a1ecec8e25d6c769004 + sha256: fb09cb9bfe4da1586d0ad3bf80bb65e70acfd5fe0f76df384250a1c0587d6acc category: dev optional: true - name: attrs @@ -1219,11 +1219,11 @@ package: platform: linux-64 dependencies: python: '>=3.10' - wrapt: <2,>=1.10 - url: https://repo.prefix.dev/conda-forge/noarch/deprecated-1.3.1-pyhd8ed1ab_0.conda + wrapt: <3,>=1.10 + url: https://repo.prefix.dev/conda-forge/noarch/deprecated-1.3.1-pyhd8ed1ab_1.conda hash: - md5: bf74a83f7a0f2a21b5d709997402cac4 - sha256: c994a70449d548dd388768090c71c1da81e1e128a281547ab9022908d46878c5 + md5: 5498feb783ab29db6ca8845f68fa0f03 + sha256: 7d57a7b8266043ffb99d092ebc25e89a0a2490bed4146b9432c83c2c476fa94d category: main optional: false - name: deprecated @@ -1232,35 +1232,35 @@ package: platform: win-64 dependencies: python: '>=3.10' - wrapt: <2,>=1.10 - url: https://repo.prefix.dev/conda-forge/noarch/deprecated-1.3.1-pyhd8ed1ab_0.conda + wrapt: <3,>=1.10 + url: https://repo.prefix.dev/conda-forge/noarch/deprecated-1.3.1-pyhd8ed1ab_1.conda hash: - md5: bf74a83f7a0f2a21b5d709997402cac4 - sha256: c994a70449d548dd388768090c71c1da81e1e128a281547ab9022908d46878c5 + md5: 5498feb783ab29db6ca8845f68fa0f03 + sha256: 7d57a7b8266043ffb99d092ebc25e89a0a2490bed4146b9432c83c2c476fa94d category: main optional: false - name: dill - version: 0.4.0 + version: 0.4.1 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/dill-0.4.0-pyhcf101f3_1.conda + url: https://repo.prefix.dev/conda-forge/noarch/dill-0.4.1-pyhcf101f3_0.conda hash: - md5: eec5b361dbbaa69dba05050977a414b0 - sha256: c0c91bd91e59940091cec1760db51a82a58e9c64edf4b808bd2da94201ccfdb4 + md5: 080a808fce955026bf82107d955d32da + sha256: 1ef84c0cc4efd0c2d58c3cb365945edbd9ee42a1c54514d1ccba4b641005f757 category: dev optional: true - name: dill - version: 0.4.0 + version: 0.4.1 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/dill-0.4.0-pyhcf101f3_1.conda + url: https://repo.prefix.dev/conda-forge/noarch/dill-0.4.1-pyhcf101f3_0.conda hash: - md5: eec5b361dbbaa69dba05050977a414b0 - sha256: c0c91bd91e59940091cec1760db51a82a58e9c64edf4b808bd2da94201ccfdb4 + md5: 080a808fce955026bf82107d955d32da + sha256: 1ef84c0cc4efd0c2d58c3cb365945edbd9ee42a1c54514d1ccba4b641005f757 category: dev optional: true - name: discretize @@ -1545,27 +1545,27 @@ package: category: main optional: false - name: fsspec - version: 2025.12.0 + version: 2026.1.0 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/fsspec-2025.12.0-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/fsspec-2026.1.0-pyhd8ed1ab_0.conda hash: - md5: a3b9510e2491c20c7fc0f5e730227fbb - sha256: 64a4ed910e39d96cd590d297982b229c57a08e70450d489faa34fd2bec36dbcc + md5: 1daaf94a304a27ba3446a306235a37ea + sha256: bfba6c280366f48b00a6a7036988fc2bc3fea5ac1d8303152c9da69d72a22936 category: main optional: false - name: fsspec - version: 2025.12.0 + version: 2026.1.0 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/fsspec-2025.12.0-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/fsspec-2026.1.0-pyhd8ed1ab_0.conda hash: - md5: a3b9510e2491c20c7fc0f5e730227fbb - sha256: 64a4ed910e39d96cd590d297982b229c57a08e70450d489faa34fd2bec36dbcc + md5: 1daaf94a304a27ba3446a306235a37ea + sha256: bfba6c280366f48b00a6a7036988fc2bc3fea5ac1d8303152c9da69d72a22936 category: main optional: false - name: geoana @@ -1704,17 +1704,17 @@ package: dependencies: __glibc: '>=2.17,<3.0.a0' libaec: '>=1.1.4,<2.0a0' - libcurl: '>=8.17.0,<9.0a0' + libcurl: '>=8.18.0,<9.0a0' libgcc: '>=14' libgfortran: '' libgfortran5: '>=14.3.0' libstdcxx: '>=14' libzlib: '>=1.3.1,<2.0a0' openssl: '>=3.5.4,<4.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/hdf5-1.14.6-nompi_h1b119a7_104.conda + url: https://repo.prefix.dev/conda-forge/linux-64/hdf5-1.14.6-nompi_h1b119a7_105.conda hash: - md5: 0857f4d157820dcd5625f61fdfefb780 - sha256: 454e9724b322cee277abd7acf4f8d688e9c4ded006b6d5bc9fcc2a1ff907d27a + md5: d58cd79121dd51128f2a5dab44edf1ea + sha256: aa85acd07b8f60d1760c6b3fa91dd8402572766e763f3989c759ecd266ed8e9f category: main optional: false - name: hdf5 @@ -1723,16 +1723,16 @@ package: platform: win-64 dependencies: libaec: '>=1.1.4,<2.0a0' - libcurl: '>=8.17.0,<9.0a0' + libcurl: '>=8.18.0,<9.0a0' libzlib: '>=1.3.1,<2.0a0' openssl: '>=3.5.4,<4.0a0' ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/hdf5-1.14.6-nompi_h89f0904_104.conda + url: https://repo.prefix.dev/conda-forge/win-64/hdf5-1.14.6-nompi_h89f0904_105.conda hash: - md5: 9cc4a5567d46c7fcde99563e86522882 - sha256: cc948149f700033ff85ce4a1854edf6adcb5881391a3df5c40cbe2a793dd9f81 + md5: c1caaf8a28c0eb3be85566e63a5fcb5a + sha256: 52e5eb039289946a32aee305e6af777d77376dc0adcb2bdcc31633dcc48d21a5 category: main optional: false - name: hpack @@ -2689,33 +2689,33 @@ package: category: dev optional: true - name: jupyter_server_terminals - version: 0.5.3 + version: 0.5.4 manager: conda platform: linux-64 dependencies: - python: '>=3.9' + python: '>=3.10' terminado: '>=0.8.3' - url: https://repo.prefix.dev/conda-forge/noarch/jupyter_server_terminals-0.5.3-pyhd8ed1ab_1.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyter_server_terminals-0.5.4-pyhcf101f3_0.conda hash: - md5: 2d983ff1b82a1ccb6f2e9d8784bdd6bd - sha256: 0890fc79422191bc29edf17d7b42cff44ba254aa225d31eb30819f8772b775b8 + md5: 7b8bace4943e0dc345fc45938826f2b8 + sha256: 5eda79ed9f53f590031d29346abd183051263227dd9ee667b5ca1133ce297654 category: dev optional: true - name: jupyter_server_terminals - version: 0.5.3 + version: 0.5.4 manager: conda platform: win-64 dependencies: - python: '>=3.9' + python: '>=3.10' terminado: '>=0.8.3' - url: https://repo.prefix.dev/conda-forge/noarch/jupyter_server_terminals-0.5.3-pyhd8ed1ab_1.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyter_server_terminals-0.5.4-pyhcf101f3_0.conda hash: - md5: 2d983ff1b82a1ccb6f2e9d8784bdd6bd - sha256: 0890fc79422191bc29edf17d7b42cff44ba254aa225d31eb30819f8772b775b8 + md5: 7b8bace4943e0dc345fc45938826f2b8 + sha256: 5eda79ed9f53f590031d29346abd183051263227dd9ee667b5ca1133ce297654 category: dev optional: true - name: jupyterlab - version: 4.5.1 + version: 4.5.2 manager: conda platform: linux-64 dependencies: @@ -2734,14 +2734,14 @@ package: tomli: '>=1.2.2' tornado: '>=6.2.0' traitlets: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.5.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.5.2-pyhd8ed1ab_0.conda hash: - md5: f8e8f8db45e1a946ce9b20b0f60b3111 - sha256: ac31a517238173eb565ba9f517b1f9437fba48035f1276a9c1190c145657cafd + md5: 513e7fcc06c82b24c84ff88ece13ac9f + sha256: 4e277cee7fc4b403c954960476375e5a51babd06f3ac46a04bd9fff5971aa569 category: dev optional: true - name: jupyterlab - version: 4.5.1 + version: 4.5.2 manager: conda platform: win-64 dependencies: @@ -2760,10 +2760,10 @@ package: tomli: '>=1.2.2' tornado: '>=6.2.0' traitlets: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.5.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.5.2-pyhd8ed1ab_0.conda hash: - md5: f8e8f8db45e1a946ce9b20b0f60b3111 - sha256: ac31a517238173eb565ba9f517b1f9437fba48035f1276a9c1190c145657cafd + md5: 513e7fcc06c82b24c84ff88ece13ac9f + sha256: 4e277cee7fc4b403c954960476375e5a51babd06f3ac46a04bd9fff5971aa569 category: dev optional: true - name: jupyterlab_pygments @@ -2855,7 +2855,7 @@ package: category: dev optional: true - name: jupytext - version: 1.18.1 + version: 1.19.0 manager: conda platform: linux-64 dependencies: @@ -2866,14 +2866,14 @@ package: python: '>=3.10' pyyaml: '' tomli: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupytext-1.18.1-pyh80e38bb_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupytext-1.19.0-pyh0398c0e_0.conda hash: - md5: 3c85f79f1debe2d2c82ac08f1c1126e1 - sha256: 07063dad3019455d786dc3b5174731eb0ef53eb699df25e21571c2b7cdcf0fd0 + md5: 1831f8fcb080707636343f5e1d8994f1 + sha256: 76f1c795088c7ad8b899ee388aafe69d3412ff11d5ca628fff0b655fbb31de05 category: dev optional: true - name: jupytext - version: 1.18.1 + version: 1.19.0 manager: conda platform: win-64 dependencies: @@ -2884,10 +2884,10 @@ package: python: '>=3.10' pyyaml: '' tomli: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupytext-1.18.1-pyh80e38bb_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupytext-1.19.0-pyh0398c0e_0.conda hash: - md5: 3c85f79f1debe2d2c82ac08f1c1126e1 - sha256: 07063dad3019455d786dc3b5174731eb0ef53eb699df25e21571c2b7cdcf0fd0 + md5: 1831f8fcb080707636343f5e1d8994f1 + sha256: 76f1c795088c7ad8b899ee388aafe69d3412ff11d5ca628fff0b655fbb31de05 category: dev optional: true - name: keyutils @@ -2991,34 +2991,34 @@ package: category: dev optional: true - name: lcms2 - version: '2.17' + version: '2.18' manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - libgcc: '>=13' - libjpeg-turbo: '>=3.0.0,<4.0a0' - libtiff: '>=4.7.0,<4.8.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/lcms2-2.17-h717163a_0.conda + libgcc: '>=14' + libjpeg-turbo: '>=3.1.2,<4.0a0' + libtiff: '>=4.7.1,<4.8.0a0' + url: https://repo.prefix.dev/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda hash: - md5: 000e85703f0fd9594c81710dd5066471 - sha256: d6a61830a354da022eae93fa896d0991385a875c6bba53c82263a289deda9db8 + md5: 6f2e2c8f58160147c4d1c6f4c14cbac4 + sha256: 836ec4b895352110335b9fdcfa83a8dcdbe6c5fb7c06c4929130600caea91c0a category: main optional: false - name: lcms2 - version: '2.17' + version: '2.18' manager: conda platform: win-64 dependencies: - libjpeg-turbo: '>=3.0.0,<4.0a0' - libtiff: '>=4.7.0,<4.8.0a0' + libjpeg-turbo: '>=3.1.2,<4.0a0' + libtiff: '>=4.7.1,<4.8.0a0' ucrt: '>=10.0.20348.0' - vc: '>=14.2,<15' - vc14_runtime: '>=14.29.30139' - url: https://repo.prefix.dev/conda-forge/win-64/lcms2-2.17-hbcf6048_0.conda + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/lcms2-2.18-hf2c6c5f_0.conda hash: - md5: 3538827f77b82a837fa681a4579e37a1 - sha256: 7712eab5f1a35ca3ea6db48ead49e0d6ac7f96f8560da8023e61b3dbe4f3b25d + md5: b6c68d6b829b044cd17a41e0a8a23ca1 + sha256: 7eeb18c5c86db146b62da66d9e8b0e753a52987f9134a494309588bbeceddf28 category: main optional: false - name: ld_impl_linux-64 @@ -3634,30 +3634,30 @@ package: category: main optional: false - name: liblzma - version: 5.8.1 + version: 5.8.2 manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' - libgcc: '>=13' - url: https://repo.prefix.dev/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda + libgcc: '>=14' + url: https://repo.prefix.dev/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda hash: - md5: 1a580f7796c7bf6393fddb8bbbde58dc - sha256: f2591c0069447bbe28d4d696b7fcb0c5bd0b4ac582769b89addbcf26fb3430d8 + md5: c7c83eecbb72d88b940c249af56c8b17 + sha256: 755c55ebab181d678c12e49cced893598f2bab22d582fbbf4d8b83c18be207eb category: main optional: false - name: liblzma - version: 5.8.1 + version: 5.8.2 manager: conda platform: win-64 dependencies: ucrt: '>=10.0.20348.0' - vc: '>=14.2,<15' - vc14_runtime: '>=14.29.30139' - url: https://repo.prefix.dev/conda-forge/win-64/liblzma-5.8.1-h2466b09_2.conda + vc: '>=14.3,<15' + vc14_runtime: '>=14.44.35208' + url: https://repo.prefix.dev/conda-forge/win-64/liblzma-5.8.2-hfd05255_0.conda hash: - md5: c15148b2e18da456f5108ccb5e411446 - sha256: 55764956eb9179b98de7cc0e55696f2eff8f7b83fc3ebff5e696ca358bca28cc + md5: ba0bfd4c3cf73f299ffe46ff0eaeb8e3 + sha256: f25bf293f550c8ed2e0c7145eb404324611cfccff37660869d97abf526eb957c category: main optional: false - name: libnghttp2 @@ -3692,21 +3692,21 @@ package: category: main optional: false - name: libpng - version: 1.6.53 + version: 1.6.54 manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' libgcc: '>=14' libzlib: '>=1.3.1,<2.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/libpng-1.6.53-h421ea60_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/libpng-1.6.54-h421ea60_0.conda hash: - md5: 00d4e66b1f746cb14944cad23fffb405 - sha256: 8acdeb9a7e3d2630176ba8e947caf6bf4985a5148dec69b801e5eb797856688b + md5: d361fa2a59e53b61c2675bfa073e5b7e + sha256: 5de60d34aac848a9991a09fcdea7c0e783d00024aefec279d55e87c0c44742cd category: main optional: false - name: libpng - version: 1.6.53 + version: 1.6.54 manager: conda platform: win-64 dependencies: @@ -3714,10 +3714,10 @@ package: ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/libpng-1.6.53-h7351971_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/libpng-1.6.54-h7351971_0.conda hash: - md5: fb6f43f6f08ca100cb24cff125ab0d9e - sha256: e5d061e7bdb2b97227b6955d1aa700a58a5703b5150ab0467cc37de609f277b6 + md5: 638ecb69e44b6a588afd5633e81f9e61 + sha256: 6e269361aa18a57bd2e593e480d83d93fc5f839d33d3bfc31b4ffe10edf6751c category: main optional: false - name: libscotch @@ -3793,31 +3793,31 @@ package: category: main optional: false - name: libsqlite - version: 3.51.1 + version: 3.51.2 manager: conda platform: linux-64 dependencies: __glibc: '>=2.17,<3.0.a0' libgcc: '>=14' libzlib: '>=1.3.1,<2.0a0' - url: https://repo.prefix.dev/conda-forge/linux-64/libsqlite-3.51.1-h0c1763c_1.conda + url: https://repo.prefix.dev/conda-forge/linux-64/libsqlite-3.51.2-h0c1763c_0.conda hash: - md5: ad1fd565aff83b543d726382c0ab0af2 - sha256: 5ef162b2a1390d1495a759734afe2312a358a58441cf8f378be651903646f3b7 + md5: f7d30045eccb83f2bb8053041f42db3c + sha256: c1ff4589b48d32ca0a2628970d869fa9f7b2c2d00269a3761edc7e9e4c1ab7b8 category: main optional: false - name: libsqlite - version: 3.51.1 + version: 3.51.2 manager: conda platform: win-64 dependencies: ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/libsqlite-3.51.1-hf5d6505_1.conda + url: https://repo.prefix.dev/conda-forge/win-64/libsqlite-3.51.2-hf5d6505_0.conda hash: - md5: be65be5f758709fc01b01626152e96b0 - sha256: d6d86715a1afe11f626b7509935e9d2e14a4946632c0ac474526e20fc6c55f99 + md5: 903979414b47d777d548e5f0165e6cd8 + sha256: 756478128e3e104bd7e7c3ce6c1b0efad7e08c7320c69fdc726e039323c63fbb category: main optional: false - name: libssh2 @@ -4797,39 +4797,39 @@ package: category: dev optional: true - name: notebook - version: 7.5.1 + version: 7.5.2 manager: conda platform: linux-64 dependencies: importlib_resources: '>=5.0' jupyter_server: '>=2.4.0,<3' - jupyterlab: '>=4.5.1,<4.6' + jupyterlab: '>=4.5.2,<4.6' jupyterlab_server: '>=2.28.0,<3' notebook-shim: '>=0.2,<0.3' python: '>=3.10' tornado: '>=6.2.0' - url: https://repo.prefix.dev/conda-forge/noarch/notebook-7.5.1-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/notebook-7.5.2-pyhcf101f3_0.conda hash: - md5: c984a8b773a34e38f5cf399b6d582e5c - sha256: 672ec7db73c8bfbacf9227c0c2287effdeded77b4d06373f2e498a310ce76a8c + md5: 47b58fa741a608dac785b71b8083bdb7 + sha256: 05bda90b7a980593c5e955dec5c556ff4dabf56e6ff45a3fb6c670f5f20b11e6 category: dev optional: true - name: notebook - version: 7.5.1 + version: 7.5.2 manager: conda platform: win-64 dependencies: importlib_resources: '>=5.0' jupyter_server: '>=2.4.0,<3' - jupyterlab: '>=4.5.1,<4.6' + jupyterlab: '>=4.5.2,<4.6' jupyterlab_server: '>=2.28.0,<3' notebook-shim: '>=0.2,<0.3' python: '>=3.10' tornado: '>=6.2.0' - url: https://repo.prefix.dev/conda-forge/noarch/notebook-7.5.1-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/notebook-7.5.2-pyhcf101f3_0.conda hash: - md5: c984a8b773a34e38f5cf399b6d582e5c - sha256: 672ec7db73c8bfbacf9227c0c2287effdeded77b4d06373f2e498a310ce76a8c + md5: 47b58fa741a608dac785b71b8083bdb7 + sha256: 05bda90b7a980593c5e955dec5c556ff4dabf56e6ff45a3fb6c670f5f20b11e6 category: dev optional: true - name: notebook-shim @@ -5324,27 +5324,27 @@ package: category: dev optional: true - name: prometheus_client - version: 0.23.1 + version: 0.24.1 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/prometheus_client-0.23.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/prometheus_client-0.24.1-pyhd8ed1ab_0.conda hash: - md5: a1e91db2d17fd258c64921cb38e6745a - sha256: 13dc67de68db151ff909f2c1d2486fa7e2d51355b25cee08d26ede1b62d48d40 + md5: 7526d20621b53440b0aae45d4797847e + sha256: 75b2589159d04b3fb92db16d9970b396b9124652c784ab05b66f584edc97f283 category: dev optional: true - name: prometheus_client - version: 0.23.1 + version: 0.24.1 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/prometheus_client-0.23.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/prometheus_client-0.24.1-pyhd8ed1ab_0.conda hash: - md5: a1e91db2d17fd258c64921cb38e6745a - sha256: 13dc67de68db151ff909f2c1d2486fa7e2d51355b25cee08d26ede1b62d48d40 + md5: 7526d20621b53440b0aae45d4797847e + sha256: 75b2589159d04b3fb92db16d9970b396b9124652c784ab05b66f584edc97f283 category: dev optional: true - name: prompt-toolkit @@ -5692,27 +5692,27 @@ package: category: main optional: false - name: pyparsing - version: 3.3.1 + version: 3.3.2 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/pyparsing-3.3.1-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda hash: - md5: d837065e4e0de4962c3462079c23f969 - sha256: 0c70bc577f5efa87501bdc841b88f594f4d3f3a992dfb851e2130fa5c817835b + md5: 3687cc0b82a8b4c17e1f0eb7e47163d5 + sha256: 417fba4783e528ee732afa82999300859b065dc59927344b4859c64aae7182de category: main optional: false - name: pyparsing - version: 3.3.1 + version: 3.3.2 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/pyparsing-3.3.1-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda hash: - md5: d837065e4e0de4962c3462079c23f969 - sha256: 0c70bc577f5efa87501bdc841b88f594f4d3f3a992dfb851e2130fa5c817835b + md5: 3687cc0b82a8b4c17e1f0eb7e47163d5 + sha256: 417fba4783e528ee732afa82999300859b065dc59927344b4859c64aae7182de category: main optional: false - name: pysocks @@ -6497,54 +6497,54 @@ package: category: main optional: false - name: send2trash - version: 2.0.0 + version: 2.1.0 manager: conda platform: linux-64 dependencies: __linux: '' python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/send2trash-2.0.0-pyha191276_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/send2trash-2.1.0-pyha191276_0.conda hash: - md5: f2cc28627a451a28ddd5ef5ab0bf579d - sha256: 27cd93b4f848a1c8193a7b1b8e6e6d03321462e96997ce95ea1a39305f7ac7cb + md5: 645026465469ecd4989188e1c4e24953 + sha256: b25d573874fe39cb8e4cf6ed0279acb9a94fedce5c5ae885da11566d595035ad category: dev optional: true - name: send2trash - version: 2.0.0 + version: 2.1.0 manager: conda platform: win-64 dependencies: __win: '' python: '>=3.10' pywin32: '' - url: https://repo.prefix.dev/conda-forge/noarch/send2trash-2.0.0-pyh6dadd2b_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/send2trash-2.1.0-pyh6dadd2b_0.conda hash: - md5: 40df72e963d80a403c1861ae9428b13c - sha256: f154f702baf550de9c1e3517f110bb71a056df5645027c8d15b37f3ea33722cc + md5: 69ba308f1356f39901f5654d82405df3 + sha256: b64e5cdb66f5d31fcef05b6ed95b8be3e80796528aa8a165428496c0dda3383f category: dev optional: true - name: setuptools - version: 80.9.0 + version: 80.10.1 manager: conda platform: linux-64 dependencies: - python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda + python: '>=3.10' + url: https://repo.prefix.dev/conda-forge/noarch/setuptools-80.10.1-pyh332efcf_0.conda hash: - md5: 4de79c071274a53dcaf2a8c749d1499e - sha256: 972560fcf9657058e3e1f97186cc94389144b46dbdf58c807ce62e83f977e863 + md5: cb72cedd94dd923c6a9405a3d3b1c018 + sha256: 89d5bb48047e7e27aa52a3a71d6ebf386e5ee4bdbd7ca91d653df9977eca8253 category: main optional: false - name: setuptools - version: 80.9.0 + version: 80.10.1 manager: conda platform: win-64 dependencies: - python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda + python: '>=3.10' + url: https://repo.prefix.dev/conda-forge/noarch/setuptools-80.10.1-pyh332efcf_0.conda hash: - md5: 4de79c071274a53dcaf2a8c749d1499e - sha256: 972560fcf9657058e3e1f97186cc94389144b46dbdf58c807ce62e83f977e863 + md5: cb72cedd94dd923c6a9405a3d3b1c018 + sha256: 89d5bb48047e7e27aa52a3a71d6ebf386e5ee4bdbd7ca91d653df9977eca8253 category: main optional: false - name: six @@ -6644,27 +6644,27 @@ package: category: main optional: false - name: soupsieve - version: 2.8.1 + version: 2.8.2 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/soupsieve-2.8.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/soupsieve-2.8.2-pyhd8ed1ab_0.conda hash: - md5: 7de28c27fe620a4f7dbfaea137c6232b - sha256: 4ba9b8c45862e54d05ed9a04cc6aab5a17756ab9865f57cbf2836e47144153d2 + md5: fcbe3971b6017792e9b24ff451daa7f5 + sha256: aacc87d88795ef887b89fe9401d1092312c43371d1ba92340d8924da1a982b6a category: dev optional: true - name: soupsieve - version: 2.8.1 + version: 2.8.2 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/soupsieve-2.8.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/soupsieve-2.8.2-pyhd8ed1ab_0.conda hash: - md5: 7de28c27fe620a4f7dbfaea137c6232b - sha256: 4ba9b8c45862e54d05ed9a04cc6aab5a17756ab9865f57cbf2836e47144153d2 + md5: fcbe3971b6017792e9b24ff451daa7f5 + sha256: aacc87d88795ef887b89fe9401d1092312c43371d1ba92340d8924da1a982b6a category: dev optional: true - name: sphinx @@ -7072,51 +7072,51 @@ package: category: main optional: false - name: tomli - version: 2.3.0 + version: 2.4.0 manager: conda platform: linux-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/tomli-2.3.0-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda hash: - md5: d2732eb636c264dc9aa4cbee404b1a53 - sha256: cb77c660b646c00a48ef942a9e1721ee46e90230c7c570cdeb5a893b5cce9bff + md5: 72e780e9aa2d0a3295f59b1874e3768b + sha256: 62940c563de45790ba0f076b9f2085a842a65662268b02dd136a8e9b1eaf47a8 category: dev optional: true - name: tomli - version: 2.3.0 + version: 2.4.0 manager: conda platform: win-64 dependencies: python: '>=3.10' - url: https://repo.prefix.dev/conda-forge/noarch/tomli-2.3.0-pyhcf101f3_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda hash: - md5: d2732eb636c264dc9aa4cbee404b1a53 - sha256: cb77c660b646c00a48ef942a9e1721ee46e90230c7c570cdeb5a893b5cce9bff + md5: 72e780e9aa2d0a3295f59b1874e3768b + sha256: 62940c563de45790ba0f076b9f2085a842a65662268b02dd136a8e9b1eaf47a8 category: dev optional: true - name: tomlkit - version: 0.13.3 + version: 0.14.0 manager: conda platform: linux-64 dependencies: - python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/tomlkit-0.13.3-pyha770c72_0.conda + python: '>=3.10' + url: https://repo.prefix.dev/conda-forge/noarch/tomlkit-0.14.0-pyha770c72_0.conda hash: - md5: 146402bf0f11cbeb8f781fa4309a95d3 - sha256: f8d3b49c084831a20923f66826f30ecfc55a4cd951e544b7213c692887343222 + md5: 385dca77a8b0ec6fa9b92cb62d09b43b + sha256: b35082091c8efd084e51bc3a4a2d3b07897eff232aaf58cbc0f959b6291a6a93 category: dev optional: true - name: tomlkit - version: 0.13.3 + version: 0.14.0 manager: conda platform: win-64 dependencies: - python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/tomlkit-0.13.3-pyha770c72_0.conda + python: '>=3.10' + url: https://repo.prefix.dev/conda-forge/noarch/tomlkit-0.14.0-pyha770c72_0.conda hash: - md5: 146402bf0f11cbeb8f781fa4309a95d3 - sha256: f8d3b49c084831a20923f66826f30ecfc55a4cd951e544b7213c692887343222 + md5: 385dca77a8b0ec6fa9b92cb62d09b43b + sha256: b35082091c8efd084e51bc3a4a2d3b07897eff232aaf58cbc0f959b6291a6a93 category: dev optional: true - name: toolz @@ -7676,7 +7676,7 @@ package: category: dev optional: true - name: wrapt - version: 1.17.3 + version: 2.0.1 manager: conda platform: linux-64 dependencies: @@ -7684,14 +7684,14 @@ package: libgcc: '>=14' python: '>=3.12,<3.13.0a0' python_abi: 3.12.* - url: https://repo.prefix.dev/conda-forge/linux-64/wrapt-1.17.3-py312h4c3975b_1.conda + url: https://repo.prefix.dev/conda-forge/linux-64/wrapt-2.0.1-py312h4c3975b_1.conda hash: - md5: 8af3faf88325836e46c6cb79828e058c - sha256: 8320d5af37eb8933e5d129884ea013b2687e75b08aff5216193df3378eaea92f + md5: b6ee834617873da8a2196c109275b38b + sha256: d1d352da699a642be0fd7a5cc894c37b1e8ddfda37c723cacfa9b1986824f80d category: main optional: false - name: wrapt - version: 1.17.3 + version: 2.0.1 manager: conda platform: win-64 dependencies: @@ -7700,10 +7700,10 @@ package: ucrt: '>=10.0.20348.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/wrapt-1.17.3-py312he06e257_1.conda + url: https://repo.prefix.dev/conda-forge/win-64/wrapt-2.0.1-py312he06e257_1.conda hash: - md5: fc10fd823d05bde83cda9e90dbef34ed - sha256: f9e9e28ef3a0564a5588427b9503ed08e5fe3624b8f8132d60383439a47baafc + md5: 3bc504b608413750156d62ce84255a87 + sha256: 212fbb75f6eaf19844feb5fb548c814665ae50aca8f7a15f39d387a63fb778dd category: main optional: false - name: xorg-libxau @@ -7966,43 +7966,43 @@ package: category: main optional: false - name: geoapps-utils - version: 0.7.0a2.dev1+3a0ee39 + version: 0.7.0a2.dev11+3f02228 manager: pip platform: linux-64 dependencies: - geoh5py: 0.13.0a2.dev34+872fd38e + geoh5py: 0.13.0a2.dev52+fda60c22 matplotlib: '>=3.8.4,<3.9.0' numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.12.0,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a hash: - sha256: 3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + sha256: 3f02228742b4837bd456438081d0a128fc3e1b3a source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a category: main optional: false - name: geoapps-utils - version: 0.7.0a2.dev1+3a0ee39 + version: 0.7.0a2.dev11+3f02228 manager: pip platform: win-64 dependencies: - geoh5py: 0.13.0a2.dev34+872fd38e + geoh5py: 0.13.0a2.dev52+fda60c22 matplotlib: '>=3.8.4,<3.9.0' numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.12.0,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a hash: - sha256: 3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + sha256: 3f02228742b4837bd456438081d0a128fc3e1b3a source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3a0ee39b295c1a1fad831a7f88a2e8630b99b2c6 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@3f02228742b4837bd456438081d0a128fc3e1b3a category: main optional: false - name: geoh5py - version: 0.13.0a2.dev34+872fd38e + version: 0.13.0a2.dev52+fda60c22 manager: pip platform: linux-64 dependencies: @@ -8010,16 +8010,16 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.12.0,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + url: git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc hash: - sha256: 872fd38e1f3a73fad567de7825e5e2bb0aadab72 + sha256: fda60c226dafdcdcb0bbe312be4c1622451479dc source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + url: git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc category: main optional: false - name: geoh5py - version: 0.13.0a2.dev34+872fd38e + version: 0.13.0a2.dev52+fda60c22 manager: pip platform: win-64 dependencies: @@ -8027,12 +8027,12 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.12.0,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + url: git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc hash: - sha256: 872fd38e1f3a73fad567de7825e5e2bb0aadab72 + sha256: fda60c226dafdcdcb0bbe312be4c1622451479dc source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@872fd38e1f3a73fad567de7825e5e2bb0aadab72 + url: git+https://github.com/MiraGeoscience/geoh5py.git@fda60c226dafdcdcb0bbe312be4c1622451479dc category: main optional: false - name: grid-apps @@ -8041,8 +8041,8 @@ package: platform: linux-64 dependencies: discretize: '>=0.11.0,<0.12.dev' - geoapps-utils: 0.7.0a2.dev1+3a0ee39 - geoh5py: 0.13.0a2.dev34+872fd38e + geoapps-utils: 0.7.0a2.dev11+3f02228 + geoh5py: 0.13.0a2.dev52+fda60c22 numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.12.0,<3.0.0' scipy: '>=1.14.0,<1.15.0' @@ -8060,8 +8060,8 @@ package: platform: win-64 dependencies: discretize: '>=0.11.0,<0.12.dev' - geoapps-utils: 0.7.0a2.dev1+3a0ee39 - geoh5py: 0.13.0a2.dev34+872fd38e + geoapps-utils: 0.7.0a2.dev11+3f02228 + geoh5py: 0.13.0a2.dev52+fda60c22 numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.12.0,<3.0.0' scipy: '>=1.14.0,<1.15.0' @@ -8074,7 +8074,7 @@ package: category: main optional: false - name: mira-simpeg - version: 0.23.0.3a1.dev105+g7d744e889 + version: 0.23.0.3a1.dev107+g1cf096ddf manager: pip platform: linux-64 dependencies: @@ -8087,16 +8087,16 @@ package: pymatsolver: '>=0.3' scipy: '>=1.8' typing-extensions: '*' - url: git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + url: git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae hash: - sha256: 7d744e889c77fa74ab5addcd26b7c709f395eb77 + sha256: 1cf096ddfe44da149fecbb53d6f6e97fae3c23ae source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + url: git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae category: main optional: false - name: mira-simpeg - version: 0.23.0.3a1.dev105+g7d744e889 + version: 0.23.0.3a1.dev107+g1cf096ddf manager: pip platform: win-64 dependencies: @@ -8109,11 +8109,11 @@ package: pymatsolver: '>=0.3' scipy: '>=1.8' typing-extensions: '*' - url: git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + url: git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae hash: - sha256: 7d744e889c77fa74ab5addcd26b7c709f395eb77 + sha256: 1cf096ddfe44da149fecbb53d6f6e97fae3c23ae source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@7d744e889c77fa74ab5addcd26b7c709f395eb77 + url: git+https://github.com/MiraGeoscience/simpeg.git@1cf096ddfe44da149fecbb53d6f6e97fae3c23ae category: main optional: false diff --git a/pyproject.toml b/pyproject.toml index 3dc5cbcc..87e4076e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,13 +94,13 @@ python-mumps = "0.0.3.*" ## Pip dependencies from Git repositories #---------------------------------------- #geoh5py = {version = ">=0.13.0a, 0.13.*", source = "pypi", allow-prereleases = true} -geoh5py = {git = "https://github.com/MiraGeoscience/geoh5py.git", rev = "GEOPY-2449"} +geoh5py = {git = "https://github.com/MiraGeoscience/geoh5py.git", rev = "develop"} #grid-apps = {version = ">=0.2.0a, 0.2.*", source = "pypi", allow-prereleases = true} grid-apps = {git = "https://github.com/MiraGeoscience/grid-apps.git", rev = "develop"} #geoapps-utils = {version = ">=0.7.0a, 0.7.*", source = "pypi", allow-prereleases = true} -geoapps-utils = {git = "https://github.com/MiraGeoscience/geoapps-utils.git", rev = "GEOPY-2449"} +geoapps-utils = {git = "https://github.com/MiraGeoscience/geoapps-utils.git", rev = "develop"} #mira-simpeg = {version = ">=0.23.0.3a, 0.23.0.*", source="pypi", allow-prereleases = true, extras = ["dask"]} mira-simpeg = {git = "https://github.com/MiraGeoscience/simpeg.git", rev = "develop", extras = ["dask"]} From 0b77fff1abcd25995dd8dee7af29157f9e56acf4 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Wed, 21 Jan 2026 13:26:40 -0800 Subject: [PATCH 16/24] Renames and docstrings --- simpeg_drivers/driver.py | 10 +++++----- .../plate_simulation/match/driver.py | 20 ++++++++++++++----- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index c156d919..358710f7 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -193,7 +193,7 @@ def validate_workers(self, workers: list[tuple[str]] | None) -> list[tuple[str]] @classmethod def start_dask_run( cls, - ifile, + json_path: Path, n_workers: int | None = None, n_threads: int | None = None, save_report: bool = True, @@ -201,7 +201,7 @@ def start_dask_run( """ Sets Dask config settings. - :param ifile: Input file path. + :param json_path: Path to input file (.ui.json) for the application. :param n_workers: Number of Dask workers. :param n_threads: Number of threads per Dask worker. :param save_report: Whether to save a performance report. @@ -229,18 +229,18 @@ def start_dask_run( ): # Full run with ( - performance_report(filename=ifile.parent / "dask_profile.html") + performance_report(filename=json_path.parent / "dask_profile.html") if (save_report and isinstance(context_client, Client)) else contextlib.nullcontext() ): - cls.start(ifile) + cls.start(json_path) sys.stdout.close() profiler.disable() if save_report: with open( - ifile.parent / "runtime_profile.txt", encoding="utf-8", mode="w" + json_path.parent / "runtime_profile.txt", encoding="utf-8", mode="w" ) as s: ps = pstats.Stats(profiler, stream=s) ps.sort_stats("cumulative") diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index ee7d78bd..6a0471e0 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -44,7 +44,7 @@ class PlateMatchDriver(BaseDriver): - """Sets up and manages workers to run all combinations of swepts parameters.""" + """Sets up and manages workers to run all combinations of swept parameters.""" _params_class = PlateMatchOptions @@ -218,9 +218,9 @@ def run(self): ) tasks.append( - self.client.submit(process_files_batch, *args) + self.client.submit(batch_files_score, *args) if self.client - else process_files_batch(*args) + else batch_files_score(*args) ) # Display progress bar @@ -312,9 +312,19 @@ def fetch_survey(workspace: Workspace) -> AirborneTEMReceivers | None: return None -def process_files_batch( +def batch_files_score( files: Path | list[Path], spatial_projection, time_projection, observed -): +) -> list[float]: + """ + Process a batch of simulation files and compute scores against observed data. + + :param files: Simulation file or list of simulation files to process. + :param spatial_projection: Spatial interpolation matrix. + :param time_projection: Time interpolation matrix. + :param observed: Observed data array. + + :return: List of scores for each simulation file. + """ scores = [] if isinstance(files, Path): From 16ff51ceaba84114089079628919e68c3268286a Mon Sep 17 00:00:00 2001 From: dominiquef Date: Wed, 21 Jan 2026 13:41:36 -0800 Subject: [PATCH 17/24] More renames --- simpeg_drivers/electromagnetics/base_1d_driver.py | 8 ++++---- simpeg_drivers/plate_simulation/match/driver.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/simpeg_drivers/electromagnetics/base_1d_driver.py b/simpeg_drivers/electromagnetics/base_1d_driver.py index c0c95771..f0bb4ae2 100644 --- a/simpeg_drivers/electromagnetics/base_1d_driver.py +++ b/simpeg_drivers/electromagnetics/base_1d_driver.py @@ -13,17 +13,17 @@ import multiprocessing from logging import getLogger +from pathlib import Path import numpy as np from discretize import TensorMesh from discretize.utils import mesh_utils from geoapps_utils.utils.locations import topo_drape_elevation from geoh5py import Workspace -from geoh5py.objects import FEMSurvey from geoh5py.shared.merging.drape_model import DrapeModelMerger from geoh5py.ui_json.ui_json import fetch_active_workspace -from simpeg_drivers.components.factories import MisfitFactory, SimulationFactory +from simpeg_drivers.components.factories import SimulationFactory from simpeg_drivers.components.meshes import InversionMesh from simpeg_drivers.driver import InversionDriver from simpeg_drivers.utils.utils import xyz_2_drape_model @@ -129,7 +129,7 @@ def workers(self): @classmethod def start_dask_run( cls, - ifile, + json_path: Path, n_workers: int | None = None, n_threads: int | None = None, save_report: bool = True, @@ -147,5 +147,5 @@ def start_dask_run( n_workers = cpu_count // n_threads super().start_dask_run( - ifile, n_workers=n_workers, n_threads=n_threads, save_report=save_report + json_path, n_workers=n_workers, n_threads=n_threads, save_report=save_report ) diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index 6a0471e0..db7f9ae5 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -263,7 +263,7 @@ def run(self): @classmethod def start_dask_run( cls, - ifile, + json_path: Path, n_workers: int | None = None, n_threads: int | None = None, save_report: bool = True, @@ -281,7 +281,7 @@ def start_dask_run( n_workers = cpu_count // n_threads super().start_dask_run( - ifile, n_workers=n_workers, n_threads=n_threads, save_report=save_report + json_path, n_workers=n_workers, n_threads=n_threads, save_report=save_report ) From aab595bfef6eb76164f368a12339770a0feba9e1 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Wed, 21 Jan 2026 13:44:50 -0800 Subject: [PATCH 18/24] Patch mvi test --- tests/run_tests/driver_mvi_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run_tests/driver_mvi_test.py b/tests/run_tests/driver_mvi_test.py index 8030f0e0..8e5504ed 100644 --- a/tests/run_tests/driver_mvi_test.py +++ b/tests/run_tests/driver_mvi_test.py @@ -45,7 +45,7 @@ # To test the full run and validate the inversion. # Move this file out of the test directory and run. -target_mvi_run = {"data_norm": 149.10117434016036, "phi_d": 1060, "phi_m": 0.0432} +target_mvi_run = {"data_norm": 149.10117434016036, "phi_d": 5.49, "phi_m": 0.0315} def test_magnetic_vector_fwr_run( From 9baf189e53d6fb5c229761cb6b68607d64809510 Mon Sep 17 00:00:00 2001 From: benjamink Date: Thu, 22 Jan 2026 11:28:12 -0800 Subject: [PATCH 19/24] restore entrypoint --- simpeg_drivers/plate_simulation/match/driver.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index 16c0cf37..e8ae2473 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -351,10 +351,7 @@ def process_files_batch( if __name__ == "__main__": - # file = Path(sys.argv[1]).resolve() - file = Path( - r"C:\Users\dominiquef\Documents\Workspace\Teck\RnD\plate_match_v2.ui.json" - ) + file = Path(sys.argv[1]).resolve() input_file = load_ui_json_as_dict(file) PlateMatchDriver.start_dask_run( file, From 15a84b542d978027d2339b430ed072970ddfdb9e Mon Sep 17 00:00:00 2001 From: dominiquef Date: Thu, 22 Jan 2026 14:15:06 -0800 Subject: [PATCH 20/24] Better checks on valid survey in template. Augment test --- .../plate_simulation/match/driver.py | 13 +++++-------- tests/plate_simulation/runtest/match_test.py | 19 ++++++++++++++++++- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index 0bd98247..eea6968b 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -26,9 +26,6 @@ from geoh5py import Workspace from geoh5py.groups import PropertyGroup, SimPEGGroup from geoh5py.objects import AirborneTEMReceivers, Surface -from geoh5py.shared.utils import ( - fetch_active_workspace, -) from geoh5py.ui_json import InputFile from scipy import signal from scipy.sparse import csr_matrix @@ -57,20 +54,20 @@ def __init__( self._template = self.get_template() self._time_mask, self._time_projection = self.time_mask_and_projection() - def get_template(self): + def get_template(self) -> AirborneTEMReceivers: """ Get a template simulation to extract time sampling. """ with Workspace(self.params.simulation_files[0], mode="r") as ws: survey = fetch_survey(ws) - if survey.channels is None: + if not isinstance(survey, AirborneTEMReceivers): raise GeoAppsError( - f"No time channels found in survey of {self.params.simulation_files[0]}" + f"No survey found under Plate Simulation of {self.params.simulation_files[0]}" ) - if survey.vertices is None: + if survey.channels is None: raise GeoAppsError( - f"No receiver locations found in survey of {self.params.simulation_files[0]}" + f"No time channels found in survey of {self.params.simulation_files[0]}" ) return survey diff --git a/tests/plate_simulation/runtest/match_test.py b/tests/plate_simulation/runtest/match_test.py index c2d116d2..731d1140 100644 --- a/tests/plate_simulation/runtest/match_test.py +++ b/tests/plate_simulation/runtest/match_test.py @@ -11,8 +11,10 @@ from pathlib import Path import numpy as np +import pytest +from geoapps_utils.utils.importing import GeoAppsError from geoh5py import Workspace -from geoh5py.groups import PropertyGroup +from geoh5py.groups import PropertyGroup, SimPEGGroup from geoh5py.objects import Points from geoh5py.ui_json import InputFile @@ -84,6 +86,21 @@ def test_file_parsing(tmp_path: Path): assert len(sim_files) == 1 assert sim_files[0].name == f"{__name__}.geoh5" + with pytest.raises(GeoAppsError, match="No survey found under Plate Simulation"): + PlateMatchDriver(options) + + # Copy the survey as if it was generated by the PlateSimulationDriver + with geoh5.open(): + sim_group = SimPEGGroup.create(geoh5, name="Plate Simulation") + survey = geoh5.get_entity("survey")[0] + new_survey = survey.copy(parent=sim_group) + metadata = survey.metadata + metadata["EM Dataset"].pop("Channels") + new_survey.metadata = metadata + + with pytest.raises(GeoAppsError, match="No time channels found in survey"): + PlateMatchDriver(options) + def test_matching_driver(tmp_path: Path): """ From 07fc6744d24344c15eca26bd413dce531af51040 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Thu, 22 Jan 2026 14:37:49 -0800 Subject: [PATCH 21/24] Re-assign computed list of dask tasks --- simpeg_drivers/plate_simulation/match/driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index eea6968b..028edbb6 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -223,7 +223,7 @@ def run(self): # Display progress bar if isinstance(tasks[0], Future): progress(tasks) - self.client.gather(tasks) + tasks = self.client.gather(tasks) scores = np.hstack(tasks) ranked = np.argsort(scores)[::-1] From 834bb6a144ed755fe14cf0b96129ce4fa882e626 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 23 Jan 2026 09:52:01 -0800 Subject: [PATCH 22/24] Store tiles on driver --- .../components/factories/misfit_factory.py | 43 +++++++++++-------- simpeg_drivers/driver.py | 41 ++++++++++++------ 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index 1db4db68..0900c504 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -16,7 +16,7 @@ from typing import TYPE_CHECKING import numpy as np -from dask.distributed import wait +from dask.distributed import Client, wait from simpeg import objective_function from simpeg.dask import objective_function as dask_objective_function from simpeg.objective_function import ComboObjectiveFunction @@ -30,17 +30,29 @@ class MisfitFactory(SimPEGFactory): - """Build SimPEG global misfit function.""" - - def __init__(self, params, client, simulation, workers): - """ - :param params: Options object containing SimPEG object parameters. - """ + """ + Build SimPEG global misfit function. + + :param params: Options object containing SimPEG object parameters. + :param simulation: SimPEG simulation object. + :param tiles: Dictionary of nested lists with arrays of indices for the tiles. + :param client: Dask client or boolean to indicate whether to use dask. + :param workers: List of worker addresses to use for dask computations. + """ + + def __init__( + self, + params, + simulation, + tiles: dict[list[np.ndarray]], + client: Client | bool, + workers: list[tuple[str]], + ): super().__init__(params) self.simpeg_object = self.concrete_object() - self.factory_type = self.params.inversion_type self.simulation = simulation + self.tiles = tiles self.client = client self.workers = workers @@ -48,14 +60,8 @@ def concrete_object(self): return objective_function.ComboObjectiveFunction def assemble_arguments( # pylint: disable=arguments-differ - self, tiles + self, ): - # Base slice over frequencies - if self.factory_type in ["magnetotellurics", "tipper", "fdem"]: - channels = self.simulation.survey.frequencies - else: - channels = [None] - use_futures = self.client # Pickle the simulation to the temporary file @@ -66,8 +72,9 @@ def assemble_arguments( # pylint: disable=arguments-differ misfits = [] tile_count = 0 - for channel in channels: + for channel, tiles in self.tiles.items(): for local_indices in tiles: + # Split again but use the same mesh extent based on tile vertices for sub_ind in local_indices: if len(sub_ind) == 0: continue @@ -117,10 +124,10 @@ def assemble_arguments( # pylint: disable=arguments-differ def assemble_keyword_arguments(self, **_): """Implementation of abstract method from SimPEGFactory.""" - def build(self, tiles, **_): + def build(self, **_): """To be over-ridden in factory implementations.""" - misfits = self.assemble_arguments(tiles) + misfits = self.assemble_arguments() if self.client: return dask_objective_function.DistributedComboMisfits( diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 358710f7..5a23dbb4 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -103,7 +103,7 @@ def __init__( "Disk storage of sensitivities is not compatible with distributed processing." ) - self._workers: list[tuple[str]] | None = self.validate_workers(workers) + self._workers: list[tuple[str]] = self.validate_workers(workers) @property def out_group(self) -> SimPEGGroup: @@ -142,7 +142,7 @@ def validate_out_group(self, out_group: SimPEGGroup | None) -> SimPEGGroup: return out_group @property - def client(self) -> Client | bool | None: + def client(self) -> Client | bool: """ Dask client or False if not using Dask.distributed. """ @@ -279,6 +279,7 @@ def __init__( self._ordering: list[np.ndarray] | None = None self._mappings: list[maps.IdentityMap] | None = None self._window = None + self.tiles: dict[list[np.ndarray]] def split_list(self, tiles: list[np.ndarray]) -> list[np.ndarray]: """ @@ -309,7 +310,9 @@ def split_list(self, tiles: list[np.ndarray]) -> list[np.ndarray]: flat_tile_list = [] for tile, split in zip(tiles, split_list): - flat_tile_list.append(np.array_split(tile, split)) + flat_tile_list.append( + sub for sub in np.array_split(tile, split) if len(sub) > 0 + ) return flat_tile_list @property @@ -318,16 +321,19 @@ def data_misfit(self): if getattr(self, "_data_misfit", None) is None: with fetch_active_workspace(self.workspace, mode="r+"): # Tile locations - tiles = self.get_tiles() - - if self.logger: - self.logger.write(f"Setting up {len(tiles)} tile(s) . . .\n") + if self.logger and self.params.compute.tile_spatial > 1: + self.logger.write( + f"Setting up {self.params.compute.tile_spatial} tiles . . .\n" + ) + self.tiles = self.get_tiles() self._data_misfit = MisfitFactory( - self.params, self.client, self.simulation, self.workers - ).build( - self.split_list(tiles), - ) + self.params, + self.simulation, + self.tiles, + client=self.client, + workers=self.workers, + ).build() return self._data_misfit @@ -776,13 +782,24 @@ def get_tiles(self): return np.array_split(indices, n_chunks) - return tile_locations( + tiles = tile_locations( self.inversion_data.locations, self.params.compute.tile_spatial, labels=self.inversion_data.parts, sorting=self.simulation.survey.sorting, ) + self.split_list(tiles) + + # Base slice over frequencies + if self.params.inversion_type in ["magnetotellurics", "tipper", "fdem"]: + channels = self.simulation.survey.frequencies + else: + channels = [None] + + # Duplicate tiles for each channel + return {channel: tiles for channel in channels} + @classmethod def start(cls, filepath: str | Path | InputFile, **kwargs) -> Self: """ From 339a18d456de94272c2e95bd77ad0dd4c4aa6631 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 23 Jan 2026 12:07:47 -0800 Subject: [PATCH 23/24] Revert "Store tiles on driver" This reverts commit 834bb6a144ed755fe14cf0b96129ce4fa882e626. Revert "Re-assign computed list of dask tasks" This reverts commit 07fc6744d24344c15eca26bd413dce531af51040. --- .../components/factories/misfit_factory.py | 43 ++++++++----------- simpeg_drivers/driver.py | 41 ++++++------------ .../plate_simulation/match/driver.py | 2 +- 3 files changed, 31 insertions(+), 55 deletions(-) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index 0900c504..1db4db68 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -16,7 +16,7 @@ from typing import TYPE_CHECKING import numpy as np -from dask.distributed import Client, wait +from dask.distributed import wait from simpeg import objective_function from simpeg.dask import objective_function as dask_objective_function from simpeg.objective_function import ComboObjectiveFunction @@ -30,29 +30,17 @@ class MisfitFactory(SimPEGFactory): - """ - Build SimPEG global misfit function. - - :param params: Options object containing SimPEG object parameters. - :param simulation: SimPEG simulation object. - :param tiles: Dictionary of nested lists with arrays of indices for the tiles. - :param client: Dask client or boolean to indicate whether to use dask. - :param workers: List of worker addresses to use for dask computations. - """ - - def __init__( - self, - params, - simulation, - tiles: dict[list[np.ndarray]], - client: Client | bool, - workers: list[tuple[str]], - ): + """Build SimPEG global misfit function.""" + + def __init__(self, params, client, simulation, workers): + """ + :param params: Options object containing SimPEG object parameters. + """ super().__init__(params) self.simpeg_object = self.concrete_object() + self.factory_type = self.params.inversion_type self.simulation = simulation - self.tiles = tiles self.client = client self.workers = workers @@ -60,8 +48,14 @@ def concrete_object(self): return objective_function.ComboObjectiveFunction def assemble_arguments( # pylint: disable=arguments-differ - self, + self, tiles ): + # Base slice over frequencies + if self.factory_type in ["magnetotellurics", "tipper", "fdem"]: + channels = self.simulation.survey.frequencies + else: + channels = [None] + use_futures = self.client # Pickle the simulation to the temporary file @@ -72,9 +66,8 @@ def assemble_arguments( # pylint: disable=arguments-differ misfits = [] tile_count = 0 - for channel, tiles in self.tiles.items(): + for channel in channels: for local_indices in tiles: - # Split again but use the same mesh extent based on tile vertices for sub_ind in local_indices: if len(sub_ind) == 0: continue @@ -124,10 +117,10 @@ def assemble_arguments( # pylint: disable=arguments-differ def assemble_keyword_arguments(self, **_): """Implementation of abstract method from SimPEGFactory.""" - def build(self, **_): + def build(self, tiles, **_): """To be over-ridden in factory implementations.""" - misfits = self.assemble_arguments() + misfits = self.assemble_arguments(tiles) if self.client: return dask_objective_function.DistributedComboMisfits( diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 5a23dbb4..358710f7 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -103,7 +103,7 @@ def __init__( "Disk storage of sensitivities is not compatible with distributed processing." ) - self._workers: list[tuple[str]] = self.validate_workers(workers) + self._workers: list[tuple[str]] | None = self.validate_workers(workers) @property def out_group(self) -> SimPEGGroup: @@ -142,7 +142,7 @@ def validate_out_group(self, out_group: SimPEGGroup | None) -> SimPEGGroup: return out_group @property - def client(self) -> Client | bool: + def client(self) -> Client | bool | None: """ Dask client or False if not using Dask.distributed. """ @@ -279,7 +279,6 @@ def __init__( self._ordering: list[np.ndarray] | None = None self._mappings: list[maps.IdentityMap] | None = None self._window = None - self.tiles: dict[list[np.ndarray]] def split_list(self, tiles: list[np.ndarray]) -> list[np.ndarray]: """ @@ -310,9 +309,7 @@ def split_list(self, tiles: list[np.ndarray]) -> list[np.ndarray]: flat_tile_list = [] for tile, split in zip(tiles, split_list): - flat_tile_list.append( - sub for sub in np.array_split(tile, split) if len(sub) > 0 - ) + flat_tile_list.append(np.array_split(tile, split)) return flat_tile_list @property @@ -321,19 +318,16 @@ def data_misfit(self): if getattr(self, "_data_misfit", None) is None: with fetch_active_workspace(self.workspace, mode="r+"): # Tile locations - if self.logger and self.params.compute.tile_spatial > 1: - self.logger.write( - f"Setting up {self.params.compute.tile_spatial} tiles . . .\n" - ) + tiles = self.get_tiles() + + if self.logger: + self.logger.write(f"Setting up {len(tiles)} tile(s) . . .\n") - self.tiles = self.get_tiles() self._data_misfit = MisfitFactory( - self.params, - self.simulation, - self.tiles, - client=self.client, - workers=self.workers, - ).build() + self.params, self.client, self.simulation, self.workers + ).build( + self.split_list(tiles), + ) return self._data_misfit @@ -782,24 +776,13 @@ def get_tiles(self): return np.array_split(indices, n_chunks) - tiles = tile_locations( + return tile_locations( self.inversion_data.locations, self.params.compute.tile_spatial, labels=self.inversion_data.parts, sorting=self.simulation.survey.sorting, ) - self.split_list(tiles) - - # Base slice over frequencies - if self.params.inversion_type in ["magnetotellurics", "tipper", "fdem"]: - channels = self.simulation.survey.frequencies - else: - channels = [None] - - # Duplicate tiles for each channel - return {channel: tiles for channel in channels} - @classmethod def start(cls, filepath: str | Path | InputFile, **kwargs) -> Self: """ diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index 028edbb6..eea6968b 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -223,7 +223,7 @@ def run(self): # Display progress bar if isinstance(tasks[0], Future): progress(tasks) - tasks = self.client.gather(tasks) + self.client.gather(tasks) scores = np.hstack(tasks) ranked = np.argsort(scores)[::-1] From 1bb0e2a0f35f286491e465a89abf1e7b2f20d7bc Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 23 Jan 2026 12:09:36 -0800 Subject: [PATCH 24/24] Remove logging of parameters --- simpeg_drivers/plate_simulation/match/driver.py | 1 - 1 file changed, 1 deletion(-) diff --git a/simpeg_drivers/plate_simulation/match/driver.py b/simpeg_drivers/plate_simulation/match/driver.py index eea6968b..8033f22e 100644 --- a/simpeg_drivers/plate_simulation/match/driver.py +++ b/simpeg_drivers/plate_simulation/match/driver.py @@ -252,7 +252,6 @@ def run(self): plate.vertices = plate.vertices + center plate.metadata = options.model.model_dump() - print(f"Best parameters:{options.model.model_dump_json(indent=2)}") results.append(self.params.simulation_files[ranked[0]].name) return results