From ef5e36a29865eed6d9494f83472a72ef122ba843 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 8 Aug 2025 12:24:47 -0700 Subject: [PATCH 01/56] Start implementing ProcessPoolExecutor for building sub-misfits. --- .../components/factories/misfit_factory.py | 220 +++++++++++------- 1 file changed, 131 insertions(+), 89 deletions(-) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index ae3d18f6..e9e9b289 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -11,6 +11,7 @@ from __future__ import annotations +from concurrent.futures import ProcessPoolExecutor, as_completed from typing import TYPE_CHECKING @@ -70,118 +71,159 @@ def assemble_arguments( # pylint: disable=arguments-differ channels = [None] local_misfits = [] - + futures = [] self.sorting = [] self.ordering = [] tile_count = 0 data_count = 0 misfit_count = 0 - for local_index in tiles: - if len(local_index) == 0: - continue - - local_sim, _, _, _ = self.create_nested_simulation( - inversion_data, - inversion_mesh, - None, - active_cells, - local_index, - channel=None, - tile_id=tile_count, - padding_cells=self.params.padding_cells, - ) - - local_mesh = getattr(local_sim, "mesh", None) - - for count, channel in enumerate(channels): + with ProcessPoolExecutor(): + for local_index in tiles: + if len(local_index) == 0: + continue + n_split = split_list[misfit_count] - for split_ind in np.array_split(local_index, n_split): - local_sim, split_ind, ordering, mapping = ( - self.create_nested_simulation( - inversion_data, - inversion_mesh, - local_mesh, - active_cells, - split_ind, - channel=channel, - tile_id=tile_count, - padding_cells=self.params.padding_cells, - ) + futures.append( + # executor.submit( + self.create_nested_misfit( + inversion_data.survey, + inversion_mesh.mesh, + active_cells, + local_index, + channels, + tile_count, + data_count, + n_split, + self.params.padding_cells, + self.params.inversion_type, + self.params.forward_only, + self.params.models.conductivity_model, ) + ) + misfit_count += len(channels) + data_count += len(local_index) + tile_count += n_split - if count == 0: - if self.factory_type in [ - "fdem", - "tdem", - "magnetotellurics", - "tipper", - ]: - self.sorting.append( - np.arange( - data_count, - data_count + len(split_ind), - dtype=int, - ) - ) - data_count += len(split_ind) - else: - self.sorting.append(split_ind) - - # TODO this should be done in the simulation factory - if "induced polarization" in self.params.inversion_type: - if "2d" in self.params.inversion_type: - proj = maps.InjectActiveCells( - inversion_mesh.mesh, active_cells, value_inactive=1e-8 - ) - else: - proj = maps.InjectActiveCells( - mapping.local_mesh, - mapping.local_active, - value_inactive=1e-8, - ) + for future in as_completed(futures): + local, ordering, sorting = future.result() + local_misfits.append(local) + self.ordering.append(ordering) + self.sorting.append(sorting) - local_sim.sigma = ( - proj * mapping * self.models.conductivity_model - ) + return local_misfits - simulation = meta.MetaSimulation( - simulations=[local_sim], mappings=[mapping] - ) + def assemble_keyword_arguments(self, **_): + """Implementation of abstract method from SimPEGFactory.""" + return {} - local_data = data.Data(local_sim.survey) + @classmethod + def create_nested_misfit( + cls, + inversion_data, + inversion_mesh, + active_cells, + local_index, + channels, + tile_count, + data_count, + n_split, + padding_cells, + inversion_type, + forward_only, + conductivity_model, + ): + local_sim, _, _, _ = cls.create_nested_simulation( + inversion_data, + inversion_mesh, + None, + active_cells, + local_index, + channel=None, + tile_id=tile_count, + padding_cells=padding_cells, + ) - if self.params.forward_only: - lmisfit = data_misfit.L2DataMisfit(local_data, simulation) + local_mesh = getattr(local_sim, "mesh", None) + sorting = [] + orderings = [] + local_misfits = [] + for count, channel in enumerate(channels): + for split_ind in np.array_split(local_index, n_split): + local_sim, split_ind, ordering, mapping = cls.create_nested_simulation( + inversion_data, + inversion_mesh, + local_mesh, + active_cells, + split_ind, + channel=channel, + tile_id=tile_count, + padding_cells=padding_cells, + ) + + if count == 0: + if cls.factory_type in [ + "fdem", + "tdem", + "magnetotellurics", + "tipper", + ]: + sorting.append( + np.arange( + data_count, + data_count + len(split_ind), + dtype=int, + ) + ) + data_count += len(split_ind) + else: + sorting.append(split_ind) + # TODO this should be done in the simulation factory + if "induced polarization" in inversion_type: + if "2d" in inversion_type: + proj = maps.InjectActiveCells( + inversion_mesh.mesh, active_cells, value_inactive=1e-8 + ) else: - local_data.dobs = local_sim.survey.dobs - local_data.standard_deviation = local_sim.survey.std - lmisfit = data_misfit.L2DataMisfit( - local_data, - simulation, + proj = maps.InjectActiveCells( + mapping.local_mesh, + mapping.local_active, + value_inactive=1e-8, ) - name = self.params.inversion_type + local_sim.sigma = proj * mapping * conductivity_model - if len(tiles) > 1 or n_split > 1: - name += f": Tile {tile_count + 1}" - if len(channels) > 1: - name += f": Channel {channel}" + simulation = meta.MetaSimulation( + simulations=[local_sim], mappings=[mapping] + ) - lmisfit.name = f"{name}" + local_data = data.Data(local_sim.survey) - local_misfits.append(lmisfit) - self.ordering.append(ordering) + if forward_only: + lmisfit = data_misfit.L2DataMisfit(local_data, simulation) - tile_count += 1 + else: + local_data.dobs = local_sim.survey.dobs + local_data.standard_deviation = local_sim.survey.std + lmisfit = data_misfit.L2DataMisfit( + local_data, + simulation, + ) - misfit_count += 1 + name = inversion_type - return [local_misfits] + name += f": Tile {tile_count + 1}" + if len(channels) > 1: + name += f": Channel {channel}" - def assemble_keyword_arguments(self, **_): - """Implementation of abstract method from SimPEGFactory.""" - return {} + lmisfit.name = f"{name}" + + local_misfits.append(lmisfit) + orderings.append(ordering) + + tile_count += 1 + + return local_misfits, sorting, orderings @staticmethod def create_nested_simulation( From 34594082bba62cc1cb0c300311f5913e2092af54 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 11 Aug 2025 07:41:55 -0700 Subject: [PATCH 02/56] Continue refactoring --- simpeg_drivers/components/data.py | 127 +--------- .../components/factories/misfit_factory.py | 218 ++++++++++-------- .../components/factories/receiver_factory.py | 2 +- .../factories/simulation_factory.py | 28 +-- .../components/factories/survey_factory.py | 87 +++---- simpeg_drivers/driver.py | 106 ++++++++- .../electromagnetics/base_1d_driver.py | 2 +- .../electromagnetics/time_domain/options.py | 18 ++ 8 files changed, 279 insertions(+), 309 deletions(-) diff --git a/simpeg_drivers/components/data.py b/simpeg_drivers/components/data.py index 588d125d..c19b3f92 100644 --- a/simpeg_drivers/components/data.py +++ b/simpeg_drivers/components/data.py @@ -16,20 +16,15 @@ from typing import TYPE_CHECKING, Any import numpy as np -from discretize import TensorMesh, TreeMesh from geoh5py.objects import PotentialElectrode from scipy.sparse import csgraph, csr_matrix from scipy.spatial import cKDTree -from simpeg import maps from simpeg.electromagnetics.static.utils.static_utils import geometric_factor -from simpeg.simulation import BaseSimulation -from simpeg_drivers.utils.utils import create_nested_mesh, drape_2_tensor +from simpeg_drivers.utils.utils import drape_2_tensor from .factories import ( EntityFactory, - SaveDataGeoh5Factory, - SimulationFactory, SurveyFactory, ) from .locations import InversionLocations @@ -54,8 +49,6 @@ class InversionData(InversionLocations): mask : Mask accumulated by windowing and downsampling operations and applied to locations and data on initialization. - n_blocks : - Number of blocks if vector. components : Component names. observed : @@ -83,7 +76,6 @@ def __init__(self, workspace: Workspace, params: InversionBaseOptions): super().__init__(workspace, params) self.locations: np.ndarray | None = None self.mask: np.ndarray | None = None - self.n_blocks: int | None = None self._observed: dict[str, np.ndarray] | None = None self._uncertainties: dict[str, np.ndarray] | None = None @@ -97,7 +89,6 @@ def __init__(self, workspace: Workspace, params: InversionBaseOptions): def _initialize(self) -> None: """Extract data from the workspace using params data.""" - self.n_blocks = 3 if self.params.inversion_type == "magnetic vector" else 1 self.components = self.params.active_components self.has_tensor = InversionData.check_tensor(self.params.components) @@ -333,126 +324,20 @@ def get_normalizations(self): return normalizations - def create_survey( - self, - local_index: np.ndarray | None = None, - channel=None, - ): + def create_survey(self): """ Generates SimPEG survey object. - :param: local_index (Optional): Indices of the data belonging to a - particular tile in case of a tiled inversion. - :return: survey: SimPEG Survey class that covers all data or optionally the portion of the data indexed by the local_index argument. - :return: local_index: receiver indices belonging to a particular tile. """ survey_factory = SurveyFactory(self.params) - survey, local_index, ordering = survey_factory.build( - data=self, - local_index=local_index, - channel=channel, - ) - + survey = survey_factory.build(data=self) if "direct current" in self.params.inversion_type: - survey.apparent_resistivity = 1 / ( - geometric_factor(survey)[np.argsort(np.hstack(local_index))] + 1e-10 - ) - - return survey, local_index, ordering - - def simulation( - self, - inversion_mesh: InversionMesh, - local_mesh: TreeMesh | TensorMesh | None, - active_cells: np.ndarray, - survey, - tile_id: int | None = None, - padding_cells: int = 6, - ) -> tuple[BaseSimulation, maps.IdentityMap]: - """ - Generates SimPEG simulation object. - - :param: mesh: inversion mesh. - :param: active_cells: Mask that reduces model to active (earth) cells. - :param: survey: SimPEG survey object. - :param: tile_id (Optional): Id associated with the tile covered by - the survey in case of a tiled inversion. - - :return: sim: SimPEG simulation object for full data or optionally - the portion of the data indexed by the local_index argument. - :return: map: If local_index and tile_id is provided, the returned - map will maps from local to global data. If no local_index or - tile_id is provided map will simply be an identity map with no - effect of the data. - """ - simulation_factory = SimulationFactory(self.params) - - if tile_id is None or "2d" in self.params.inversion_type: - mapping = maps.IdentityMap(nP=int(self.n_blocks * active_cells.sum())) - simulation = simulation_factory.build( - survey=survey, - global_mesh=inversion_mesh.mesh, - active_cells=active_cells, - mapping=mapping, - ) - elif "1d" in self.params.inversion_type: - slice_ind = np.arange( - tile_id, inversion_mesh.mesh.n_cells, inversion_mesh.mesh.shape_cells[0] - )[::-1] - mapping = maps.Projection(inversion_mesh.mesh.n_cells, slice_ind) - simulation = simulation_factory.build( - survey=survey, - receivers=self.entity, - global_mesh=inversion_mesh.mesh, - local_mesh=inversion_mesh.layers_mesh, - active_cells=active_cells, - mapping=mapping, - tile_id=tile_id, - ) - else: - if local_mesh is None: - local_mesh = create_nested_mesh( - survey, - inversion_mesh.mesh, - minimum_level=3, - padding_cells=padding_cells, - ) - mapping = maps.TileMap( - inversion_mesh.mesh, - active_cells, - local_mesh, - enforce_active=True, - components=self.n_blocks, - ) - simulation = simulation_factory.build( - survey=survey, - receivers=self.entity, - global_mesh=inversion_mesh.mesh, - local_mesh=local_mesh, - active_cells=mapping.local_active, - mapping=mapping, - tile_id=tile_id, - ) - - return simulation, mapping - - def simulate(self, model, inverse_problem, sorting, ordering): - """Simulate fields for a particular model.""" - dpred = inverse_problem.get_dpred( - model, compute_J=False if self.params.forward_only else True - ) - if self.params.forward_only: - save_directive = SaveDataGeoh5Factory(self.params).build( - inversion_object=self, - sorting=np.argsort(np.hstack(sorting)), - ordering=ordering, - ) - save_directive.write(0, dpred) + survey.apparent_resistivity = 1 / (geometric_factor(survey) + 1e-10) - inverse_problem.dpred = dpred + return survey @property def observed_data_types(self): @@ -495,7 +380,7 @@ def update_params(self, data_dict, uncert_dict): @property def survey(self): if self._survey is None: - self._survey, _, _ = self.create_survey() + self._survey = self.create_survey() return self._survey diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index e9e9b289..a8543b4b 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -14,6 +14,16 @@ from concurrent.futures import ProcessPoolExecutor, as_completed from typing import TYPE_CHECKING +import numpy as np +from discretize import TensorMesh, TreeMesh +from geoh5py.objects import Octree +from simpeg import data, data_misfit, maps, meta, objective_function +from simpeg.simulation import BaseSimulation + +from simpeg_drivers.components.factories.simpeg_factory import SimPEGFactory +from simpeg_drivers.components.factories.simulation_factory import SimulationFactory +from simpeg_drivers.utils.utils import create_nested_mesh + if TYPE_CHECKING: from geoapps_utils.driver.params import BaseParams @@ -22,93 +32,76 @@ from simpeg_drivers.components.meshes import InversionMesh from simpeg_drivers.options import BaseOptions -import numpy as np -from geoh5py.objects import Octree -from simpeg import data, data_misfit, maps, meta, objective_function - -from simpeg_drivers.components.factories.simpeg_factory import SimPEGFactory - class MisfitFactory(SimPEGFactory): """Build SimPEG global misfit function.""" - def __init__(self, params: BaseParams | BaseOptions, models=None): + def __init__(self, params: BaseParams | BaseOptions, simulation: BaseSimulation): """ :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.models = models + self.simulation = simulation self.sorting = None - self.ordering = None + self.n_blocks = 3 if self.params.inversion_type == "magnetic vector" else 1 def concrete_object(self): return objective_function.ComboObjectiveFunction - def build(self, tiles, split_list, inversion_data, inversion_mesh, active_cells): # pylint: disable=arguments-differ + def build(self, tiles, split_list): # pylint: disable=arguments-differ global_misfit = super().build( tiles=tiles, split_list=split_list, - inversion_data=inversion_data, - inversion_mesh=inversion_mesh, - active_cells=active_cells, ) - return global_misfit, self.sorting, self.ordering + return global_misfit, self.sorting def assemble_arguments( # pylint: disable=arguments-differ self, tiles, split_list, - inversion_data, - inversion_mesh, - active_cells, ): # Base slice over frequencies if self.factory_type in ["magnetotellurics", "tipper", "fdem"]: - channels = inversion_data.entity.channels + channels = self.simulation.survey.frequencies else: channels = [None] local_misfits = [] futures = [] self.sorting = [] - self.ordering = [] tile_count = 0 data_count = 0 misfit_count = 0 - with ProcessPoolExecutor(): - for local_index in tiles: - if len(local_index) == 0: - continue - - n_split = split_list[misfit_count] - futures.append( - # executor.submit( - self.create_nested_misfit( - inversion_data.survey, - inversion_mesh.mesh, - active_cells, - local_index, - channels, - tile_count, - data_count, - n_split, - self.params.padding_cells, - self.params.inversion_type, - self.params.forward_only, - self.params.models.conductivity_model, - ) + # with ProcessPoolExecutor() as executor: + for local_index in tiles: + if len(local_index) == 0: + continue + + n_split = split_list[misfit_count] + futures.append( + # executor.submit( + self.create_nested_misfit( + self.simulation, + local_index, + channels, + tile_count, + data_count, + n_split, + self.params.padding_cells, + self.params.inversion_type, + self.params.forward_only, ) - misfit_count += len(channels) - data_count += len(local_index) - tile_count += n_split + ) + misfit_count += len(channels) + data_count += len(local_index) + tile_count += n_split - for future in as_completed(futures): - local, ordering, sorting = future.result() - local_misfits.append(local) - self.ordering.append(ordering) - self.sorting.append(sorting) + for future in as_completed(futures): + local, sorting = future # future.result() + local_misfits.append(local) + self.sorting.append(sorting) return local_misfits @@ -119,9 +112,7 @@ def assemble_keyword_arguments(self, **_): @classmethod def create_nested_misfit( cls, - inversion_data, - inversion_mesh, - active_cells, + simulation, local_index, channels, tile_count, @@ -130,13 +121,10 @@ def create_nested_misfit( padding_cells, inversion_type, forward_only, - conductivity_model, ): - local_sim, _, _, _ = cls.create_nested_simulation( - inversion_data, - inversion_mesh, + local_sim, _ = cls.create_nested_simulation( + simulation, None, - active_cells, local_index, channel=None, tile_id=tile_count, @@ -145,15 +133,12 @@ def create_nested_misfit( local_mesh = getattr(local_sim, "mesh", None) sorting = [] - orderings = [] local_misfits = [] for count, channel in enumerate(channels): for split_ind in np.array_split(local_index, n_split): - local_sim, split_ind, ordering, mapping = cls.create_nested_simulation( - inversion_data, - inversion_mesh, + local_sim, mapping = cls.create_nested_simulation( + simulation, local_mesh, - active_cells, split_ind, channel=channel, tile_id=tile_count, @@ -179,19 +164,19 @@ def create_nested_misfit( sorting.append(split_ind) # TODO this should be done in the simulation factory - if "induced polarization" in inversion_type: - if "2d" in inversion_type: - proj = maps.InjectActiveCells( - inversion_mesh.mesh, active_cells, value_inactive=1e-8 - ) - else: - proj = maps.InjectActiveCells( - mapping.local_mesh, - mapping.local_active, - value_inactive=1e-8, - ) - - local_sim.sigma = proj * mapping * conductivity_model + # if "induced polarization" in inversion_type: + # if "2d" in inversion_type: + # proj = maps.InjectActiveCells( + # inversion_mesh.mesh, active_cells, value_inactive=1e-8 + # ) + # else: + # proj = maps.InjectActiveCells( + # mapping.local_mesh, + # mapping.local_active, + # value_inactive=1e-8, + # ) + # + # local_sim.sigma = proj * mapping * conductivity_model simulation = meta.MetaSimulation( simulations=[local_sim], mappings=[mapping] @@ -219,18 +204,15 @@ def create_nested_misfit( lmisfit.name = f"{name}" local_misfits.append(lmisfit) - orderings.append(ordering) tile_count += 1 - return local_misfits, sorting, orderings + return local_misfits, sorting @staticmethod def create_nested_simulation( - inversion_data: InversionData, - inversion_mesh: InversionMesh, - local_mesh: Octree | None, - active_cells: np.ndarray, + simulation, + local_mesh: TreeMesh | None, indices: np.ndarray, *, channel: int | None = None, @@ -248,25 +230,67 @@ def create_nested_simulation( :param tile_id: Tile id stored on the simulation. :param padding_cells: Number of padding cells around the local survey. """ - survey, indices, ordering = inversion_data.create_survey( - local_index=indices, channel=channel + survey = create_nested_survey( + simulation.survey, indices=indices, channel=channel ) - local_sim, mapping = inversion_data.simulation( - inversion_mesh, + + if local_mesh is None: + local_mesh = create_nested_mesh( + survey, + simulation.mesh, + minimum_level=3, + padding_cells=padding_cells, + ) + + mapping = maps.TileMap( + simulation.mesh, + simulation.active_cells, local_mesh, - active_cells, - survey, - tile_id=tile_id, - padding_cells=padding_cells, + enforce_active=True, + components=3 if getattr(simulation, "model_type", None) == "vector" else 1, + ) + + local_sim = type(simulation)( + local_mesh, + mapping=mapping.local_active, + survey=survey, ) - inv_type = inversion_data.params.inversion_type - if inv_type in ["fdem", "tdem"]: - compute_em_projections(inversion_data, local_sim) - elif ("current" in inv_type or "polarization" in inv_type) and ( - "2d" not in inv_type or "pseudo" in inv_type - ): - compute_dc_projections(inversion_data, local_sim, indices) - return local_sim, np.hstack(indices), ordering, mapping + + # TODO bring back + # inv_type = inversion_data.params.inversion_type + # if inv_type in ["fdem", "tdem"]: + # compute_em_projections(inversion_data, local_sim) + # elif ("current" in inv_type or "polarization" in inv_type) and ( + # "2d" not in inv_type or "pseudo" in inv_type + # ): + # compute_dc_projections(inversion_data, local_sim, indices) + return local_sim, mapping + + +def create_nested_survey(survey, indices, channel=None): + """ + Extract source and receivers belonging to the indices. + """ + sources = [] + for src in survey.source_list: + receivers = [] + for rx in src.receiver_list: + intersect = set(rx.local_index).intersection(indices) + if any(intersect): + new_rx = rx.copy() + new_rx.locations = (rx.locations[intersect],) + receivers.append(new_rx) + + if any(receivers): + new_src = src.copy() + new_src.receiver_list = receivers + sources.append(new_src) + + new_survey = type(survey)(sources) + new_survey.dobs = survey.dobs[indices] + new_survey.std = survey.std[indices] + + return new_survey def compute_em_projections(inversion_data, simulation): diff --git a/simpeg_drivers/components/factories/receiver_factory.py b/simpeg_drivers/components/factories/receiver_factory.py index 1649ad25..4a22d9a7 100644 --- a/simpeg_drivers/components/factories/receiver_factory.py +++ b/simpeg_drivers/components/factories/receiver_factory.py @@ -153,7 +153,7 @@ def build(self, locations=None, data=None, local_index=None, component=None): local_index=local_index, component=component, ) - + receivers.local_index = local_index if ( self.factory_type in ["tipper"] and getattr(self.params.data_object, "base_stations", None) is not None diff --git a/simpeg_drivers/components/factories/simulation_factory.py b/simpeg_drivers/components/factories/simulation_factory.py index d15e6559..139564aa 100644 --- a/simpeg_drivers/components/factories/simulation_factory.py +++ b/simpeg_drivers/components/factories/simulation_factory.py @@ -120,35 +120,22 @@ def concrete_object(self): def assemble_arguments( self, survey=None, - receivers=None, - global_mesh=None, - local_mesh=None, + mesh=None, active_cells=None, - mapping=None, - tile_id=None, ): if "1d" in self.factory_type: return () - mesh = global_mesh if tile_id is None else local_mesh return [mesh] def assemble_keyword_arguments( self, survey=None, - receivers=None, - global_mesh=None, - local_mesh=None, + mesh=None, active_cells=None, - mapping=None, - tile_id=None, ): - mesh = global_mesh if tile_id is None else local_mesh - sensitivity_path = self._get_sensitivity_path(tile_id) - kwargs = {} kwargs["survey"] = survey - kwargs["sensitivity_path"] = sensitivity_path kwargs["max_chunk_size"] = self.params.compute.max_chunk_size kwargs["store_sensitivities"] = ( "forward_only" @@ -193,16 +180,13 @@ def assemble_keyword_arguments( kwargs["sigmaMap"] = maps.ExpMap(mesh) * actmap if "tdem" in self.factory_type: - kwargs["t0"] = -receivers.timing_mark * self.params.unit_conversion - kwargs["time_steps"] = ( - np.round((np.diff(np.unique(receivers.waveform[:, 0]))), decimals=6) - * self.params.unit_conversion - ) + kwargs["t0"] = -self.params.timing_mark + kwargs["time_steps"] = self.params.time_steps if "1d" in self.factory_type: kwargs["sigmaMap"] = maps.ExpMap(mesh) - kwargs["thicknesses"] = local_mesh.h[0][1:][::-1] - kwargs["topo"] = active_cells[tile_id] + kwargs["thicknesses"] = mesh.h[0][1:][::-1] + # kwargs["topo"] = active_cells[tile_id] return kwargs diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index 5ba1b035..2ed908d7 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -75,33 +75,20 @@ def concrete_object(self): return survey.Survey - def assemble_arguments(self, data=None, local_index=None, channel=None): + def assemble_arguments(self, data=None): """Provides implementations to assemble arguments for receivers object.""" - receiver_entity = data.entity - - if local_index is None: - if "current" in self.factory_type or "polarization" in self.factory_type: - n_data = receiver_entity.n_cells - else: - n_data = receiver_entity.n_vertices - - self.local_index = np.arange(n_data) - else: - self.local_index = local_index - if "current" in self.factory_type or "polarization" in self.factory_type: - return self._dcip_arguments(data=data, local_index=local_index) + return self._dcip_arguments(data=data) elif "tdem" in self.factory_type: return self._tdem_arguments(data=data) elif self.factory_type in ["magnetotellurics", "tipper"]: - return self._naturalsource_arguments(data=data, frequency=channel) + return self._naturalsource_arguments(data=data) elif "fdem" in self.factory_type: - return self._fem_arguments(data=data, channel=channel) + return self._fem_arguments(data=data) else: receivers = ReceiversFactory(self.params).build( locations=data.locations, data=data.observed, - local_index=self.local_index, ) sources = SourcesFactory(self.params).build(receivers=receivers) return [sources] @@ -113,26 +100,21 @@ def assemble_keyword_arguments(self, **_): def build( self, data=None, - local_index=None, - indices=None, channel=None, ): """Overloads base method to add dobs, std attributes to survey class instance.""" - survey = super().build( data=data, - local_index=local_index, - channel=channel, ) if not self.params.forward_only: - self._add_data(survey, data, self.local_index, channel) + self._add_data(survey, data, channel) survey.dummy = self.dummy - return survey, self.local_index, self.ordering + return survey - def _get_local_data(self, data, channel, local_index): + def _get_local_data(self, data, channel): local_data = {} local_uncertainties = {} @@ -152,15 +134,12 @@ def _get_local_data(self, data, channel, local_index): }[comp] key = "_".join([str(channel), str(comp_name)]) - local_data[key] = data.observed[comp][channel][local_index] - local_uncertainties[key] = data.uncertainties[comp][channel][local_index] + local_data[key] = data.observed[comp][channel] + local_uncertainties[key] = data.uncertainties[comp][channel] return local_data, local_uncertainties - def _add_data(self, survey, data, local_index, channel): - if isinstance(local_index, list): - local_index = np.hstack(local_index) - + def _add_data(self, survey, data, channel): if self.factory_type in ["fdem", "fdem 1d", "tdem", "tdem 1d"]: dobs = [] uncerts = [] @@ -184,12 +163,12 @@ def _add_data(self, survey, data, local_index, channel): if channel is None: channels = np.unique([list(v.keys()) for v in data.observed.values()]) for chan in channels: - dat, unc = self._get_local_data(data, chan, local_index) + dat, unc = self._get_local_data(data, chan) local_data.update(dat) local_uncertainties.update(unc) else: - dat, unc = self._get_local_data(data, channel, local_index) + dat, unc = self._get_local_data(data, channel) local_data.update(dat) local_uncertainties.update(unc) @@ -197,10 +176,8 @@ def _add_data(self, survey, data, local_index, channel): uncertainty_vec = self._stack_channels(local_uncertainties, "row") else: - local_data = {k: v[local_index] for k, v in data.observed.items()} - local_uncertainties = { - k: v[local_index] for k, v in data.uncertainties.items() - } + local_data = data.observed + local_uncertainties = data.uncertainties data_vec = self._stack_channels(local_data, "column") uncertainty_vec = self._stack_channels(local_uncertainties, "column") @@ -232,16 +209,13 @@ def _stack_channels(self, channel_data: dict[str, np.ndarray], mode: str): elif mode == "row": return np.row_stack(list(channel_data.values())).ravel() - def _dcip_arguments(self, data=None, local_index=None): + def _dcip_arguments(self, data=None): if getattr(data, "entity", None) is None: return None receiver_entity = data.entity - if "2d" in self.factory_type: - self.local_index = np.arange(receiver_entity.n_cells) - source_ids, order = np.unique( - receiver_entity.ab_cell_id.values[self.local_index], return_index=True + receiver_entity.ab_cell_id.values, return_index=True ) currents = receiver_entity.current_electrodes @@ -252,17 +226,12 @@ def _dcip_arguments(self, data=None, local_index=None): receiver_locations = receiver_entity.vertices source_locations = currents.vertices - # TODO hook up tile_spatial to handle local_index handling sources = [] - self.local_index = [] for source_id in source_ids[np.argsort(order)]: # Cycle in original order receiver_indices = np.where(receiver_entity.ab_cell_id.values == source_id)[ 0 ] - if local_index is not None: - receiver_indices = list(set(receiver_indices).intersection(local_index)) - if len(receiver_indices) == 0: continue @@ -282,9 +251,7 @@ def _dcip_arguments(self, data=None, local_index=None): receivers=receivers, locations=source_locations[currents.cells[cell_ind].flatten()], ) - sources.append(source) - self.local_index.append(receiver_indices) return [sources] @@ -306,12 +273,12 @@ def _tdem_arguments(self, data=None): "Transmitter ID property required for LargeLoopGroundTEMReceivers" ) - tx_rx = receivers.tx_id_property.values[self.local_index] + tx_rx = receivers.tx_id_property.values tx_ids = transmitters.tx_id_property.values rx_lookup = [] tx_locs = [] for tx_id in np.unique(tx_rx): - rx_lookup.append(self.local_index[tx_rx == tx_id]) + rx_lookup.append(np.where(tx_rx == tx_id)[0]) tx_ind = tx_ids == tx_id loop_cells = transmitters.cells[ np.all(tx_ind[transmitters.cells], axis=1), : @@ -319,8 +286,10 @@ def _tdem_arguments(self, data=None): loop_ind = np.r_[loop_cells[:, 0], loop_cells[-1, 1]] tx_locs.append(transmitters.vertices[loop_ind, :]) else: - rx_lookup = self.local_index[:, np.newaxis].tolist() - tx_locs = [transmitters.vertices[k, :] for k in self.local_index] + rx_lookup = np.arange(receivers.n_vertices).tolist() + tx_locs = [ + transmitters.vertices[k, :] for k in receivers.tx_id_property.values + ] wave_times = ( receivers.waveform[:, 0] - receivers.timing_mark @@ -353,7 +322,6 @@ def _tdem_arguments(self, data=None): for component_id, component in enumerate(data.components): rx_obj = rx_factory.build( locations=locs, - local_index=self.local_index, data=data, component=component, ) @@ -385,11 +353,11 @@ def _fem_arguments(self, data=None, channel=None): receiver_groups = {} ordering = [] - for receiver_id in self.local_index: + for receiver_id, locs in enumerate(rx_locs): receivers = [] for component_id, component in enumerate(data.components): receiver = rx_factory.build( - locations=rx_locs[receiver_id, :], + locations=locs, data=data, component=component, ) @@ -432,14 +400,13 @@ def _naturalsource_arguments(self, data=None, frequency=None): receivers.append( rx_factory.build( locations=data.locations, - local_index=self.local_index, data=data, component=comp, ) ) - ordering.append( - np.c_[np.ones_like(self.local_index) * component_id, self.local_index] - ) + + n_locs = data.locations.shape[0] + ordering.append(np.c_[np.ones(n_locs) * component_id, np.arange(n_locs)]) ordering = np.vstack(ordering) self.ordering = [] diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index fc4dc8f5..68bdb95b 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -48,6 +48,7 @@ maps, objective_function, optimization, + simulation, ) from simpeg.regularization import ( @@ -65,7 +66,11 @@ InversionTopography, InversionWindow, ) -from simpeg_drivers.components.factories import DirectivesFactory, MisfitFactory +from simpeg_drivers.components.factories import ( + DirectivesFactory, + MisfitFactory, + SimulationFactory, +) from simpeg_drivers.options import ( BaseForwardOptions, BaseInversionOptions, @@ -100,6 +105,7 @@ def __init__(self, params: BaseForwardOptions | BaseInversionOptions): self._n_values: int | None = None self._optimization: optimization.ProjectedGNCG | None = None self._regularization: None = None + self._simulation: simulation.BaseSimulation | None = None self._sorting: list[np.ndarray] | None = None self._ordering: list[np.ndarray] | None = None self._mappings: list[maps.IdentityMap] | None = None @@ -163,14 +169,11 @@ def data_misfit(self): self.logger.write(f"Setting up {len(tiles)} tile(s) . . .\n") # Build tiled misfits and combine to form global misfit - self._data_misfit, self._sorting, self._ordering = MisfitFactory( - self.params, models=self.models + self._data_misfit, self._sorting = MisfitFactory( + self.params, self.simulation ).build( tiles, self.split_list, - self.inversion_data, - self.inversion_mesh, - self.models.active_cells, ) self.logger.write("Saving data to file...\n") @@ -315,7 +318,7 @@ def optimization(self): @property def ordering(self): """List of ordering of the data.""" - return self._ordering + return self.survey.ordering @property def out_group(self): @@ -378,6 +381,95 @@ def regularization(self, regularization: objective_function.ComboObjectiveFuncti ) self._regularization = regularization + @property + def simulation(self): + """ + The simulation object used in the inversion. + """ + if getattr(self, "_simulation", None) is None: + simulation_factory = SimulationFactory(self.params) + + self._simulation = simulation_factory.build( + survey=self.inversion_data.survey, + mesh=self.inversion_mesh.mesh, + active_cells=self.models.active_cells, + ) + return self._simulation + + # def simulation( + # self, + # inversion_mesh: TreeMesh, + # local_mesh: TreeMesh | TensorMesh | None, + # active_cells: np.ndarray, + # survey, + # tile_id: int | None = None, + # padding_cells: int = 6, + # ) -> tuple[simulation.BaseSimulation, maps.IdentityMap]: + # """ + # Generates SimPEG simulation object. + # + # :param: mesh: inversion mesh. + # :param: active_cells: Mask that reduces model to active (earth) cells. + # :param: survey: SimPEG survey object. + # :param: tile_id (Optional): Id associated with the tile covered by + # the survey in case of a tiled inversion. + # + # :return: sim: SimPEG simulation object for full data or optionally + # the portion of the data indexed by the local_index argument. + # :return: map: If local_index and tile_id is provided, the returned + # map will maps from local to global data. If no local_index or + # tile_id is provided map will simply be an identity map with no + # effect of the data. + # """ + # simulation_factory = SimulationFactory(self.params) + # + # if tile_id is None or "2d" in self.params.inversion_type: + # mapping = maps.IdentityMap(nP=int(self.n_blocks * active_cells.sum())) + # simulation = simulation_factory.build( + # survey=survey, + # global_mesh=inversion_mesh, + # active_cells=active_cells, + # mapping=mapping, + # ) + # elif "1d" in self.params.inversion_type: + # slice_ind = np.arange( + # tile_id, inversion_mesh.n_cells, inversion_mesh.shape_cells[0] + # )[::-1] + # mapping = maps.Projection(inversion_mesh.n_cells, slice_ind) + # simulation = simulation_factory.build( + # survey=survey, + # global_mesh=inversion_mesh, + # local_mesh=local_mesh, + # active_cells=active_cells, + # mapping=mapping, + # tile_id=tile_id, + # ) + # else: + # if local_mesh is None: + # local_mesh = create_nested_mesh( + # survey, + # inversion_mesh, + # minimum_level=3, + # padding_cells=padding_cells, + # ) + # mapping = maps.TileMap( + # inversion_mesh, + # active_cells, + # local_mesh, + # enforce_active=True, + # components=self.n_blocks, + # ) + # simulation = simulation_factory.build( + # survey=survey, + # receivers=self.entity, + # global_mesh=inversion_mesh, + # local_mesh=local_mesh, + # active_cells=mapping.local_active, + # mapping=mapping, + # tile_id=tile_id, + # ) + # + # return simulation, mapping @property def sorting(self): """List of arrays for sorting of data from tiles.""" diff --git a/simpeg_drivers/electromagnetics/base_1d_driver.py b/simpeg_drivers/electromagnetics/base_1d_driver.py index e5befd66..f1a82098 100644 --- a/simpeg_drivers/electromagnetics/base_1d_driver.py +++ b/simpeg_drivers/electromagnetics/base_1d_driver.py @@ -96,7 +96,7 @@ def data_misfit(self): logger.info("Setting up %i tile(s) . . .", len(tiles)) # Build tiled misfits and combine to form global misfit - self._data_misfit, self._sorting, self._ordering = MisfitFactory( + self._data_misfit, self._sorting = MisfitFactory( self.params, models=self.models ).build( tiles, diff --git a/simpeg_drivers/electromagnetics/time_domain/options.py b/simpeg_drivers/electromagnetics/time_domain/options.py index 9ff341b6..6ec47162 100644 --- a/simpeg_drivers/electromagnetics/time_domain/options.py +++ b/simpeg_drivers/electromagnetics/time_domain/options.py @@ -14,6 +14,7 @@ from pathlib import Path from typing import ClassVar, TypeAlias +import numpy as np from geoh5py.groups import PropertyGroup from geoh5py.objects import ( AirborneTEMReceivers, @@ -56,6 +57,23 @@ def unit_conversion(self): } return conversion[self.data_object.unit] + @property + def timing_mark(self): + """ + Return the "zero time" mark of the TDEM data in the appropriate units. + """ + return self.data_object.timing_mark * self.unit_conversion + + @property + def time_steps(self): + """ + Return the time steps of the TDEM data in the appropriate units. + """ + return ( + np.round((np.diff(np.unique(self.data_object.waveform[:, 0]))), decimals=6) + * self.unit_conversion + ) + class TDEMForwardOptions(BaseTDEMOptions, BaseForwardOptions): """ From d1dfdaabb5a431bed2aec82a6c0d7d3418f31bb1 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 11 Aug 2025 10:26:53 -0700 Subject: [PATCH 03/56] Fix for PF --- simpeg_drivers/components/factories/receiver_factory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simpeg_drivers/components/factories/receiver_factory.py b/simpeg_drivers/components/factories/receiver_factory.py index 4a22d9a7..8da23d72 100644 --- a/simpeg_drivers/components/factories/receiver_factory.py +++ b/simpeg_drivers/components/factories/receiver_factory.py @@ -118,7 +118,7 @@ def assemble_arguments( ) else: - args.append(locations[local_index]) + args.append(locations) return args From 212f0efddf4347a532e5c6738e51a94eb4efbad5 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 12 Aug 2025 11:06:47 -0700 Subject: [PATCH 04/56] Full run through gravity --- simpeg_drivers/components/data.py | 1 + .../components/factories/misfit_factory.py | 244 +++++++++++------- .../factories/simulation_factory.py | 15 +- .../components/factories/survey_factory.py | 65 +++-- simpeg_drivers/driver.py | 4 +- 5 files changed, 203 insertions(+), 126 deletions(-) diff --git a/simpeg_drivers/components/data.py b/simpeg_drivers/components/data.py index c19b3f92..c4a9c48a 100644 --- a/simpeg_drivers/components/data.py +++ b/simpeg_drivers/components/data.py @@ -334,6 +334,7 @@ def create_survey(self): survey_factory = SurveyFactory(self.params) survey = survey_factory.build(data=self) + survey.ordering = survey_factory.ordering if "direct current" in self.params.inversion_type: survey.apparent_resistivity = 1 / (geometric_factor(survey) + 1e-10) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index a8543b4b..04e40549 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -12,6 +12,7 @@ from __future__ import annotations from concurrent.futures import ProcessPoolExecutor, as_completed +from copy import copy from typing import TYPE_CHECKING import numpy as np @@ -68,9 +69,7 @@ def assemble_arguments( # pylint: disable=arguments-differ else: channels = [None] - local_misfits = [] futures = [] - self.sorting = [] tile_count = 0 data_count = 0 misfit_count = 0 @@ -87,7 +86,7 @@ def assemble_arguments( # pylint: disable=arguments-differ local_index, channels, tile_count, - data_count, + # data_count, n_split, self.params.padding_cells, self.params.inversion_type, @@ -98,12 +97,14 @@ def assemble_arguments( # pylint: disable=arguments-differ data_count += len(local_index) tile_count += n_split - for future in as_completed(futures): - local, sorting = future # future.result() - local_misfits.append(local) + local_misfits = [] + self.sorting = [] + for future in futures: # as_completed(futures): + functions, sorting = future # future.result() + local_misfits += functions self.sorting.append(sorting) - return local_misfits + return [local_misfits] def assemble_keyword_arguments(self, **_): """Implementation of abstract method from SimPEGFactory.""" @@ -116,13 +117,13 @@ def create_nested_misfit( local_index, channels, tile_count, - data_count, + # data_count, n_split, padding_cells, inversion_type, forward_only, ): - local_sim, _ = cls.create_nested_simulation( + local_sim, _ = create_nested_simulation( simulation, None, local_index, @@ -134,9 +135,9 @@ def create_nested_misfit( local_mesh = getattr(local_sim, "mesh", None) sorting = [] local_misfits = [] - for count, channel in enumerate(channels): + for channel in channels: for split_ind in np.array_split(local_index, n_split): - local_sim, mapping = cls.create_nested_simulation( + local_sim, mapping = create_nested_simulation( simulation, local_mesh, split_ind, @@ -145,38 +146,24 @@ def create_nested_misfit( padding_cells=padding_cells, ) - if count == 0: - if cls.factory_type in [ - "fdem", - "tdem", - "magnetotellurics", - "tipper", - ]: - sorting.append( - np.arange( - data_count, - data_count + len(split_ind), - dtype=int, - ) - ) - data_count += len(split_ind) - else: - sorting.append(split_ind) - - # TODO this should be done in the simulation factory - # if "induced polarization" in inversion_type: - # if "2d" in inversion_type: - # proj = maps.InjectActiveCells( - # inversion_mesh.mesh, active_cells, value_inactive=1e-8 + # Potentially remove if ordering works out + # if count == 0: + # if cls.factory_type in [ + # "fdem", + # "tdem", + # "magnetotellurics", + # "tipper", + # ]: + # sorting.append( + # np.arange( + # data_count, + # data_count + len(split_ind), + # dtype=int, + # ) # ) + # data_count += len(split_ind) # else: - # proj = maps.InjectActiveCells( - # mapping.local_mesh, - # mapping.local_active, - # value_inactive=1e-8, - # ) - # - # local_sim.sigma = proj * mapping * conductivity_model + sorting.append(split_ind) simulation = meta.MetaSimulation( simulations=[local_sim], mappings=[mapping] @@ -209,62 +196,106 @@ def create_nested_misfit( return local_misfits, sorting - @staticmethod - def create_nested_simulation( - simulation, - local_mesh: TreeMesh | None, - indices: np.ndarray, - *, - channel: int | None = None, - tile_id: int | None = None, - padding_cells=100, - ): - """ - Generate a survey, mesh and simulation based on indices. - - :param inversion_data: InversionData object. - :param mesh: Octree mesh. - :param active_cells: Active cell model. - :param indices: Indices of receivers belonging to the tile. - :param channel: Channel number for frequency or time channels. - :param tile_id: Tile id stored on the simulation. - :param padding_cells: Number of padding cells around the local survey. - """ - survey = create_nested_survey( - simulation.survey, indices=indices, channel=channel - ) - if local_mesh is None: - local_mesh = create_nested_mesh( - survey, - simulation.mesh, - minimum_level=3, - padding_cells=padding_cells, - ) +def create_nested_simulation( + simulation: BaseSimulation, + local_mesh: TreeMesh | None, + indices: np.ndarray, + *, + channel: int | None = None, + tile_id: int | None = None, + padding_cells=100, +): + """ + Generate a survey, mesh and simulation based on indices. + + :param inversion_data: InversionData object. + :param mesh: Octree mesh. + :param active_cells: Active cell model. + :param indices: Indices of receivers belonging to the tile. + :param channel: Channel number for frequency or time channels. + :param tile_id: Tile id stored on the simulation. + :param padding_cells: Number of padding cells around the local survey. + """ + local_survey = create_nested_survey( + simulation.survey, indices=indices, channel=channel + ) - mapping = maps.TileMap( + if local_mesh is None: + local_mesh = create_nested_mesh( + local_survey, simulation.mesh, - simulation.active_cells, - local_mesh, - enforce_active=True, - components=3 if getattr(simulation, "model_type", None) == "vector" else 1, + minimum_level=3, + padding_cells=padding_cells, ) - local_sim = type(simulation)( - local_mesh, - mapping=mapping.local_active, - survey=survey, + mapping = maps.TileMap( + simulation.mesh, + simulation.active_cells, + local_mesh, + enforce_active=True, + components=3 if getattr(simulation, "model_type", None) == "vector" else 1, + ) + + kwargs = {"survey": local_survey} + + n_actives = int(mapping.local_active.sum()) + if hasattr(simulation, "chiMap"): + if simulation.model_type == "vector": + kwargs["chiMap"] = maps.IdentityMap(nP=n_actives * 3) + kwargs["model_type"] = "vector" + else: + kwargs["chiMap"] = maps.IdentityMap(nP=n_actives) + + kwargs["active_cells"] = mapping.local_active + kwargs["sensitivity_path"] = ( + simulation.sensitivity_path.parent / f"Tile{tile_id}.zarr" ) - # TODO bring back - # inv_type = inversion_data.params.inversion_type - # if inv_type in ["fdem", "tdem"]: - # compute_em_projections(inversion_data, local_sim) - # elif ("current" in inv_type or "polarization" in inv_type) and ( - # "2d" not in inv_type or "pseudo" in inv_type - # ): - # compute_dc_projections(inversion_data, local_sim, indices) - return local_sim, mapping + if hasattr(simulation, "rhoMap"): + kwargs["rhoMap"] = maps.IdentityMap(nP=n_actives) + kwargs["active_cells"] = mapping.local_active + kwargs["sensitivity_path"] = ( + simulation.sensitivity_path.parent / f"Tile{tile_id}.zarr" + ) + + if hasattr(simulation, "sigmaMap"): + kwargs["sigmaMap"] = maps.ExpMap(local_mesh) * maps.InjectActiveCells( + local_mesh, mapping.local_active, value_inactive=np.log(1e-8) + ) + + if hasattr(simulation, "etaMap"): + kwargs["etaMap"] = maps.InjectActiveCells( + local_mesh, mapping.local_active, value_inactive=0 + ) + proj = maps.InjectActiveCells( + local_mesh, + mapping.local_active, + value_inactive=1e-8, + ) + kwargs["sigma"] = proj * mapping * simulation.sigma + + for key in [ + "max_chunk_sizestore_sensitivities", + "solver", + "t0", + "time_steps", + "thicknesses", + ]: + if hasattr(simulation, key): + kwargs[key] = getattr(simulation, key) + + local_sim = type(simulation)(local_mesh, **kwargs) + + # TODO bring back + # inv_type = inversion_data.params.inversion_type + # if inv_type in ["fdem", "tdem"]: + # compute_em_projections(inversion_data, local_sim) + # elif ("current" in inv_type or "polarization" in inv_type) and ( + # "2d" not in inv_type or "pseudo" in inv_type + # ): + # compute_dc_projections(inversion_data, local_sim, indices) + return local_sim, mapping def create_nested_survey(survey, indices, channel=None): @@ -272,23 +303,36 @@ def create_nested_survey(survey, indices, channel=None): Extract source and receivers belonging to the indices. """ sources = [] - for src in survey.source_list: + for src in survey.source_list or [survey.source_field]: + if channel is not None and getattr(src, "frequency", None) != channel: + continue + receivers = [] for rx in src.receiver_list: - intersect = set(rx.local_index).intersection(indices) - if any(intersect): - new_rx = rx.copy() - new_rx.locations = (rx.locations[intersect],) - receivers.append(new_rx) + # intersect = set(rx.local_index).intersection(indices) + new_rx = copy(rx) + new_rx.locations = rx.locations[indices] + receivers.append(new_rx) if any(receivers): - new_src = src.copy() + new_src = copy(src) new_src.receiver_list = receivers sources.append(new_src) - new_survey = type(survey)(sources) - new_survey.dobs = survey.dobs[indices] - new_survey.std = survey.std[indices] + if hasattr(survey, "source_field"): + new_survey = type(survey)(sources[0]) + else: + new_survey = type(survey)(sources) + + if hasattr(survey, "dobs") and survey.dobs is not None: + n_channels = len(getattr(survey, "frequencies", [None])) + n_comps = len(getattr(survey, "components", [None])) + new_survey.dobs = survey.dobs.reshape((n_channels, n_comps, -1), order="F")[ + :, :, indices + ].flatten(order="F") + new_survey.std = survey.std.reshape((n_channels, n_comps, -1), order="F")[ + :, :, indices + ].flatten(order="F") return new_survey diff --git a/simpeg_drivers/components/factories/simulation_factory.py b/simpeg_drivers/components/factories/simulation_factory.py index 139564aa..02e9e4b7 100644 --- a/simpeg_drivers/components/factories/simulation_factory.py +++ b/simpeg_drivers/components/factories/simulation_factory.py @@ -121,7 +121,7 @@ def assemble_arguments( self, survey=None, mesh=None, - active_cells=None, + models=None, ): if "1d" in self.factory_type: return () @@ -132,7 +132,7 @@ def assemble_keyword_arguments( self, survey=None, mesh=None, - active_cells=None, + models=None, ): kwargs = {} kwargs["survey"] = survey @@ -143,28 +143,31 @@ def assemble_keyword_arguments( else self.params.store_sensitivities ) kwargs["solver"] = self.solver - + active_cells = models.active_cells if self.factory_type == "magnetic vector": kwargs["active_cells"] = active_cells kwargs["chiMap"] = maps.IdentityMap(nP=int(active_cells.sum()) * 3) kwargs["model_type"] = "vector" - kwargs["chunk_format"] = "row" if self.factory_type == "magnetic scalar": kwargs["active_cells"] = active_cells kwargs["chiMap"] = maps.IdentityMap(nP=int(active_cells.sum())) - kwargs["chunk_format"] = "row" if self.factory_type == "gravity": kwargs["active_cells"] = active_cells kwargs["rhoMap"] = maps.IdentityMap(nP=int(active_cells.sum())) - kwargs["chunk_format"] = "row" if "induced polarization" in self.factory_type: etamap = maps.InjectActiveCells( mesh, active_cells=active_cells, value_inactive=0 ) kwargs["etaMap"] = etamap + kwargs["sigma"] = ( + maps.InjectActiveCells( + mesh, active_cells=active_cells, value_inactive=1e-8 + ) + * models.conductivity + ) if self.factory_type in [ "direct current 3d", diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index 2ed908d7..ff79c410 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -85,12 +85,20 @@ def assemble_arguments(self, data=None): return self._naturalsource_arguments(data=data) elif "fdem" in self.factory_type: return self._fem_arguments(data=data) - else: + else: # Gravity and Magnetic receivers = ReceiversFactory(self.params).build( locations=data.locations, data=data.observed, ) sources = SourcesFactory(self.params).build(receivers=receivers) + n_rx = data.locations.shape[0] + n_comp = len(data.components) + self.ordering = np.c_[ + np.ones(n_rx * n_comp), # Single channel + np.kron(np.ones(n_rx), np.arange(n_comp)), # Components + np.kron(np.arange(n_rx), np.ones(n_comp)), # Receivers + ].astype(int) + return [sources] def assemble_keyword_arguments(self, **_): @@ -227,6 +235,7 @@ def _dcip_arguments(self, data=None): source_locations = currents.vertices sources = [] + ordering = [] for source_id in source_ids[np.argsort(order)]: # Cycle in original order receiver_indices = np.where(receiver_entity.ab_cell_id.values == source_id)[ 0 @@ -235,6 +244,7 @@ def _dcip_arguments(self, data=None): if len(receiver_indices) == 0: continue + ordering.append(receiver_indices) receivers = ReceiversFactory(self.params).build( locations=receiver_locations, local_index=receiver_entity.cells[receiver_indices], @@ -253,6 +263,12 @@ def _dcip_arguments(self, data=None): ) sources.append(source) + self.ordering = np.c_[ + np.ones(receiver_entity.n_cells), # Single channel + np.ones(receiver_entity.n_cells), # Single component + np.hstack(ordering), # Multi-receivers + ].astype(int) + return [sources] def _tdem_arguments(self, data=None): @@ -311,7 +327,7 @@ def _tdem_arguments(self, data=None): waveform_function=wave_function, offTime=0.0 ) - self.ordering = [] + ordering = [] tx_list = [] rx_factory = ReceiversFactory(self.params) tx_factory = SourcesFactory(self.params) @@ -330,12 +346,13 @@ def _tdem_arguments(self, data=None): for time_id in range(len(receivers.channels)): for rx_id in rx_ids: - self.ordering.append([time_id, component_id, rx_id]) + ordering.append([time_id, component_id, rx_id]) tx_list.append( tx_factory.build(rx_list, locations=cur_tx_locs, waveform=waveform) ) + self.ordering = np.vstack(ordering).astype(int) return [tx_list] def _fem_arguments(self, data=None, channel=None): @@ -346,13 +363,12 @@ def _fem_arguments(self, data=None, channel=None): freqs = data.entity.transmitters.workspace.get_entity("Tx frequency")[0] freqs = np.array([int(freqs.value_map[f]) for f in freqs.values]) - self.ordering = [] sources = [] rx_factory = ReceiversFactory(self.params) tx_factory = SourcesFactory(self.params) receiver_groups = {} - ordering = [] + block_ordering = [] for receiver_id, locs in enumerate(rx_locs): receivers = [] for component_id, component in enumerate(data.components): @@ -364,15 +380,21 @@ def _fem_arguments(self, data=None, channel=None): receiver.local_index = receiver_id receivers.append(receiver) - ordering.append([component_id, receiver_id]) + block_ordering.append([component_id, receiver_id]) receiver_groups[receiver_id] = receivers - ordering = np.vstack(ordering) - self.ordering = [] + block_ordering = np.vstack(block_ordering) + + ordering = [] for frequency in frequencies: frequency_id = np.where(frequency == channels)[0][0] - self.ordering.append( - np.hstack([np.ones((ordering.shape[0], 1)) * frequency_id, ordering]) + ordering.append( + np.hstack( + [ + np.ones((block_ordering.shape[0], 1)) * frequency_id, + block_ordering, + ] + ) ) for receiver_id, receivers in receiver_groups.items(): @@ -385,7 +407,7 @@ def _fem_arguments(self, data=None, channel=None): ) ) - self.ordering = np.vstack(self.ordering).astype(int) + self.ordering = np.vstack(ordering).astype(int) return [sources] @@ -394,7 +416,7 @@ def _naturalsource_arguments(self, data=None, frequency=None): sources = [] rx_factory = ReceiversFactory(self.params) tx_factory = SourcesFactory(self.params) - ordering = [] + block_ordering = [] channels = np.array(data.entity.channels) for component_id, comp in enumerate(data.components): receivers.append( @@ -406,10 +428,12 @@ def _naturalsource_arguments(self, data=None, frequency=None): ) n_locs = data.locations.shape[0] - ordering.append(np.c_[np.ones(n_locs) * component_id, np.arange(n_locs)]) + block_ordering.append( + np.c_[np.ones(n_locs) * component_id, np.arange(n_locs)] + ) - ordering = np.vstack(ordering) - self.ordering = [] + block_ordering = np.vstack(block_ordering) + ordering = [] if frequency is None: frequencies = channels else: @@ -418,10 +442,15 @@ def _naturalsource_arguments(self, data=None, frequency=None): for frequency in frequencies: sources.append(tx_factory.build(receivers, frequency=frequency)) frequency_id = np.where(frequency == channels)[0][0] - self.ordering.append( - np.hstack([np.ones((ordering.shape[0], 1)) * frequency_id, ordering]) + ordering.append( + np.hstack( + [ + np.ones((block_ordering.shape[0], 1)) * frequency_id, + block_ordering, + ] + ) ) - self.ordering = np.vstack(self.ordering).astype(int) + self.ordering = np.vstack(ordering).astype(int) return [sources] diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 68bdb95b..b915b510 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -318,7 +318,7 @@ def optimization(self): @property def ordering(self): """List of ordering of the data.""" - return self.survey.ordering + return self.inversion_data.survey.ordering @property def out_group(self): @@ -392,7 +392,7 @@ def simulation(self): self._simulation = simulation_factory.build( survey=self.inversion_data.survey, mesh=self.inversion_mesh.mesh, - active_cells=self.models.active_cells, + models=self.models, ) return self._simulation From 301d19999c75df0689366b9e212e69bc4dcc6113 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 12 Aug 2025 12:42:04 -0700 Subject: [PATCH 05/56] Run-through ATEM --- .../components/factories/misfit_factory.py | 39 +++++++++++++------ .../components/factories/survey_factory.py | 21 +++++++--- simpeg_drivers/driver.py | 2 + 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index 04e40549..a9fdc0d6 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -240,7 +240,7 @@ def create_nested_simulation( kwargs = {"survey": local_survey} n_actives = int(mapping.local_active.sum()) - if hasattr(simulation, "chiMap"): + if getattr(simulation, "_chiMap", None) is not None: if simulation.model_type == "vector": kwargs["chiMap"] = maps.IdentityMap(nP=n_actives * 3) kwargs["model_type"] = "vector" @@ -252,19 +252,19 @@ def create_nested_simulation( simulation.sensitivity_path.parent / f"Tile{tile_id}.zarr" ) - if hasattr(simulation, "rhoMap"): + if getattr(simulation, "_rhoMap", None) is not None: kwargs["rhoMap"] = maps.IdentityMap(nP=n_actives) kwargs["active_cells"] = mapping.local_active kwargs["sensitivity_path"] = ( simulation.sensitivity_path.parent / f"Tile{tile_id}.zarr" ) - if hasattr(simulation, "sigmaMap"): + if getattr(simulation, "_sigmaMap", None) is not None: kwargs["sigmaMap"] = maps.ExpMap(local_mesh) * maps.InjectActiveCells( local_mesh, mapping.local_active, value_inactive=np.log(1e-8) ) - if hasattr(simulation, "etaMap"): + if getattr(simulation, "_etaMap", None) is not None: kwargs["etaMap"] = maps.InjectActiveCells( local_mesh, mapping.local_active, value_inactive=0 ) @@ -303,15 +303,23 @@ def create_nested_survey(survey, indices, channel=None): Extract source and receivers belonging to the indices. """ sources = [] + location_count = 0 for src in survey.source_list or [survey.source_field]: if channel is not None and getattr(src, "frequency", None) != channel: continue + rx_indices = np.arange(src.receiver_list[0].locations.shape[0]) + location_count + _, intersect, _ = np.intersect1d(rx_indices, indices, return_indices=True) + + if len(intersect) == 0: + continue + + location_count += len(intersect) receivers = [] for rx in src.receiver_list: # intersect = set(rx.local_index).intersection(indices) new_rx = copy(rx) - new_rx.locations = rx.locations[indices] + new_rx.locations = rx.locations[intersect] receivers.append(new_rx) if any(receivers): @@ -325,14 +333,23 @@ def create_nested_survey(survey, indices, channel=None): new_survey = type(survey)(sources) if hasattr(survey, "dobs") and survey.dobs is not None: - n_channels = len(getattr(survey, "frequencies", [None])) - n_comps = len(getattr(survey, "components", [None])) - new_survey.dobs = survey.dobs.reshape((n_channels, n_comps, -1), order="F")[ + n_channels = len(np.unique(survey.ordering[:, 0])) + n_comps = len(np.unique(survey.ordering[:, 1])) + + data_slice = survey.dobs.reshape((n_channels, n_comps, -1), order="F")[ :, :, indices - ].flatten(order="F") - new_survey.std = survey.std.reshape((n_channels, n_comps, -1), order="F")[ + ] + uncert_slice = survey.std.reshape((n_channels, n_comps, -1), order="F")[ :, :, indices - ].flatten(order="F") + ] + + if channel is not None: + ind = np.where(survey.frequencies == channel)[0] + data_slice = data_slice[ind, :, :] + uncert_slice = uncert_slice[ind, :, :] + + new_survey.dobs = data_slice.flatten(order="F") + new_survey.std = uncert_slice.flatten(order="F") return new_survey diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index ff79c410..70573796 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -13,6 +13,7 @@ from __future__ import annotations +from gc import is_finalized from typing import TYPE_CHECKING @@ -302,10 +303,9 @@ def _tdem_arguments(self, data=None): loop_ind = np.r_[loop_cells[:, 0], loop_cells[-1, 1]] tx_locs.append(transmitters.vertices[loop_ind, :]) else: + # Assumes 1:1 mapping of tx to rx rx_lookup = np.arange(receivers.n_vertices).tolist() - tx_locs = [ - transmitters.vertices[k, :] for k in receivers.tx_id_property.values - ] + tx_locs = transmitters.vertices wave_times = ( receivers.waveform[:, 0] - receivers.timing_mark @@ -344,9 +344,18 @@ def _tdem_arguments(self, data=None): rx_obj.local_index = rx_ids rx_list.append(rx_obj) - for time_id in range(len(receivers.channels)): - for rx_id in rx_ids: - ordering.append([time_id, component_id, rx_id]) + n_times = len(receivers.channels) + n_rx = len(rx_ids) if isinstance(rx_ids, list) else 1 + ordering.append( + np.c_[ + np.kron(np.arange(n_times), np.ones(n_rx)), + np.ones(n_times * n_rx) * component_id, + np.kron(np.ones(n_times), np.asarray(rx_ids)), + ] + ) + # for time_id in range(len(receivers.channels)): + # for rx_id in rx_ids: + # ordering.append([time_id, component_id, rx_id]) tx_list.append( tx_factory.build(rx_list, locations=cur_tx_locs, waveform=waveform) diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index b915b510..038f7f34 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -394,6 +394,8 @@ def simulation(self): mesh=self.inversion_mesh.mesh, models=self.models, ) + self._simulation.active_cells = self.models.active_cells + return self._simulation # def simulation( From a01aedb04d6cc6734faab2ce9a3202a744c91352 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 12 Aug 2025 14:20:34 -0700 Subject: [PATCH 06/56] MT almost through --- .../components/factories/misfit_factory.py | 59 ++++++++----------- .../components/factories/receiver_factory.py | 7 +-- 2 files changed, 25 insertions(+), 41 deletions(-) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index a9fdc0d6..a81b5211 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -135,7 +135,7 @@ def create_nested_misfit( local_mesh = getattr(local_sim, "mesh", None) sorting = [] local_misfits = [] - for channel in channels: + for count, channel in enumerate(channels): for split_ind in np.array_split(local_index, n_split): local_sim, mapping = create_nested_simulation( simulation, @@ -146,44 +146,19 @@ def create_nested_misfit( padding_cells=padding_cells, ) - # Potentially remove if ordering works out - # if count == 0: - # if cls.factory_type in [ - # "fdem", - # "tdem", - # "magnetotellurics", - # "tipper", - # ]: - # sorting.append( - # np.arange( - # data_count, - # data_count + len(split_ind), - # dtype=int, - # ) - # ) - # data_count += len(split_ind) - # else: - sorting.append(split_ind) - - simulation = meta.MetaSimulation( + if count == 0: + sorting.append(split_ind) + + meta_simulation = meta.MetaSimulation( simulations=[local_sim], mappings=[mapping] ) local_data = data.Data(local_sim.survey) - - if forward_only: - lmisfit = data_misfit.L2DataMisfit(local_data, simulation) - - else: + lmisfit = data_misfit.L2DataMisfit(local_data, meta_simulation) + if not forward_only: local_data.dobs = local_sim.survey.dobs local_data.standard_deviation = local_sim.survey.std - lmisfit = data_misfit.L2DataMisfit( - local_data, - simulation, - ) - name = inversion_type - name += f": Tile {tile_count + 1}" if len(channels) > 1: name += f": Channel {channel}" @@ -308,7 +283,15 @@ def create_nested_survey(survey, indices, channel=None): if channel is not None and getattr(src, "frequency", None) != channel: continue - rx_indices = np.arange(src.receiver_list[0].locations.shape[0]) + location_count + # Extract the indices of the receivers that belong to this source + locations = src.receiver_list[0].locations + if isinstance(locations, tuple): # For MT survey + n_verts = locations[0].shape[0] + else: + n_verts = locations.shape[0] + + rx_indices = np.arange(n_verts) + location_count + _, intersect, _ = np.intersect1d(rx_indices, indices, return_indices=True) if len(intersect) == 0: @@ -319,7 +302,12 @@ def create_nested_survey(survey, indices, channel=None): for rx in src.receiver_list: # intersect = set(rx.local_index).intersection(indices) new_rx = copy(rx) - new_rx.locations = rx.locations[intersect] + + if isinstance(rx.locations, tuple): # For MT survey + new_rx.locations = tuple(loc[intersect] for loc in rx.locations) + else: + new_rx.locations = rx.locations[intersect] + receivers.append(new_rx) if any(receivers): @@ -343,8 +331,9 @@ def create_nested_survey(survey, indices, channel=None): :, :, indices ] + # For FEM surveys only if channel is not None: - ind = np.where(survey.frequencies == channel)[0] + ind = np.where(np.asarray(survey.frequencies) == channel)[0] data_slice = data_slice[ind, :, :] uncert_slice = uncert_slice[ind, :, :] diff --git a/simpeg_drivers/components/factories/receiver_factory.py b/simpeg_drivers/components/factories/receiver_factory.py index 8da23d72..97c17b18 100644 --- a/simpeg_drivers/components/factories/receiver_factory.py +++ b/simpeg_drivers/components/factories/receiver_factory.py @@ -193,9 +193,4 @@ def _tdem_arguments(self, data=None, locations=None, local_index=None): ] def _magnetotellurics_arguments(self, locations=None, local_index=None): - args = [] - locs = locations[local_index] - - args.append(locs) - - return args + return [locations] From 34fc52cba7fe77d79294bd58828a5a9da4c11cb7 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Wed, 13 Aug 2025 10:46:09 -0700 Subject: [PATCH 07/56] Combine EM and MT data parsing without looping --- .../components/factories/survey_factory.py | 87 ++++++++++++------- simpeg_drivers/options.py | 16 +--- 2 files changed, 58 insertions(+), 45 deletions(-) diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index 70573796..cfb726cc 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -149,40 +149,50 @@ def _get_local_data(self, data, channel): return local_data, local_uncertainties def _add_data(self, survey, data, channel): - if self.factory_type in ["fdem", "fdem 1d", "tdem", "tdem 1d"]: - dobs = [] - uncerts = [] - - data_stack = [np.vstack(list(k.values())) for k in data.observed.values()] - uncert_stack = [ - np.vstack(list(k.values())) for k in data.uncertainties.values() + if self.factory_type in [ + "fdem", + "fdem 1d", + "tdem", + "tdem 1d", + "magnetotellurics", + "tipper", + ]: + data_stack = np.dstack( + [np.vstack(list(k.values())) for k in data.observed.values()] + ).transpose((0, 2, 1)) + uncert_stack = np.dstack( + [np.vstack(list(k.values())) for k in data.uncertainties.values()] + ).transpose((0, 2, 1)) + # for order in self.ordering: + # channel_id, component_id, rx_id = order + # dobs.append(data_stack[component_id][channel_id, rx_id]) + # uncerts.append(uncert_stack[component_id][channel_id, rx_id]) + + data_vec = data_stack[ + self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] + ] + uncertainty_vec = uncert_stack[ + self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] ] - for order in self.ordering: - channel_id, component_id, rx_id = order - dobs.append(data_stack[component_id][channel_id, rx_id]) - uncerts.append(uncert_stack[component_id][channel_id, rx_id]) - - data_vec = np.vstack([dobs]).flatten() - uncertainty_vec = np.vstack([uncerts]).flatten() - - elif self.factory_type in ["magnetotellurics", "tipper"]: - local_data = {} - local_uncertainties = {} - - if channel is None: - channels = np.unique([list(v.keys()) for v in data.observed.values()]) - for chan in channels: - dat, unc = self._get_local_data(data, chan) - local_data.update(dat) - local_uncertainties.update(unc) - - else: - dat, unc = self._get_local_data(data, channel) - local_data.update(dat) - local_uncertainties.update(unc) - data_vec = self._stack_channels(local_data, "row") - uncertainty_vec = self._stack_channels(local_uncertainties, "row") + # elif self.factory_type in ["magnetotellurics", "tipper"]: + # local_data = {} + # local_uncertainties = {} + # + # if channel is None: + # channels = np.unique([list(v.keys()) for v in data.observed.values()]) + # for chan in channels: + # dat, unc = self._get_local_data(data, chan) + # local_data.update(dat) + # local_uncertainties.update(unc) + # + # else: + # dat, unc = self._get_local_data(data, channel) + # local_data.update(dat) + # local_uncertainties.update(unc) + # + # data_vec = self._stack_channels(local_data, "row") + # uncertainty_vec = self._stack_channels(local_uncertainties, "row") else: local_data = data.observed @@ -421,6 +431,17 @@ def _fem_arguments(self, data=None, channel=None): return [sources] def _naturalsource_arguments(self, data=None, frequency=None): + simpeg_mt_translate = { + "zxx_real": "zyy_real", + "zxx_imag": "zyy_imag", + "zxy_real": "zyx_real", + "zxy_imag": "zyx_imag", + "zyx_real": "zxy_real", + "zyx_imag": "zxy_imag", + "zyy_real": "zxx_real", + "zyy_imag": "zxx_imag", + } + receivers = [] sources = [] rx_factory = ReceiversFactory(self.params) @@ -432,7 +453,7 @@ def _naturalsource_arguments(self, data=None, frequency=None): rx_factory.build( locations=data.locations, data=data, - component=comp, + component=simpeg_mt_translate.get(comp, comp), ) ) diff --git a/simpeg_drivers/options.py b/simpeg_drivers/options.py index efc8f0f6..bf59820f 100644 --- a/simpeg_drivers/options.py +++ b/simpeg_drivers/options.py @@ -466,21 +466,13 @@ def property_group_data(self, property_group: PropertyGroup): if property_group is None: return dict.fromkeys(frequencies) - data = {} group = next( k for k in self.data_object.property_groups if k.uid == property_group.uid ) - property_names = [self.geoh5.get_entity(p)[0].name for p in group.properties] - properties = [self.geoh5.get_entity(p)[0].values for p in group.properties] - for i, f in enumerate(frequencies): - try: - f_ind = property_names.index( - next(k for k in property_names if f"{f:.2e}" in k) - ) # Safer if data was saved with geoapps naming convention - data[f] = properties[f_ind] - except StopIteration: - data[f] = properties[i] # in case of other naming conventions - + data = { + freq: self.geoh5.get_entity(p)[0].values + for freq, p in zip(frequencies, group.properties, strict=False) + } return data From 1bba32bb652825f93721b7f8f4d3ef162237e6e6 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Wed, 13 Aug 2025 12:34:10 -0700 Subject: [PATCH 08/56] Fixes for DC and PF --- .../components/factories/misfit_factory.py | 7 +++--- .../components/factories/survey_factory.py | 24 +------------------ simpeg_drivers/driver.py | 5 ++-- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index a81b5211..df942fda 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -13,6 +13,7 @@ from concurrent.futures import ProcessPoolExecutor, as_completed from copy import copy +from pathlib import Path from typing import TYPE_CHECKING import numpy as np @@ -224,7 +225,7 @@ def create_nested_simulation( kwargs["active_cells"] = mapping.local_active kwargs["sensitivity_path"] = ( - simulation.sensitivity_path.parent / f"Tile{tile_id}.zarr" + Path(simulation.sensitivity_path).parent / f"Tile{tile_id}.zarr" ) if getattr(simulation, "_rhoMap", None) is not None: @@ -285,7 +286,7 @@ def create_nested_survey(survey, indices, channel=None): # Extract the indices of the receivers that belong to this source locations = src.receiver_list[0].locations - if isinstance(locations, tuple): # For MT survey + if isinstance(locations, tuple | list): # For MT survey n_verts = locations[0].shape[0] else: n_verts = locations.shape[0] @@ -303,7 +304,7 @@ def create_nested_survey(survey, indices, channel=None): # intersect = set(rx.local_index).intersection(indices) new_rx = copy(rx) - if isinstance(rx.locations, tuple): # For MT survey + if isinstance(rx.locations, tuple | list): # For MT survey new_rx.locations = tuple(loc[intersect] for loc in rx.locations) else: new_rx.locations = rx.locations[intersect] diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index cfb726cc..40fbcdf8 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -163,11 +163,8 @@ def _add_data(self, survey, data, channel): uncert_stack = np.dstack( [np.vstack(list(k.values())) for k in data.uncertainties.values()] ).transpose((0, 2, 1)) - # for order in self.ordering: - # channel_id, component_id, rx_id = order - # dobs.append(data_stack[component_id][channel_id, rx_id]) - # uncerts.append(uncert_stack[component_id][channel_id, rx_id]) + # Flatten in the order of the channel, component, receiver data_vec = data_stack[ self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] ] @@ -175,25 +172,6 @@ def _add_data(self, survey, data, channel): self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] ] - # elif self.factory_type in ["magnetotellurics", "tipper"]: - # local_data = {} - # local_uncertainties = {} - # - # if channel is None: - # channels = np.unique([list(v.keys()) for v in data.observed.values()]) - # for chan in channels: - # dat, unc = self._get_local_data(data, chan) - # local_data.update(dat) - # local_uncertainties.update(unc) - # - # else: - # dat, unc = self._get_local_data(data, channel) - # local_data.update(dat) - # local_uncertainties.update(unc) - # - # data_vec = self._stack_channels(local_data, "row") - # uncertainty_vec = self._stack_channels(local_uncertainties, "row") - else: local_data = data.observed local_uncertainties = data.uncertainties diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 038f7f34..56685631 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -388,13 +388,14 @@ def simulation(self): """ if getattr(self, "_simulation", None) is None: simulation_factory = SimulationFactory(self.params) - self._simulation = simulation_factory.build( survey=self.inversion_data.survey, mesh=self.inversion_mesh.mesh, models=self.models, ) - self._simulation.active_cells = self.models.active_cells + + if not hasattr(self._simulation, "active_cells"): + self._simulation.active_cells = self.models.active_cells return self._simulation From 08c152c94c24687ae413f9d7caa62efb15d68faa Mon Sep 17 00:00:00 2001 From: dominiquef Date: Wed, 13 Aug 2025 13:42:39 -0700 Subject: [PATCH 09/56] Change ordering for FEM methods --- simpeg_drivers/components/factories/misfit_factory.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index df942fda..2e5e3548 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -324,11 +324,11 @@ def create_nested_survey(survey, indices, channel=None): if hasattr(survey, "dobs") and survey.dobs is not None: n_channels = len(np.unique(survey.ordering[:, 0])) n_comps = len(np.unique(survey.ordering[:, 1])) - - data_slice = survey.dobs.reshape((n_channels, n_comps, -1), order="F")[ + order = "C" if hasattr(survey, "frequencies") else "F" + data_slice = survey.dobs.reshape((n_channels, n_comps, -1), order=order)[ :, :, indices ] - uncert_slice = survey.std.reshape((n_channels, n_comps, -1), order="F")[ + uncert_slice = survey.std.reshape((n_channels, n_comps, -1), order=order)[ :, :, indices ] @@ -338,8 +338,8 @@ def create_nested_survey(survey, indices, channel=None): data_slice = data_slice[ind, :, :] uncert_slice = uncert_slice[ind, :, :] - new_survey.dobs = data_slice.flatten(order="F") - new_survey.std = uncert_slice.flatten(order="F") + new_survey.dobs = data_slice.flatten(order=order) + new_survey.std = uncert_slice.flatten(order=order) return new_survey From 938daf55c142ff2832a982ede70fd0220e352d20 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Wed, 13 Aug 2025 14:03:03 -0700 Subject: [PATCH 10/56] Full run through NS tests --- simpeg_drivers/components/factories/misfit_factory.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index 2e5e3548..3280bd10 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -79,7 +79,7 @@ def assemble_arguments( # pylint: disable=arguments-differ if len(local_index) == 0: continue - n_split = split_list[misfit_count] + n_split = split_list[misfit_count : misfit_count + len(channels)] futures.append( # executor.submit( self.create_nested_misfit( @@ -96,7 +96,7 @@ def assemble_arguments( # pylint: disable=arguments-differ ) misfit_count += len(channels) data_count += len(local_index) - tile_count += n_split + tile_count += np.sum(n_split) local_misfits = [] self.sorting = [] @@ -137,7 +137,7 @@ def create_nested_misfit( sorting = [] local_misfits = [] for count, channel in enumerate(channels): - for split_ind in np.array_split(local_index, n_split): + for split_ind in np.array_split(local_index, n_split[count]): local_sim, mapping = create_nested_simulation( simulation, local_mesh, From bfb339caf62c91fbf0d75a5f5deccfe82c1c1fa8 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Wed, 13 Aug 2025 14:34:00 -0700 Subject: [PATCH 11/56] Line up PF with the rest --- simpeg_drivers/components/data.py | 4 +- .../factories/directives_factory.py | 2 +- .../components/factories/misfit_factory.py | 103 +++++++++--------- .../components/factories/survey_factory.py | 93 +++------------- simpeg_drivers/options.py | 6 +- 5 files changed, 72 insertions(+), 136 deletions(-) diff --git a/simpeg_drivers/components/data.py b/simpeg_drivers/components/data.py index c4a9c48a..ffb2ff34 100644 --- a/simpeg_drivers/components/data.py +++ b/simpeg_drivers/components/data.py @@ -224,8 +224,8 @@ def save_data(self): continue # Non-EM methods - if not has_channels: - channels = {None: channels} + # if not has_channels: + # channels = {None: channels} for ind, (channel, values) in enumerate(channels.items()): suffix = f"_{component}" diff --git a/simpeg_drivers/components/factories/directives_factory.py b/simpeg_drivers/components/factories/directives_factory.py index f76cd0e9..53fa37b4 100644 --- a/simpeg_drivers/components/factories/directives_factory.py +++ b/simpeg_drivers/components/factories/directives_factory.py @@ -592,7 +592,7 @@ def assemble_data_keywords_potential_fields( data = inversion_object.normalize(inversion_object.observed) def potfield_transform(x): - data_stack = np.row_stack(list(data.values())) + data_stack = np.vstack([k[None] for k in data.values()]) data_stack = data_stack[:, np.argsort(sorting)] return data_stack.ravel() - x diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index 3280bd10..97586243 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -82,7 +82,7 @@ def assemble_arguments( # pylint: disable=arguments-differ n_split = split_list[misfit_count : misfit_count + len(channels)] futures.append( # executor.submit( - self.create_nested_misfit( + create_nested_misfit( self.simulation, local_index, channels, @@ -111,66 +111,65 @@ def assemble_keyword_arguments(self, **_): """Implementation of abstract method from SimPEGFactory.""" return {} - @classmethod - def create_nested_misfit( - cls, + +def create_nested_misfit( + simulation, + local_index, + channels, + tile_count, + # data_count, + n_split, + padding_cells, + inversion_type, + forward_only, +): + local_sim, _ = create_nested_simulation( simulation, + None, local_index, - channels, - tile_count, - # data_count, - n_split, - padding_cells, - inversion_type, - forward_only, - ): - local_sim, _ = create_nested_simulation( - simulation, - None, - local_index, - channel=None, - tile_id=tile_count, - padding_cells=padding_cells, - ) + channel=None, + tile_id=tile_count, + padding_cells=padding_cells, + ) - local_mesh = getattr(local_sim, "mesh", None) - sorting = [] - local_misfits = [] - for count, channel in enumerate(channels): - for split_ind in np.array_split(local_index, n_split[count]): - local_sim, mapping = create_nested_simulation( - simulation, - local_mesh, - split_ind, - channel=channel, - tile_id=tile_count, - padding_cells=padding_cells, - ) + local_mesh = getattr(local_sim, "mesh", None) + sorting = [] + local_misfits = [] + for count, channel in enumerate(channels): + for split_ind in np.array_split(local_index, n_split[count]): + local_sim, mapping = create_nested_simulation( + simulation, + local_mesh, + split_ind, + channel=channel, + tile_id=tile_count, + padding_cells=padding_cells, + ) - if count == 0: - sorting.append(split_ind) + if count == 0: + sorting.append(split_ind) - meta_simulation = meta.MetaSimulation( - simulations=[local_sim], mappings=[mapping] - ) + meta_simulation = meta.MetaSimulation( + simulations=[local_sim], mappings=[mapping] + ) - local_data = data.Data(local_sim.survey) - lmisfit = data_misfit.L2DataMisfit(local_data, meta_simulation) - if not forward_only: - local_data.dobs = local_sim.survey.dobs - local_data.standard_deviation = local_sim.survey.std - name = inversion_type - name += f": Tile {tile_count + 1}" - if len(channels) > 1: - name += f": Channel {channel}" + local_data = data.Data(local_sim.survey) + lmisfit = data_misfit.L2DataMisfit(local_data, meta_simulation) + if not forward_only: + local_data.dobs = local_sim.survey.dobs + local_data.standard_deviation = local_sim.survey.std + name = inversion_type + name += f": Tile {tile_count + 1}" + if len(channels) > 1: + name += f": Channel {channel}" - lmisfit.name = f"{name}" + lmisfit.name = f"{name}" - local_misfits.append(lmisfit) + local_misfits.append(lmisfit) - tile_count += 1 + tile_count += 1 - return local_misfits, sorting + return local_misfits, sorting def create_nested_simulation( @@ -232,7 +231,7 @@ def create_nested_simulation( kwargs["rhoMap"] = maps.IdentityMap(nP=n_actives) kwargs["active_cells"] = mapping.local_active kwargs["sensitivity_path"] = ( - simulation.sensitivity_path.parent / f"Tile{tile_id}.zarr" + Path(simulation.sensitivity_path).parent / f"Tile{tile_id}.zarr" ) if getattr(simulation, "_sigmaMap", None) is not None: diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index 40fbcdf8..efc538e1 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -95,7 +95,7 @@ def assemble_arguments(self, data=None): n_rx = data.locations.shape[0] n_comp = len(data.components) self.ordering = np.c_[ - np.ones(n_rx * n_comp), # Single channel + np.zeros(n_rx * n_comp), # Single channel np.kron(np.ones(n_rx), np.arange(n_comp)), # Components np.kron(np.arange(n_rx), np.ones(n_comp)), # Receivers ].astype(int) @@ -123,89 +123,26 @@ def build( return survey - def _get_local_data(self, data, channel): - local_data = {} - local_uncertainties = {} - - components = list(data.observed.keys()) - for comp in components: - comp_name = comp - if self.factory_type == "magnetotellurics": - comp_name = { - "zxx_real": "zyy_real", - "zxx_imag": "zyy_imag", - "zxy_real": "zyx_real", - "zxy_imag": "zyx_imag", - "zyx_real": "zxy_real", - "zyx_imag": "zxy_imag", - "zyy_real": "zxx_real", - "zyy_imag": "zxx_imag", - }[comp] - - key = "_".join([str(channel), str(comp_name)]) - local_data[key] = data.observed[comp][channel] - local_uncertainties[key] = data.uncertainties[comp][channel] - - return local_data, local_uncertainties - def _add_data(self, survey, data, channel): - if self.factory_type in [ - "fdem", - "fdem 1d", - "tdem", - "tdem 1d", - "magnetotellurics", - "tipper", - ]: - data_stack = np.dstack( - [np.vstack(list(k.values())) for k in data.observed.values()] - ).transpose((0, 2, 1)) - uncert_stack = np.dstack( - [np.vstack(list(k.values())) for k in data.uncertainties.values()] - ).transpose((0, 2, 1)) - - # Flatten in the order of the channel, component, receiver - data_vec = data_stack[ - self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] - ] - uncertainty_vec = uncert_stack[ - self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] - ] - - else: - local_data = data.observed - local_uncertainties = data.uncertainties - - data_vec = self._stack_channels(local_data, "column") - uncertainty_vec = self._stack_channels(local_uncertainties, "column") - + data_stack = np.dstack( + [np.vstack(list(k.values())) for k in data.observed.values()] + ).transpose((0, 2, 1)) + uncert_stack = np.dstack( + [np.vstack(list(k.values())) for k in data.uncertainties.values()] + ).transpose((0, 2, 1)) + + # Flatten in the order of the channel, component, receiver + data_vec = data_stack[ + self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] + ] + uncertainty_vec = uncert_stack[ + self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] + ] uncertainty_vec[np.isnan(data_vec)] = np.inf data_vec[np.isnan(data_vec)] = self.dummy # Nan's handled by inf uncertainties survey.dobs = data_vec survey.std = uncertainty_vec - def _stack_channels(self, channel_data: dict[str, np.ndarray], mode: str): - """ - Convert dictionary of data/uncertainties to stacked array. - - parameters: - ---------- - - channel_data: Array of data to stack - mode: Stacks rows or columns before flattening. Must be either 'row' or 'column'. - - - notes: - ------ - If mode is row the components will be clustered in the resulting 1D array. - Column stacking results in the locations being clustered. - - """ - if mode == "column": - return np.column_stack(list(channel_data.values())).ravel() - elif mode == "row": - return np.row_stack(list(channel_data.values())).ravel() - def _dcip_arguments(self, data=None): if getattr(data, "entity", None) is None: return None diff --git a/simpeg_drivers/options.py b/simpeg_drivers/options.py index bf59820f..42c9e2e8 100644 --- a/simpeg_drivers/options.py +++ b/simpeg_drivers/options.py @@ -625,7 +625,7 @@ def component_data(self, component: str) -> np.ndarray | None: data = getattr(self, "_".join([component, "channel"]), None) if isinstance(data, NumericData): data = data.values - return data + return {None: data} def component_uncertainty(self, component: str) -> np.ndarray | None: """ @@ -640,6 +640,6 @@ def component_uncertainty(self, component: str) -> np.ndarray | None: if isinstance(data, NumericData): data = data.values elif isinstance(data, float): - data *= np.ones_like(self.component_data(component)) + data *= np.ones_like(self.component_data(component)[None]) - return data + return {None: data} From cf77def1875955263fd8c1124b7560911b364286 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Wed, 13 Aug 2025 15:10:05 -0700 Subject: [PATCH 12/56] Work through kinks for DC --- .../components/factories/directives_factory.py | 6 +++--- simpeg_drivers/components/factories/misfit_factory.py | 10 +++++----- simpeg_drivers/components/factories/survey_factory.py | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/simpeg_drivers/components/factories/directives_factory.py b/simpeg_drivers/components/factories/directives_factory.py index 53fa37b4..0bef436f 100644 --- a/simpeg_drivers/components/factories/directives_factory.py +++ b/simpeg_drivers/components/factories/directives_factory.py @@ -653,9 +653,9 @@ def assemble_data_keywords_dcip( data = inversion_object.normalize(inversion_object.observed) def dcip_transform(x): - data_stack = np.row_stack(list(data.values())).ravel() - sorting_stack = np.tile(np.argsort(sorting), len(data)) - return data_stack[sorting_stack] - x + data_stack = np.vstack([k[None] for k in data.values()]) + data_stack = data_stack[:, np.argsort(sorting)] + return data_stack.ravel() - x kwargs["transforms"].insert(0, dcip_transform) kwargs.pop("data_type") diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index 97586243..62fca61c 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -286,24 +286,24 @@ def create_nested_survey(survey, indices, channel=None): # Extract the indices of the receivers that belong to this source locations = src.receiver_list[0].locations if isinstance(locations, tuple | list): # For MT survey - n_verts = locations[0].shape[0] + n_data = locations[0].shape[0] else: - n_verts = locations.shape[0] + n_data = locations.shape[0] - rx_indices = np.arange(n_verts) + location_count + rx_indices = np.arange(n_data) + location_count _, intersect, _ = np.intersect1d(rx_indices, indices, return_indices=True) + location_count += n_data if len(intersect) == 0: continue - location_count += len(intersect) receivers = [] for rx in src.receiver_list: # intersect = set(rx.local_index).intersection(indices) new_rx = copy(rx) - if isinstance(rx.locations, tuple | list): # For MT survey + if isinstance(rx.locations, tuple | list): # For MT and DC surveys new_rx.locations = tuple(loc[intersect] for loc in rx.locations) else: new_rx.locations = rx.locations[intersect] diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index efc538e1..8cc985c0 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -190,8 +190,8 @@ def _dcip_arguments(self, data=None): sources.append(source) self.ordering = np.c_[ - np.ones(receiver_entity.n_cells), # Single channel - np.ones(receiver_entity.n_cells), # Single component + np.zeros(receiver_entity.n_cells), # Single channel + np.zeros(receiver_entity.n_cells), # Single component np.hstack(ordering), # Multi-receivers ].astype(int) From 787d9c701ea324aa7487222203089c2171432acf Mon Sep 17 00:00:00 2001 From: dominiquef Date: Thu, 14 Aug 2025 08:03:46 -0700 Subject: [PATCH 13/56] Clean out commented code --- .../components/factories/survey_factory.py | 8 +- simpeg_drivers/driver.py | 74 ------------------- 2 files changed, 3 insertions(+), 79 deletions(-) diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index 8cc985c0..e1b384b4 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -235,6 +235,7 @@ def _tdem_arguments(self, data=None): wave_times = ( receivers.waveform[:, 0] - receivers.timing_mark ) * self.params.unit_conversion + if "1d" in self.factory_type: on_times = wave_times <= 0.0 waveform = tdem.sources.PiecewiseLinearWaveform( @@ -256,10 +257,11 @@ def _tdem_arguments(self, data=None): tx_list = [] rx_factory = ReceiversFactory(self.params) tx_factory = SourcesFactory(self.params) + for cur_tx_locs, rx_ids in zip(tx_locs, rx_lookup, strict=True): locs = receivers.vertices[rx_ids, :] - rx_list = [] + for component_id, component in enumerate(data.components): rx_obj = rx_factory.build( locations=locs, @@ -278,9 +280,6 @@ def _tdem_arguments(self, data=None): np.kron(np.ones(n_times), np.asarray(rx_ids)), ] ) - # for time_id in range(len(receivers.channels)): - # for rx_id in rx_ids: - # ordering.append([time_id, component_id, rx_id]) tx_list.append( tx_factory.build(rx_list, locations=cur_tx_locs, waveform=waveform) @@ -356,7 +355,6 @@ def _naturalsource_arguments(self, data=None, frequency=None): "zyy_real": "zxx_real", "zyy_imag": "zxx_imag", } - receivers = [] sources = [] rx_factory = ReceiversFactory(self.params) diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 56685631..3b2092c2 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -399,80 +399,6 @@ def simulation(self): return self._simulation - # def simulation( - # self, - # inversion_mesh: TreeMesh, - # local_mesh: TreeMesh | TensorMesh | None, - # active_cells: np.ndarray, - # survey, - # tile_id: int | None = None, - # padding_cells: int = 6, - # ) -> tuple[simulation.BaseSimulation, maps.IdentityMap]: - # """ - # Generates SimPEG simulation object. - # - # :param: mesh: inversion mesh. - # :param: active_cells: Mask that reduces model to active (earth) cells. - # :param: survey: SimPEG survey object. - # :param: tile_id (Optional): Id associated with the tile covered by - # the survey in case of a tiled inversion. - # - # :return: sim: SimPEG simulation object for full data or optionally - # the portion of the data indexed by the local_index argument. - # :return: map: If local_index and tile_id is provided, the returned - # map will maps from local to global data. If no local_index or - # tile_id is provided map will simply be an identity map with no - # effect of the data. - # """ - # simulation_factory = SimulationFactory(self.params) - # - # if tile_id is None or "2d" in self.params.inversion_type: - # mapping = maps.IdentityMap(nP=int(self.n_blocks * active_cells.sum())) - # simulation = simulation_factory.build( - # survey=survey, - # global_mesh=inversion_mesh, - # active_cells=active_cells, - # mapping=mapping, - # ) - # elif "1d" in self.params.inversion_type: - # slice_ind = np.arange( - # tile_id, inversion_mesh.n_cells, inversion_mesh.shape_cells[0] - # )[::-1] - # mapping = maps.Projection(inversion_mesh.n_cells, slice_ind) - # simulation = simulation_factory.build( - # survey=survey, - # global_mesh=inversion_mesh, - # local_mesh=local_mesh, - # active_cells=active_cells, - # mapping=mapping, - # tile_id=tile_id, - # ) - # else: - # if local_mesh is None: - # local_mesh = create_nested_mesh( - # survey, - # inversion_mesh, - # minimum_level=3, - # padding_cells=padding_cells, - # ) - # mapping = maps.TileMap( - # inversion_mesh, - # active_cells, - # local_mesh, - # enforce_active=True, - # components=self.n_blocks, - # ) - # simulation = simulation_factory.build( - # survey=survey, - # receivers=self.entity, - # global_mesh=inversion_mesh, - # local_mesh=local_mesh, - # active_cells=mapping.local_active, - # mapping=mapping, - # tile_id=tile_id, - # ) - # - # return simulation, mapping @property def sorting(self): """List of arrays for sorting of data from tiles.""" From a529ccbf8ee99963721215426bb7c65293a5156d Mon Sep 17 00:00:00 2001 From: dominiquef Date: Thu, 14 Aug 2025 09:44:37 -0700 Subject: [PATCH 14/56] Move functions under utils/nested --- .../components/factories/misfit_factory.py | 284 +--------------- simpeg_drivers/driver.py | 2 +- simpeg_drivers/utils/nested.py | 321 ++++++++++++++++++ simpeg_drivers/utils/surveys.py | 39 +++ simpeg_drivers/utils/utils.py | 72 +--- 5 files changed, 366 insertions(+), 352 deletions(-) create mode 100644 simpeg_drivers/utils/nested.py diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index 62fca61c..47856d4c 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -11,27 +11,19 @@ from __future__ import annotations -from concurrent.futures import ProcessPoolExecutor, as_completed -from copy import copy -from pathlib import Path from typing import TYPE_CHECKING import numpy as np -from discretize import TensorMesh, TreeMesh -from geoh5py.objects import Octree -from simpeg import data, data_misfit, maps, meta, objective_function +from simpeg import objective_function from simpeg.simulation import BaseSimulation from simpeg_drivers.components.factories.simpeg_factory import SimPEGFactory -from simpeg_drivers.components.factories.simulation_factory import SimulationFactory -from simpeg_drivers.utils.utils import create_nested_mesh +from simpeg_drivers.utils.nested import create_nested_misfit if TYPE_CHECKING: from geoapps_utils.driver.params import BaseParams - from simpeg_drivers.components.data import InversionData - from simpeg_drivers.components.meshes import InversionMesh from simpeg_drivers.options import BaseOptions @@ -74,6 +66,8 @@ def assemble_arguments( # pylint: disable=arguments-differ tile_count = 0 data_count = 0 misfit_count = 0 + + # TODO bring back on GEOPY-2182 # with ProcessPoolExecutor() as executor: for local_index in tiles: if len(local_index) == 0: @@ -110,273 +104,3 @@ def assemble_arguments( # pylint: disable=arguments-differ def assemble_keyword_arguments(self, **_): """Implementation of abstract method from SimPEGFactory.""" return {} - - -def create_nested_misfit( - simulation, - local_index, - channels, - tile_count, - # data_count, - n_split, - padding_cells, - inversion_type, - forward_only, -): - local_sim, _ = create_nested_simulation( - simulation, - None, - local_index, - channel=None, - tile_id=tile_count, - padding_cells=padding_cells, - ) - - local_mesh = getattr(local_sim, "mesh", None) - sorting = [] - local_misfits = [] - for count, channel in enumerate(channels): - for split_ind in np.array_split(local_index, n_split[count]): - local_sim, mapping = create_nested_simulation( - simulation, - local_mesh, - split_ind, - channel=channel, - tile_id=tile_count, - padding_cells=padding_cells, - ) - - if count == 0: - sorting.append(split_ind) - - meta_simulation = meta.MetaSimulation( - simulations=[local_sim], mappings=[mapping] - ) - - local_data = data.Data(local_sim.survey) - lmisfit = data_misfit.L2DataMisfit(local_data, meta_simulation) - if not forward_only: - local_data.dobs = local_sim.survey.dobs - local_data.standard_deviation = local_sim.survey.std - name = inversion_type - name += f": Tile {tile_count + 1}" - if len(channels) > 1: - name += f": Channel {channel}" - - lmisfit.name = f"{name}" - - local_misfits.append(lmisfit) - - tile_count += 1 - - return local_misfits, sorting - - -def create_nested_simulation( - simulation: BaseSimulation, - local_mesh: TreeMesh | None, - indices: np.ndarray, - *, - channel: int | None = None, - tile_id: int | None = None, - padding_cells=100, -): - """ - Generate a survey, mesh and simulation based on indices. - - :param inversion_data: InversionData object. - :param mesh: Octree mesh. - :param active_cells: Active cell model. - :param indices: Indices of receivers belonging to the tile. - :param channel: Channel number for frequency or time channels. - :param tile_id: Tile id stored on the simulation. - :param padding_cells: Number of padding cells around the local survey. - """ - local_survey = create_nested_survey( - simulation.survey, indices=indices, channel=channel - ) - - if local_mesh is None: - local_mesh = create_nested_mesh( - local_survey, - simulation.mesh, - minimum_level=3, - padding_cells=padding_cells, - ) - - mapping = maps.TileMap( - simulation.mesh, - simulation.active_cells, - local_mesh, - enforce_active=True, - components=3 if getattr(simulation, "model_type", None) == "vector" else 1, - ) - - kwargs = {"survey": local_survey} - - n_actives = int(mapping.local_active.sum()) - if getattr(simulation, "_chiMap", None) is not None: - if simulation.model_type == "vector": - kwargs["chiMap"] = maps.IdentityMap(nP=n_actives * 3) - kwargs["model_type"] = "vector" - else: - kwargs["chiMap"] = maps.IdentityMap(nP=n_actives) - - kwargs["active_cells"] = mapping.local_active - kwargs["sensitivity_path"] = ( - Path(simulation.sensitivity_path).parent / f"Tile{tile_id}.zarr" - ) - - if getattr(simulation, "_rhoMap", None) is not None: - kwargs["rhoMap"] = maps.IdentityMap(nP=n_actives) - kwargs["active_cells"] = mapping.local_active - kwargs["sensitivity_path"] = ( - Path(simulation.sensitivity_path).parent / f"Tile{tile_id}.zarr" - ) - - if getattr(simulation, "_sigmaMap", None) is not None: - kwargs["sigmaMap"] = maps.ExpMap(local_mesh) * maps.InjectActiveCells( - local_mesh, mapping.local_active, value_inactive=np.log(1e-8) - ) - - if getattr(simulation, "_etaMap", None) is not None: - kwargs["etaMap"] = maps.InjectActiveCells( - local_mesh, mapping.local_active, value_inactive=0 - ) - proj = maps.InjectActiveCells( - local_mesh, - mapping.local_active, - value_inactive=1e-8, - ) - kwargs["sigma"] = proj * mapping * simulation.sigma - - for key in [ - "max_chunk_sizestore_sensitivities", - "solver", - "t0", - "time_steps", - "thicknesses", - ]: - if hasattr(simulation, key): - kwargs[key] = getattr(simulation, key) - - local_sim = type(simulation)(local_mesh, **kwargs) - - # TODO bring back - # inv_type = inversion_data.params.inversion_type - # if inv_type in ["fdem", "tdem"]: - # compute_em_projections(inversion_data, local_sim) - # elif ("current" in inv_type or "polarization" in inv_type) and ( - # "2d" not in inv_type or "pseudo" in inv_type - # ): - # compute_dc_projections(inversion_data, local_sim, indices) - return local_sim, mapping - - -def create_nested_survey(survey, indices, channel=None): - """ - Extract source and receivers belonging to the indices. - """ - sources = [] - location_count = 0 - for src in survey.source_list or [survey.source_field]: - if channel is not None and getattr(src, "frequency", None) != channel: - continue - - # Extract the indices of the receivers that belong to this source - locations = src.receiver_list[0].locations - if isinstance(locations, tuple | list): # For MT survey - n_data = locations[0].shape[0] - else: - n_data = locations.shape[0] - - rx_indices = np.arange(n_data) + location_count - - _, intersect, _ = np.intersect1d(rx_indices, indices, return_indices=True) - location_count += n_data - - if len(intersect) == 0: - continue - - receivers = [] - for rx in src.receiver_list: - # intersect = set(rx.local_index).intersection(indices) - new_rx = copy(rx) - - if isinstance(rx.locations, tuple | list): # For MT and DC surveys - new_rx.locations = tuple(loc[intersect] for loc in rx.locations) - else: - new_rx.locations = rx.locations[intersect] - - receivers.append(new_rx) - - if any(receivers): - new_src = copy(src) - new_src.receiver_list = receivers - sources.append(new_src) - - if hasattr(survey, "source_field"): - new_survey = type(survey)(sources[0]) - else: - new_survey = type(survey)(sources) - - if hasattr(survey, "dobs") and survey.dobs is not None: - n_channels = len(np.unique(survey.ordering[:, 0])) - n_comps = len(np.unique(survey.ordering[:, 1])) - order = "C" if hasattr(survey, "frequencies") else "F" - data_slice = survey.dobs.reshape((n_channels, n_comps, -1), order=order)[ - :, :, indices - ] - uncert_slice = survey.std.reshape((n_channels, n_comps, -1), order=order)[ - :, :, indices - ] - - # For FEM surveys only - if channel is not None: - ind = np.where(np.asarray(survey.frequencies) == channel)[0] - data_slice = data_slice[ind, :, :] - uncert_slice = uncert_slice[ind, :, :] - - new_survey.dobs = data_slice.flatten(order=order) - new_survey.std = uncert_slice.flatten(order=order) - - return new_survey - - -def compute_em_projections(inversion_data, simulation): - """ - Pre-compute projections for the receivers for efficiency. - """ - rx_locs = inversion_data.entity.vertices - projections = {} - for component in "xyz": - projections[component] = simulation.mesh.get_interpolation_matrix( - rx_locs, "faces_" + component[0] - ) - - for source in simulation.survey.source_list: - for receiver in source.receiver_list: - projection = 0.0 - for orientation, comp in zip(receiver.orientation, "xyz", strict=True): - if orientation == 0: - continue - projection += orientation * projections[comp][receiver.local_index, :] - receiver.spatialP = projection - - -def compute_dc_projections(inversion_data, simulation, indices): - """ - Pre-compute projections for the receivers for efficiency. - """ - rx_locs = inversion_data.entity.vertices - mn_pairs = inversion_data.entity.cells - projection = simulation.mesh.get_interpolation_matrix(rx_locs, "nodes") - - for source, ind in zip(simulation.survey.source_list, indices, strict=True): - proj_mn = projection[mn_pairs[ind, 0], :] - - # Check if dipole receiver - if not np.all(mn_pairs[ind, 0] == mn_pairs[ind, 1]): - proj_mn -= projection[mn_pairs[ind, 1], :] - - source.receiver_list[0].spatialP = proj_mn # pylint: disable=protected-access diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 9c420edd..8cff0d4b 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -623,7 +623,7 @@ def get_tiles(self): return np.arange(self.inversion_data.mask.sum()).reshape((-1, 1)) return tile_locations( - self.inversion_data.locations, + self.simulation.survey, self.params.compute.tile_spatial, labels=self.inversion_data.parts, ) diff --git a/simpeg_drivers/utils/nested.py b/simpeg_drivers/utils/nested.py new file mode 100644 index 00000000..71ee18a1 --- /dev/null +++ b/simpeg_drivers/utils/nested.py @@ -0,0 +1,321 @@ +# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +# Copyright (c) 2025 Mira Geoscience Ltd. ' +# ' +# This file is part of simpeg-drivers package. ' +# ' +# simpeg-drivers is distributed under the terms and conditions of the MIT License ' +# (see LICENSE file at the root of this source code package). ' +# ' +# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +from __future__ import annotations + +from copy import copy +from pathlib import Path + +import numpy as np +from discretize import TreeMesh +from scipy.spatial import cKDTree +from simpeg import data, data_misfit, maps, meta +from simpeg.electromagnetics.frequency_domain.sources import ( + LineCurrent as FEMLineCurrent, +) +from simpeg.electromagnetics.time_domain.sources import LineCurrent as TEMLineCurrent +from simpeg.simulation import BaseSimulation +from simpeg.survey import BaseSurvey + +from .surveys import get_intersecting_cells, get_unique_locations + + +def create_nested_mesh( + survey: BaseSurvey, + base_mesh: TreeMesh, + padding_cells: int = 8, + minimum_level: int = 4, + finalize: bool = True, +): + """ + Create a nested mesh with the same extent as the input global mesh. + Refinement levels are preserved only around the input locations (local survey). + + Parameters + ---------- + + locations: Array of coordinates for the local survey shape(*, 3). + base_mesh: Input global TreeMesh object. + padding_cells: Used for 'method'= 'padding_cells'. Number of cells in each concentric shell. + minimum_level: Minimum octree level to preserve everywhere outside the local survey area. + finalize: Return a finalized local treemesh. + """ + locations = get_unique_locations(survey) + nested_mesh = TreeMesh( + [base_mesh.h[0], base_mesh.h[1], base_mesh.h[2]], + x0=base_mesh.x0, + diagonal_balance=False, + ) + base_level = base_mesh.max_level - minimum_level + base_refinement = base_mesh.cell_levels_by_index(np.arange(base_mesh.nC)) + base_refinement[base_refinement > base_level] = base_level + nested_mesh.insert_cells( + base_mesh.gridCC, + base_refinement, + finalize=False, + ) + base_cell = np.min([base_mesh.h[0][0], base_mesh.h[1][0]]) + tx_loops = [] + for source in survey.source_list: + if isinstance(source, TEMLineCurrent | FEMLineCurrent): + mesh_indices = get_intersecting_cells(source.location, base_mesh) + tx_loops.append(base_mesh.cell_centers[mesh_indices, :]) + + if tx_loops: + locations = np.vstack([locations, *tx_loops]) + + tree = cKDTree(locations[:, :2]) + rad, _ = tree.query(base_mesh.gridCC[:, :2]) + pad_distance = 0.0 + for ii in range(minimum_level): + pad_distance += base_cell * 2**ii * padding_cells + indices = np.where(rad < pad_distance)[0] + levels = base_mesh.cell_levels_by_index(indices) + levels[levels > (base_mesh.max_level - ii)] = base_mesh.max_level - ii + nested_mesh.insert_cells( + base_mesh.gridCC[indices, :], + levels, + finalize=False, + ) + + if finalize: + nested_mesh.finalize() + + return nested_mesh + + +def create_nested_misfit( + simulation, + local_index, + channels, + tile_count, + # data_count, + n_split, + padding_cells, + inversion_type, + forward_only, +): + local_sim, _ = create_nested_simulation( + simulation, + None, + local_index, + channel=None, + tile_id=tile_count, + padding_cells=padding_cells, + ) + + local_mesh = getattr(local_sim, "mesh", None) + sorting = [] + local_misfits = [] + for count, channel in enumerate(channels): + for split_ind in np.array_split(local_index, n_split[count]): + local_sim, mapping = create_nested_simulation( + simulation, + local_mesh, + split_ind, + channel=channel, + tile_id=tile_count, + padding_cells=padding_cells, + ) + + if count == 0: + sorting.append(split_ind) + + meta_simulation = meta.MetaSimulation( + simulations=[local_sim], mappings=[mapping] + ) + + local_data = data.Data(local_sim.survey) + lmisfit = data_misfit.L2DataMisfit(local_data, meta_simulation) + if not forward_only: + local_data.dobs = local_sim.survey.dobs + local_data.standard_deviation = local_sim.survey.std + name = inversion_type + name += f": Tile {tile_count + 1}" + if len(channels) > 1: + name += f": Channel {channel}" + + lmisfit.name = f"{name}" + + local_misfits.append(lmisfit) + + tile_count += 1 + + return local_misfits, sorting + + +def create_nested_simulation( + simulation: BaseSimulation, + local_mesh: TreeMesh | None, + indices: np.ndarray, + *, + channel: int | None = None, + tile_id: int | None = None, + padding_cells=100, +): + """ + Generate a survey, mesh and simulation based on indices. + + :param inversion_data: InversionData object. + :param mesh: Octree mesh. + :param active_cells: Active cell model. + :param indices: Indices of receivers belonging to the tile. + :param channel: Channel number for frequency or time channels. + :param tile_id: Tile id stored on the simulation. + :param padding_cells: Number of padding cells around the local survey. + """ + local_survey = create_nested_survey( + simulation.survey, indices=indices, channel=channel + ) + + if local_mesh is None: + local_mesh = create_nested_mesh( + local_survey, + simulation.mesh, + minimum_level=3, + padding_cells=padding_cells, + ) + + mapping = maps.TileMap( + simulation.mesh, + simulation.active_cells, + local_mesh, + enforce_active=True, + components=3 if getattr(simulation, "model_type", None) == "vector" else 1, + ) + + kwargs = {"survey": local_survey} + + n_actives = int(mapping.local_active.sum()) + if getattr(simulation, "_chiMap", None) is not None: + if simulation.model_type == "vector": + kwargs["chiMap"] = maps.IdentityMap(nP=n_actives * 3) + kwargs["model_type"] = "vector" + else: + kwargs["chiMap"] = maps.IdentityMap(nP=n_actives) + + kwargs["active_cells"] = mapping.local_active + kwargs["sensitivity_path"] = ( + Path(simulation.sensitivity_path).parent / f"Tile{tile_id}.zarr" + ) + + if getattr(simulation, "_rhoMap", None) is not None: + kwargs["rhoMap"] = maps.IdentityMap(nP=n_actives) + kwargs["active_cells"] = mapping.local_active + kwargs["sensitivity_path"] = ( + Path(simulation.sensitivity_path).parent / f"Tile{tile_id}.zarr" + ) + + if getattr(simulation, "_sigmaMap", None) is not None: + kwargs["sigmaMap"] = maps.ExpMap(local_mesh) * maps.InjectActiveCells( + local_mesh, mapping.local_active, value_inactive=np.log(1e-8) + ) + + if getattr(simulation, "_etaMap", None) is not None: + kwargs["etaMap"] = maps.InjectActiveCells( + local_mesh, mapping.local_active, value_inactive=0 + ) + proj = maps.InjectActiveCells( + local_mesh, + mapping.local_active, + value_inactive=1e-8, + ) + kwargs["sigma"] = proj * mapping * simulation.sigma + + for key in [ + "max_chunk_sizestore_sensitivities", + "solver", + "t0", + "time_steps", + "thicknesses", + ]: + if hasattr(simulation, key): + kwargs[key] = getattr(simulation, key) + + local_sim = type(simulation)(local_mesh, **kwargs) + + # TODO bring back + # inv_type = inversion_data.params.inversion_type + # if inv_type in ["fdem", "tdem"]: + # compute_em_projections(inversion_data, local_sim) + # elif ("current" in inv_type or "polarization" in inv_type) and ( + # "2d" not in inv_type or "pseudo" in inv_type + # ): + # compute_dc_projections(inversion_data, local_sim, indices) + return local_sim, mapping + + +def create_nested_survey(survey, indices, channel=None): + """ + Extract source and receivers belonging to the indices. + """ + sources = [] + location_count = 0 + for src in survey.source_list or [survey.source_field]: + if channel is not None and getattr(src, "frequency", None) != channel: + continue + + # Extract the indices of the receivers that belong to this source + locations = src.receiver_list[0].locations + if isinstance(locations, tuple | list): # For MT survey + n_data = locations[0].shape[0] + else: + n_data = locations.shape[0] + + rx_indices = np.arange(n_data) + location_count + + _, intersect, _ = np.intersect1d(rx_indices, indices, return_indices=True) + location_count += n_data + + if len(intersect) == 0: + continue + + receivers = [] + for rx in src.receiver_list: + # intersect = set(rx.local_index).intersection(indices) + new_rx = copy(rx) + + if isinstance(rx.locations, tuple | list): # For MT and DC surveys + new_rx.locations = tuple(loc[intersect] for loc in rx.locations) + else: + new_rx.locations = rx.locations[intersect] + + receivers.append(new_rx) + + if any(receivers): + new_src = copy(src) + new_src.receiver_list = receivers + sources.append(new_src) + + if hasattr(survey, "source_field"): + new_survey = type(survey)(sources[0]) + else: + new_survey = type(survey)(sources) + + if hasattr(survey, "dobs") and survey.dobs is not None: + n_channels = len(np.unique(survey.ordering[:, 0])) + n_comps = len(np.unique(survey.ordering[:, 1])) + order = "C" if hasattr(survey, "frequencies") else "F" + data_slice = survey.dobs.reshape((n_channels, n_comps, -1), order=order)[ + :, :, indices + ] + uncert_slice = survey.std.reshape((n_channels, n_comps, -1), order=order)[ + :, :, indices + ] + + # For FEM surveys only + if channel is not None: + ind = np.where(np.asarray(survey.frequencies) == channel)[0] + data_slice = data_slice[ind, :, :] + uncert_slice = uncert_slice[ind, :, :] + + new_survey.dobs = data_slice.flatten(order=order) + new_survey.std = uncert_slice.flatten(order=order) + + return new_survey diff --git a/simpeg_drivers/utils/surveys.py b/simpeg_drivers/utils/surveys.py index 992de52d..a1742924 100644 --- a/simpeg_drivers/utils/surveys.py +++ b/simpeg_drivers/utils/surveys.py @@ -143,3 +143,42 @@ def get_unique_locations(survey: BaseSurvey) -> np.ndarray: locations = survey.receiver_locations return np.unique(locations, axis=0) + + +def compute_em_projections(inversion_data, simulation): + """ + Pre-compute projections for the receivers for efficiency. + """ + rx_locs = inversion_data.entity.vertices + projections = {} + for component in "xyz": + projections[component] = simulation.mesh.get_interpolation_matrix( + rx_locs, "faces_" + component[0] + ) + + for source in simulation.survey.source_list: + for receiver in source.receiver_list: + projection = 0.0 + for orientation, comp in zip(receiver.orientation, "xyz", strict=True): + if orientation == 0: + continue + projection += orientation * projections[comp][receiver.local_index, :] + receiver.spatialP = projection + + +def compute_dc_projections(inversion_data, simulation, indices): + """ + Pre-compute projections for the receivers for efficiency. + """ + rx_locs = inversion_data.entity.vertices + mn_pairs = inversion_data.entity.cells + projection = simulation.mesh.get_interpolation_matrix(rx_locs, "nodes") + + for source, ind in zip(simulation.survey.source_list, indices, strict=True): + proj_mn = projection[mn_pairs[ind, 0], :] + + # Check if dipole receiver + if not np.all(mn_pairs[ind, 0] == mn_pairs[ind, 1]): + proj_mn -= projection[mn_pairs[ind, 1], :] + + source.receiver_list[0].spatialP = proj_mn # pylint: disable=protected-access diff --git a/simpeg_drivers/utils/utils.py b/simpeg_drivers/utils/utils.py index 425a2ae4..e326d1ac 100644 --- a/simpeg_drivers/utils/utils.py +++ b/simpeg_drivers/utils/utils.py @@ -34,17 +34,11 @@ from scipy.optimize import linear_sum_assignment from scipy.spatial import ConvexHull, Delaunay, cKDTree from scipy.spatial.distance import cdist -from simpeg.electromagnetics.frequency_domain.sources import ( - LineCurrent as FEMLineCurrent, -) -from simpeg.electromagnetics.time_domain.sources import LineCurrent as TEMLineCurrent from simpeg.survey import BaseSurvey from simpeg_drivers import DRIVER_MAP from simpeg_drivers.utils.surveys import ( compute_alongline_distance, - get_intersecting_cells, - get_unique_locations, ) @@ -141,70 +135,6 @@ def calculate_2D_trend( return data_trend, params -def create_nested_mesh( - survey: BaseSurvey, - base_mesh: TreeMesh, - padding_cells: int = 8, - minimum_level: int = 4, - finalize: bool = True, -): - """ - Create a nested mesh with the same extent as the input global mesh. - Refinement levels are preserved only around the input locations (local survey). - - Parameters - ---------- - - locations: Array of coordinates for the local survey shape(*, 3). - base_mesh: Input global TreeMesh object. - padding_cells: Used for 'method'= 'padding_cells'. Number of cells in each concentric shell. - minimum_level: Minimum octree level to preserve everywhere outside the local survey area. - finalize: Return a finalized local treemesh. - """ - locations = get_unique_locations(survey) - nested_mesh = TreeMesh( - [base_mesh.h[0], base_mesh.h[1], base_mesh.h[2]], - x0=base_mesh.x0, - diagonal_balance=False, - ) - base_level = base_mesh.max_level - minimum_level - base_refinement = base_mesh.cell_levels_by_index(np.arange(base_mesh.nC)) - base_refinement[base_refinement > base_level] = base_level - nested_mesh.insert_cells( - base_mesh.gridCC, - base_refinement, - finalize=False, - ) - base_cell = np.min([base_mesh.h[0][0], base_mesh.h[1][0]]) - tx_loops = [] - for source in survey.source_list: - if isinstance(source, TEMLineCurrent | FEMLineCurrent): - mesh_indices = get_intersecting_cells(source.location, base_mesh) - tx_loops.append(base_mesh.cell_centers[mesh_indices, :]) - - if tx_loops: - locations = np.vstack([locations, *tx_loops]) - - tree = cKDTree(locations[:, :2]) - rad, _ = tree.query(base_mesh.gridCC[:, :2]) - pad_distance = 0.0 - for ii in range(minimum_level): - pad_distance += base_cell * 2**ii * padding_cells - indices = np.where(rad < pad_distance)[0] - levels = base_mesh.cell_levels_by_index(indices) - levels[levels > (base_mesh.max_level - ii)] = base_mesh.max_level - ii - nested_mesh.insert_cells( - base_mesh.gridCC[indices, :], - levels, - finalize=False, - ) - - if finalize: - nested_mesh.finalize() - - return nested_mesh - - def drape_to_octree( octree: Octree, drape_model: DrapeModel | list[DrapeModel], @@ -507,7 +437,7 @@ def xyz_2_drape_model( def tile_locations( - locations: np.ndarray, + locations: BaseSurvey, n_tiles: int, labels: np.ndarray | None = None, ) -> list[np.ndarray]: From b6fed5c0c2f648bfc7615cc8450766e08dd1c67a Mon Sep 17 00:00:00 2001 From: dominiquef Date: Thu, 14 Aug 2025 11:05:14 -0700 Subject: [PATCH 15/56] Rename functions --- .../components/factories/misfit_factory.py | 4 ++-- simpeg_drivers/utils/nested.py | 18 ++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index 47856d4c..9c9e9fb9 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -18,7 +18,7 @@ from simpeg.simulation import BaseSimulation from simpeg_drivers.components.factories.simpeg_factory import SimPEGFactory -from simpeg_drivers.utils.nested import create_nested_misfit +from simpeg_drivers.utils.nested import create_misfit if TYPE_CHECKING: @@ -76,7 +76,7 @@ def assemble_arguments( # pylint: disable=arguments-differ n_split = split_list[misfit_count : misfit_count + len(channels)] futures.append( # executor.submit( - create_nested_misfit( + create_misfit( self.simulation, local_index, channels, diff --git a/simpeg_drivers/utils/nested.py b/simpeg_drivers/utils/nested.py index 71ee18a1..0b44a9a9 100644 --- a/simpeg_drivers/utils/nested.py +++ b/simpeg_drivers/utils/nested.py @@ -26,7 +26,7 @@ from .surveys import get_intersecting_cells, get_unique_locations -def create_nested_mesh( +def create_mesh( survey: BaseSurvey, base_mesh: TreeMesh, padding_cells: int = 8, @@ -90,7 +90,7 @@ def create_nested_mesh( return nested_mesh -def create_nested_misfit( +def create_misfit( simulation, local_index, channels, @@ -101,7 +101,7 @@ def create_nested_misfit( inversion_type, forward_only, ): - local_sim, _ = create_nested_simulation( + local_sim, _ = create_simulation( simulation, None, local_index, @@ -115,7 +115,7 @@ def create_nested_misfit( local_misfits = [] for count, channel in enumerate(channels): for split_ind in np.array_split(local_index, n_split[count]): - local_sim, mapping = create_nested_simulation( + local_sim, mapping = create_simulation( simulation, local_mesh, split_ind, @@ -150,7 +150,7 @@ def create_nested_misfit( return local_misfits, sorting -def create_nested_simulation( +def create_simulation( simulation: BaseSimulation, local_mesh: TreeMesh | None, indices: np.ndarray, @@ -170,12 +170,10 @@ def create_nested_simulation( :param tile_id: Tile id stored on the simulation. :param padding_cells: Number of padding cells around the local survey. """ - local_survey = create_nested_survey( - simulation.survey, indices=indices, channel=channel - ) + local_survey = create_survey(simulation.survey, indices=indices, channel=channel) if local_mesh is None: - local_mesh = create_nested_mesh( + local_mesh = create_mesh( local_survey, simulation.mesh, minimum_level=3, @@ -251,7 +249,7 @@ def create_nested_simulation( return local_sim, mapping -def create_nested_survey(survey, indices, channel=None): +def create_survey(survey, indices, channel=None): """ Extract source and receivers belonging to the indices. """ From e44c9a3210a12fd54c214ae32b11f12dd1f82dd1 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Thu, 14 Aug 2025 14:52:13 -0700 Subject: [PATCH 16/56] Start removing ordering as tensor array. Only reference to the rx locs sorting --- simpeg_drivers/components/data.py | 5 +- .../factories/directives_factory.py | 22 +-- .../components/factories/survey_factory.py | 105 +++---------- simpeg_drivers/driver.py | 15 +- .../electromagnetics/time_domain/driver.py | 87 ----------- simpeg_drivers/joint/driver.py | 2 +- simpeg_drivers/utils/nested.py | 141 +++++++++++++++++- simpeg_drivers/utils/tile_estimate.py | 8 +- simpeg_drivers/utils/utils.py | 70 --------- tests/run_tests/driver_ground_tem_test.py | 3 +- 10 files changed, 182 insertions(+), 276 deletions(-) diff --git a/simpeg_drivers/components/data.py b/simpeg_drivers/components/data.py index ffb2ff34..6fba351b 100644 --- a/simpeg_drivers/components/data.py +++ b/simpeg_drivers/components/data.py @@ -16,7 +16,7 @@ from typing import TYPE_CHECKING, Any import numpy as np -from geoh5py.objects import PotentialElectrode +from geoh5py.objects import LargeLoopGroundTEMReceivers, PotentialElectrode from scipy.sparse import csgraph, csr_matrix from scipy.spatial import cKDTree from simpeg.electromagnetics.static.utils.static_utils import geometric_factor @@ -151,6 +151,9 @@ def parts(self): connections = csgraph.connected_components(edge_array)[1] return connections[self.entity.cells[:, 0]] + if isinstance(self.entity, LargeLoopGroundTEMReceivers): + return self.entity.tx_id_property.values + return getattr(self.entity, "parts", None) def drape_locations(self, locations: np.ndarray) -> np.ndarray: diff --git a/simpeg_drivers/components/factories/directives_factory.py b/simpeg_drivers/components/factories/directives_factory.py index 0bef436f..56df3a01 100644 --- a/simpeg_drivers/components/factories/directives_factory.py +++ b/simpeg_drivers/components/factories/directives_factory.py @@ -181,7 +181,7 @@ def save_iteration_apparent_resistivity_directive(self): ).build( inversion_object=self.driver.inversion_data, active_cells=self.driver.models.active_cells, - sorting=np.argsort(np.hstack(self.driver.sorting)), + sorting=np.argsort(self.driver.sorting), name="Apparent Resistivity", ) return self._save_iteration_apparent_resistivity_directive @@ -224,8 +224,7 @@ def save_iteration_data_directive(self): ).build( inversion_object=self.driver.inversion_data, active_cells=self.driver.models.active_cells, - sorting=np.argsort(np.hstack(self.driver.sorting)), - ordering=self.driver.ordering, + sorting=np.argsort(self.driver.sorting), global_misfit=self.driver.data_misfit, name="Data", ) @@ -266,8 +265,7 @@ def save_iteration_residual_directive(self): ).build( inversion_object=self.driver.inversion_data, active_cells=self.driver.models.active_cells, - sorting=np.argsort(np.hstack(self.driver.sorting)), - ordering=self.driver.ordering, + sorting=np.argsort(self.driver.sorting), name="Residual", ) return self._save_iteration_residual_directive @@ -367,7 +365,6 @@ def assemble_arguments( inversion_object=None, active_cells=None, sorting=None, - ordering=None, transform=None, global_misfit=None, name=None, @@ -387,7 +384,6 @@ def assemble_keyword_arguments( inversion_object=None, active_cells=None, sorting=None, - ordering=None, transform=None, global_misfit=None, name=None, @@ -451,7 +447,6 @@ def assemble_keyword_arguments( inversion_object=None, active_cells=None, sorting=None, - ordering=None, transform=None, global_misfit=None, name=None, @@ -499,7 +494,6 @@ def assemble_keyword_arguments( inversion_object=None, active_cells=None, sorting=None, - ordering=None, transform=None, global_misfit=None, name=None, @@ -516,7 +510,6 @@ def assemble_keyword_arguments( inversion_object=inversion_object, active_cells=active_cells, sorting=sorting, - ordering=ordering, transform=transform, global_misfit=global_misfit, name=name, @@ -667,7 +660,6 @@ def assemble_data_keywords_em( inversion_object=None, active_cells=None, sorting=None, - ordering=None, transform=None, global_misfit=None, name=None, @@ -675,14 +667,10 @@ def assemble_data_keywords_em( receivers = inversion_object.entity channels = np.array(receivers.channels, dtype=float) components = list(inversion_object.observed) - ordering = np.vstack(ordering) - channel_ids = ordering[:, 0] - component_ids = ordering[:, 1] - rx_ids = ordering[:, 2] + order = "F" if hasattr(receivers, "frequencies") else "C" def reshape(values): - data = np.zeros((len(channels), len(components), receivers.n_vertices)) - data[channel_ids, component_ids, rx_ids] = values + data = values.reshape((len(channels), len(components), -1), order=order) return data kwargs = { diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index e1b384b4..2dbc3901 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -93,12 +93,7 @@ def assemble_arguments(self, data=None): ) sources = SourcesFactory(self.params).build(receivers=receivers) n_rx = data.locations.shape[0] - n_comp = len(data.components) - self.ordering = np.c_[ - np.zeros(n_rx * n_comp), # Single channel - np.kron(np.ones(n_rx), np.arange(n_comp)), # Components - np.kron(np.arange(n_rx), np.ones(n_comp)), # Receivers - ].astype(int) + self.ordering = np.arange(n_rx).astype(int) return [sources] @@ -109,21 +104,23 @@ def assemble_keyword_arguments(self, **_): def build( self, data=None, - channel=None, ): """Overloads base method to add dobs, std attributes to survey class instance.""" survey = super().build( data=data, ) - + survey.n_channels = len( + data.normalizations + ) # Either time channels or frequencies + survey.n_components = len(data.components) if not self.params.forward_only: - self._add_data(survey, data, channel) + self._add_data(survey, data) survey.dummy = self.dummy return survey - def _add_data(self, survey, data, channel): + def _add_data(self, survey, data): data_stack = np.dstack( [np.vstack(list(k.values())) for k in data.observed.values()] ).transpose((0, 2, 1)) @@ -132,12 +129,9 @@ def _add_data(self, survey, data, channel): ).transpose((0, 2, 1)) # Flatten in the order of the channel, component, receiver - data_vec = data_stack[ - self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] - ] - uncertainty_vec = uncert_stack[ - self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] - ] + order = "C" if hasattr(survey, "frequencies") else "F" + data_vec = data_stack[:, :, self.ordering].flatten(order=order) + uncertainty_vec = uncert_stack[:, :, self.ordering].flatten(order=order) uncertainty_vec[np.isnan(data_vec)] = np.inf data_vec[np.isnan(data_vec)] = self.dummy # Nan's handled by inf uncertainties survey.dobs = data_vec @@ -189,11 +183,7 @@ def _dcip_arguments(self, data=None): ) sources.append(source) - self.ordering = np.c_[ - np.zeros(receiver_entity.n_cells), # Single channel - np.zeros(receiver_entity.n_cells), # Single component - np.hstack(ordering), # Multi-receivers - ].astype(int) + self.ordering = np.hstack(ordering).astype(int) return [sources] @@ -253,7 +243,6 @@ def _tdem_arguments(self, data=None): waveform_function=wave_function, offTime=0.0 ) - ordering = [] tx_list = [] rx_factory = ReceiversFactory(self.params) tx_factory = SourcesFactory(self.params) @@ -262,7 +251,7 @@ def _tdem_arguments(self, data=None): locs = receivers.vertices[rx_ids, :] rx_list = [] - for component_id, component in enumerate(data.components): + for component in data.components: rx_obj = rx_factory.build( locations=locs, data=data, @@ -271,26 +260,15 @@ def _tdem_arguments(self, data=None): rx_obj.local_index = rx_ids rx_list.append(rx_obj) - n_times = len(receivers.channels) - n_rx = len(rx_ids) if isinstance(rx_ids, list) else 1 - ordering.append( - np.c_[ - np.kron(np.arange(n_times), np.ones(n_rx)), - np.ones(n_times * n_rx) * component_id, - np.kron(np.ones(n_times), np.asarray(rx_ids)), - ] - ) - tx_list.append( tx_factory.build(rx_list, locations=cur_tx_locs, waveform=waveform) ) - self.ordering = np.vstack(ordering).astype(int) + self.ordering = np.hstack(rx_lookup).astype(int) return [tx_list] - def _fem_arguments(self, data=None, channel=None): + def _fem_arguments(self, data=None): channels = np.array(data.entity.channels) - frequencies = channels if channel is None else [channel] rx_locs = data.entity.vertices tx_locs = data.entity.transmitters.vertices freqs = data.entity.transmitters.workspace.get_entity("Tx frequency")[0] @@ -301,10 +279,10 @@ def _fem_arguments(self, data=None, channel=None): tx_factory = SourcesFactory(self.params) receiver_groups = {} - block_ordering = [] + for receiver_id, locs in enumerate(rx_locs): receivers = [] - for component_id, component in enumerate(data.components): + for component in data.components: receiver = rx_factory.build( locations=locs, data=data, @@ -313,23 +291,10 @@ def _fem_arguments(self, data=None, channel=None): receiver.local_index = receiver_id receivers.append(receiver) - block_ordering.append([component_id, receiver_id]) - receiver_groups[receiver_id] = receivers - - block_ordering = np.vstack(block_ordering) - ordering = [] - for frequency in frequencies: - frequency_id = np.where(frequency == channels)[0][0] - ordering.append( - np.hstack( - [ - np.ones((block_ordering.shape[0], 1)) * frequency_id, - block_ordering, - ] - ) - ) + receiver_groups[receiver_id] = receivers + for frequency in channels: for receiver_id, receivers in receiver_groups.items(): locs = tx_locs[frequency == freqs, :][receiver_id, :] sources.append( @@ -340,11 +305,11 @@ def _fem_arguments(self, data=None, channel=None): ) ) - self.ordering = np.vstack(ordering).astype(int) + self.ordering = np.arange(rx_locs.shape[0], dtype=int) return [sources] - def _naturalsource_arguments(self, data=None, frequency=None): + def _naturalsource_arguments(self, data=None): simpeg_mt_translate = { "zxx_real": "zyy_real", "zxx_imag": "zyy_imag", @@ -359,9 +324,8 @@ def _naturalsource_arguments(self, data=None, frequency=None): sources = [] rx_factory = ReceiversFactory(self.params) tx_factory = SourcesFactory(self.params) - block_ordering = [] - channels = np.array(data.entity.channels) - for component_id, comp in enumerate(data.components): + + for comp in data.components: receivers.append( rx_factory.build( locations=data.locations, @@ -370,30 +334,9 @@ def _naturalsource_arguments(self, data=None, frequency=None): ) ) - n_locs = data.locations.shape[0] - block_ordering.append( - np.c_[np.ones(n_locs) * component_id, np.arange(n_locs)] - ) - - block_ordering = np.vstack(block_ordering) - ordering = [] - if frequency is None: - frequencies = channels - else: - frequencies = [frequency] if not isinstance(frequency, list) else frequency - - for frequency in frequencies: + for frequency in data.entity.channels: sources.append(tx_factory.build(receivers, frequency=frequency)) - frequency_id = np.where(frequency == channels)[0][0] - ordering.append( - np.hstack( - [ - np.ones((block_ordering.shape[0], 1)) * frequency_id, - block_ordering, - ] - ) - ) - self.ordering = np.vstack(ordering).astype(int) + self.ordering = np.arange(data.locations.shape[0]).astype(int) return [sources] diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 8cff0d4b..f55ed45d 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -76,7 +76,7 @@ BaseInversionOptions, ) from simpeg_drivers.joint.options import BaseJointOptions -from simpeg_drivers.utils.utils import tile_locations +from simpeg_drivers.utils.nested import tile_locations from simpeg_drivers.utils.regularization import cell_neighbors, set_rotated_operators mlogger = logging.getLogger("distributed") @@ -400,9 +400,13 @@ def simulation(self): return self._simulation @property - def sorting(self): - """List of arrays for sorting of data from tiles.""" - return self._sorting + def sorting(self) -> np.ndarray: + """ + Arrays for sorting of data from tile, taking into account the + ordering of the survey. + """ + sorting = np.hstack(self._sorting) + return self.inversion_data.survey.ordering[sorting] @property def window(self): @@ -623,9 +627,10 @@ def get_tiles(self): return np.arange(self.inversion_data.mask.sum()).reshape((-1, 1)) return tile_locations( - self.simulation.survey, + self.inversion_data.locations, self.params.compute.tile_spatial, labels=self.inversion_data.parts, + sorting=self.simulation.survey.ordering, ) def configure_dask(self): diff --git a/simpeg_drivers/electromagnetics/time_domain/driver.py b/simpeg_drivers/electromagnetics/time_domain/driver.py index c77c5e6c..e790e0c4 100644 --- a/simpeg_drivers/electromagnetics/time_domain/driver.py +++ b/simpeg_drivers/electromagnetics/time_domain/driver.py @@ -17,7 +17,6 @@ ) from simpeg_drivers.driver import InversionDriver -from simpeg_drivers.utils.utils import tile_locations from .options import ( TDEMForwardOptions, @@ -25,101 +24,15 @@ ) -def tile_large_group_transmitters( - survey: LargeLoopGroundTEMReceivers, n_tiles: int -) -> list[np.ndarray]: - """ - Tile the data based on the transmitters center locations. - - :param survey: LargeLoopGroundTEMReceivers object. - :param n_tiles: Number of tiles. - - :return: List of numpy arrays containing the indices of the receivers in each tile. - """ - if not isinstance(survey, LargeLoopGroundTEMReceivers): - raise TypeError("Data object must be of type LargeLoopGroundTEMReceivers") - - tx_ids = survey.transmitters.tx_id_property.values - unique_tile_ids = np.unique(tx_ids) - n_groups = np.min([len(unique_tile_ids), n_tiles]) - locations = [] - for uid in unique_tile_ids: - locations.append( - np.mean( - survey.transmitters.vertices[tx_ids == uid], - axis=0, - ) - ) - - # Tile transmitters spatially by loop center - tx_tiles = tile_locations( - np.vstack(locations), - n_groups, - ) - receivers_tx_ids = survey.tx_id_property.values - tiles = [] - for _t_id, group in enumerate(tx_tiles): - sub_group = [] - for value in group: - receiver_ind = receivers_tx_ids == unique_tile_ids[value] - sub_group.append(np.where(receiver_ind)[0]) - - tiles.append(np.hstack(sub_group)) - - # If number of tiles remaining, brake up receivers spatially per transmitter - while len(tiles) < n_tiles: - largest_group = np.argmax([len(tile) for tile in tiles]) - tile = tiles.pop(largest_group) - new_tiles = tile_locations( - survey.vertices[tile], - 2, - ) - tiles += [tile[new_tiles[0]], tile[new_tiles[1]]] - - return tiles - - class TDEMForwardDriver(InversionDriver): """Time Domain Electromagnetic forward driver.""" _options_class = TDEMForwardOptions _validations = None - def get_tiles(self) -> list[np.ndarray]: - """ - Special method to tile the data based on the transmitters center locations. - - First the transmitter locations are grouped into groups using kmeans clustering. - Second, if the number of groups is less than the number of 'tile_spatial' value, the groups are - further divided into groups based on the clustering of receiver locations. - """ - if not isinstance(self.params.data_object, LargeLoopGroundTEMReceivers): - return super().get_tiles() - - return tile_large_group_transmitters( - self.params.data_object, - self.params.compute.tile_spatial, - ) - class TDEMInversionDriver(InversionDriver): """Time Domain Electromagnetic inversion driver.""" _options_class = TDEMInversionOptions _validations = None - - def get_tiles(self) -> list[np.ndarray]: - """ - Special method to tile the data based on the transmitters center locations. - - First the transmitter locations are grouped into groups using kmeans clustering. - Second, if the number of groups is less than the number of 'tile_spatial' value, the groups are - further divided into groups based on the clustering of receiver locations. - """ - if not isinstance(self.params.data_object, LargeLoopGroundTEMReceivers): - return super().get_tiles() - - return tile_large_group_transmitters( - self.params.data_object, - self.params.compute.tile_spatial, - ) diff --git a/simpeg_drivers/joint/driver.py b/simpeg_drivers/joint/driver.py index 16f162ac..0b5c32db 100644 --- a/simpeg_drivers/joint/driver.py +++ b/simpeg_drivers/joint/driver.py @@ -239,7 +239,7 @@ def run(self): for sub, driver in zip(predicted, self.drivers, strict=True): SaveDataGeoh5Factory(driver.params).build( inversion_object=driver.inversion_data, - sorting=np.argsort(np.hstack(driver.sorting)), + sorting=np.argsort(driver.sorting), ordering=driver.ordering, ).write(0, sub) else: diff --git a/simpeg_drivers/utils/nested.py b/simpeg_drivers/utils/nested.py index 0b44a9a9..c06edd32 100644 --- a/simpeg_drivers/utils/nested.py +++ b/simpeg_drivers/utils/nested.py @@ -9,12 +9,15 @@ # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' from __future__ import annotations +import warnings from copy import copy from pathlib import Path import numpy as np from discretize import TreeMesh +from scipy.optimize import linear_sum_assignment from scipy.spatial import cKDTree +from scipy.spatial.distance import cdist from simpeg import data, data_misfit, maps, meta from simpeg.electromagnetics.frequency_domain.sources import ( LineCurrent as FEMLineCurrent, @@ -297,15 +300,13 @@ def create_survey(survey, indices, channel=None): new_survey = type(survey)(sources) if hasattr(survey, "dobs") and survey.dobs is not None: - n_channels = len(np.unique(survey.ordering[:, 0])) - n_comps = len(np.unique(survey.ordering[:, 1])) order = "C" if hasattr(survey, "frequencies") else "F" - data_slice = survey.dobs.reshape((n_channels, n_comps, -1), order=order)[ - :, :, indices - ] - uncert_slice = survey.std.reshape((n_channels, n_comps, -1), order=order)[ - :, :, indices - ] + data_slice = survey.dobs.reshape( + (survey.n_channels, survey.n_components, -1), order=order + )[:, :, indices] + uncert_slice = survey.std.reshape( + (survey.n_channels, survey.n_components, -1), order=order + )[:, :, indices] # For FEM surveys only if channel is not None: @@ -317,3 +318,127 @@ def create_survey(survey, indices, channel=None): new_survey.std = uncert_slice.flatten(order=order) return new_survey + + +def tile_locations( + locations: np.ndarray, + n_tiles: int, + labels: np.ndarray | None = None, + sorting: np.ndarray | None = None, +) -> list[np.ndarray]: + """ + Function to tile a survey points into smaller square subsets of points using + a k-means clustering approach. + + If labels are provided and the number of unique labels is less than or equal to + the number of tiles, the function will return an even split of the unique labels. + + :param locations: Array of locations. + :param n_tiles: Number of tiles (for 'cluster') + :param labels: Array of values to append to the locations + + :return: List of arrays containing the indices of the points in each tile. + """ + grid_locs = locations[:, :2].copy() + + if labels is not None: + if len(labels) != grid_locs.shape[0]: + raise ValueError( + "Labels array must have the same length as the locations array." + ) + + if len(np.unique(labels)) >= n_tiles: + label_groups = np.array_split(np.unique(labels), n_tiles) + return [np.where(np.isin(labels, group))[0] for group in label_groups] + + # Normalize location coordinates to [0, 1] range + grid_locs -= grid_locs.min(axis=0) + max_val = grid_locs.max(axis=0) + grid_locs[:, max_val > 0] /= max_val[max_val > 0] + grid_locs = np.c_[grid_locs, labels] + + if sorting is not None: + grid_locs = grid_locs[sorting, :] + + # Cluster + # TODO turn off filter once sklearn has dealt with the issue causing the warning + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=UserWarning) + from sklearn.cluster import KMeans + + kmeans = KMeans(n_clusters=n_tiles, random_state=0, n_init="auto") + cluster_size = int(np.ceil(grid_locs.shape[0] / n_tiles)) + kmeans.fit(grid_locs) + + if labels is not None: + cluster_id = kmeans.labels_ + else: + # Redistribute cluster centers to even out the number of points + centers = kmeans.cluster_centers_ + centers = ( + centers.reshape(-1, 1, grid_locs.shape[1]) + .repeat(cluster_size, 1) + .reshape(-1, grid_locs.shape[1]) + ) + distance_matrix = cdist(grid_locs, centers) + cluster_id = linear_sum_assignment(distance_matrix)[1] // cluster_size + + tiles = [] + for tid in set(cluster_id): + tiles += [np.where(cluster_id == tid)[0]] + + return tiles + + +# def tile_large_group_transmitters( +# survey: LargeLoopGroundTEMReceivers, n_tiles: int +# ) -> list[np.ndarray]: +# """ +# Tile the data based on the transmitters center locations. +# +# :param survey: LargeLoopGroundTEMReceivers object. +# :param n_tiles: Number of tiles. +# +# :return: List of numpy arrays containing the indices of the receivers in each tile. +# """ +# if not isinstance(survey, LargeLoopGroundTEMReceivers): +# raise TypeError("Data object must be of type LargeLoopGroundTEMReceivers") +# +# tx_ids = survey.transmitters.tx_id_property.values +# unique_tile_ids = np.unique(tx_ids) +# n_groups = np.min([len(unique_tile_ids), n_tiles]) +# locations = [] +# for uid in unique_tile_ids: +# locations.append( +# np.mean( +# survey.transmitters.vertices[tx_ids == uid], +# axis=0, +# ) +# ) +# +# # Tile transmitters spatially by loop center +# tx_tiles = tile_locations( +# np.vstack(locations), +# n_groups, +# ) +# receivers_tx_ids = survey.tx_id_property.values +# tiles = [] +# for _t_id, group in enumerate(tx_tiles): +# sub_group = [] +# for value in group: +# receiver_ind = receivers_tx_ids == unique_tile_ids[value] +# sub_group.append(np.where(receiver_ind)[0]) +# +# tiles.append(np.hstack(sub_group)) +# +# # If number of tiles remaining, brake up receivers spatially per transmitter +# while len(tiles) < n_tiles: +# largest_group = np.argmax([len(tile) for tile in tiles]) +# tile = tiles.pop(largest_group) +# new_tiles = tile_locations( +# survey.vertices[tile], +# 2, +# ) +# tiles += [tile[new_tiles[0]], tile[new_tiles[1]]] +# +# return tiles diff --git a/simpeg_drivers/utils/tile_estimate.py b/simpeg_drivers/utils/tile_estimate.py index 59becb23..241d9044 100644 --- a/simpeg_drivers/utils/tile_estimate.py +++ b/simpeg_drivers/utils/tile_estimate.py @@ -38,10 +38,10 @@ from simpeg_drivers.components.data import InversionData from simpeg_drivers.components.factories.misfit_factory import MisfitFactory from simpeg_drivers.driver import InversionDriver +from simpeg_drivers.utils.nested import create_simulation, tile_locations from simpeg_drivers.utils.utils import ( active_from_xyz, simpeg_group_to_driver, - tile_locations, ) @@ -100,11 +100,9 @@ def get_results(self, max_tiles: int = 13) -> dict: # Get the median tile ind = int(np.argsort([len(tile) for tile in tiles])[int(count / 2)]) self.driver.params.compute.tile_spatial = int(count) - sim, _, _, mapping = MisfitFactory.create_nested_simulation( - self.driver.inversion_data, - self.driver.inversion_mesh, + sim, _, _, mapping = create_simulation( + self.driver.simulation, None, - self.active_cells, tiles[ind], tile_id=ind, padding_cells=self.driver.params.padding_cells, diff --git a/simpeg_drivers/utils/utils.py b/simpeg_drivers/utils/utils.py index e326d1ac..11c87a79 100644 --- a/simpeg_drivers/utils/utils.py +++ b/simpeg_drivers/utils/utils.py @@ -11,7 +11,6 @@ from __future__ import annotations -import warnings from copy import deepcopy from typing import TYPE_CHECKING from uuid import UUID @@ -31,10 +30,7 @@ from geoh5py.ui_json import InputFile from octree_creation_app.utils import octree_2_treemesh from scipy.interpolate import LinearNDInterpolator, NearestNDInterpolator, interp1d -from scipy.optimize import linear_sum_assignment from scipy.spatial import ConvexHull, Delaunay, cKDTree -from scipy.spatial.distance import cdist -from simpeg.survey import BaseSurvey from simpeg_drivers import DRIVER_MAP from simpeg_drivers.utils.surveys import ( @@ -436,72 +432,6 @@ def xyz_2_drape_model( return model -def tile_locations( - locations: BaseSurvey, - n_tiles: int, - labels: np.ndarray | None = None, -) -> list[np.ndarray]: - """ - Function to tile a survey points into smaller square subsets of points using - a k-means clustering approach. - - If labels are provided and the number of unique labels is less than or equal to - the number of tiles, the function will return an even split of the unique labels. - - :param locations: Array of locations. - :param n_tiles: Number of tiles (for 'cluster') - :param labels: Array of values to append to the locations - - :return: List of arrays containing the indices of the points in each tile. - """ - grid_locs = locations[:, :2].copy() - - if labels is not None: - if len(labels) != grid_locs.shape[0]: - raise ValueError( - "Labels array must have the same length as the locations array." - ) - - if len(np.unique(labels)) >= n_tiles: - label_groups = np.array_split(np.unique(labels), n_tiles) - return [np.where(np.isin(labels, group))[0] for group in label_groups] - - # Normalize location coordinates to [0, 1] range - grid_locs -= grid_locs.min(axis=0) - max_val = grid_locs.max(axis=0) - grid_locs[:, max_val > 0] /= max_val[max_val > 0] - grid_locs = np.c_[grid_locs, labels] - - # Cluster - # TODO turn off filter once sklearn has dealt with the issue causing the warning - with warnings.catch_warnings(): - warnings.simplefilter("ignore", category=UserWarning) - from sklearn.cluster import KMeans - - kmeans = KMeans(n_clusters=n_tiles, random_state=0, n_init="auto") - cluster_size = int(np.ceil(grid_locs.shape[0] / n_tiles)) - kmeans.fit(grid_locs) - - if labels is not None: - cluster_id = kmeans.labels_ - else: - # Redistribute cluster centers to even out the number of points - centers = kmeans.cluster_centers_ - centers = ( - centers.reshape(-1, 1, grid_locs.shape[1]) - .repeat(cluster_size, 1) - .reshape(-1, grid_locs.shape[1]) - ) - distance_matrix = cdist(grid_locs, centers) - cluster_id = linear_sum_assignment(distance_matrix)[1] // cluster_size - - tiles = [] - for tid in set(cluster_id): - tiles += [np.where(cluster_id == tid)[0]] - - return tiles - - def get_containing_cells( mesh: TreeMesh | TensorMesh, data: InversionData ) -> np.ndarray: diff --git a/tests/run_tests/driver_ground_tem_test.py b/tests/run_tests/driver_ground_tem_test.py index 33783acc..ca66054c 100644 --- a/tests/run_tests/driver_ground_tem_test.py +++ b/tests/run_tests/driver_ground_tem_test.py @@ -81,7 +81,8 @@ def test_tiling_ground_tem( ) fwr_driver = TDEMForwardDriver(params) - tiles = fwr_driver.get_tiles() + with geoh5.open(): + tiles = fwr_driver.get_tiles() assert len(tiles) == 4 From 303f164ff09768c7209c805e8d0ea4912941e36b Mon Sep 17 00:00:00 2001 From: dominiquef Date: Thu, 14 Aug 2025 15:33:14 -0700 Subject: [PATCH 17/56] Fix TEM --- simpeg_drivers/components/factories/directives_factory.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/simpeg_drivers/components/factories/directives_factory.py b/simpeg_drivers/components/factories/directives_factory.py index 56df3a01..d90232b8 100644 --- a/simpeg_drivers/components/factories/directives_factory.py +++ b/simpeg_drivers/components/factories/directives_factory.py @@ -667,10 +667,9 @@ def assemble_data_keywords_em( receivers = inversion_object.entity channels = np.array(receivers.channels, dtype=float) components = list(inversion_object.observed) - order = "F" if hasattr(receivers, "frequencies") else "C" def reshape(values): - data = values.reshape((len(channels), len(components), -1), order=order) + data = values.reshape((len(channels), len(components), -1), order="F") return data kwargs = { From 0adbbcbc8edccabeeb3bcf388eabc9e6c5c1d295 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Thu, 14 Aug 2025 15:46:40 -0700 Subject: [PATCH 18/56] Re-lock --- .../py-3.10-linux-64-dev.conda.lock.yml | 10 ++--- environments/py-3.10-linux-64.conda.lock.yml | 10 ++--- .../py-3.10-win-64-dev.conda.lock.yml | 10 ++--- environments/py-3.10-win-64.conda.lock.yml | 10 ++--- .../py-3.11-linux-64-dev.conda.lock.yml | 10 ++--- environments/py-3.11-linux-64.conda.lock.yml | 10 ++--- .../py-3.11-win-64-dev.conda.lock.yml | 10 ++--- environments/py-3.11-win-64.conda.lock.yml | 10 ++--- .../py-3.12-linux-64-dev.conda.lock.yml | 10 ++--- environments/py-3.12-linux-64.conda.lock.yml | 10 ++--- .../py-3.12-win-64-dev.conda.lock.yml | 10 ++--- environments/py-3.12-win-64.conda.lock.yml | 10 ++--- py-3.10.conda-lock.yml | 42 ++++++++++--------- py-3.11.conda-lock.yml | 42 ++++++++++--------- py-3.12.conda-lock.yml | 42 ++++++++++--------- 15 files changed, 126 insertions(+), 120 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 7a678dd4..ea7eac8e 100644 --- a/environments/py-3.10-linux-64-dev.conda.lock.yml +++ b/environments/py-3.10-linux-64-dev.conda.lock.yml @@ -304,11 +304,11 @@ dependencies: - zstandard=0.23.0=py310ha75aee5_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 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 78e76be7..48d364f7 100644 --- a/environments/py-3.10-linux-64.conda.lock.yml +++ b/environments/py-3.10-linux-64.conda.lock.yml @@ -156,11 +156,11 @@ dependencies: - zstandard=0.23.0=py310ha75aee5_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 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 26fc5b79..94c6efef 100644 --- a/environments/py-3.10-win-64-dev.conda.lock.yml +++ b/environments/py-3.10-win-64-dev.conda.lock.yml @@ -294,11 +294,11 @@ dependencies: - zstandard=0.23.0=py310ha8f682b_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 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 921ebe29..89dd5d1b 100644 --- a/environments/py-3.10-win-64.conda.lock.yml +++ b/environments/py-3.10-win-64.conda.lock.yml @@ -144,11 +144,11 @@ dependencies: - zstandard=0.23.0=py310ha8f682b_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 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 48121094..54247094 100644 --- a/environments/py-3.11-linux-64-dev.conda.lock.yml +++ b/environments/py-3.11-linux-64-dev.conda.lock.yml @@ -307,11 +307,11 @@ dependencies: - zstandard=0.23.0=py311h9ecbd09_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 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 6a20c3fa..0f0e39a0 100644 --- a/environments/py-3.11-linux-64.conda.lock.yml +++ b/environments/py-3.11-linux-64.conda.lock.yml @@ -158,11 +158,11 @@ dependencies: - zstandard=0.23.0=py311h9ecbd09_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 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 bcbaa726..c063f6ba 100644 --- a/environments/py-3.11-win-64-dev.conda.lock.yml +++ b/environments/py-3.11-win-64-dev.conda.lock.yml @@ -297,11 +297,11 @@ dependencies: - zstandard=0.23.0=py311he736701_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 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 6a88ffb4..0b73b9b0 100644 --- a/environments/py-3.11-win-64.conda.lock.yml +++ b/environments/py-3.11-win-64.conda.lock.yml @@ -146,11 +146,11 @@ dependencies: - zstandard=0.23.0=py311he736701_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 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 ee5b4509..ca01ff72 100644 --- a/environments/py-3.12-linux-64-dev.conda.lock.yml +++ b/environments/py-3.12-linux-64-dev.conda.lock.yml @@ -307,11 +307,11 @@ dependencies: - zstandard=0.23.0=py312h66e93f0_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 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 48a2b80c..ba1eaff3 100644 --- a/environments/py-3.12-linux-64.conda.lock.yml +++ b/environments/py-3.12-linux-64.conda.lock.yml @@ -158,11 +158,11 @@ dependencies: - zstandard=0.23.0=py312h66e93f0_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 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 e04200b8..f7205c36 100644 --- a/environments/py-3.12-win-64-dev.conda.lock.yml +++ b/environments/py-3.12-win-64-dev.conda.lock.yml @@ -297,11 +297,11 @@ dependencies: - zstandard=0.23.0=py312h4389bb4_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 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 6eab8e5f..1ad58ef1 100644 --- a/environments/py-3.12-win-64.conda.lock.yml +++ b/environments/py-3.12-win-64.conda.lock.yml @@ -146,11 +146,11 @@ dependencies: - zstandard=0.23.0=py312h4389bb4_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 variables: KMP_WARNINGS: 0 diff --git a/py-3.10.conda-lock.yml b/py-3.10.conda-lock.yml index 32fb32f6..75934e22 100644 --- a/py-3.10.conda-lock.yml +++ b/py-3.10.conda-lock.yml @@ -6011,6 +6011,7 @@ package: libzlib: '>=1.3.1,<2.0a0' ncurses: '>=6.5,<7.0a0' openssl: '>=3.5.0,<4.0a0' + pip: '' readline: '>=8.2,<9.0a0' tk: '>=8.6.13,<8.7.0a0' tzdata: '' @@ -6032,6 +6033,7 @@ package: libsqlite: '>=3.50.0,<4.0a0' libzlib: '>=1.3.1,<2.0a0' openssl: '>=3.5.0,<4.0a0' + pip: '' tk: '>=8.6.13,<8.7.0a0' tzdata: '' ucrt: '>=10.0.20348.0' @@ -8528,12 +8530,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f hash: - sha256: 1dbe97d441d65962a94e071b5c1c27d9facd2050 + sha256: d0d3ced2e3f84109ee49270adb936f42b490d99f source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f category: main optional: false - name: geoapps-utils @@ -8545,12 +8547,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f hash: - sha256: 1dbe97d441d65962a94e071b5c1c27d9facd2050 + sha256: d0d3ced2e3f84109ee49270adb936f42b490d99f source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f category: main optional: false - name: geoh5py @@ -8562,12 +8564,12 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.5.2,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 hash: - sha256: 570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + sha256: cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 category: main optional: false - name: geoh5py @@ -8579,16 +8581,16 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.5.2,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 hash: - sha256: 570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + sha256: cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 category: main optional: false - name: mira-simpeg - version: 0.23.0.1.post2.dev39+gd0311c252 + version: 0.23.0.1.post2.dev42+g26cae9aae manager: pip platform: linux-64 dependencies: @@ -8600,16 +8602,16 @@ package: numpy: '>=1.22' pymatsolver: '>=0.3' scipy: '>=1.8' - url: git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 + url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 hash: - sha256: d0311c2528658b0dcd70d6491ba53bf7c8288946 + sha256: 26cae9aae7018fa4da8b1132138d2beff9fc5a91 source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 + url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 category: main optional: false - name: mira-simpeg - version: 0.23.0.1.post2.dev39+gd0311c252 + version: 0.23.0.1.post2.dev42+g26cae9aae manager: pip platform: win-64 dependencies: @@ -8621,12 +8623,12 @@ package: numpy: '>=1.22' pymatsolver: '>=0.3' scipy: '>=1.8' - url: git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 + url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 hash: - sha256: d0311c2528658b0dcd70d6491ba53bf7c8288946 + sha256: 26cae9aae7018fa4da8b1132138d2beff9fc5a91 source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 + url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 category: main optional: false - name: octree-creation-app diff --git a/py-3.11.conda-lock.yml b/py-3.11.conda-lock.yml index 857c5344..97c793cd 100644 --- a/py-3.11.conda-lock.yml +++ b/py-3.11.conda-lock.yml @@ -6065,6 +6065,7 @@ package: libzlib: '>=1.3.1,<2.0a0' ncurses: '>=6.5,<7.0a0' openssl: '>=3.5.0,<4.0a0' + pip: '' readline: '>=8.2,<9.0a0' tk: '>=8.6.13,<8.7.0a0' tzdata: '' @@ -6086,6 +6087,7 @@ package: libsqlite: '>=3.50.0,<4.0a0' libzlib: '>=1.3.1,<2.0a0' openssl: '>=3.5.0,<4.0a0' + pip: '' tk: '>=8.6.13,<8.7.0a0' tzdata: '' ucrt: '>=10.0.20348.0' @@ -8613,12 +8615,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f hash: - sha256: 1dbe97d441d65962a94e071b5c1c27d9facd2050 + sha256: d0d3ced2e3f84109ee49270adb936f42b490d99f source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f category: main optional: false - name: geoapps-utils @@ -8630,12 +8632,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f hash: - sha256: 1dbe97d441d65962a94e071b5c1c27d9facd2050 + sha256: d0d3ced2e3f84109ee49270adb936f42b490d99f source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f category: main optional: false - name: geoh5py @@ -8647,12 +8649,12 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.5.2,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 hash: - sha256: 570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + sha256: cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 category: main optional: false - name: geoh5py @@ -8664,16 +8666,16 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.5.2,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 hash: - sha256: 570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + sha256: cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 category: main optional: false - name: mira-simpeg - version: 0.23.0.1.post2.dev39+gd0311c252 + version: 0.23.0.1.post2.dev42+g26cae9aae manager: pip platform: linux-64 dependencies: @@ -8685,16 +8687,16 @@ package: numpy: '>=1.22' pymatsolver: '>=0.3' scipy: '>=1.8' - url: git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 + url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 hash: - sha256: d0311c2528658b0dcd70d6491ba53bf7c8288946 + sha256: 26cae9aae7018fa4da8b1132138d2beff9fc5a91 source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 + url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 category: main optional: false - name: mira-simpeg - version: 0.23.0.1.post2.dev39+gd0311c252 + version: 0.23.0.1.post2.dev42+g26cae9aae manager: pip platform: win-64 dependencies: @@ -8706,12 +8708,12 @@ package: numpy: '>=1.22' pymatsolver: '>=0.3' scipy: '>=1.8' - url: git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 + url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 hash: - sha256: d0311c2528658b0dcd70d6491ba53bf7c8288946 + sha256: 26cae9aae7018fa4da8b1132138d2beff9fc5a91 source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 + url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 category: main optional: false - name: octree-creation-app diff --git a/py-3.12.conda-lock.yml b/py-3.12.conda-lock.yml index 4b889815..206ed28a 100644 --- a/py-3.12.conda-lock.yml +++ b/py-3.12.conda-lock.yml @@ -6065,6 +6065,7 @@ package: libzlib: '>=1.3.1,<2.0a0' ncurses: '>=6.5,<7.0a0' openssl: '>=3.5.0,<4.0a0' + pip: '' readline: '>=8.2,<9.0a0' tk: '>=8.6.13,<8.7.0a0' tzdata: '' @@ -6086,6 +6087,7 @@ package: libsqlite: '>=3.50.0,<4.0a0' libzlib: '>=1.3.1,<2.0a0' openssl: '>=3.5.0,<4.0a0' + pip: '' tk: '>=8.6.13,<8.7.0a0' tzdata: '' ucrt: '>=10.0.20348.0' @@ -8613,12 +8615,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f hash: - sha256: 1dbe97d441d65962a94e071b5c1c27d9facd2050 + sha256: d0d3ced2e3f84109ee49270adb936f42b490d99f source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f category: main optional: false - name: geoapps-utils @@ -8630,12 +8632,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f hash: - sha256: 1dbe97d441d65962a94e071b5c1c27d9facd2050 + sha256: d0d3ced2e3f84109ee49270adb936f42b490d99f source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@1dbe97d441d65962a94e071b5c1c27d9facd2050 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f category: main optional: false - name: geoh5py @@ -8647,12 +8649,12 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.5.2,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 hash: - sha256: 570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + sha256: cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 category: main optional: false - name: geoh5py @@ -8664,16 +8666,16 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.5.2,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 hash: - sha256: 570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + sha256: cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@570ea996ae7e48ab1b8b971b23c9c73b7f5637b2 + url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 category: main optional: false - name: mira-simpeg - version: 0.23.0.1.post2.dev39+gd0311c252 + version: 0.23.0.1.post2.dev42+g26cae9aae manager: pip platform: linux-64 dependencies: @@ -8685,16 +8687,16 @@ package: numpy: '>=1.22' pymatsolver: '>=0.3' scipy: '>=1.8' - url: git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 + url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 hash: - sha256: d0311c2528658b0dcd70d6491ba53bf7c8288946 + sha256: 26cae9aae7018fa4da8b1132138d2beff9fc5a91 source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 + url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 category: main optional: false - name: mira-simpeg - version: 0.23.0.1.post2.dev39+gd0311c252 + version: 0.23.0.1.post2.dev42+g26cae9aae manager: pip platform: win-64 dependencies: @@ -8706,12 +8708,12 @@ package: numpy: '>=1.22' pymatsolver: '>=0.3' scipy: '>=1.8' - url: git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 + url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 hash: - sha256: d0311c2528658b0dcd70d6491ba53bf7c8288946 + sha256: 26cae9aae7018fa4da8b1132138d2beff9fc5a91 source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@d0311c2528658b0dcd70d6491ba53bf7c8288946 + url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 category: main optional: false - name: octree-creation-app From ebba70985fbf0373868ca95df3eac36a66b4fcf7 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Thu, 14 Aug 2025 16:02:49 -0700 Subject: [PATCH 19/56] Fix imports in test --- tests/locations_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/locations_test.py b/tests/locations_test.py index 948e8825..7426c613 100644 --- a/tests/locations_test.py +++ b/tests/locations_test.py @@ -21,7 +21,7 @@ from simpeg_drivers.components.locations import InversionLocations from simpeg_drivers.options import ActiveCellsOptions from simpeg_drivers.potential_fields import MVIInversionOptions -from simpeg_drivers.utils.utils import tile_locations +from simpeg_drivers.utils.nested import tile_locations from tests.testing_utils import Geoh5Tester, setup_inversion_workspace From f64cc534bf73f540c50373619933be5e45137e95 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 15 Aug 2025 08:04:25 -0700 Subject: [PATCH 20/56] Order of operation for 2D --- simpeg_drivers/driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index f55ed45d..a40e1f80 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -389,9 +389,9 @@ def simulation(self): if getattr(self, "_simulation", None) is None: simulation_factory = SimulationFactory(self.params) self._simulation = simulation_factory.build( - survey=self.inversion_data.survey, mesh=self.inversion_mesh.mesh, models=self.models, + survey=self.inversion_data.survey, ) if not hasattr(self._simulation, "active_cells"): From 7cc7430bc38c014f65b891bb63db52afab3c63a8 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 15 Aug 2025 08:18:03 -0700 Subject: [PATCH 21/56] Skip nesting for 2D problems --- simpeg_drivers/utils/nested.py | 36 ++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/simpeg_drivers/utils/nested.py b/simpeg_drivers/utils/nested.py index c06edd32..e8d22b53 100644 --- a/simpeg_drivers/utils/nested.py +++ b/simpeg_drivers/utils/nested.py @@ -49,6 +49,9 @@ def create_mesh( minimum_level: Minimum octree level to preserve everywhere outside the local survey area. finalize: Return a finalized local treemesh. """ + if not isinstance(base_mesh, TreeMesh): + return base_mesh + locations = get_unique_locations(survey) nested_mesh = TreeMesh( [base_mesh.h[0], base_mesh.h[1], base_mesh.h[2]], @@ -183,17 +186,22 @@ def create_simulation( padding_cells=padding_cells, ) - mapping = maps.TileMap( - simulation.mesh, - simulation.active_cells, - local_mesh, - enforce_active=True, - components=3 if getattr(simulation, "model_type", None) == "vector" else 1, - ) + if not isinstance(local_mesh, TreeMesh): + mapping = maps.IdentityMap(nP=int(simulation.active_cells.sum())) + actives = simulation.active_cells + else: + mapping = maps.TileMap( + simulation.mesh, + simulation.active_cells, + local_mesh, + enforce_active=True, + components=3 if getattr(simulation, "model_type", None) == "vector" else 1, + ) + actives = mapping.local_active kwargs = {"survey": local_survey} - n_actives = int(mapping.local_active.sum()) + n_actives = int(actives.sum()) if getattr(simulation, "_chiMap", None) is not None: if simulation.model_type == "vector": kwargs["chiMap"] = maps.IdentityMap(nP=n_actives * 3) @@ -201,30 +209,28 @@ def create_simulation( else: kwargs["chiMap"] = maps.IdentityMap(nP=n_actives) - kwargs["active_cells"] = mapping.local_active + kwargs["active_cells"] = actives kwargs["sensitivity_path"] = ( Path(simulation.sensitivity_path).parent / f"Tile{tile_id}.zarr" ) if getattr(simulation, "_rhoMap", None) is not None: kwargs["rhoMap"] = maps.IdentityMap(nP=n_actives) - kwargs["active_cells"] = mapping.local_active + kwargs["active_cells"] = actives kwargs["sensitivity_path"] = ( Path(simulation.sensitivity_path).parent / f"Tile{tile_id}.zarr" ) if getattr(simulation, "_sigmaMap", None) is not None: kwargs["sigmaMap"] = maps.ExpMap(local_mesh) * maps.InjectActiveCells( - local_mesh, mapping.local_active, value_inactive=np.log(1e-8) + local_mesh, actives, value_inactive=np.log(1e-8) ) if getattr(simulation, "_etaMap", None) is not None: - kwargs["etaMap"] = maps.InjectActiveCells( - local_mesh, mapping.local_active, value_inactive=0 - ) + kwargs["etaMap"] = maps.InjectActiveCells(local_mesh, actives, value_inactive=0) proj = maps.InjectActiveCells( local_mesh, - mapping.local_active, + actives, value_inactive=1e-8, ) kwargs["sigma"] = proj * mapping * simulation.sigma From 24188253d84dbd9ee0c10a77b8ca8497d85bcd8f Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 15 Aug 2025 08:37:38 -0700 Subject: [PATCH 22/56] Clean up --- simpeg_drivers/components/data.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/simpeg_drivers/components/data.py b/simpeg_drivers/components/data.py index 6fba351b..2f49184d 100644 --- a/simpeg_drivers/components/data.py +++ b/simpeg_drivers/components/data.py @@ -226,10 +226,6 @@ def save_data(self): if channels is None: continue - # Non-EM methods - # if not has_channels: - # channels = {None: channels} - for ind, (channel, values) in enumerate(channels.items()): suffix = f"_{component}" if has_channels: From 2bd95d125fcb8bce1ee89341f7f416eef4e8912b Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 15 Aug 2025 10:07:22 -0700 Subject: [PATCH 23/56] Continue work on FEM sorting --- simpeg_drivers/components/factories/directives_factory.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/simpeg_drivers/components/factories/directives_factory.py b/simpeg_drivers/components/factories/directives_factory.py index d90232b8..73720557 100644 --- a/simpeg_drivers/components/factories/directives_factory.py +++ b/simpeg_drivers/components/factories/directives_factory.py @@ -20,6 +20,7 @@ import numpy as np from geoh5py.groups.property_group import GroupTypeEnum +from geoh5py.objects.surveys.electromagnetics.base import FEMSurvey from numpy import sqrt from simpeg import directives, maps from simpeg.utils.mat_utils import cartesian2amplitude_dip_azimuth @@ -668,8 +669,13 @@ def assemble_data_keywords_em( channels = np.array(receivers.channels, dtype=float) components = list(inversion_object.observed) + if isinstance(receivers, FEMSurvey): + order = "C" + else: + order = "F" + def reshape(values): - data = values.reshape((len(channels), len(components), -1), order="F") + data = values.reshape((len(channels), len(components), -1), order=order) return data kwargs = { From 5c7858e430694f63e867de5e2e7b8c54e4100c9b Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 15 Aug 2025 11:24:41 -0700 Subject: [PATCH 24/56] Add MT_fwr_example --- simpeg_drivers-assets/MT_fwr_UBC_example.geoh5 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 simpeg_drivers-assets/MT_fwr_UBC_example.geoh5 diff --git a/simpeg_drivers-assets/MT_fwr_UBC_example.geoh5 b/simpeg_drivers-assets/MT_fwr_UBC_example.geoh5 new file mode 100644 index 00000000..9bd051c0 --- /dev/null +++ b/simpeg_drivers-assets/MT_fwr_UBC_example.geoh5 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dd94d02140664dfa589048fd8bf13a8d2af97d4905a2073d7cef60beef7b1fc5 +size 1477617 From 2e74af827c2da778ae76fa948d4a6db1297d49e9 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 15 Aug 2025 11:36:07 -0700 Subject: [PATCH 25/56] Continue work on 1D --- .../factories/simulation_factory.py | 2 +- .../electromagnetics/base_1d_driver.py | 88 +++++++++---------- simpeg_drivers/utils/nested.py | 7 +- 3 files changed, 51 insertions(+), 46 deletions(-) diff --git a/simpeg_drivers/components/factories/simulation_factory.py b/simpeg_drivers/components/factories/simulation_factory.py index 02e9e4b7..477f98e4 100644 --- a/simpeg_drivers/components/factories/simulation_factory.py +++ b/simpeg_drivers/components/factories/simulation_factory.py @@ -188,7 +188,7 @@ def assemble_keyword_arguments( if "1d" in self.factory_type: kwargs["sigmaMap"] = maps.ExpMap(mesh) - kwargs["thicknesses"] = mesh.h[0][1:][::-1] + kwargs["thicknesses"] = mesh.h[1][1:][::-1] # kwargs["topo"] = active_cells[tile_id] return kwargs diff --git a/simpeg_drivers/electromagnetics/base_1d_driver.py b/simpeg_drivers/electromagnetics/base_1d_driver.py index f1a82098..d5606773 100644 --- a/simpeg_drivers/electromagnetics/base_1d_driver.py +++ b/simpeg_drivers/electromagnetics/base_1d_driver.py @@ -86,47 +86,47 @@ def get_1d_mesh(self) -> TensorMesh: ) return layers_mesh - @property - def data_misfit(self): - """The Simpeg.data_misfit class""" - if getattr(self, "_data_misfit", None) is None: - with fetch_active_workspace(self.workspace, mode="r+"): - # Tile locations - tiles = self.get_tiles() - - logger.info("Setting up %i tile(s) . . .", len(tiles)) - # Build tiled misfits and combine to form global misfit - self._data_misfit, self._sorting = MisfitFactory( - self.params, models=self.models - ).build( - tiles, - self.split_list, - self.inversion_data, - self.inversion_mesh, - self.topo_z_drape, - ) - self.models.active_cells = np.ones( - self.inversion_mesh.mesh.n_cells, dtype=bool - ) - logger.info("Done.") - - self._data_misfit.multipliers = np.asarray( - self._data_misfit.multipliers, dtype=float - ) - - if self.client: - self.distributed_misfits() - - return self._data_misfit - - @property - def split_list(self): - """ - Split the list of data into chunks for parallel processing. - """ - n_misfits = self.inversion_data.mask.sum() - - if isinstance(self.params.data_object, FEMSurvey): - n_misfits *= len(self.params.data_object.channels) - - return [1] * n_misfits + # @property + # def data_misfit(self): + # """The Simpeg.data_misfit class""" + # if getattr(self, "_data_misfit", None) is None: + # with fetch_active_workspace(self.workspace, mode="r+"): + # # Tile locations + # tiles = self.get_tiles() + # + # logger.info("Setting up %i tile(s) . . .", len(tiles)) + # # Build tiled misfits and combine to form global misfit + # self._data_misfit, self._sorting = MisfitFactory( + # self.params, models=self.models + # ).build( + # tiles, + # self.split_list, + # self.inversion_data, + # self.inversion_mesh, + # self.topo_z_drape, + # ) + # self.models.active_cells = np.ones( + # self.inversion_mesh.mesh.n_cells, dtype=bool + # ) + # logger.info("Done.") + # + # self._data_misfit.multipliers = np.asarray( + # self._data_misfit.multipliers, dtype=float + # ) + # + # if self.client: + # self.distributed_misfits() + # + # return self._data_misfit + # + # @property + # def split_list(self): + # """ + # Split the list of data into chunks for parallel processing. + # """ + # n_misfits = self.inversion_data.mask.sum() + # + # if isinstance(self.params.data_object, FEMSurvey): + # n_misfits *= len(self.params.data_object.channels) + # + # return [1] * n_misfits diff --git a/simpeg_drivers/utils/nested.py b/simpeg_drivers/utils/nested.py index e8d22b53..5f1f4a35 100644 --- a/simpeg_drivers/utils/nested.py +++ b/simpeg_drivers/utils/nested.py @@ -31,7 +31,7 @@ def create_mesh( survey: BaseSurvey, - base_mesh: TreeMesh, + base_mesh: TreeMesh | TensorMesh | None, padding_cells: int = 8, minimum_level: int = 4, finalize: bool = True, @@ -186,6 +186,11 @@ def create_simulation( padding_cells=padding_cells, ) + # slice_ind = np.arange( + # tile_id, inversion_mesh.mesh.n_cells, inversion_mesh.mesh.shape_cells[0] + # )[::-1] + # mapping = maps.Projection(inversion_mesh.mesh.n_cells, slice_ind) + # if not isinstance(local_mesh, TreeMesh): mapping = maps.IdentityMap(nP=int(simulation.active_cells.sum())) actives = simulation.active_cells From 45827d3186d002945e9efcde2bc9c584a4e44352 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 15 Aug 2025 13:40:51 -0700 Subject: [PATCH 26/56] Fix tem 1D and IP --- .../components/factories/misfit_factory.py | 2 +- .../factories/simulation_factory.py | 3 +- .../electromagnetics/base_1d_driver.py | 77 ++++++++----------- simpeg_drivers/utils/nested.py | 40 ++++++---- 4 files changed, 58 insertions(+), 64 deletions(-) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index 9c9e9fb9..3674fecd 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -57,7 +57,7 @@ def assemble_arguments( # pylint: disable=arguments-differ split_list, ): # Base slice over frequencies - if self.factory_type in ["magnetotellurics", "tipper", "fdem"]: + if self.factory_type in ["magnetotellurics", "tipper", "fdem", "fdem 1d"]: channels = self.simulation.survey.frequencies else: channels = [None] diff --git a/simpeg_drivers/components/factories/simulation_factory.py b/simpeg_drivers/components/factories/simulation_factory.py index 477f98e4..17b94873 100644 --- a/simpeg_drivers/components/factories/simulation_factory.py +++ b/simpeg_drivers/components/factories/simulation_factory.py @@ -166,7 +166,7 @@ def assemble_keyword_arguments( maps.InjectActiveCells( mesh, active_cells=active_cells, value_inactive=1e-8 ) - * models.conductivity + * models.conductivity_model ) if self.factory_type in [ @@ -189,7 +189,6 @@ def assemble_keyword_arguments( if "1d" in self.factory_type: kwargs["sigmaMap"] = maps.ExpMap(mesh) kwargs["thicknesses"] = mesh.h[1][1:][::-1] - # kwargs["topo"] = active_cells[tile_id] return kwargs diff --git a/simpeg_drivers/electromagnetics/base_1d_driver.py b/simpeg_drivers/electromagnetics/base_1d_driver.py index d5606773..8f171fa7 100644 --- a/simpeg_drivers/electromagnetics/base_1d_driver.py +++ b/simpeg_drivers/electromagnetics/base_1d_driver.py @@ -21,7 +21,7 @@ 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 +from simpeg_drivers.components.factories import MisfitFactory, SimulationFactory from simpeg_drivers.components.meshes import InversionMesh from simpeg_drivers.driver import InversionDriver from simpeg_drivers.utils.utils import topo_drape_elevation, xyz_2_drape_model @@ -69,7 +69,6 @@ def inversion_mesh(self) -> InversionMesh: self._inversion_mesh = InversionMesh( self.workspace, self.params, entity=entity ) - self._inversion_mesh.layers_mesh = self.layers_mesh return self._inversion_mesh @@ -86,47 +85,33 @@ def get_1d_mesh(self) -> TensorMesh: ) return layers_mesh - # @property - # def data_misfit(self): - # """The Simpeg.data_misfit class""" - # if getattr(self, "_data_misfit", None) is None: - # with fetch_active_workspace(self.workspace, mode="r+"): - # # Tile locations - # tiles = self.get_tiles() - # - # logger.info("Setting up %i tile(s) . . .", len(tiles)) - # # Build tiled misfits and combine to form global misfit - # self._data_misfit, self._sorting = MisfitFactory( - # self.params, models=self.models - # ).build( - # tiles, - # self.split_list, - # self.inversion_data, - # self.inversion_mesh, - # self.topo_z_drape, - # ) - # self.models.active_cells = np.ones( - # self.inversion_mesh.mesh.n_cells, dtype=bool - # ) - # logger.info("Done.") - # - # self._data_misfit.multipliers = np.asarray( - # self._data_misfit.multipliers, dtype=float - # ) - # - # if self.client: - # self.distributed_misfits() - # - # return self._data_misfit - # - # @property - # def split_list(self): - # """ - # Split the list of data into chunks for parallel processing. - # """ - # n_misfits = self.inversion_data.mask.sum() - # - # if isinstance(self.params.data_object, FEMSurvey): - # n_misfits *= len(self.params.data_object.channels) - # - # return [1] * n_misfits + @property + def simulation(self): + """ + The simulation object used in the inversion. + """ + if getattr(self, "_simulation", None) is None: + simulation_factory = SimulationFactory(self.params) + self._simulation = simulation_factory.build( + mesh=self.inversion_mesh.mesh, + models=self.models, + survey=self.inversion_data.survey, + ) + + self._simulation.mesh = self.inversion_mesh.mesh + self._simulation.layers_mesh = self.layers_mesh + self._simulation.active_cells = self.topo_z_drape + + return self._simulation + + @property + def split_list(self): + """ + Split the list of data into chunks for parallel processing. + """ + n_misfits = self.inversion_data.mask.sum() + + if isinstance(self.params.data_object, FEMSurvey): + n_misfits *= len(self.params.data_object.channels) + + return [1] * n_misfits diff --git a/simpeg_drivers/utils/nested.py b/simpeg_drivers/utils/nested.py index 5f1f4a35..4f93215b 100644 --- a/simpeg_drivers/utils/nested.py +++ b/simpeg_drivers/utils/nested.py @@ -14,11 +14,12 @@ from pathlib import Path import numpy as np -from discretize import TreeMesh +from discretize import TensorMesh, TreeMesh from scipy.optimize import linear_sum_assignment from scipy.spatial import cKDTree from scipy.spatial.distance import cdist from simpeg import data, data_misfit, maps, meta +from simpeg.electromagnetics.base_1d import BaseEM1DSimulation from simpeg.electromagnetics.frequency_domain.sources import ( LineCurrent as FEMLineCurrent, ) @@ -31,7 +32,7 @@ def create_mesh( survey: BaseSurvey, - base_mesh: TreeMesh | TensorMesh | None, + base_mesh: TreeMesh | TensorMesh, padding_cells: int = 8, minimum_level: int = 4, finalize: bool = True, @@ -177,6 +178,7 @@ def create_simulation( :param padding_cells: Number of padding cells around the local survey. """ local_survey = create_survey(simulation.survey, indices=indices, channel=channel) + kwargs = {"survey": local_survey} if local_mesh is None: local_mesh = create_mesh( @@ -186,15 +188,21 @@ def create_simulation( padding_cells=padding_cells, ) - # slice_ind = np.arange( - # tile_id, inversion_mesh.mesh.n_cells, inversion_mesh.mesh.shape_cells[0] - # )[::-1] - # mapping = maps.Projection(inversion_mesh.mesh.n_cells, slice_ind) - # - if not isinstance(local_mesh, TreeMesh): - mapping = maps.IdentityMap(nP=int(simulation.active_cells.sum())) - actives = simulation.active_cells - else: + args = (local_mesh,) + if isinstance(simulation, BaseEM1DSimulation): + sounding_id = np.floor( + tile_id / len(getattr(simulation.survey, "frequencies", [None])) + ).astype(int) + local_mesh = simulation.layers_mesh + actives = np.ones(simulation.layers_mesh.n_cells, dtype=bool) + slice_ind = np.arange( + sounding_id, simulation.mesh.n_cells, simulation.mesh.shape_cells[0] + )[::-1] + mapping = maps.Projection(simulation.mesh.n_cells, slice_ind) + kwargs["topo"] = simulation.active_cells[sounding_id] + args = () + + elif isinstance(local_mesh, TreeMesh): mapping = maps.TileMap( simulation.mesh, simulation.active_cells, @@ -203,8 +211,10 @@ def create_simulation( components=3 if getattr(simulation, "model_type", None) == "vector" else 1, ) actives = mapping.local_active - - kwargs = {"survey": local_survey} + # For DCIP-2D + else: + actives = simulation.active_cells + mapping = maps.IdentityMap(nP=int(actives.sum())) n_actives = int(actives.sum()) if getattr(simulation, "_chiMap", None) is not None: @@ -238,7 +248,7 @@ def create_simulation( actives, value_inactive=1e-8, ) - kwargs["sigma"] = proj * mapping * simulation.sigma + kwargs["sigma"] = proj * mapping * simulation.sigma[simulation.active_cells] for key in [ "max_chunk_sizestore_sensitivities", @@ -250,7 +260,7 @@ def create_simulation( if hasattr(simulation, key): kwargs[key] = getattr(simulation, key) - local_sim = type(simulation)(local_mesh, **kwargs) + local_sim = type(simulation)(*args, **kwargs) # TODO bring back # inv_type = inversion_data.params.inversion_type From 1337c3e9b45f92ac839b5ee61855fef9da5a553e Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 15 Aug 2025 15:16:09 -0700 Subject: [PATCH 27/56] Proper handling of reshape for various EMs --- .../components/factories/directives_factory.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/simpeg_drivers/components/factories/directives_factory.py b/simpeg_drivers/components/factories/directives_factory.py index 73720557..cacc441b 100644 --- a/simpeg_drivers/components/factories/directives_factory.py +++ b/simpeg_drivers/components/factories/directives_factory.py @@ -21,6 +21,8 @@ import numpy as np from geoh5py.groups.property_group import GroupTypeEnum from geoh5py.objects.surveys.electromagnetics.base import FEMSurvey +from geoh5py.objects.surveys.electromagnetics.magnetotellurics import MTReceivers +from geoh5py.objects.surveys.electromagnetics.tipper import TipperReceivers from numpy import sqrt from simpeg import directives, maps from simpeg.utils.mat_utils import cartesian2amplitude_dip_azimuth @@ -669,14 +671,16 @@ def assemble_data_keywords_em( channels = np.array(receivers.channels, dtype=float) components = list(inversion_object.observed) - if isinstance(receivers, FEMSurvey): - order = "C" - else: - order = "F" - def reshape(values): - data = values.reshape((len(channels), len(components), -1), order=order) - return data + if isinstance(receivers, MTReceivers | TipperReceivers): + return values.reshape((len(channels), len(components), -1), order="C") + + if isinstance(receivers, FEMSurvey): + return values.reshape( + (len(channels), -1, len(components)), order="C" + ).transpose((0, 2, 1)) + + return values.reshape((len(channels), len(components), -1), order="F") kwargs = { "data_type": inversion_object.observed_data_types, From 3a0a059916007484433a82b95432f8cab9b4daa9 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 15 Aug 2025 16:07:16 -0700 Subject: [PATCH 28/56] Fix FEM3D --- .../components/factories/survey_factory.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index 2dbc3901..b26addc7 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -24,6 +24,7 @@ import numpy as np import simpeg.electromagnetics.time_domain as tdem +from geoh5py.objects.surveys.electromagnetics.airborne_fem import AirborneFEMReceivers from geoh5py.objects.surveys.electromagnetics.ground_tem import ( LargeLoopGroundTEMTransmitters, ) @@ -123,15 +124,20 @@ def build( def _add_data(self, survey, data): data_stack = np.dstack( [np.vstack(list(k.values())) for k in data.observed.values()] - ).transpose((0, 2, 1)) + ).transpose((0, 2, 1))[:, :, self.ordering] uncert_stack = np.dstack( [np.vstack(list(k.values())) for k in data.uncertainties.values()] - ).transpose((0, 2, 1)) + ).transpose((0, 2, 1))[:, :, self.ordering] # Flatten in the order of the channel, component, receiver order = "C" if hasattr(survey, "frequencies") else "F" - data_vec = data_stack[:, :, self.ordering].flatten(order=order) - uncertainty_vec = uncert_stack[:, :, self.ordering].flatten(order=order) + + if isinstance(data.entity, AirborneFEMReceivers): + data_stack = data_stack.transpose((0, 2, 1)) + uncert_stack = uncert_stack.transpose((0, 2, 1)) + + data_vec = data_stack.flatten(order=order) + uncertainty_vec = uncert_stack.flatten(order=order) uncertainty_vec[np.isnan(data_vec)] = np.inf data_vec[np.isnan(data_vec)] = self.dummy # Nan's handled by inf uncertainties survey.dobs = data_vec From e9872273f2254dd661bf0c0e73ddcede360b9125 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Fri, 15 Aug 2025 16:12:03 -0700 Subject: [PATCH 29/56] Fix joints --- simpeg_drivers/components/factories/misfit_factory.py | 1 - simpeg_drivers/driver.py | 7 +++++++ simpeg_drivers/joint/driver.py | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index 3674fecd..d2f45fbb 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -39,7 +39,6 @@ def __init__(self, params: BaseParams | BaseOptions, simulation: BaseSimulation) self.factory_type = self.params.inversion_type self.simulation = simulation self.sorting = None - self.n_blocks = 3 if self.params.inversion_type == "magnetic vector" else 1 def concrete_object(self): return objective_function.ComboObjectiveFunction diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index a40e1f80..757f3201 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -289,6 +289,13 @@ def models(self): return self._models + @property + def n_blocks(self): + """ + Number of model components in the inversion. + """ + return 3 if self.params.inversion_type == "magnetic vector" else 1 + @property def n_values(self): """Number of values in the model""" diff --git a/simpeg_drivers/joint/driver.py b/simpeg_drivers/joint/driver.py index 0b5c32db..01899e61 100644 --- a/simpeg_drivers/joint/driver.py +++ b/simpeg_drivers/joint/driver.py @@ -123,7 +123,7 @@ def initialize(self): global_actives, driver.inversion_mesh.mesh, enforce_active=False, - components=driver.inversion_data.n_blocks, + components=driver.n_blocks, ) driver.params.active_model = None driver.models.active_cells = projection.local_active @@ -211,7 +211,7 @@ def n_values(self): n_values = self.models.n_active count = [] for driver in self.drivers: - n_comp = driver.inversion_data.n_blocks # If vector of scalar model + n_comp = driver.n_blocks # If vector of scalar model count.append(n_values * n_comp) self._n_values = count From 5d1f69fbacf04d7af505be430f84c88bfd98009f Mon Sep 17 00:00:00 2001 From: dominiquef Date: Sat, 16 Aug 2025 09:08:16 -0700 Subject: [PATCH 30/56] Revert back to ordering per type --- .../factories/directives_factory.py | 13 +-- .../components/factories/survey_factory.py | 106 ++++++++++++------ simpeg_drivers/driver.py | 22 +++- 3 files changed, 97 insertions(+), 44 deletions(-) diff --git a/simpeg_drivers/components/factories/directives_factory.py b/simpeg_drivers/components/factories/directives_factory.py index cacc441b..54ba4acb 100644 --- a/simpeg_drivers/components/factories/directives_factory.py +++ b/simpeg_drivers/components/factories/directives_factory.py @@ -672,15 +672,10 @@ def assemble_data_keywords_em( components = list(inversion_object.observed) def reshape(values): - if isinstance(receivers, MTReceivers | TipperReceivers): - return values.reshape((len(channels), len(components), -1), order="C") - - if isinstance(receivers, FEMSurvey): - return values.reshape( - (len(channels), -1, len(components)), order="C" - ).transpose((0, 2, 1)) - - return values.reshape((len(channels), len(components), -1), order="F") + ordering = inversion_object.survey.ordering + data = np.zeros((len(channels), len(components), receivers.n_vertices)) + data[ordering[:, 0], ordering[:, 1], ordering[:, 2]] = values + return data kwargs = { "data_type": inversion_object.observed_data_types, diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index b26addc7..4ab82c6a 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -94,7 +94,12 @@ def assemble_arguments(self, data=None): ) sources = SourcesFactory(self.params).build(receivers=receivers) n_rx = data.locations.shape[0] - self.ordering = np.arange(n_rx).astype(int) + n_comp = len(data.components) + self.ordering = np.c_[ + np.zeros(n_rx * n_comp), # Single channel + np.kron(np.ones(n_rx), np.arange(n_comp)), # Components + np.kron(np.arange(n_rx), np.ones(n_comp)), # Receivers + ].astype(int) return [sources] @@ -124,20 +129,17 @@ def build( def _add_data(self, survey, data): data_stack = np.dstack( [np.vstack(list(k.values())) for k in data.observed.values()] - ).transpose((0, 2, 1))[:, :, self.ordering] + ).transpose((0, 2, 1)) uncert_stack = np.dstack( [np.vstack(list(k.values())) for k in data.uncertainties.values()] - ).transpose((0, 2, 1))[:, :, self.ordering] - - # Flatten in the order of the channel, component, receiver - order = "C" if hasattr(survey, "frequencies") else "F" - - if isinstance(data.entity, AirborneFEMReceivers): - data_stack = data_stack.transpose((0, 2, 1)) - uncert_stack = uncert_stack.transpose((0, 2, 1)) - - data_vec = data_stack.flatten(order=order) - uncertainty_vec = uncert_stack.flatten(order=order) + ).transpose((0, 2, 1)) + + data_vec = data_stack[ + self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] + ] + uncertainty_vec = uncert_stack[ + self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] + ] uncertainty_vec[np.isnan(data_vec)] = np.inf data_vec[np.isnan(data_vec)] = self.dummy # Nan's handled by inf uncertainties survey.dobs = data_vec @@ -189,7 +191,11 @@ def _dcip_arguments(self, data=None): ) sources.append(source) - self.ordering = np.hstack(ordering).astype(int) + self.ordering = np.c_[ + np.zeros(receiver_entity.n_cells), # Single channel + np.zeros(receiver_entity.n_cells), # Single component + np.hstack(ordering), # Multi-receivers + ].astype(int) return [sources] @@ -252,12 +258,12 @@ def _tdem_arguments(self, data=None): tx_list = [] rx_factory = ReceiversFactory(self.params) tx_factory = SourcesFactory(self.params) - + ordering = [] for cur_tx_locs, rx_ids in zip(tx_locs, rx_lookup, strict=True): locs = receivers.vertices[rx_ids, :] rx_list = [] - for component in data.components: + for comp_id, component in enumerate(data.components): rx_obj = rx_factory.build( locations=locs, data=data, @@ -265,44 +271,67 @@ def _tdem_arguments(self, data=None): ) rx_obj.local_index = rx_ids rx_list.append(rx_obj) + n_times = len(receivers.channels) + n_rx = len(rx_ids) if isinstance(rx_ids, np.ndarray) else 1 + ordering.append( + np.c_[ + np.kron(np.arange(n_times), np.ones(n_rx)), + np.ones(n_times * n_rx) * comp_id, + np.kron(np.ones(n_times), np.asarray(rx_ids)), + ] + ) tx_list.append( tx_factory.build(rx_list, locations=cur_tx_locs, waveform=waveform) ) - self.ordering = np.hstack(rx_lookup).astype(int) + self.ordering = np.vstack(ordering).astype(int) return [tx_list] def _fem_arguments(self, data=None): channels = np.array(data.entity.channels) rx_locs = data.entity.vertices tx_locs = data.entity.transmitters.vertices - freqs = data.entity.transmitters.workspace.get_entity("Tx frequency")[0] - freqs = np.array([int(freqs.value_map[f]) for f in freqs.values]) + frequencies = data.entity.transmitters.workspace.get_entity("Tx frequency")[0] + frequencies = np.array( + [int(frequencies.value_map[f]) for f in frequencies.values] + ) sources = [] rx_factory = ReceiversFactory(self.params) tx_factory = SourcesFactory(self.params) receiver_groups = {} - - for receiver_id, locs in enumerate(rx_locs): + block_ordering = [] + for rx_id, locs in enumerate(rx_locs): receivers = [] - for component in data.components: + for comp_id, component in enumerate(data.components): receiver = rx_factory.build( locations=locs, data=data, component=component, ) - receiver.local_index = receiver_id + receiver.local_index = rx_id + block_ordering.append([comp_id, rx_id]) receivers.append(receiver) - receiver_groups[receiver_id] = receivers + receiver_groups[rx_id] = receivers - for frequency in channels: - for receiver_id, receivers in receiver_groups.items(): - locs = tx_locs[frequency == freqs, :][receiver_id, :] + block_ordering = np.vstack(block_ordering) + ordering = [] + for freq_id, frequency in enumerate(channels): + ordering.append( + np.hstack( + [ + np.ones((block_ordering.shape[0], 1)) * freq_id, + block_ordering, + ] + ) + ) + + for rx_id, receivers in receiver_groups.items(): + locs = tx_locs[frequency == frequencies, :][rx_id, :] sources.append( tx_factory.build( receivers, @@ -311,7 +340,7 @@ def _fem_arguments(self, data=None): ) ) - self.ordering = np.arange(rx_locs.shape[0], dtype=int) + self.ordering = np.vstack(ordering).astype(int) return [sources] @@ -330,8 +359,8 @@ def _naturalsource_arguments(self, data=None): sources = [] rx_factory = ReceiversFactory(self.params) tx_factory = SourcesFactory(self.params) - - for comp in data.components: + block_ordering = [] + for comp_id, comp in enumerate(data.components): receivers.append( rx_factory.build( locations=data.locations, @@ -339,10 +368,23 @@ def _naturalsource_arguments(self, data=None): component=simpeg_mt_translate.get(comp, comp), ) ) + n_locs = data.locations.shape[0] + block_ordering.append(np.c_[np.ones(n_locs) * comp_id, np.arange(n_locs)]) - for frequency in data.entity.channels: + block_ordering = np.vstack(block_ordering) + ordering = [] + + for freq_id, frequency in enumerate(data.entity.channels): sources.append(tx_factory.build(receivers, frequency=frequency)) + ordering.append( + np.hstack( + [ + np.ones((block_ordering.shape[0], 1)) * freq_id, + block_ordering, + ] + ) + ) - self.ordering = np.arange(data.locations.shape[0]).astype(int) + self.ordering = np.vstack(ordering).astype(int) return [sources] diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 757f3201..1a791ed9 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -50,7 +50,7 @@ optimization, simulation, ) - +from simpeg.potential_fields.base import BasePFSimulation from simpeg.regularization import ( BaseRegularization, RegularizationMesh, @@ -413,7 +413,19 @@ def sorting(self) -> np.ndarray: ordering of the survey. """ sorting = np.hstack(self._sorting) - return self.inversion_data.survey.ordering[sorting] + + order = "C" + if isinstance(self.simulation, BasePFSimulation): + order = "F" + ordering = self.simulation.survey.ordering[:, -1].reshape( + ( + self.simulation.survey.n_channels, + self.simulation.survey.n_components, + -1, + ), + order=order, + ) + return ordering[0, 0, :][sorting] @property def window(self): @@ -633,11 +645,15 @@ def get_tiles(self): if "1d" in self.params.inversion_type: return np.arange(self.inversion_data.mask.sum()).reshape((-1, 1)) + ordering = self.simulation.survey.ordering[:, -1].reshape( + (self.simulation.survey.n_channels, self.simulation.survey.n_components, -1) + ) + return tile_locations( self.inversion_data.locations, self.params.compute.tile_spatial, labels=self.inversion_data.parts, - sorting=self.simulation.survey.ordering, + sorting=ordering[0, 0, :], ) def configure_dask(self): From a0aae26c66faceb23b30c79941a9576c01d5a988 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Sun, 17 Aug 2025 08:47:33 -0700 Subject: [PATCH 31/56] Review sorting array --- simpeg_drivers/components/data.py | 1 + .../components/factories/misfit_factory.py | 6 +- .../components/factories/survey_factory.py | 55 +++++++++-------- simpeg_drivers/driver.py | 21 +------ .../electromagnetics/base_1d_driver.py | 21 +++++++ simpeg_drivers/utils/nested.py | 61 +------------------ 6 files changed, 58 insertions(+), 107 deletions(-) diff --git a/simpeg_drivers/components/data.py b/simpeg_drivers/components/data.py index 2f49184d..69f23a45 100644 --- a/simpeg_drivers/components/data.py +++ b/simpeg_drivers/components/data.py @@ -334,6 +334,7 @@ def create_survey(self): survey_factory = SurveyFactory(self.params) survey = survey_factory.build(data=self) survey.ordering = survey_factory.ordering + survey.sorting = survey_factory.sorting if "direct current" in self.params.inversion_type: survey.apparent_resistivity = 1 / (geometric_factor(survey) + 1e-10) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index d2f45fbb..851b01bd 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -92,11 +92,9 @@ def assemble_arguments( # pylint: disable=arguments-differ tile_count += np.sum(n_split) local_misfits = [] - self.sorting = [] + for future in futures: # as_completed(futures): - functions, sorting = future # future.result() - local_misfits += functions - self.sorting.append(sorting) + local_misfits += future # future.result() return [local_misfits] diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index 4ab82c6a..c6fcdf89 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -49,6 +49,7 @@ def __init__(self, params: BaseParams | BaseOptions): self.local_index = None self.survey = None self.ordering = None + self.sorting = None def concrete_object(self): if self.factory_type in ["magnetic vector", "magnetic scalar"]: @@ -100,6 +101,7 @@ def assemble_arguments(self, data=None): np.kron(np.ones(n_rx), np.arange(n_comp)), # Components np.kron(np.arange(n_rx), np.ones(n_comp)), # Receivers ].astype(int) + self.sorting = np.arange(n_rx, dtype=int) return [sources] @@ -127,6 +129,7 @@ def build( return survey def _add_data(self, survey, data): + # Stack the data by [channel, component, receiver] data_stack = np.dstack( [np.vstack(list(k.values())) for k in data.observed.values()] ).transpose((0, 2, 1)) @@ -134,6 +137,8 @@ def _add_data(self, survey, data): [np.vstack(list(k.values())) for k in data.uncertainties.values()] ).transpose((0, 2, 1)) + # Reorder the data and uncertainties based on the ordering + # of the SimPEG sources and receivers data_vec = data_stack[ self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] ] @@ -163,7 +168,7 @@ def _dcip_arguments(self, data=None): source_locations = currents.vertices sources = [] - ordering = [] + sorting = [] for source_id in source_ids[np.argsort(order)]: # Cycle in original order receiver_indices = np.where(receiver_entity.ab_cell_id.values == source_id)[ 0 @@ -172,7 +177,7 @@ def _dcip_arguments(self, data=None): if len(receiver_indices) == 0: continue - ordering.append(receiver_indices) + sorting.append(receiver_indices) receivers = ReceiversFactory(self.params).build( locations=receiver_locations, local_index=receiver_entity.cells[receiver_indices], @@ -194,9 +199,9 @@ def _dcip_arguments(self, data=None): self.ordering = np.c_[ np.zeros(receiver_entity.n_cells), # Single channel np.zeros(receiver_entity.n_cells), # Single component - np.hstack(ordering), # Multi-receivers + np.hstack(sorting), # Multi-receivers ].astype(int) - + self.sorting = np.hstack(sorting).astype(int) return [sources] def _tdem_arguments(self, data=None): @@ -219,10 +224,10 @@ def _tdem_arguments(self, data=None): tx_rx = receivers.tx_id_property.values tx_ids = transmitters.tx_id_property.values - rx_lookup = [] + sorting = [] tx_locs = [] for tx_id in np.unique(tx_rx): - rx_lookup.append(np.where(tx_rx == tx_id)[0]) + sorting.append(np.where(tx_rx == tx_id)[0]) tx_ind = tx_ids == tx_id loop_cells = transmitters.cells[ np.all(tx_ind[transmitters.cells], axis=1), : @@ -231,7 +236,7 @@ def _tdem_arguments(self, data=None): tx_locs.append(transmitters.vertices[loop_ind, :]) else: # Assumes 1:1 mapping of tx to rx - rx_lookup = np.arange(receivers.n_vertices).tolist() + sorting = np.arange(receivers.n_vertices).tolist() tx_locs = transmitters.vertices wave_times = ( @@ -259,7 +264,7 @@ def _tdem_arguments(self, data=None): rx_factory = ReceiversFactory(self.params) tx_factory = SourcesFactory(self.params) ordering = [] - for cur_tx_locs, rx_ids in zip(tx_locs, rx_lookup, strict=True): + for cur_tx_locs, rx_ids in zip(tx_locs, sorting, strict=True): locs = receivers.vertices[rx_ids, :] rx_list = [] @@ -286,6 +291,7 @@ def _tdem_arguments(self, data=None): ) self.ordering = np.vstack(ordering).astype(int) + self.sorting = np.hstack(sorting).astype(int) return [tx_list] def _fem_arguments(self, data=None): @@ -300,8 +306,7 @@ def _fem_arguments(self, data=None): sources = [] rx_factory = ReceiversFactory(self.params) tx_factory = SourcesFactory(self.params) - - receiver_groups = {} + receiver_groups = [] block_ordering = [] for rx_id, locs in enumerate(rx_locs): receivers = [] @@ -316,21 +321,12 @@ def _fem_arguments(self, data=None): block_ordering.append([comp_id, rx_id]) receivers.append(receiver) - receiver_groups[rx_id] = receivers + receiver_groups.append(receivers) block_ordering = np.vstack(block_ordering) ordering = [] for freq_id, frequency in enumerate(channels): - ordering.append( - np.hstack( - [ - np.ones((block_ordering.shape[0], 1)) * freq_id, - block_ordering, - ] - ) - ) - - for rx_id, receivers in receiver_groups.items(): + for rx_id, receivers in enumerate(receiver_groups): locs = tx_locs[frequency == frequencies, :][rx_id, :] sources.append( tx_factory.build( @@ -340,8 +336,17 @@ def _fem_arguments(self, data=None): ) ) - self.ordering = np.vstack(ordering).astype(int) + ordering.append( + np.hstack( + [ + np.ones((block_ordering.shape[0], 1)) * freq_id, + block_ordering, + ] + ) + ) + self.ordering = np.vstack(ordering).astype(int) + self.sorting = np.arange(rx_locs.shape[0], dtype=int) return [sources] def _naturalsource_arguments(self, data=None): @@ -360,6 +365,7 @@ def _naturalsource_arguments(self, data=None): rx_factory = ReceiversFactory(self.params) tx_factory = SourcesFactory(self.params) block_ordering = [] + self.sorting = np.arange(data.locations.shape[0], dtype=int) for comp_id, comp in enumerate(data.components): receivers.append( rx_factory.build( @@ -368,8 +374,9 @@ def _naturalsource_arguments(self, data=None): component=simpeg_mt_translate.get(comp, comp), ) ) - n_locs = data.locations.shape[0] - block_ordering.append(np.c_[np.ones(n_locs) * comp_id, np.arange(n_locs)]) + block_ordering.append( + np.c_[np.ones_like(self.sorting) * comp_id, self.sorting] + ) block_ordering = np.vstack(block_ordering) ordering = [] diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 1a791ed9..ca43b630 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -412,20 +412,7 @@ def sorting(self) -> np.ndarray: Arrays for sorting of data from tile, taking into account the ordering of the survey. """ - sorting = np.hstack(self._sorting) - - order = "C" - if isinstance(self.simulation, BasePFSimulation): - order = "F" - ordering = self.simulation.survey.ordering[:, -1].reshape( - ( - self.simulation.survey.n_channels, - self.simulation.survey.n_components, - -1, - ), - order=order, - ) - return ordering[0, 0, :][sorting] + return self.simulation.survey.sorting @property def window(self): @@ -645,15 +632,11 @@ def get_tiles(self): if "1d" in self.params.inversion_type: return np.arange(self.inversion_data.mask.sum()).reshape((-1, 1)) - ordering = self.simulation.survey.ordering[:, -1].reshape( - (self.simulation.survey.n_channels, self.simulation.survey.n_components, -1) - ) - return tile_locations( self.inversion_data.locations, self.params.compute.tile_spatial, labels=self.inversion_data.parts, - sorting=ordering[0, 0, :], + sorting=self.simulation.survey.sorting, ) def configure_dask(self): diff --git a/simpeg_drivers/electromagnetics/base_1d_driver.py b/simpeg_drivers/electromagnetics/base_1d_driver.py index 8f171fa7..d5517a74 100644 --- a/simpeg_drivers/electromagnetics/base_1d_driver.py +++ b/simpeg_drivers/electromagnetics/base_1d_driver.py @@ -104,6 +104,27 @@ def simulation(self): return self._simulation + @property + def sorting(self) -> np.ndarray: + """ + Arrays for sorting of data from tile, taking into account the + ordering of the survey. + """ + sorting = np.hstack(self._sorting) + ordering = ( + self.simulation.survey.ordering[:, -1] + .reshape( + ( + self.simulation.survey.n_channels, + -1, + self.simulation.survey.n_components, + ), + ) + .transpose((0, 2, 1)) + ) + + return ordering[0, 0, :][sorting] + @property def split_list(self): """ diff --git a/simpeg_drivers/utils/nested.py b/simpeg_drivers/utils/nested.py index 4f93215b..ecba04b3 100644 --- a/simpeg_drivers/utils/nested.py +++ b/simpeg_drivers/utils/nested.py @@ -118,7 +118,6 @@ def create_misfit( ) local_mesh = getattr(local_sim, "mesh", None) - sorting = [] local_misfits = [] for count, channel in enumerate(channels): for split_ind in np.array_split(local_index, n_split[count]): @@ -130,10 +129,6 @@ def create_misfit( tile_id=tile_count, padding_cells=padding_cells, ) - - if count == 0: - sorting.append(split_ind) - meta_simulation = meta.MetaSimulation( simulations=[local_sim], mappings=[mapping] ) @@ -154,7 +149,7 @@ def create_misfit( tile_count += 1 - return local_misfits, sorting + return local_misfits def create_simulation( @@ -409,57 +404,3 @@ def tile_locations( tiles += [np.where(cluster_id == tid)[0]] return tiles - - -# def tile_large_group_transmitters( -# survey: LargeLoopGroundTEMReceivers, n_tiles: int -# ) -> list[np.ndarray]: -# """ -# Tile the data based on the transmitters center locations. -# -# :param survey: LargeLoopGroundTEMReceivers object. -# :param n_tiles: Number of tiles. -# -# :return: List of numpy arrays containing the indices of the receivers in each tile. -# """ -# if not isinstance(survey, LargeLoopGroundTEMReceivers): -# raise TypeError("Data object must be of type LargeLoopGroundTEMReceivers") -# -# tx_ids = survey.transmitters.tx_id_property.values -# unique_tile_ids = np.unique(tx_ids) -# n_groups = np.min([len(unique_tile_ids), n_tiles]) -# locations = [] -# for uid in unique_tile_ids: -# locations.append( -# np.mean( -# survey.transmitters.vertices[tx_ids == uid], -# axis=0, -# ) -# ) -# -# # Tile transmitters spatially by loop center -# tx_tiles = tile_locations( -# np.vstack(locations), -# n_groups, -# ) -# receivers_tx_ids = survey.tx_id_property.values -# tiles = [] -# for _t_id, group in enumerate(tx_tiles): -# sub_group = [] -# for value in group: -# receiver_ind = receivers_tx_ids == unique_tile_ids[value] -# sub_group.append(np.where(receiver_ind)[0]) -# -# tiles.append(np.hstack(sub_group)) -# -# # If number of tiles remaining, brake up receivers spatially per transmitter -# while len(tiles) < n_tiles: -# largest_group = np.argmax([len(tile) for tile in tiles]) -# tile = tiles.pop(largest_group) -# new_tiles = tile_locations( -# survey.vertices[tile], -# 2, -# ) -# tiles += [tile[new_tiles[0]], tile[new_tiles[1]]] -# -# return tiles From f92dd1bf9eeea6bdf5496903f0d2b6fe597a6bbd Mon Sep 17 00:00:00 2001 From: dominiquef Date: Sun, 17 Aug 2025 09:04:06 -0700 Subject: [PATCH 32/56] Apply tile sorting to survey sorting --- simpeg_drivers/driver.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index ca43b630..3315bcc3 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -176,7 +176,7 @@ def data_misfit(self): self.split_list, ) self.logger.write("Saving data to file...\n") - + self._sorting = np.hstack(tiles) if isinstance(self.params, BaseInversionOptions): self._data_misfit.multipliers = np.asarray( self._data_misfit.multipliers, dtype=float @@ -412,7 +412,7 @@ def sorting(self) -> np.ndarray: Arrays for sorting of data from tile, taking into account the ordering of the survey. """ - return self.simulation.survey.sorting + return self.simulation.survey.sorting[self._sorting] @property def window(self): From 3fc6e6fdc892b0f392b935b38087a3a1918157f9 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Sun, 17 Aug 2025 09:25:24 -0700 Subject: [PATCH 33/56] Fix sorting of app res --- simpeg_drivers/components/data.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/simpeg_drivers/components/data.py b/simpeg_drivers/components/data.py index 69f23a45..acf0b7b4 100644 --- a/simpeg_drivers/components/data.py +++ b/simpeg_drivers/components/data.py @@ -335,8 +335,12 @@ def create_survey(self): survey = survey_factory.build(data=self) survey.ordering = survey_factory.ordering survey.sorting = survey_factory.sorting + + # Save apparent resistivity in geoh5 order if "direct current" in self.params.inversion_type: - survey.apparent_resistivity = 1 / (geometric_factor(survey) + 1e-10) + survey.apparent_resistivity = 1 / ( + geometric_factor(survey)[np.argsort(survey.sorting)] + 1e-10 + ) return survey From acb043bbb5f01122ce27649f82aa4c97262096ab Mon Sep 17 00:00:00 2001 From: dominiquef Date: Sun, 17 Aug 2025 09:44:38 -0700 Subject: [PATCH 34/56] Adjust data_tests --- tests/data_test.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/tests/data_test.py b/tests/data_test.py index 851cdad8..8fbbd3e6 100644 --- a/tests/data_test.py +++ b/tests/data_test.py @@ -153,11 +153,15 @@ def test_survey_data(tmp_path: Path): # test locations np.testing.assert_array_equal( - verts[driver.sorting[0], :2], local_survey_a.receiver_locations[:, :2] - ) - np.testing.assert_array_equal( - verts[driver.sorting[1], :2], local_survey_b.receiver_locations[:, :2] + verts[driver.sorting, :2], + np.vstack( + [ + local_survey_a.receiver_locations[:, :2], + local_survey_b.receiver_locations[:, :2], + ] + ), ) + assert all(local_survey_a.receiver_locations[:, 2] == 0.0) assert all(local_survey_b.receiver_locations[:, 2] == 0.0) @@ -215,9 +219,9 @@ def test_get_uncertainty_component(tmp_path: Path): with geoh5.open(): data = InversionData(geoh5, params) unc = params.uncertainties["tmi"] - assert len(np.unique(unc)) == 1 - assert np.unique(unc)[0] == 1 - assert len(unc) == data.entity.n_vertices + assert len(unc) == 1 + assert np.unique(unc[None])[0] == 1 + assert len(unc[None]) == data.entity.n_vertices def test_normalize(tmp_path: Path): @@ -227,7 +231,7 @@ def test_normalize(tmp_path: Path): data = InversionData(geoh5, params) data.normalizations = data.get_normalizations() test_data = data.normalize(data.observed) - assert all(test_data["tmi"] == params.data["tmi"]) + assert all(test_data["tmi"][None] == params.data["tmi"][None]) assert len(test_data) == 1 @@ -237,7 +241,7 @@ def test_get_survey(tmp_path: Path): with geoh5.open(): data = InversionData(geoh5, params) survey = data.create_survey() - assert isinstance(survey[0], simpeg.potential_fields.magnetics.Survey) + assert isinstance(survey, simpeg.potential_fields.magnetics.Survey) def test_data_parts(tmp_path: Path): From 723dc54022b2321ed428bd072c29a326bdaf0196 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Sun, 17 Aug 2025 09:45:47 -0700 Subject: [PATCH 35/56] Remove special sorting for 1D driver --- .../electromagnetics/base_1d_driver.py | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/simpeg_drivers/electromagnetics/base_1d_driver.py b/simpeg_drivers/electromagnetics/base_1d_driver.py index d5517a74..8f171fa7 100644 --- a/simpeg_drivers/electromagnetics/base_1d_driver.py +++ b/simpeg_drivers/electromagnetics/base_1d_driver.py @@ -104,27 +104,6 @@ def simulation(self): return self._simulation - @property - def sorting(self) -> np.ndarray: - """ - Arrays for sorting of data from tile, taking into account the - ordering of the survey. - """ - sorting = np.hstack(self._sorting) - ordering = ( - self.simulation.survey.ordering[:, -1] - .reshape( - ( - self.simulation.survey.n_channels, - -1, - self.simulation.survey.n_components, - ), - ) - .transpose((0, 2, 1)) - ) - - return ordering[0, 0, :][sorting] - @property def split_list(self): """ From 297d870eface8c05e58d507111e2d014cd5ec188 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Sun, 17 Aug 2025 14:03:28 -0700 Subject: [PATCH 36/56] Fix FEM 1D again --- .../components/factories/misfit_factory.py | 47 +++++----- .../components/factories/survey_factory.py | 18 ++-- simpeg_drivers/utils/nested.py | 91 +++++++++---------- 3 files changed, 73 insertions(+), 83 deletions(-) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index 851b01bd..08bec358 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -62,34 +62,31 @@ def assemble_arguments( # pylint: disable=arguments-differ channels = [None] futures = [] - tile_count = 0 - data_count = 0 - misfit_count = 0 - # TODO bring back on GEOPY-2182 # with ProcessPoolExecutor() as executor: - for local_index in tiles: - if len(local_index) == 0: - continue - - n_split = split_list[misfit_count : misfit_count + len(channels)] - futures.append( - # executor.submit( - create_misfit( - self.simulation, - local_index, - channels, - tile_count, - # data_count, - n_split, - self.params.padding_cells, - self.params.inversion_type, - self.params.forward_only, + count = 0 + for channel in channels: + tile_count = 0 + for local_index in tiles: + if len(local_index) == 0: + continue + + n_split = split_list[count] + futures.append( + # executor.submit( + create_misfit( + self.simulation, + local_index, + channel, + tile_count, + n_split, + self.params.padding_cells, + self.params.inversion_type, + self.params.forward_only, + ) ) - ) - misfit_count += len(channels) - data_count += len(local_index) - tile_count += np.sum(n_split) + tile_count += np.sum(n_split) + count += 1 local_misfits = [] diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index c6fcdf89..8fff77e3 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -137,18 +137,12 @@ def _add_data(self, survey, data): [np.vstack(list(k.values())) for k in data.uncertainties.values()] ).transpose((0, 2, 1)) - # Reorder the data and uncertainties based on the ordering - # of the SimPEG sources and receivers - data_vec = data_stack[ - self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] - ] - uncertainty_vec = uncert_stack[ - self.ordering[:, 0], self.ordering[:, 1], self.ordering[:, 2] - ] - uncertainty_vec[np.isnan(data_vec)] = np.inf - data_vec[np.isnan(data_vec)] = self.dummy # Nan's handled by inf uncertainties - survey.dobs = data_vec - survey.std = uncertainty_vec + uncert_stack[np.isnan(data_stack)] = np.inf + data_stack[np.isnan(data_stack)] = ( + self.dummy + ) # Nan's handled by inf uncertainties + survey.dobs = data_stack + survey.std = uncert_stack def _dcip_arguments(self, data=None): if getattr(data, "entity", None) is None: diff --git a/simpeg_drivers/utils/nested.py b/simpeg_drivers/utils/nested.py index ecba04b3..76a71f4d 100644 --- a/simpeg_drivers/utils/nested.py +++ b/simpeg_drivers/utils/nested.py @@ -100,7 +100,7 @@ def create_mesh( def create_misfit( simulation, local_index, - channels, + channel, tile_count, # data_count, n_split, @@ -119,35 +119,34 @@ def create_misfit( local_mesh = getattr(local_sim, "mesh", None) local_misfits = [] - for count, channel in enumerate(channels): - for split_ind in np.array_split(local_index, n_split[count]): - local_sim, mapping = create_simulation( - simulation, - local_mesh, - split_ind, - channel=channel, - tile_id=tile_count, - padding_cells=padding_cells, - ) - meta_simulation = meta.MetaSimulation( - simulations=[local_sim], mappings=[mapping] - ) + for split_ind in np.array_split(local_index, n_split): + local_sim, mapping = create_simulation( + simulation, + local_mesh, + split_ind, + channel=channel, + tile_id=tile_count, + padding_cells=padding_cells, + ) + meta_simulation = meta.MetaSimulation( + simulations=[local_sim], mappings=[mapping] + ) - local_data = data.Data(local_sim.survey) - lmisfit = data_misfit.L2DataMisfit(local_data, meta_simulation) - if not forward_only: - local_data.dobs = local_sim.survey.dobs - local_data.standard_deviation = local_sim.survey.std - name = inversion_type - name += f": Tile {tile_count + 1}" - if len(channels) > 1: - name += f": Channel {channel}" + local_data = data.Data(local_sim.survey) + lmisfit = data_misfit.L2DataMisfit(local_data, meta_simulation) + if not forward_only: + local_data.dobs = local_sim.survey.dobs + local_data.standard_deviation = local_sim.survey.std + name = inversion_type + name += f": Tile {tile_count + 1}" + if channel is not None: + name += f": Channel {channel}" - lmisfit.name = f"{name}" + lmisfit.name = f"{name}" - local_misfits.append(lmisfit) + local_misfits.append(lmisfit) - tile_count += 1 + tile_count += 1 return local_misfits @@ -185,16 +184,13 @@ def create_simulation( args = (local_mesh,) if isinstance(simulation, BaseEM1DSimulation): - sounding_id = np.floor( - tile_id / len(getattr(simulation.survey, "frequencies", [None])) - ).astype(int) local_mesh = simulation.layers_mesh actives = np.ones(simulation.layers_mesh.n_cells, dtype=bool) slice_ind = np.arange( - sounding_id, simulation.mesh.n_cells, simulation.mesh.shape_cells[0] + tile_id, simulation.mesh.n_cells, simulation.mesh.shape_cells[0] )[::-1] mapping = maps.Projection(simulation.mesh.n_cells, slice_ind) - kwargs["topo"] = simulation.active_cells[sounding_id] + kwargs["topo"] = simulation.active_cells[tile_id] args = () elif isinstance(local_mesh, TreeMesh): @@ -280,7 +276,9 @@ def create_survey(survey, indices, channel=None): # Extract the indices of the receivers that belong to this source locations = src.receiver_list[0].locations - if isinstance(locations, tuple | list): # For MT survey + + # For MT and DC surveys with multiple locations per receiver + if isinstance(locations, tuple | list): n_data = locations[0].shape[0] else: n_data = locations.shape[0] @@ -298,7 +296,8 @@ def create_survey(survey, indices, channel=None): # intersect = set(rx.local_index).intersection(indices) new_rx = copy(rx) - if isinstance(rx.locations, tuple | list): # For MT and DC surveys + # For MT and DC surveys with multiple locations per receiver + if isinstance(rx.locations, tuple | list): new_rx.locations = tuple(loc[intersect] for loc in rx.locations) else: new_rx.locations = rx.locations[intersect] @@ -316,22 +315,22 @@ def create_survey(survey, indices, channel=None): new_survey = type(survey)(sources) if hasattr(survey, "dobs") and survey.dobs is not None: - order = "C" if hasattr(survey, "frequencies") else "F" - data_slice = survey.dobs.reshape( - (survey.n_channels, survey.n_components, -1), order=order - )[:, :, indices] - uncert_slice = survey.std.reshape( - (survey.n_channels, survey.n_components, -1), order=order - )[:, :, indices] - + data_slice = np.isin(survey.ordering[:, 2], indices) # For FEM surveys only if channel is not None: ind = np.where(np.asarray(survey.frequencies) == channel)[0] - data_slice = data_slice[ind, :, :] - uncert_slice = uncert_slice[ind, :, :] - - new_survey.dobs = data_slice.flatten(order=order) - new_survey.std = uncert_slice.flatten(order=order) + data_slice *= np.isin(survey.ordering[:, 0], ind) + + new_survey.dobs = survey.dobs[ + survey.ordering[data_slice, 0], + survey.ordering[data_slice, 1], + survey.ordering[data_slice, 2], + ] + new_survey.std = survey.std[ + survey.ordering[data_slice, 0], + survey.ordering[data_slice, 1], + survey.ordering[data_slice, 2], + ] return new_survey From 8e97ac1cc5d884d0822ec79f5142e5320a95b2a6 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 18 Aug 2025 08:03:15 -0700 Subject: [PATCH 37/56] Attach receiver indices to the source for reference in create_survey. Slice the ordering --- .../components/factories/misfit_factory.py | 15 +++-- .../components/factories/survey_factory.py | 26 +++++--- simpeg_drivers/driver.py | 2 +- .../electromagnetics/base_1d_driver.py | 3 - simpeg_drivers/utils/nested.py | 66 +++++++++---------- 5 files changed, 56 insertions(+), 56 deletions(-) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index 08bec358..e79abf88 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -56,7 +56,7 @@ def assemble_arguments( # pylint: disable=arguments-differ split_list, ): # Base slice over frequencies - if self.factory_type in ["magnetotellurics", "tipper", "fdem", "fdem 1d"]: + if self.factory_type in ["magnetotellurics", "tipper", "fdem"]: channels = self.simulation.survey.frequencies else: channels = [None] @@ -67,8 +67,8 @@ def assemble_arguments( # pylint: disable=arguments-differ count = 0 for channel in channels: tile_count = 0 - for local_index in tiles: - if len(local_index) == 0: + for local_indices in tiles: + if len(local_indices) == 0: continue n_split = split_list[count] @@ -76,7 +76,7 @@ def assemble_arguments( # pylint: disable=arguments-differ # executor.submit( create_misfit( self.simulation, - local_index, + local_indices, channel, tile_count, n_split, @@ -89,10 +89,13 @@ def assemble_arguments( # pylint: disable=arguments-differ count += 1 local_misfits = [] - + local_orderings = [] for future in futures: # as_completed(futures): - local_misfits += future # future.result() + misfits, orderings = future # future.result() + local_misfits += misfits + local_orderings += orderings + self.simulation.survey.ordering = np.vstack(local_orderings) return [local_misfits] def assemble_keyword_arguments(self, **_): diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index 8fff77e3..0f5b5029 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -95,6 +95,7 @@ def assemble_arguments(self, data=None): ) sources = SourcesFactory(self.params).build(receivers=receivers) n_rx = data.locations.shape[0] + sources.rx_ids = np.arange(n_rx, dtype=int) n_comp = len(data.components) self.ordering = np.c_[ np.zeros(n_rx * n_comp), # Single channel @@ -188,6 +189,7 @@ def _dcip_arguments(self, data=None): receivers=receivers, locations=source_locations[currents.cells[cell_ind].flatten()], ) + source.rx_ids = np.asarray(receiver_indices) sources.append(source) self.ordering = np.c_[ @@ -280,9 +282,9 @@ def _tdem_arguments(self, data=None): ] ) - tx_list.append( - tx_factory.build(rx_list, locations=cur_tx_locs, waveform=waveform) - ) + tx = tx_factory.build(rx_list, locations=cur_tx_locs, waveform=waveform) + tx.rx_ids = np.asarray(rx_ids, dtype=int) + tx_list.append(tx) self.ordering = np.vstack(ordering).astype(int) self.sorting = np.hstack(sorting).astype(int) @@ -322,13 +324,15 @@ def _fem_arguments(self, data=None): for freq_id, frequency in enumerate(channels): for rx_id, receivers in enumerate(receiver_groups): locs = tx_locs[frequency == frequencies, :][rx_id, :] - sources.append( - tx_factory.build( - receivers, - locations=locs, - frequency=frequency, - ) + tx = tx_factory.build( + receivers, + locations=locs, + frequency=frequency, + ) + tx.rx_ids = np.unique( + np.hstack([rec.local_index for rec in receivers], dtype=int) ) + sources.append(tx) ordering.append( np.hstack( @@ -376,7 +380,9 @@ def _naturalsource_arguments(self, data=None): ordering = [] for freq_id, frequency in enumerate(data.entity.channels): - sources.append(tx_factory.build(receivers, frequency=frequency)) + tx = tx_factory.build(receivers, frequency=frequency) + tx.rx_ids = np.arange(data.locations.shape[0], dtype=int) + sources.append(tx) ordering.append( np.hstack( [ diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 3315bcc3..0fc3f294 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -412,7 +412,7 @@ def sorting(self) -> np.ndarray: Arrays for sorting of data from tile, taking into account the ordering of the survey. """ - return self.simulation.survey.sorting[self._sorting] + return self.simulation.survey.sorting @property def window(self): diff --git a/simpeg_drivers/electromagnetics/base_1d_driver.py b/simpeg_drivers/electromagnetics/base_1d_driver.py index 8f171fa7..9aa2e1c1 100644 --- a/simpeg_drivers/electromagnetics/base_1d_driver.py +++ b/simpeg_drivers/electromagnetics/base_1d_driver.py @@ -111,7 +111,4 @@ def split_list(self): """ n_misfits = self.inversion_data.mask.sum() - if isinstance(self.params.data_object, FEMSurvey): - n_misfits *= len(self.params.data_object.channels) - return [1] * n_misfits diff --git a/simpeg_drivers/utils/nested.py b/simpeg_drivers/utils/nested.py index 76a71f4d..3eb635b8 100644 --- a/simpeg_drivers/utils/nested.py +++ b/simpeg_drivers/utils/nested.py @@ -99,7 +99,7 @@ def create_mesh( def create_misfit( simulation, - local_index, + local_indices, channel, tile_count, # data_count, @@ -108,19 +108,20 @@ def create_misfit( inversion_type, forward_only, ): - local_sim, _ = create_simulation( + local_sim, _, _ = create_simulation( simulation, None, - local_index, - channel=None, + local_indices, + channel=channel, tile_id=tile_count, padding_cells=padding_cells, ) local_mesh = getattr(local_sim, "mesh", None) local_misfits = [] - for split_ind in np.array_split(local_index, n_split): - local_sim, mapping = create_simulation( + data_slices = [] + for split_ind in np.array_split(local_indices, n_split): + local_sim, mapping, data_slice = create_simulation( simulation, local_mesh, split_ind, @@ -145,10 +146,11 @@ def create_misfit( lmisfit.name = f"{name}" local_misfits.append(lmisfit) + data_slices.append(data_slice) tile_count += 1 - return local_misfits + return local_misfits, data_slices def create_simulation( @@ -171,7 +173,9 @@ def create_simulation( :param tile_id: Tile id stored on the simulation. :param padding_cells: Number of padding cells around the local survey. """ - local_survey = create_survey(simulation.survey, indices=indices, channel=channel) + local_survey, local_ordering = create_survey( + simulation.survey, indices=indices, channel=channel + ) kwargs = {"survey": local_survey} if local_mesh is None: @@ -186,10 +190,10 @@ def create_simulation( if isinstance(simulation, BaseEM1DSimulation): local_mesh = simulation.layers_mesh actives = np.ones(simulation.layers_mesh.n_cells, dtype=bool) - slice_ind = np.arange( + model_slice = np.arange( tile_id, simulation.mesh.n_cells, simulation.mesh.shape_cells[0] )[::-1] - mapping = maps.Projection(simulation.mesh.n_cells, slice_ind) + mapping = maps.Projection(simulation.mesh.n_cells, model_slice) kwargs["topo"] = simulation.active_cells[tile_id] args = () @@ -261,7 +265,7 @@ def create_simulation( # "2d" not in inv_type or "pseudo" in inv_type # ): # compute_dc_projections(inversion_data, local_sim, indices) - return local_sim, mapping + return local_sim, mapping, local_ordering def create_survey(survey, indices, channel=None): @@ -269,24 +273,19 @@ def create_survey(survey, indices, channel=None): Extract source and receivers belonging to the indices. """ sources = [] - location_count = 0 + + # Return the subset of data that belongs to the tile + slice_inds = np.isin(survey.ordering[:, 2], indices) + if channel is not None: + ind = np.where(np.asarray(survey.frequencies) == channel)[0] + slice_inds *= np.isin(survey.ordering[:, 0], ind) + for src in survey.source_list or [survey.source_field]: if channel is not None and getattr(src, "frequency", None) != channel: continue # Extract the indices of the receivers that belong to this source - locations = src.receiver_list[0].locations - - # For MT and DC surveys with multiple locations per receiver - if isinstance(locations, tuple | list): - n_data = locations[0].shape[0] - else: - n_data = locations.shape[0] - - rx_indices = np.arange(n_data) + location_count - - _, intersect, _ = np.intersect1d(rx_indices, indices, return_indices=True) - location_count += n_data + _, intersect, _ = np.intersect1d(src.rx_ids, indices, return_indices=True) if len(intersect) == 0: continue @@ -315,24 +314,19 @@ def create_survey(survey, indices, channel=None): new_survey = type(survey)(sources) if hasattr(survey, "dobs") and survey.dobs is not None: - data_slice = np.isin(survey.ordering[:, 2], indices) # For FEM surveys only - if channel is not None: - ind = np.where(np.asarray(survey.frequencies) == channel)[0] - data_slice *= np.isin(survey.ordering[:, 0], ind) - new_survey.dobs = survey.dobs[ - survey.ordering[data_slice, 0], - survey.ordering[data_slice, 1], - survey.ordering[data_slice, 2], + survey.ordering[slice_inds, 0], + survey.ordering[slice_inds, 1], + survey.ordering[slice_inds, 2], ] new_survey.std = survey.std[ - survey.ordering[data_slice, 0], - survey.ordering[data_slice, 1], - survey.ordering[data_slice, 2], + survey.ordering[slice_inds, 0], + survey.ordering[slice_inds, 1], + survey.ordering[slice_inds, 2], ] - return new_survey + return new_survey, survey.ordering[slice_inds, :] def tile_locations( From ddfc83d2c08539aeb6ea954f1e26d5017589456d Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 18 Aug 2025 08:32:19 -0700 Subject: [PATCH 38/56] Adjust tile estimator --- simpeg_drivers/utils/tile_estimate.py | 2 +- tests/run_tests/driver_tile_estimator_test.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/simpeg_drivers/utils/tile_estimate.py b/simpeg_drivers/utils/tile_estimate.py index 241d9044..bd245a91 100644 --- a/simpeg_drivers/utils/tile_estimate.py +++ b/simpeg_drivers/utils/tile_estimate.py @@ -100,7 +100,7 @@ def get_results(self, max_tiles: int = 13) -> dict: # Get the median tile ind = int(np.argsort([len(tile) for tile in tiles])[int(count / 2)]) self.driver.params.compute.tile_spatial = int(count) - sim, _, _, mapping = create_simulation( + sim, mapping, _ = create_simulation( self.driver.simulation, None, tiles[ind], diff --git a/tests/run_tests/driver_tile_estimator_test.py b/tests/run_tests/driver_tile_estimator_test.py index 0c74ef21..b4e965c5 100644 --- a/tests/run_tests/driver_tile_estimator_test.py +++ b/tests/run_tests/driver_tile_estimator_test.py @@ -62,9 +62,8 @@ def test_tile_estimator_run( tile_params = TileParameters(geoh5=geoh5, simulation=driver.out_group) estimator = TileEstimator(tile_params) - assert len(estimator.get_results(max_tiles=32)) == 8 - with geoh5.open(): + assert len(estimator.get_results(max_tiles=32)) == 8 simpeg_group = estimator.run() driver = simpeg_group_to_driver(simpeg_group, geoh5) From e7b0f9afa774a4397f794669f5d5da77277d6967 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 18 Aug 2025 10:04:41 -0700 Subject: [PATCH 39/56] Clean up SaveData directive --- .../factories/directives_factory.py | 180 ++++-------------- simpeg_drivers/driver.py | 8 - simpeg_drivers/joint/driver.py | 2 - 3 files changed, 36 insertions(+), 154 deletions(-) diff --git a/simpeg_drivers/components/factories/directives_factory.py b/simpeg_drivers/components/factories/directives_factory.py index 54ba4acb..161d83f9 100644 --- a/simpeg_drivers/components/factories/directives_factory.py +++ b/simpeg_drivers/components/factories/directives_factory.py @@ -183,8 +183,6 @@ def save_iteration_apparent_resistivity_directive(self): self.params ).build( inversion_object=self.driver.inversion_data, - active_cells=self.driver.models.active_cells, - sorting=np.argsort(self.driver.sorting), name="Apparent Resistivity", ) return self._save_iteration_apparent_resistivity_directive @@ -226,9 +224,6 @@ def save_iteration_data_directive(self): self.params ).build( inversion_object=self.driver.inversion_data, - active_cells=self.driver.models.active_cells, - sorting=np.argsort(self.driver.sorting), - global_misfit=self.driver.data_misfit, name="Data", ) return self._save_iteration_data_directive @@ -267,8 +262,6 @@ def save_iteration_residual_directive(self): self.params ).build( inversion_object=self.driver.inversion_data, - active_cells=self.driver.models.active_cells, - sorting=np.argsort(self.driver.sorting), name="Residual", ) return self._save_iteration_residual_directive @@ -367,7 +360,6 @@ def assemble_arguments( self, inversion_object=None, active_cells=None, - sorting=None, transform=None, global_misfit=None, name=None, @@ -386,7 +378,6 @@ def assemble_keyword_arguments( self, inversion_object=None, active_cells=None, - sorting=None, transform=None, global_misfit=None, name=None, @@ -449,7 +440,6 @@ def assemble_keyword_arguments( self, inversion_object=None, active_cells=None, - sorting=None, transform=None, global_misfit=None, name=None, @@ -495,101 +485,67 @@ class SaveDataGeoh5Factory(SaveGeoh5Factory): def assemble_keyword_arguments( self, inversion_object=None, - active_cells=None, - sorting=None, - transform=None, - global_misfit=None, name=None, ): - if self.factory_type in [ - "fdem", - "fdem 1d", - "tdem", - "tdem 1d", - "magnetotellurics", - "tipper", - ]: - kwargs = self.assemble_data_keywords_em( - inversion_object=inversion_object, - active_cells=active_cells, - sorting=sorting, - transform=transform, - global_misfit=global_misfit, - name=name, - ) + receivers = inversion_object.entity + channels = getattr(receivers, "channels", [None]) + components = list(inversion_object.observed) + ordering = inversion_object.survey.ordering + n_locations = len(np.unique(ordering[:, 2])) - elif self.factory_type in [ + def reshape(values): + data = np.zeros((len(channels), len(components), n_locations)) + data[ordering[:, 0], ordering[:, 1], ordering[:, 2]] = values + return data + + kwargs = { + "data_type": inversion_object.observed_data_types, + "association": "VERTEX", + "transforms": [ + np.hstack( + [ + inversion_object.normalizations[chan][comp] + for chan in channels + for comp in components + ], + ), + ], + "channels": channels, + "components": components, + "reshape": reshape, + } + + if self.factory_type in [ "direct current 3d", "direct current 2d", "induced polarization 3d", "induced polarization 2d", ]: kwargs = self.assemble_data_keywords_dcip( - inversion_object=inversion_object, - active_cells=active_cells, - sorting=sorting, - transform=transform, - global_misfit=global_misfit, - name=name, + inversion_object=inversion_object, name=name, **kwargs ) elif self.factory_type in ["gravity", "magnetic scalar", "magnetic vector"]: kwargs = self.assemble_data_keywords_potential_fields( inversion_object=inversion_object, - active_cells=active_cells, - sorting=sorting, - transform=transform, - global_misfit=global_misfit, name=name, + **kwargs, ) - else: - return None - - if transform is not None: - kwargs["transforms"].append(transform) return kwargs @staticmethod def assemble_data_keywords_potential_fields( inversion_object=None, - active_cells=None, - sorting=None, - transform=None, - global_misfit=None, name=None, + **kwargs, ): - components = list(inversion_object.observed) - channels = [None] - kwargs = { - "data_type": inversion_object.observed_data_types, - "transforms": [ - np.hstack( - [ - inversion_object.normalizations[chan][comp] - for chan in channels - for comp in components - ] - ) - ], - "channels": channels, - "components": components, - "association": "VERTEX", - "reshape": lambda x: x.reshape( - (len(channels), len(components), -1), order="F" - ), - } - - if sorting is not None: - kwargs["sorting"] = np.hstack(sorting) - if name == "Residual": kwargs["label"] = name data = inversion_object.normalize(inversion_object.observed) def potfield_transform(x): data_stack = np.vstack([k[None] for k in data.values()]) - data_stack = data_stack[:, np.argsort(sorting)] return data_stack.ravel() - x kwargs.pop("data_type") @@ -600,48 +556,22 @@ def potfield_transform(x): def assemble_data_keywords_dcip( self, inversion_object=None, - active_cells=None, - sorting=None, - transform=None, - global_misfit=None, name=None, + **kwargs, ): components = list(inversion_object.observed) - channels = [None] - is_dc = True if "direct current" in self.factory_type else False - component = "dc" if is_dc else "ip" - kwargs = { - "data_type": inversion_object.observed_data_types, - "transforms": [ - np.hstack( - [ - inversion_object.normalizations[chan][comp] - for chan in channels - for comp in components - ] - ) - ], - "channels": channels, - "components": [component], - "reshape": lambda x: x.reshape( - (len(channels), len(components), -1), order="F" - ), - "association": "CELL", - } - - if sorting is not None: - kwargs["sorting"] = np.hstack(sorting) + kwargs["association"] = "CELL" - if is_dc and name == "Apparent Resistivity": + if "direct current" in self.factory_type and name == "Apparent Resistivity": kwargs["transforms"].insert( 0, - inversion_object.survey.apparent_resistivity[np.argsort(sorting)], + inversion_object.survey.apparent_resistivity, ) kwargs["channels"] = ["apparent_resistivity"] observed = self.params.geoh5.get_entity("Observed_apparent_resistivity")[0] if observed is not None: kwargs["data_type"] = { - component: {"apparent_resistivity": observed.entity_type} + components[0]: {"apparent_resistivity": observed.entity_type} } if name == "Residual": @@ -650,47 +580,9 @@ def assemble_data_keywords_dcip( def dcip_transform(x): data_stack = np.vstack([k[None] for k in data.values()]) - data_stack = data_stack[:, np.argsort(sorting)] return data_stack.ravel() - x kwargs["transforms"].insert(0, dcip_transform) kwargs.pop("data_type") return kwargs - - def assemble_data_keywords_em( - self, - inversion_object=None, - active_cells=None, - sorting=None, - transform=None, - global_misfit=None, - name=None, - ): - receivers = inversion_object.entity - channels = np.array(receivers.channels, dtype=float) - components = list(inversion_object.observed) - - def reshape(values): - ordering = inversion_object.survey.ordering - data = np.zeros((len(channels), len(components), receivers.n_vertices)) - data[ordering[:, 0], ordering[:, 1], ordering[:, 2]] = values - return data - - kwargs = { - "data_type": inversion_object.observed_data_types, - "association": "VERTEX", - "transforms": np.hstack( - [ - 1 / inversion_object.normalizations[chan][comp] - for chan in channels - for comp in components - ] - ), - "channels": channels, - "components": components, - "sorting": sorting, - "_reshape": reshape, - } - - return kwargs diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 0fc3f294..9a2173fc 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -406,14 +406,6 @@ def simulation(self): return self._simulation - @property - def sorting(self) -> np.ndarray: - """ - Arrays for sorting of data from tile, taking into account the - ordering of the survey. - """ - return self.simulation.survey.sorting - @property def window(self): """Inversion window""" diff --git a/simpeg_drivers/joint/driver.py b/simpeg_drivers/joint/driver.py index 01899e61..6f698fc1 100644 --- a/simpeg_drivers/joint/driver.py +++ b/simpeg_drivers/joint/driver.py @@ -239,8 +239,6 @@ def run(self): for sub, driver in zip(predicted, self.drivers, strict=True): SaveDataGeoh5Factory(driver.params).build( inversion_object=driver.inversion_data, - sorting=np.argsort(driver.sorting), - ordering=driver.ordering, ).write(0, sub) else: # Run the inversion From 071dc2e7e4c54e7fde8bd5939b5335e90d8d6e2f Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 18 Aug 2025 10:28:25 -0700 Subject: [PATCH 40/56] Adjust naming in IP tests --- tests/run_tests/driver_ip_2d_test.py | 2 +- tests/run_tests/driver_ip_b2d_test.py | 2 +- tests/run_tests/driver_ip_test.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run_tests/driver_ip_2d_test.py b/tests/run_tests/driver_ip_2d_test.py index 5c2248f5..d8759760 100644 --- a/tests/run_tests/driver_ip_2d_test.py +++ b/tests/run_tests/driver_ip_2d_test.py @@ -80,7 +80,7 @@ def test_ip_2d_run( workpath = tmp_path.parent / "test_ip_2d_fwr_run0" / "inversion_test.ui.geoh5" with Workspace(workpath) as geoh5: - chargeability = geoh5.get_entity("Iteration_0_ip")[0] + chargeability = geoh5.get_entity("Iteration_0_chargeability")[0] mesh = geoh5.get_entity("Models")[0] topography = geoh5.get_entity("topography")[0] diff --git a/tests/run_tests/driver_ip_b2d_test.py b/tests/run_tests/driver_ip_b2d_test.py index 7fd3d686..96f1e3f5 100644 --- a/tests/run_tests/driver_ip_b2d_test.py +++ b/tests/run_tests/driver_ip_b2d_test.py @@ -97,7 +97,7 @@ def test_ip_p3d_run( workpath = tmp_path.parent / "test_ip_p3d_fwr_run0" / "inversion_test.ui.geoh5" with Workspace(workpath) as geoh5: - chargeability = geoh5.get_entity("Iteration_0_ip")[0] + chargeability = geoh5.get_entity("Iteration_0_chargeability")[0] out_group = geoh5.get_entity("Line 1")[0].parent mesh = out_group.get_entity("mesh")[0] # Finds the octree mesh topography = geoh5.get_entity("topography")[0] diff --git a/tests/run_tests/driver_ip_test.py b/tests/run_tests/driver_ip_test.py index b17377dd..3a846f9e 100644 --- a/tests/run_tests/driver_ip_test.py +++ b/tests/run_tests/driver_ip_test.py @@ -75,7 +75,7 @@ def test_ip_3d_run( workpath = tmp_path.parent / "test_ip_3d_fwr_run0" / "inversion_test.ui.geoh5" with Workspace(workpath) as geoh5: - potential = geoh5.get_entity("Iteration_0_ip")[0] + potential = geoh5.get_entity("Iteration_0_chargeability")[0] mesh = geoh5.get_entity("mesh")[0] topography = geoh5.get_entity("topography")[0] From ec864b792c3759f927ad45d06ab8a01b80829c33 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 18 Aug 2025 10:39:05 -0700 Subject: [PATCH 41/56] Fix naming of dc tests --- tests/run_tests/driver_2d_rotated_gradients_test.py | 2 +- tests/run_tests/driver_dc_2d_test.py | 2 +- tests/run_tests/driver_dc_b2d_rotated_gradients_test.py | 2 +- tests/run_tests/driver_dc_b2d_test.py | 2 +- tests/run_tests/driver_dc_test.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/run_tests/driver_2d_rotated_gradients_test.py b/tests/run_tests/driver_2d_rotated_gradients_test.py index 2b3a41b1..6af90b5f 100644 --- a/tests/run_tests/driver_2d_rotated_gradients_test.py +++ b/tests/run_tests/driver_2d_rotated_gradients_test.py @@ -108,7 +108,7 @@ def test_dc2d_rotated_grad_run( ) with Workspace(workpath) as geoh5: - potential = geoh5.get_entity("Iteration_0_dc")[0] + potential = geoh5.get_entity("Iteration_0_potential")[0] topography = geoh5.get_entity("topography")[0] orig_potential = potential.values.copy() diff --git a/tests/run_tests/driver_dc_2d_test.py b/tests/run_tests/driver_dc_2d_test.py index 66a15975..bbe18294 100644 --- a/tests/run_tests/driver_dc_2d_test.py +++ b/tests/run_tests/driver_dc_2d_test.py @@ -87,7 +87,7 @@ def test_dc_2d_run(tmp_path: Path, max_iterations=1, pytest=True): workpath = tmp_path.parent / "test_dc_2d_fwr_run0" / "inversion_test.ui.geoh5" with Workspace(workpath) as geoh5: - potential = geoh5.get_entity("Iteration_0_dc")[0] + potential = geoh5.get_entity("Iteration_0_potential")[0] topography = geoh5.get_entity("topography")[0] # Run the inverse diff --git a/tests/run_tests/driver_dc_b2d_rotated_gradients_test.py b/tests/run_tests/driver_dc_b2d_rotated_gradients_test.py index 9484e2df..0589559a 100644 --- a/tests/run_tests/driver_dc_b2d_rotated_gradients_test.py +++ b/tests/run_tests/driver_dc_b2d_rotated_gradients_test.py @@ -103,7 +103,7 @@ def test_dc_rotated_gradient_p3d_run( ) with Workspace(workpath) as geoh5: - potential = geoh5.get_entity("Iteration_0_dc")[0] + potential = geoh5.get_entity("Iteration_0_potential")[0] out_group = geoh5.get_entity("Line 1")[0].parent mesh = out_group.get_entity("mesh")[0] # Finds the octree mesh topography = geoh5.get_entity("topography")[0] diff --git a/tests/run_tests/driver_dc_b2d_test.py b/tests/run_tests/driver_dc_b2d_test.py index d6bba018..dcb703e9 100644 --- a/tests/run_tests/driver_dc_b2d_test.py +++ b/tests/run_tests/driver_dc_b2d_test.py @@ -93,7 +93,7 @@ def test_dc_p3d_run( workpath = tmp_path.parent / "test_dc_p3d_fwr_run0" / "inversion_test.ui.geoh5" with Workspace(workpath) as geoh5: - potential = geoh5.get_entity("Iteration_0_dc")[0] + potential = geoh5.get_entity("Iteration_0_potential")[0] out_group = geoh5.get_entity("Line 1")[0].parent mesh = out_group.get_entity("mesh")[0] # Finds the octree mesh topography = geoh5.get_entity("topography")[0] diff --git a/tests/run_tests/driver_dc_test.py b/tests/run_tests/driver_dc_test.py index dc891abd..0d6cb2e2 100644 --- a/tests/run_tests/driver_dc_test.py +++ b/tests/run_tests/driver_dc_test.py @@ -87,7 +87,7 @@ def test_dc_3d_run( workpath = tmp_path.parent / "test_dc_3d_fwr_run0" / "inversion_test.ui.geoh5" with Workspace(workpath) as geoh5: - potential = geoh5.get_entity("Iteration_0_dc")[0] + potential = geoh5.get_entity("Iteration_0_potential")[0] mesh = geoh5.get_entity("mesh")[0] topography = geoh5.get_entity("topography")[0] From ac3d7a6139692b48ead364e9d7cfc41be89ffb47 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 18 Aug 2025 10:50:56 -0700 Subject: [PATCH 42/56] Clean up attribute sorting of driver and MisfitFactory --- .../components/factories/misfit_factory.py | 3 +-- simpeg_drivers/driver.py | 13 +++++++++---- tests/data_test.py | 5 ++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/simpeg_drivers/components/factories/misfit_factory.py b/simpeg_drivers/components/factories/misfit_factory.py index e79abf88..439b3e0d 100644 --- a/simpeg_drivers/components/factories/misfit_factory.py +++ b/simpeg_drivers/components/factories/misfit_factory.py @@ -38,7 +38,6 @@ def __init__(self, params: BaseParams | BaseOptions, simulation: BaseSimulation) self.simpeg_object = self.concrete_object() self.factory_type = self.params.inversion_type self.simulation = simulation - self.sorting = None def concrete_object(self): return objective_function.ComboObjectiveFunction @@ -48,7 +47,7 @@ def build(self, tiles, split_list): # pylint: disable=arguments-differ tiles=tiles, split_list=split_list, ) - return global_misfit, self.sorting + return global_misfit def assemble_arguments( # pylint: disable=arguments-differ self, diff --git a/simpeg_drivers/driver.py b/simpeg_drivers/driver.py index 9a2173fc..4152ef1d 100644 --- a/simpeg_drivers/driver.py +++ b/simpeg_drivers/driver.py @@ -169,14 +169,12 @@ def data_misfit(self): self.logger.write(f"Setting up {len(tiles)} tile(s) . . .\n") # Build tiled misfits and combine to form global misfit - self._data_misfit, self._sorting = MisfitFactory( - self.params, self.simulation - ).build( + self._data_misfit = MisfitFactory(self.params, self.simulation).build( tiles, self.split_list, ) self.logger.write("Saving data to file...\n") - self._sorting = np.hstack(tiles) + self._sorting = tiles if isinstance(self.params, BaseInversionOptions): self._data_misfit.multipliers = np.asarray( self._data_misfit.multipliers, dtype=float @@ -406,6 +404,13 @@ def simulation(self): return self._simulation + @property + def sorting(self) -> list[np.ndarray] | None: + """ + Sorting of the data locations. + """ + return self._sorting + @property def window(self): """Inversion window""" diff --git a/tests/data_test.py b/tests/data_test.py index 8fbbd3e6..9d40dfca 100644 --- a/tests/data_test.py +++ b/tests/data_test.py @@ -153,7 +153,7 @@ def test_survey_data(tmp_path: Path): # test locations np.testing.assert_array_equal( - verts[driver.sorting, :2], + verts[np.hstack(driver.sorting), :2], np.vstack( [ local_survey_a.receiver_locations[:, :2], @@ -166,10 +166,9 @@ def test_survey_data(tmp_path: Path): assert all(local_survey_b.receiver_locations[:, 2] == 0.0) # test observed data - sorting = np.hstack(driver.sorting) expected_dobs = np.column_stack( [bxx_data.values, byy_data.values, bzz_data.values] - )[sorting].ravel() + )[np.hstack(driver.sorting)].ravel() survey_dobs = [local_survey_a.dobs, local_survey_b.dobs] np.testing.assert_array_equal(expected_dobs, np.hstack(survey_dobs)) From c6b37963895b8e350ec38864af3bb3add75f2364 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 18 Aug 2025 11:11:15 -0700 Subject: [PATCH 43/56] Use divide for normalizations --- simpeg_drivers/components/factories/directives_factory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simpeg_drivers/components/factories/directives_factory.py b/simpeg_drivers/components/factories/directives_factory.py index 161d83f9..6301d2ff 100644 --- a/simpeg_drivers/components/factories/directives_factory.py +++ b/simpeg_drivers/components/factories/directives_factory.py @@ -504,7 +504,7 @@ def reshape(values): "transforms": [ np.hstack( [ - inversion_object.normalizations[chan][comp] + 1 / inversion_object.normalizations[chan][comp] for chan in channels for comp in components ], From 959755b495c02fc9e1131e8b92f4f656cbce1c63 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 18 Aug 2025 12:51:38 -0700 Subject: [PATCH 44/56] Re-lock --- .../py-3.10-linux-64-dev.conda.lock.yml | 16 +-- environments/py-3.10-linux-64.conda.lock.yml | 10 +- .../py-3.10-win-64-dev.conda.lock.yml | 16 +-- environments/py-3.10-win-64.conda.lock.yml | 10 +- .../py-3.11-linux-64-dev.conda.lock.yml | 16 +-- environments/py-3.11-linux-64.conda.lock.yml | 10 +- .../py-3.11-win-64-dev.conda.lock.yml | 16 +-- environments/py-3.11-win-64.conda.lock.yml | 10 +- .../py-3.12-linux-64-dev.conda.lock.yml | 16 +-- environments/py-3.12-linux-64.conda.lock.yml | 10 +- .../py-3.12-win-64-dev.conda.lock.yml | 16 +-- environments/py-3.12-win-64.conda.lock.yml | 10 +- py-3.10.conda-lock.yml | 134 +++++++++--------- py-3.11.conda-lock.yml | 132 ++++++++--------- py-3.12.conda-lock.yml | 132 ++++++++--------- 15 files changed, 277 insertions(+), 277 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 ea7eac8e..6e1c01af 100644 --- a/environments/py-3.10-linux-64-dev.conda.lock.yml +++ b/environments/py-3.10-linux-64-dev.conda.lock.yml @@ -40,7 +40,7 @@ dependencies: - colorama=0.4.6=pyhd8ed1ab_1 - comm=0.2.3=pyhe01879c_0 - contourpy=1.3.2=py310h3788b33_0 - - coverage=7.10.3=py310h3406613_0 + - coverage=7.10.4=py310h3406613_0 - cycler=0.12.1=pyhd8ed1ab_1 - cytoolz=1.0.1=py310ha75aee5_0 - dask-core=2025.3.0=pyhd8ed1ab_0 @@ -55,7 +55,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - executing=2.2.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - - fonttools=4.59.0=py310h3406613_0 + - fonttools=4.59.1=py310h3406613_0 - fqdn=1.5.1=pyhd8ed1ab_1 - freetype=2.13.3=ha770c72_1 - fsspec=2025.7.0=pyhd8ed1ab_0 @@ -96,7 +96,7 @@ dependencies: - jupyter_events=0.12.0=pyh29332c3_0 - jupyter_server=2.16.0=pyhe01879c_0 - jupyter_server_terminals=0.5.3=pyhd8ed1ab_1 - - jupyterlab=4.4.5=pyhd8ed1ab_0 + - jupyterlab=4.4.6=pyhd8ed1ab_0 - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_server=2.27.3=pyhd8ed1ab_1 - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 @@ -217,7 +217,7 @@ dependencies: - pytest-cov=6.2.1=pyhd8ed1ab_0 - python=3.10.18=hd6af730_0_cpython - python-dateutil=2.9.0.post0=pyhe01879c_2 - - python-fastjsonschema=2.21.1=pyhd8ed1ab_0 + - python-fastjsonschema=2.21.2=pyhe01879c_0 - python-json-logger=2.0.7=pyhd8ed1ab_0 - python-mumps=0.0.3=py310h6410a28_0 - python-tzdata=2025.2=pyhd8ed1ab_0 @@ -304,11 +304,11 @@ dependencies: - zstandard=0.23.0=py310ha75aee5_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d 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 48d364f7..b4c7de31 100644 --- a/environments/py-3.10-linux-64.conda.lock.yml +++ b/environments/py-3.10-linux-64.conda.lock.yml @@ -30,7 +30,7 @@ dependencies: - discretize=0.11.3=py310ha2bacc8_0 - distributed=2025.3.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - - fonttools=4.59.0=py310h3406613_0 + - fonttools=4.59.1=py310h3406613_0 - freetype=2.13.3=ha770c72_1 - fsspec=2025.7.0=pyhd8ed1ab_0 - geoana=0.7.2=py310ha2bacc8_0 @@ -156,11 +156,11 @@ dependencies: - zstandard=0.23.0=py310ha75aee5_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d 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 94c6efef..d84f9d4d 100644 --- a/environments/py-3.10-win-64-dev.conda.lock.yml +++ b/environments/py-3.10-win-64-dev.conda.lock.yml @@ -39,7 +39,7 @@ dependencies: - colorama=0.4.6=pyhd8ed1ab_1 - comm=0.2.3=pyhe01879c_0 - contourpy=1.3.2=py310hc19bc0b_0 - - coverage=7.10.3=py310hdb0e946_0 + - coverage=7.10.4=py310hdb0e946_0 - cpython=3.10.18=py310hd8ed1ab_0 - cycler=0.12.1=pyhd8ed1ab_1 - cytoolz=1.0.1=py310ha8f682b_0 @@ -55,7 +55,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - executing=2.2.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - - fonttools=4.59.0=py310hdb0e946_0 + - fonttools=4.59.1=py310hdb0e946_0 - fqdn=1.5.1=pyhd8ed1ab_1 - freetype=2.13.3=h57928b3_1 - fsspec=2025.7.0=pyhd8ed1ab_0 @@ -96,7 +96,7 @@ dependencies: - jupyter_events=0.12.0=pyh29332c3_0 - jupyter_server=2.16.0=pyhe01879c_0 - jupyter_server_terminals=0.5.3=pyhd8ed1ab_1 - - jupyterlab=4.4.5=pyhd8ed1ab_0 + - jupyterlab=4.4.6=pyhd8ed1ab_0 - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_server=2.27.3=pyhd8ed1ab_1 - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 @@ -200,7 +200,7 @@ dependencies: - pytest-cov=6.2.1=pyhd8ed1ab_0 - python=3.10.18=h8c5b53a_0_cpython - python-dateutil=2.9.0.post0=pyhe01879c_2 - - python-fastjsonschema=2.21.1=pyhd8ed1ab_0 + - python-fastjsonschema=2.21.2=pyhe01879c_0 - python-json-logger=2.0.7=pyhd8ed1ab_0 - python-mumps=0.0.3=py310hb64895d_0 - python-tzdata=2025.2=pyhd8ed1ab_0 @@ -294,11 +294,11 @@ dependencies: - zstandard=0.23.0=py310ha8f682b_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d 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 89dd5d1b..5ce88592 100644 --- a/environments/py-3.10-win-64.conda.lock.yml +++ b/environments/py-3.10-win-64.conda.lock.yml @@ -29,7 +29,7 @@ dependencies: - discretize=0.11.3=py310h3e8ed56_0 - distributed=2025.3.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - - fonttools=4.59.0=py310hdb0e946_0 + - fonttools=4.59.1=py310hdb0e946_0 - freetype=2.13.3=h57928b3_1 - fsspec=2025.7.0=pyhd8ed1ab_0 - geoana=0.7.2=py310h3e8ed56_0 @@ -144,11 +144,11 @@ dependencies: - zstandard=0.23.0=py310ha8f682b_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d 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 54247094..df316b8c 100644 --- a/environments/py-3.11-linux-64-dev.conda.lock.yml +++ b/environments/py-3.11-linux-64-dev.conda.lock.yml @@ -40,7 +40,7 @@ dependencies: - colorama=0.4.6=pyhd8ed1ab_1 - comm=0.2.3=pyhe01879c_0 - contourpy=1.3.3=py311hdf67eae_1 - - coverage=7.10.3=py311h3778330_0 + - coverage=7.10.4=py311h3778330_0 - cycler=0.12.1=pyhd8ed1ab_1 - cytoolz=1.0.1=py311h9ecbd09_0 - dask-core=2025.3.0=pyhd8ed1ab_0 @@ -56,7 +56,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - executing=2.2.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - - fonttools=4.59.0=py311h3778330_0 + - fonttools=4.59.1=py311h3778330_0 - fqdn=1.5.1=pyhd8ed1ab_1 - freetype=2.13.3=ha770c72_1 - fsspec=2025.7.0=pyhd8ed1ab_0 @@ -98,7 +98,7 @@ dependencies: - jupyter_events=0.12.0=pyh29332c3_0 - jupyter_server=2.16.0=pyhe01879c_0 - jupyter_server_terminals=0.5.3=pyhd8ed1ab_1 - - jupyterlab=4.4.5=pyhd8ed1ab_0 + - jupyterlab=4.4.6=pyhd8ed1ab_0 - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_server=2.27.3=pyhd8ed1ab_1 - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 @@ -219,7 +219,7 @@ dependencies: - pytest-cov=6.2.1=pyhd8ed1ab_0 - python=3.11.13=h9e4cc4f_0_cpython - python-dateutil=2.9.0.post0=pyhe01879c_2 - - python-fastjsonschema=2.21.1=pyhd8ed1ab_0 + - python-fastjsonschema=2.21.2=pyhe01879c_0 - python-json-logger=2.0.7=pyhd8ed1ab_0 - python-mumps=0.0.3=py311h4b558b0_0 - python-tzdata=2025.2=pyhd8ed1ab_0 @@ -307,11 +307,11 @@ dependencies: - zstandard=0.23.0=py311h9ecbd09_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d 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 0f0e39a0..55f09b4c 100644 --- a/environments/py-3.11-linux-64.conda.lock.yml +++ b/environments/py-3.11-linux-64.conda.lock.yml @@ -31,7 +31,7 @@ dependencies: - discretize=0.11.3=py311h5b7b71f_0 - distributed=2025.3.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - - fonttools=4.59.0=py311h3778330_0 + - fonttools=4.59.1=py311h3778330_0 - freetype=2.13.3=ha770c72_1 - fsspec=2025.7.0=pyhd8ed1ab_0 - geoana=0.7.2=py311h5b7b71f_0 @@ -158,11 +158,11 @@ dependencies: - zstandard=0.23.0=py311h9ecbd09_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d 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 c063f6ba..d52e63c3 100644 --- a/environments/py-3.11-win-64-dev.conda.lock.yml +++ b/environments/py-3.11-win-64-dev.conda.lock.yml @@ -39,7 +39,7 @@ dependencies: - colorama=0.4.6=pyhd8ed1ab_1 - comm=0.2.3=pyhe01879c_0 - contourpy=1.3.3=py311h3fd045d_1 - - coverage=7.10.3=py311h3f79411_0 + - coverage=7.10.4=py311h3f79411_0 - cpython=3.11.13=py311hd8ed1ab_0 - cycler=0.12.1=pyhd8ed1ab_1 - cytoolz=1.0.1=py311he736701_0 @@ -56,7 +56,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - executing=2.2.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - - fonttools=4.59.0=py311h3f79411_0 + - fonttools=4.59.1=py311h3f79411_0 - fqdn=1.5.1=pyhd8ed1ab_1 - freetype=2.13.3=h57928b3_1 - fsspec=2025.7.0=pyhd8ed1ab_0 @@ -98,7 +98,7 @@ dependencies: - jupyter_events=0.12.0=pyh29332c3_0 - jupyter_server=2.16.0=pyhe01879c_0 - jupyter_server_terminals=0.5.3=pyhd8ed1ab_1 - - jupyterlab=4.4.5=pyhd8ed1ab_0 + - jupyterlab=4.4.6=pyhd8ed1ab_0 - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_server=2.27.3=pyhd8ed1ab_1 - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 @@ -202,7 +202,7 @@ dependencies: - pytest-cov=6.2.1=pyhd8ed1ab_0 - python=3.11.13=h3f84c4b_0_cpython - python-dateutil=2.9.0.post0=pyhe01879c_2 - - python-fastjsonschema=2.21.1=pyhd8ed1ab_0 + - python-fastjsonschema=2.21.2=pyhe01879c_0 - python-json-logger=2.0.7=pyhd8ed1ab_0 - python-mumps=0.0.3=py311h5bfbc98_0 - python-tzdata=2025.2=pyhd8ed1ab_0 @@ -297,11 +297,11 @@ dependencies: - zstandard=0.23.0=py311he736701_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d 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 0b73b9b0..6619c4ac 100644 --- a/environments/py-3.11-win-64.conda.lock.yml +++ b/environments/py-3.11-win-64.conda.lock.yml @@ -30,7 +30,7 @@ dependencies: - discretize=0.11.3=py311h9b10771_0 - distributed=2025.3.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - - fonttools=4.59.0=py311h3f79411_0 + - fonttools=4.59.1=py311h3f79411_0 - freetype=2.13.3=h57928b3_1 - fsspec=2025.7.0=pyhd8ed1ab_0 - geoana=0.7.2=py311h9b10771_0 @@ -146,11 +146,11 @@ dependencies: - zstandard=0.23.0=py311he736701_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d 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 ca01ff72..8eedf9b8 100644 --- a/environments/py-3.12-linux-64-dev.conda.lock.yml +++ b/environments/py-3.12-linux-64-dev.conda.lock.yml @@ -40,7 +40,7 @@ dependencies: - colorama=0.4.6=pyhd8ed1ab_1 - comm=0.2.3=pyhe01879c_0 - contourpy=1.3.3=py312hd9148b4_1 - - coverage=7.10.3=py312h8a5da7c_0 + - coverage=7.10.4=py312h8a5da7c_0 - cycler=0.12.1=pyhd8ed1ab_1 - cytoolz=1.0.1=py312h66e93f0_0 - dask-core=2025.3.0=pyhd8ed1ab_0 @@ -56,7 +56,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - executing=2.2.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - - fonttools=4.59.0=py312h8a5da7c_0 + - fonttools=4.59.1=py312h8a5da7c_0 - fqdn=1.5.1=pyhd8ed1ab_1 - freetype=2.13.3=ha770c72_1 - fsspec=2025.7.0=pyhd8ed1ab_0 @@ -98,7 +98,7 @@ dependencies: - jupyter_events=0.12.0=pyh29332c3_0 - jupyter_server=2.16.0=pyhe01879c_0 - jupyter_server_terminals=0.5.3=pyhd8ed1ab_1 - - jupyterlab=4.4.5=pyhd8ed1ab_0 + - jupyterlab=4.4.6=pyhd8ed1ab_0 - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_server=2.27.3=pyhd8ed1ab_1 - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 @@ -219,7 +219,7 @@ dependencies: - pytest-cov=6.2.1=pyhd8ed1ab_0 - python=3.12.11=h9e4cc4f_0_cpython - python-dateutil=2.9.0.post0=pyhe01879c_2 - - python-fastjsonschema=2.21.1=pyhd8ed1ab_0 + - python-fastjsonschema=2.21.2=pyhe01879c_0 - python-json-logger=2.0.7=pyhd8ed1ab_0 - python-mumps=0.0.3=py312h6ad3ee3_0 - python-tzdata=2025.2=pyhd8ed1ab_0 @@ -307,11 +307,11 @@ dependencies: - zstandard=0.23.0=py312h66e93f0_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d 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 ba1eaff3..8fcec162 100644 --- a/environments/py-3.12-linux-64.conda.lock.yml +++ b/environments/py-3.12-linux-64.conda.lock.yml @@ -31,7 +31,7 @@ dependencies: - discretize=0.11.3=py312hc39e661_0 - distributed=2025.3.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - - fonttools=4.59.0=py312h8a5da7c_0 + - fonttools=4.59.1=py312h8a5da7c_0 - freetype=2.13.3=ha770c72_1 - fsspec=2025.7.0=pyhd8ed1ab_0 - geoana=0.7.2=py312hc39e661_0 @@ -158,11 +158,11 @@ dependencies: - zstandard=0.23.0=py312h66e93f0_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d 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 f7205c36..78ea60cb 100644 --- a/environments/py-3.12-win-64-dev.conda.lock.yml +++ b/environments/py-3.12-win-64-dev.conda.lock.yml @@ -39,7 +39,7 @@ dependencies: - colorama=0.4.6=pyhd8ed1ab_1 - comm=0.2.3=pyhe01879c_0 - contourpy=1.3.3=py312hf90b1b7_1 - - coverage=7.10.3=py312h05f76fc_0 + - coverage=7.10.4=py312h05f76fc_0 - cpython=3.12.11=py312hd8ed1ab_0 - cycler=0.12.1=pyhd8ed1ab_1 - cytoolz=1.0.1=py312h4389bb4_0 @@ -56,7 +56,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - executing=2.2.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - - fonttools=4.59.0=py312h05f76fc_0 + - fonttools=4.59.1=py312h05f76fc_0 - fqdn=1.5.1=pyhd8ed1ab_1 - freetype=2.13.3=h57928b3_1 - fsspec=2025.7.0=pyhd8ed1ab_0 @@ -98,7 +98,7 @@ dependencies: - jupyter_events=0.12.0=pyh29332c3_0 - jupyter_server=2.16.0=pyhe01879c_0 - jupyter_server_terminals=0.5.3=pyhd8ed1ab_1 - - jupyterlab=4.4.5=pyhd8ed1ab_0 + - jupyterlab=4.4.6=pyhd8ed1ab_0 - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_server=2.27.3=pyhd8ed1ab_1 - jupyterlab_widgets=1.1.11=pyhd8ed1ab_0 @@ -202,7 +202,7 @@ dependencies: - pytest-cov=6.2.1=pyhd8ed1ab_0 - python=3.12.11=h3f84c4b_0_cpython - python-dateutil=2.9.0.post0=pyhe01879c_2 - - python-fastjsonschema=2.21.1=pyhd8ed1ab_0 + - python-fastjsonschema=2.21.2=pyhe01879c_0 - python-json-logger=2.0.7=pyhd8ed1ab_0 - python-mumps=0.0.3=py312h8095395_0 - python-tzdata=2025.2=pyhd8ed1ab_0 @@ -297,11 +297,11 @@ dependencies: - zstandard=0.23.0=py312h4389bb4_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d 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 1ad58ef1..0b9891c9 100644 --- a/environments/py-3.12-win-64.conda.lock.yml +++ b/environments/py-3.12-win-64.conda.lock.yml @@ -30,7 +30,7 @@ dependencies: - discretize=0.11.3=py312hbaa7e33_0 - distributed=2025.3.0=pyhd8ed1ab_0 - fasteners=0.19=pyhd8ed1ab_1 - - fonttools=4.59.0=py312h05f76fc_0 + - fonttools=4.59.1=py312h05f76fc_0 - freetype=2.13.3=h57928b3_1 - fsspec=2025.7.0=pyhd8ed1ab_0 - geoana=0.7.2=py312hbaa7e33_0 @@ -146,11 +146,11 @@ dependencies: - zstandard=0.23.0=py312h4389bb4_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 - - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 - - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d variables: KMP_WARNINGS: 0 diff --git a/py-3.10.conda-lock.yml b/py-3.10.conda-lock.yml index 75934e22..e09a4f43 100644 --- a/py-3.10.conda-lock.yml +++ b/py-3.10.conda-lock.yml @@ -949,7 +949,7 @@ package: category: main optional: false - name: coverage - version: 7.10.3 + version: 7.10.4 manager: conda platform: linux-64 dependencies: @@ -958,14 +958,14 @@ package: python: '>=3.10,<3.11.0a0' python_abi: 3.10.* tomli: '' - url: https://repo.prefix.dev/conda-forge/linux-64/coverage-7.10.3-py310h3406613_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/coverage-7.10.4-py310h3406613_0.conda hash: - md5: 075e8dd909720be418b6d94ed1b3d517 - sha256: 6163d00602de9937a5af06eefbf2a2c83e865d24c2efc8e55abf8f2f6ff8691e + md5: ac9c681b16e9b9d24eca83a367b52fcd + sha256: caf25a0e293b86d93ff036f6e0b0769673031e136716faa0b7bae9fda125ff76 category: dev optional: true - name: coverage - version: 7.10.3 + version: 7.10.4 manager: conda platform: win-64 dependencies: @@ -975,10 +975,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/coverage-7.10.3-py310hdb0e946_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/coverage-7.10.4-py310hdb0e946_0.conda hash: - md5: ae729ad9cc463282ad54c8380576d799 - sha256: 255952213dce744c952042f87865947d431b69cbadae08de8d3a7c97ceac2729 + md5: 31ceebbc098babf2d50d2745205c633b + sha256: a3887e59288526c8230a036af4f317bbc188ae11101ff2c00996eb5919ddcf89 category: dev optional: true - name: cpython @@ -1412,7 +1412,7 @@ package: category: main optional: false - name: fonttools - version: 4.59.0 + version: 4.59.1 manager: conda platform: linux-64 dependencies: @@ -1423,14 +1423,14 @@ package: python: '>=3.10,<3.11.0a0' python_abi: 3.10.* unicodedata2: '>=15.1.0' - url: https://repo.prefix.dev/conda-forge/linux-64/fonttools-4.59.0-py310h3406613_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/fonttools-4.59.1-py310h3406613_0.conda hash: - md5: dc2e5602e20bbffb18314a70094b3c4a - sha256: 7ac6105dbbdb2e648b685b813f38a0df39b1d4264cbd13953c83ff7cf451269d + md5: 14e450afac608165ced4b0b93cfc1df1 + sha256: b634c855e3308e3463d75d57ef8188b023c14778c6ede7fc2ddddd22f7ee2df7 category: main optional: false - name: fonttools - version: 4.59.0 + version: 4.59.1 manager: conda platform: win-64 dependencies: @@ -1442,10 +1442,10 @@ package: unicodedata2: '>=15.1.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/fonttools-4.59.0-py310hdb0e946_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/fonttools-4.59.1-py310hdb0e946_0.conda hash: - md5: eae900c4fcb37e4a3f9fe9417c669f11 - sha256: 8dc419489a74d368312a685d217896a04936373b409cf0da99807f59857cba48 + md5: 6df5bf934873bcf1d2d2208a364afe1b + sha256: 67bb84f9aeb1ba4f2efced2cc3059faabc878d6d4a25bbcffc0a1134b702ab56 category: main optional: false - name: fqdn @@ -2720,14 +2720,14 @@ package: category: dev optional: true - name: jupyterlab - version: 4.4.5 + version: 4.4.6 manager: conda platform: linux-64 dependencies: async-lru: '>=1.0.0' - httpx: '>=0.25.0' + httpx: '>=0.25.0,<1' importlib-metadata: '>=4.8.3' - ipykernel: '>=6.5.0' + ipykernel: '>=6.5.0,!=6.30.0' jinja2: '>=3.0.3' jupyter-lsp: '>=2.0.0' jupyter_core: '' @@ -2740,21 +2740,21 @@ package: tomli: '>=1.2.2' tornado: '>=6.2.0' traitlets: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.4.5-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.4.6-pyhd8ed1ab_0.conda hash: - md5: ad6bbe770780dcf9cf55d724c5a213fd - sha256: 2013c2dd13bc773167e1ad11ae885b550c0297d030e2107bdc303243ff05d3f2 + md5: 70cb2903114eafc6ed5d70ca91ba6545 + sha256: c3558f1c2a5977799ce425f1f7c8d8d1cae3408da41ec4f5c3771a21e673d465 category: dev optional: true - name: jupyterlab - version: 4.4.5 + version: 4.4.6 manager: conda platform: win-64 dependencies: async-lru: '>=1.0.0' - httpx: '>=0.25.0' + httpx: '>=0.25.0,<1' importlib-metadata: '>=4.8.3' - ipykernel: '>=6.5.0' + ipykernel: '>=6.5.0,!=6.30.0' jinja2: '>=3.0.3' jupyter-lsp: '>=2.0.0' jupyter_core: '' @@ -2767,10 +2767,10 @@ package: tomli: '>=1.2.2' tornado: '>=6.2.0' traitlets: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.4.5-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.4.6-pyhd8ed1ab_0.conda hash: - md5: ad6bbe770780dcf9cf55d724c5a213fd - sha256: 2013c2dd13bc773167e1ad11ae885b550c0297d030e2107bdc303243ff05d3f2 + md5: 70cb2903114eafc6ed5d70ca91ba6545 + sha256: c3558f1c2a5977799ce425f1f7c8d8d1cae3408da41ec4f5c3771a21e673d465 category: dev optional: true - name: jupyterlab_pygments @@ -6072,27 +6072,27 @@ package: category: main optional: false - name: python-fastjsonschema - version: 2.21.1 + version: 2.21.2 manager: conda platform: linux-64 dependencies: - python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/python-fastjsonschema-2.21.1-pyhd8ed1ab_0.conda + python: '' + url: https://repo.prefix.dev/conda-forge/noarch/python-fastjsonschema-2.21.2-pyhe01879c_0.conda hash: - md5: 38e34d2d1d9dca4fb2b9a0a04f604e2c - sha256: 1b09a28093071c1874862422696429d0d35bd0b8420698003ac004746c5e82a2 + md5: 23029aae904a2ba587daba708208012f + sha256: df9aa74e9e28e8d1309274648aac08ec447a92512c33f61a8de0afa9ce32ebe8 category: dev optional: true - name: python-fastjsonschema - version: 2.21.1 + version: 2.21.2 manager: conda platform: win-64 dependencies: python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/python-fastjsonschema-2.21.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/python-fastjsonschema-2.21.2-pyhe01879c_0.conda hash: - md5: 38e34d2d1d9dca4fb2b9a0a04f604e2c - sha256: 1b09a28093071c1874862422696429d0d35bd0b8420698003ac004746c5e82a2 + md5: 23029aae904a2ba587daba708208012f + sha256: df9aa74e9e28e8d1309274648aac08ec447a92512c33f61a8de0afa9ce32ebe8 category: dev optional: true - name: python-json-logger @@ -8522,7 +8522,7 @@ package: category: main optional: false - name: geoapps-utils - version: 0.6.0-alpha.1 + version: 0.6.0a1 manager: pip platform: linux-64 dependencies: @@ -8530,16 +8530,16 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 hash: - sha256: d0d3ced2e3f84109ee49270adb936f42b490d99f + sha256: 183ed8f654bc393eeafdf89b2c258a224f4b4b73 source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 category: main optional: false - name: geoapps-utils - version: 0.6.0-alpha.1 + version: 0.6.0a1 manager: pip platform: win-64 dependencies: @@ -8547,12 +8547,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 hash: - sha256: d0d3ced2e3f84109ee49270adb936f42b490d99f + sha256: 183ed8f654bc393eeafdf89b2c258a224f4b4b73 source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 category: main optional: false - name: geoh5py @@ -8590,7 +8590,7 @@ package: category: main optional: false - name: mira-simpeg - version: 0.23.0.1.post2.dev42+g26cae9aae + version: 0.23.0.1.post2.dev55+mira.g2e61aceb1 manager: pip platform: linux-64 dependencies: @@ -8602,16 +8602,16 @@ package: numpy: '>=1.22' pymatsolver: '>=0.3' scipy: '>=1.8' - url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + url: git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e hash: - sha256: 26cae9aae7018fa4da8b1132138d2beff9fc5a91 + sha256: 2e61aceb15b21e896c6190b8426075e9a04cf78e source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + url: git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e category: main optional: false - name: mira-simpeg - version: 0.23.0.1.post2.dev42+g26cae9aae + version: 0.23.0.1.post2.dev55+mira.g2e61aceb1 manager: pip platform: win-64 dependencies: @@ -8623,12 +8623,12 @@ package: numpy: '>=1.22' pymatsolver: '>=0.3' scipy: '>=1.8' - url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + url: git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e hash: - sha256: 26cae9aae7018fa4da8b1132138d2beff9fc5a91 + sha256: 2e61aceb15b21e896c6190b8426075e9a04cf78e source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + url: git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e category: main optional: false - name: octree-creation-app @@ -8637,17 +8637,17 @@ package: platform: linux-64 dependencies: discretize: ==0.11.* - geoapps-utils: 0.6.0-alpha.1 + geoapps-utils: 0.6.0a1 geoh5py: 0.12.0a1 numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 hash: - sha256: 02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + sha256: 47fa41aa60b8473b7333f846ff329705b8a62129 source: type: url - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 category: main optional: false - name: octree-creation-app @@ -8656,17 +8656,17 @@ package: platform: win-64 dependencies: discretize: ==0.11.* - geoapps-utils: 0.6.0-alpha.1 + geoapps-utils: 0.6.0a1 geoh5py: 0.12.0a1 numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 hash: - sha256: 02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + sha256: 47fa41aa60b8473b7333f846ff329705b8a62129 source: type: url - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 category: main optional: false - name: param-sweeps @@ -8676,12 +8676,12 @@ package: dependencies: geoh5py: 0.12.0a1 numpy: '>=1.26.0,<1.27.0' - url: git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + url: git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d hash: - sha256: 9ed6091534d638171957a17324e1a1e8f067b434 + sha256: cee0044fc645d73d33444cc82ce040772741dc1d source: type: url - url: git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + url: git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d category: main optional: false - name: param-sweeps @@ -8691,11 +8691,11 @@ package: dependencies: geoh5py: 0.12.0a1 numpy: '>=1.26.0,<1.27.0' - url: git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + url: git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d hash: - sha256: 9ed6091534d638171957a17324e1a1e8f067b434 + sha256: cee0044fc645d73d33444cc82ce040772741dc1d source: type: url - url: git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + url: git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d category: main optional: false diff --git a/py-3.11.conda-lock.yml b/py-3.11.conda-lock.yml index 97c793cd..353771d5 100644 --- a/py-3.11.conda-lock.yml +++ b/py-3.11.conda-lock.yml @@ -947,7 +947,7 @@ package: category: main optional: false - name: coverage - version: 7.10.3 + version: 7.10.4 manager: conda platform: linux-64 dependencies: @@ -956,14 +956,14 @@ package: python: '>=3.11,<3.12.0a0' python_abi: 3.11.* tomli: '' - url: https://repo.prefix.dev/conda-forge/linux-64/coverage-7.10.3-py311h3778330_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/coverage-7.10.4-py311h3778330_0.conda hash: - md5: ad2711c0c4366177466c4bb7d3dd6809 - sha256: 1da38824b3e4337f8bd3407936222677d6accc882a3badf39244600fc73f140e + md5: 9b03916fb3692cfed283361d809b8d56 + sha256: 121a56fcc30a295ca96f160925325d5611c06a70363d98dce1693e50497c9c32 category: dev optional: true - name: coverage - version: 7.10.3 + version: 7.10.4 manager: conda platform: win-64 dependencies: @@ -973,10 +973,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/coverage-7.10.3-py311h3f79411_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/coverage-7.10.4-py311h3f79411_0.conda hash: - md5: 19738e4a2b8c0f882769c4ecf2663b09 - sha256: e046c26ed49e18fbaa258a5705691acec6aab8f2017e45ecea104a0d5e50c1be + md5: 81fa156b61a922d0bf7603ff13727dcd + sha256: 6699830c768103a5bb7be93eda055915965295923ed4006316a2926e551d26bd category: dev optional: true - name: cpython @@ -1436,7 +1436,7 @@ package: category: main optional: false - name: fonttools - version: 4.59.0 + version: 4.59.1 manager: conda platform: linux-64 dependencies: @@ -1447,14 +1447,14 @@ package: python: '>=3.11,<3.12.0a0' python_abi: 3.11.* unicodedata2: '>=15.1.0' - url: https://repo.prefix.dev/conda-forge/linux-64/fonttools-4.59.0-py311h3778330_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/fonttools-4.59.1-py311h3778330_0.conda hash: - md5: 2eaecc2e416852815abb85dc47d425b3 - sha256: d82af0b7a12c6fdb30de81f83da5aba89ac8628744630dc67cd9cfc5eedadb3d + md5: a879d36924dd853bf855ed423b02d92b + sha256: a272826eb8bda4c7207db735448f67f1e5ce79a08eb5a78271c62d9ea452a275 category: main optional: false - name: fonttools - version: 4.59.0 + version: 4.59.1 manager: conda platform: win-64 dependencies: @@ -1466,10 +1466,10 @@ package: unicodedata2: '>=15.1.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/fonttools-4.59.0-py311h3f79411_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/fonttools-4.59.1-py311h3f79411_0.conda hash: - md5: 4ca28d9b6582ba8c7dfc0d738ca43258 - sha256: f26dafd8a4fd0b98a8e8363e6ff98bfc1c1be8a378f89829323b16ce6e05e675 + md5: 3d3e2e033fff6713ab0764b096075216 + sha256: fe80ef99e7c4d7fcc1be28615a7d1e91396c3410cad245969633d1d1155f62ef category: main optional: false - name: fqdn @@ -2772,14 +2772,14 @@ package: category: dev optional: true - name: jupyterlab - version: 4.4.5 + version: 4.4.6 manager: conda platform: linux-64 dependencies: async-lru: '>=1.0.0' - httpx: '>=0.25.0' + httpx: '>=0.25.0,<1' importlib-metadata: '>=4.8.3' - ipykernel: '>=6.5.0' + ipykernel: '>=6.5.0,!=6.30.0' jinja2: '>=3.0.3' jupyter-lsp: '>=2.0.0' jupyter_core: '' @@ -2792,21 +2792,21 @@ package: tomli: '>=1.2.2' tornado: '>=6.2.0' traitlets: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.4.5-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.4.6-pyhd8ed1ab_0.conda hash: - md5: ad6bbe770780dcf9cf55d724c5a213fd - sha256: 2013c2dd13bc773167e1ad11ae885b550c0297d030e2107bdc303243ff05d3f2 + md5: 70cb2903114eafc6ed5d70ca91ba6545 + sha256: c3558f1c2a5977799ce425f1f7c8d8d1cae3408da41ec4f5c3771a21e673d465 category: dev optional: true - name: jupyterlab - version: 4.4.5 + version: 4.4.6 manager: conda platform: win-64 dependencies: async-lru: '>=1.0.0' - httpx: '>=0.25.0' + httpx: '>=0.25.0,<1' importlib-metadata: '>=4.8.3' - ipykernel: '>=6.5.0' + ipykernel: '>=6.5.0,!=6.30.0' jinja2: '>=3.0.3' jupyter-lsp: '>=2.0.0' jupyter_core: '' @@ -2819,10 +2819,10 @@ package: tomli: '>=1.2.2' tornado: '>=6.2.0' traitlets: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.4.5-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.4.6-pyhd8ed1ab_0.conda hash: - md5: ad6bbe770780dcf9cf55d724c5a213fd - sha256: 2013c2dd13bc773167e1ad11ae885b550c0297d030e2107bdc303243ff05d3f2 + md5: 70cb2903114eafc6ed5d70ca91ba6545 + sha256: c3558f1c2a5977799ce425f1f7c8d8d1cae3408da41ec4f5c3771a21e673d465 category: dev optional: true - name: jupyterlab_pygments @@ -6126,27 +6126,27 @@ package: category: main optional: false - name: python-fastjsonschema - version: 2.21.1 + version: 2.21.2 manager: conda platform: linux-64 dependencies: python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/python-fastjsonschema-2.21.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/python-fastjsonschema-2.21.2-pyhe01879c_0.conda hash: - md5: 38e34d2d1d9dca4fb2b9a0a04f604e2c - sha256: 1b09a28093071c1874862422696429d0d35bd0b8420698003ac004746c5e82a2 + md5: 23029aae904a2ba587daba708208012f + sha256: df9aa74e9e28e8d1309274648aac08ec447a92512c33f61a8de0afa9ce32ebe8 category: dev optional: true - name: python-fastjsonschema - version: 2.21.1 + version: 2.21.2 manager: conda platform: win-64 dependencies: python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/python-fastjsonschema-2.21.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/python-fastjsonschema-2.21.2-pyhe01879c_0.conda hash: - md5: 38e34d2d1d9dca4fb2b9a0a04f604e2c - sha256: 1b09a28093071c1874862422696429d0d35bd0b8420698003ac004746c5e82a2 + md5: 23029aae904a2ba587daba708208012f + sha256: df9aa74e9e28e8d1309274648aac08ec447a92512c33f61a8de0afa9ce32ebe8 category: dev optional: true - name: python-json-logger @@ -8607,7 +8607,7 @@ package: category: main optional: false - name: geoapps-utils - version: 0.6.0-alpha.1 + version: 0.6.0a1 manager: pip platform: linux-64 dependencies: @@ -8615,16 +8615,16 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 hash: - sha256: d0d3ced2e3f84109ee49270adb936f42b490d99f + sha256: 183ed8f654bc393eeafdf89b2c258a224f4b4b73 source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 category: main optional: false - name: geoapps-utils - version: 0.6.0-alpha.1 + version: 0.6.0a1 manager: pip platform: win-64 dependencies: @@ -8632,12 +8632,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 hash: - sha256: d0d3ced2e3f84109ee49270adb936f42b490d99f + sha256: 183ed8f654bc393eeafdf89b2c258a224f4b4b73 source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 category: main optional: false - name: geoh5py @@ -8675,7 +8675,7 @@ package: category: main optional: false - name: mira-simpeg - version: 0.23.0.1.post2.dev42+g26cae9aae + version: 0.23.0.1.post2.dev55+mira.g2e61aceb1 manager: pip platform: linux-64 dependencies: @@ -8687,16 +8687,16 @@ package: numpy: '>=1.22' pymatsolver: '>=0.3' scipy: '>=1.8' - url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + url: git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e hash: - sha256: 26cae9aae7018fa4da8b1132138d2beff9fc5a91 + sha256: 2e61aceb15b21e896c6190b8426075e9a04cf78e source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + url: git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e category: main optional: false - name: mira-simpeg - version: 0.23.0.1.post2.dev42+g26cae9aae + version: 0.23.0.1.post2.dev55+mira.g2e61aceb1 manager: pip platform: win-64 dependencies: @@ -8708,12 +8708,12 @@ package: numpy: '>=1.22' pymatsolver: '>=0.3' scipy: '>=1.8' - url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + url: git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e hash: - sha256: 26cae9aae7018fa4da8b1132138d2beff9fc5a91 + sha256: 2e61aceb15b21e896c6190b8426075e9a04cf78e source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + url: git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e category: main optional: false - name: octree-creation-app @@ -8722,17 +8722,17 @@ package: platform: linux-64 dependencies: discretize: ==0.11.* - geoapps-utils: 0.6.0-alpha.1 + geoapps-utils: 0.6.0a1 geoh5py: 0.12.0a1 numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 hash: - sha256: 02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + sha256: 47fa41aa60b8473b7333f846ff329705b8a62129 source: type: url - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 category: main optional: false - name: octree-creation-app @@ -8741,17 +8741,17 @@ package: platform: win-64 dependencies: discretize: ==0.11.* - geoapps-utils: 0.6.0-alpha.1 + geoapps-utils: 0.6.0a1 geoh5py: 0.12.0a1 numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 hash: - sha256: 02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + sha256: 47fa41aa60b8473b7333f846ff329705b8a62129 source: type: url - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 category: main optional: false - name: param-sweeps @@ -8761,12 +8761,12 @@ package: dependencies: geoh5py: 0.12.0a1 numpy: '>=1.26.0,<1.27.0' - url: git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + url: git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d hash: - sha256: 9ed6091534d638171957a17324e1a1e8f067b434 + sha256: cee0044fc645d73d33444cc82ce040772741dc1d source: type: url - url: git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + url: git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d category: main optional: false - name: param-sweeps @@ -8776,11 +8776,11 @@ package: dependencies: geoh5py: 0.12.0a1 numpy: '>=1.26.0,<1.27.0' - url: git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + url: git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d hash: - sha256: 9ed6091534d638171957a17324e1a1e8f067b434 + sha256: cee0044fc645d73d33444cc82ce040772741dc1d source: type: url - url: git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + url: git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d category: main optional: false diff --git a/py-3.12.conda-lock.yml b/py-3.12.conda-lock.yml index 206ed28a..636167ae 100644 --- a/py-3.12.conda-lock.yml +++ b/py-3.12.conda-lock.yml @@ -947,7 +947,7 @@ package: category: main optional: false - name: coverage - version: 7.10.3 + version: 7.10.4 manager: conda platform: linux-64 dependencies: @@ -956,14 +956,14 @@ package: python: '>=3.12,<3.13.0a0' python_abi: 3.12.* tomli: '' - url: https://repo.prefix.dev/conda-forge/linux-64/coverage-7.10.3-py312h8a5da7c_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/coverage-7.10.4-py312h8a5da7c_0.conda hash: - md5: 47633b6600c6ff2b4930b5b0b4704a53 - sha256: 9e170e3cebebedd2e685aac8cab09f3ad7489c7f9de2d014c1d46e4b4270ab28 + md5: bad9b9d3b7b39204823c3ec42bf58473 + sha256: 7411b5574c914eb9484e536d6fa211b2ec3694b74f4a36115ab848c997213cc0 category: dev optional: true - name: coverage - version: 7.10.3 + version: 7.10.4 manager: conda platform: win-64 dependencies: @@ -973,10 +973,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/coverage-7.10.3-py312h05f76fc_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/coverage-7.10.4-py312h05f76fc_0.conda hash: - md5: e539a0d708db866075cb03f692e7e10c - sha256: 9aece073f835373d95572db67a9a412bdca9c7aac83283517be3b3788b50be3a + md5: c8f541c460e8b5168ee894419571d0d3 + sha256: 7cd1280f8ced38d7523f97fe39a44dd8302d80359655d827452e76f844fa59a9 category: dev optional: true - name: cpython @@ -1436,7 +1436,7 @@ package: category: main optional: false - name: fonttools - version: 4.59.0 + version: 4.59.1 manager: conda platform: linux-64 dependencies: @@ -1447,14 +1447,14 @@ package: python: '>=3.12,<3.13.0a0' python_abi: 3.12.* unicodedata2: '>=15.1.0' - url: https://repo.prefix.dev/conda-forge/linux-64/fonttools-4.59.0-py312h8a5da7c_0.conda + url: https://repo.prefix.dev/conda-forge/linux-64/fonttools-4.59.1-py312h8a5da7c_0.conda hash: - md5: 008d44a468c24a59d2e67c014fba8f12 - sha256: ead830a4d12f26066f09b6ea54fb5c9e26a548c901063381412636db92cf7f61 + md5: 313520338e97b747315b5be6a563c315 + sha256: 8c65a6c9592828ca767161b47e66e66fe8d32b8e1f8af37b10b6594ad1c77340 category: main optional: false - name: fonttools - version: 4.59.0 + version: 4.59.1 manager: conda platform: win-64 dependencies: @@ -1466,10 +1466,10 @@ package: unicodedata2: '>=15.1.0' vc: '>=14.3,<15' vc14_runtime: '>=14.44.35208' - url: https://repo.prefix.dev/conda-forge/win-64/fonttools-4.59.0-py312h05f76fc_0.conda + url: https://repo.prefix.dev/conda-forge/win-64/fonttools-4.59.1-py312h05f76fc_0.conda hash: - md5: 42adff2f96da04998250e18d965bc4f9 - sha256: 8a3f1183933f67bd845db6dbe85f18157b6160947ab1001d1ee5b5fa654d9832 + md5: 8994cea102b73b5bd7824e291056ebe3 + sha256: aa34796eb45b4c8ed12263f32bbadfdb9a02535c93067963374530035d31a505 category: main optional: false - name: fqdn @@ -2772,14 +2772,14 @@ package: category: dev optional: true - name: jupyterlab - version: 4.4.5 + version: 4.4.6 manager: conda platform: linux-64 dependencies: async-lru: '>=1.0.0' - httpx: '>=0.25.0' + httpx: '>=0.25.0,<1' importlib-metadata: '>=4.8.3' - ipykernel: '>=6.5.0' + ipykernel: '>=6.5.0,!=6.30.0' jinja2: '>=3.0.3' jupyter-lsp: '>=2.0.0' jupyter_core: '' @@ -2792,21 +2792,21 @@ package: tomli: '>=1.2.2' tornado: '>=6.2.0' traitlets: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.4.5-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.4.6-pyhd8ed1ab_0.conda hash: - md5: ad6bbe770780dcf9cf55d724c5a213fd - sha256: 2013c2dd13bc773167e1ad11ae885b550c0297d030e2107bdc303243ff05d3f2 + md5: 70cb2903114eafc6ed5d70ca91ba6545 + sha256: c3558f1c2a5977799ce425f1f7c8d8d1cae3408da41ec4f5c3771a21e673d465 category: dev optional: true - name: jupyterlab - version: 4.4.5 + version: 4.4.6 manager: conda platform: win-64 dependencies: async-lru: '>=1.0.0' - httpx: '>=0.25.0' + httpx: '>=0.25.0,<1' importlib-metadata: '>=4.8.3' - ipykernel: '>=6.5.0' + ipykernel: '>=6.5.0,!=6.30.0' jinja2: '>=3.0.3' jupyter-lsp: '>=2.0.0' jupyter_core: '' @@ -2819,10 +2819,10 @@ package: tomli: '>=1.2.2' tornado: '>=6.2.0' traitlets: '' - url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.4.5-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jupyterlab-4.4.6-pyhd8ed1ab_0.conda hash: - md5: ad6bbe770780dcf9cf55d724c5a213fd - sha256: 2013c2dd13bc773167e1ad11ae885b550c0297d030e2107bdc303243ff05d3f2 + md5: 70cb2903114eafc6ed5d70ca91ba6545 + sha256: c3558f1c2a5977799ce425f1f7c8d8d1cae3408da41ec4f5c3771a21e673d465 category: dev optional: true - name: jupyterlab_pygments @@ -6126,27 +6126,27 @@ package: category: main optional: false - name: python-fastjsonschema - version: 2.21.1 + version: 2.21.2 manager: conda platform: linux-64 dependencies: python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/python-fastjsonschema-2.21.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/python-fastjsonschema-2.21.2-pyhe01879c_0.conda hash: - md5: 38e34d2d1d9dca4fb2b9a0a04f604e2c - sha256: 1b09a28093071c1874862422696429d0d35bd0b8420698003ac004746c5e82a2 + md5: 23029aae904a2ba587daba708208012f + sha256: df9aa74e9e28e8d1309274648aac08ec447a92512c33f61a8de0afa9ce32ebe8 category: dev optional: true - name: python-fastjsonschema - version: 2.21.1 + version: 2.21.2 manager: conda platform: win-64 dependencies: python: '>=3.9' - url: https://repo.prefix.dev/conda-forge/noarch/python-fastjsonschema-2.21.1-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/python-fastjsonschema-2.21.2-pyhe01879c_0.conda hash: - md5: 38e34d2d1d9dca4fb2b9a0a04f604e2c - sha256: 1b09a28093071c1874862422696429d0d35bd0b8420698003ac004746c5e82a2 + md5: 23029aae904a2ba587daba708208012f + sha256: df9aa74e9e28e8d1309274648aac08ec447a92512c33f61a8de0afa9ce32ebe8 category: dev optional: true - name: python-json-logger @@ -8607,7 +8607,7 @@ package: category: main optional: false - name: geoapps-utils - version: 0.6.0-alpha.1 + version: 0.6.0a1 manager: pip platform: linux-64 dependencies: @@ -8615,16 +8615,16 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 hash: - sha256: d0d3ced2e3f84109ee49270adb936f42b490d99f + sha256: 183ed8f654bc393eeafdf89b2c258a224f4b4b73 source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 category: main optional: false - name: geoapps-utils - version: 0.6.0-alpha.1 + version: 0.6.0a1 manager: pip platform: win-64 dependencies: @@ -8632,12 +8632,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 hash: - sha256: d0d3ced2e3f84109ee49270adb936f42b490d99f + sha256: 183ed8f654bc393eeafdf89b2c258a224f4b4b73 source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@d0d3ced2e3f84109ee49270adb936f42b490d99f + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 category: main optional: false - name: geoh5py @@ -8675,7 +8675,7 @@ package: category: main optional: false - name: mira-simpeg - version: 0.23.0.1.post2.dev42+g26cae9aae + version: 0.23.0.1.post2.dev55+mira.g2e61aceb1 manager: pip platform: linux-64 dependencies: @@ -8687,16 +8687,16 @@ package: numpy: '>=1.22' pymatsolver: '>=0.3' scipy: '>=1.8' - url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + url: git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e hash: - sha256: 26cae9aae7018fa4da8b1132138d2beff9fc5a91 + sha256: 2e61aceb15b21e896c6190b8426075e9a04cf78e source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + url: git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e category: main optional: false - name: mira-simpeg - version: 0.23.0.1.post2.dev42+g26cae9aae + version: 0.23.0.1.post2.dev55+mira.g2e61aceb1 manager: pip platform: win-64 dependencies: @@ -8708,12 +8708,12 @@ package: numpy: '>=1.22' pymatsolver: '>=0.3' scipy: '>=1.8' - url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + url: git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e hash: - sha256: 26cae9aae7018fa4da8b1132138d2beff9fc5a91 + sha256: 2e61aceb15b21e896c6190b8426075e9a04cf78e source: type: url - url: git+https://github.com/MiraGeoscience/simpeg.git@26cae9aae7018fa4da8b1132138d2beff9fc5a91 + url: git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e category: main optional: false - name: octree-creation-app @@ -8722,17 +8722,17 @@ package: platform: linux-64 dependencies: discretize: ==0.11.* - geoapps-utils: 0.6.0-alpha.1 + geoapps-utils: 0.6.0a1 geoh5py: 0.12.0a1 numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 hash: - sha256: 02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + sha256: 47fa41aa60b8473b7333f846ff329705b8a62129 source: type: url - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 category: main optional: false - name: octree-creation-app @@ -8741,17 +8741,17 @@ package: platform: win-64 dependencies: discretize: ==0.11.* - geoapps-utils: 0.6.0-alpha.1 + geoapps-utils: 0.6.0a1 geoh5py: 0.12.0a1 numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 hash: - sha256: 02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + sha256: 47fa41aa60b8473b7333f846ff329705b8a62129 source: type: url - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@02fbd85bf7d54b8f4336f1f0094c1c3e27714e81 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 category: main optional: false - name: param-sweeps @@ -8761,12 +8761,12 @@ package: dependencies: geoh5py: 0.12.0a1 numpy: '>=1.26.0,<1.27.0' - url: git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + url: git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d hash: - sha256: 9ed6091534d638171957a17324e1a1e8f067b434 + sha256: cee0044fc645d73d33444cc82ce040772741dc1d source: type: url - url: git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + url: git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d category: main optional: false - name: param-sweeps @@ -8776,11 +8776,11 @@ package: dependencies: geoh5py: 0.12.0a1 numpy: '>=1.26.0,<1.27.0' - url: git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + url: git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d hash: - sha256: 9ed6091534d638171957a17324e1a1e8f067b434 + sha256: cee0044fc645d73d33444cc82ce040772741dc1d source: type: url - url: git+https://github.com/MiraGeoscience/param-sweeps.git@9ed6091534d638171957a17324e1a1e8f067b434 + url: git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d category: main optional: false From 2968a6c2ed9850b76cc5a5d2f2394ee845180b9b Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 18 Aug 2025 13:30:09 -0700 Subject: [PATCH 45/56] Revert back to Pardiso? --- tests/run_tests/driver_ground_tem_test.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/run_tests/driver_ground_tem_test.py b/tests/run_tests/driver_ground_tem_test.py index ca66054c..c5197c08 100644 --- a/tests/run_tests/driver_ground_tem_test.py +++ b/tests/run_tests/driver_ground_tem_test.py @@ -132,7 +132,6 @@ def test_ground_tem_fwr_run( x_channel_bool=True, y_channel_bool=True, z_channel_bool=True, - solver_type="Mumps", ) fwr_driver = TDEMForwardDriver(params) @@ -228,7 +227,6 @@ def test_ground_tem_run(tmp_path: Path, max_iterations=1, pytest=True): cooling_rate=2, max_cg_iterations=200, percentile=100, - solver_type="Mumps", **data_kwargs, ) params.write_ui_json(path=tmp_path / "Inv_run.ui.json") From e48dfb51eca0afe80138ef55d1eb7cff6d2ea35d Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 18 Aug 2025 13:51:42 -0700 Subject: [PATCH 46/56] Remove check for Mumps --- tests/run_tests/driver_ground_tem_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run_tests/driver_ground_tem_test.py b/tests/run_tests/driver_ground_tem_test.py index c5197c08..d737d919 100644 --- a/tests/run_tests/driver_ground_tem_test.py +++ b/tests/run_tests/driver_ground_tem_test.py @@ -149,7 +149,7 @@ def test_ground_tem_fwr_run( assert "closed" in caplog.records[0].message - assert fwr_driver.data_misfit.objfcts[0].simulation.simulations[0].solver == Mumps + # assert fwr_driver.data_misfit.objfcts[0].simulation.simulations[0].solver == Mumps fwr_driver.run() From 54ffd479ea1db861e6b87c04165c1f1bed535dd8 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 18 Aug 2025 14:03:43 -0700 Subject: [PATCH 47/56] Revert "Remove check for Mumps" This reverts commit e48dfb51eca0afe80138ef55d1eb7cff6d2ea35d. Revert "Revert back to Pardiso?" This reverts commit 2968a6c2ed9850b76cc5a5d2f2394ee845180b9b. --- tests/run_tests/driver_ground_tem_test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/run_tests/driver_ground_tem_test.py b/tests/run_tests/driver_ground_tem_test.py index d737d919..ca66054c 100644 --- a/tests/run_tests/driver_ground_tem_test.py +++ b/tests/run_tests/driver_ground_tem_test.py @@ -132,6 +132,7 @@ def test_ground_tem_fwr_run( x_channel_bool=True, y_channel_bool=True, z_channel_bool=True, + solver_type="Mumps", ) fwr_driver = TDEMForwardDriver(params) @@ -149,7 +150,7 @@ def test_ground_tem_fwr_run( assert "closed" in caplog.records[0].message - # assert fwr_driver.data_misfit.objfcts[0].simulation.simulations[0].solver == Mumps + assert fwr_driver.data_misfit.objfcts[0].simulation.simulations[0].solver == Mumps fwr_driver.run() @@ -227,6 +228,7 @@ def test_ground_tem_run(tmp_path: Path, max_iterations=1, pytest=True): cooling_rate=2, max_cg_iterations=200, percentile=100, + solver_type="Mumps", **data_kwargs, ) params.write_ui_json(path=tmp_path / "Inv_run.ui.json") From bee387e01bf4154bae12526feaaab3f05abaec11 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 18 Aug 2025 14:09:16 -0700 Subject: [PATCH 48/56] Set Mumps in test --- tests/run_tests/driver_ground_tem_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run_tests/driver_ground_tem_test.py b/tests/run_tests/driver_ground_tem_test.py index ca66054c..90fe6128 100644 --- a/tests/run_tests/driver_ground_tem_test.py +++ b/tests/run_tests/driver_ground_tem_test.py @@ -78,6 +78,7 @@ def test_tiling_ground_tem( y_channel_bool=True, z_channel_bool=True, tile_spatial=4, + solver_type="Mumps", ) fwr_driver = TDEMForwardDriver(params) From c4ba10b0f8428c3f6388a2f2b4aaf2889e637efe Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 19 Aug 2025 11:12:33 -0700 Subject: [PATCH 49/56] Beef up docstrings in nested --- simpeg_drivers/utils/nested.py | 49 +++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/simpeg_drivers/utils/nested.py b/simpeg_drivers/utils/nested.py index 3eb635b8..6c536b2c 100644 --- a/simpeg_drivers/utils/nested.py +++ b/simpeg_drivers/utils/nested.py @@ -36,19 +36,19 @@ def create_mesh( padding_cells: int = 8, minimum_level: int = 4, finalize: bool = True, -): +) -> TreeMesh | TensorMesh: """ Create a nested mesh with the same extent as the input global mesh. Refinement levels are preserved only around the input locations (local survey). - Parameters - ---------- - locations: Array of coordinates for the local survey shape(*, 3). - base_mesh: Input global TreeMesh object. - padding_cells: Used for 'method'= 'padding_cells'. Number of cells in each concentric shell. - minimum_level: Minimum octree level to preserve everywhere outside the local survey area. - finalize: Return a finalized local treemesh. + :param survey: SimPEG survey object. + :param base_mesh: Input global TreeMesh object. + :param padding_cells: Used for 'method'= 'padding_cells'. Number of cells in each concentric shell. + :param minimum_level: Minimum octree level to preserve everywhere outside the local survey area. + :param finalize: Return a finalized local treemesh. + + :return: A TreeMesh object with the same extent as the input global mesh. """ if not isinstance(base_mesh, TreeMesh): return base_mesh @@ -102,12 +102,29 @@ def create_misfit( local_indices, channel, tile_count, - # data_count, n_split, padding_cells, inversion_type, forward_only, ): + """ + Create a list of local misfits based on the local indices. + + The local indices are further split into smaller chunks if requested, sharing + the same mesh. + + :param simulation: SimPEG simulation object. + :param local_indices: Indices of the receiver locations belonging to the tile. + :param channel: Channel of the simulationm, for frequency systems only. + :param tile_count: Current tile ID, used to name the file on disk and for sampling + of topography for 1D simulations. + :param n_split: Number of splits to create for the local indices. + :param padding_cells: Number of padding cells around the local survey. + :param inversion_type: Type of inversion, used to name the misfit (joint inversion). + :param forward_only: If False, data is transferred to the local simulation. + + :return: List of local misfits and data slices. + """ local_sim, _, _ = create_simulation( simulation, None, @@ -165,13 +182,14 @@ def create_simulation( """ Generate a survey, mesh and simulation based on indices. - :param inversion_data: InversionData object. - :param mesh: Octree mesh. - :param active_cells: Active cell model. + :param simulation: SimPEG.simulation object. + :param local_mesh: Local mesh for the simulation, else created. :param indices: Indices of receivers belonging to the tile. - :param channel: Channel number for frequency or time channels. + :param channel: Channel of the simulation, for frequency simulations only. :param tile_id: Tile id stored on the simulation. :param padding_cells: Number of padding cells around the local survey. + + :return: Local simulation, mapping and local ordering. """ local_survey, local_ordering = create_survey( simulation.survey, indices=indices, channel=channel @@ -271,6 +289,10 @@ def create_simulation( def create_survey(survey, indices, channel=None): """ Extract source and receivers belonging to the indices. + + :param survey: SimPEG survey object. + :param indices: Indices of the receivers belonging to the tile. + :param channel: Channel of the survey, for frequency systems only. """ sources = [] @@ -345,6 +367,7 @@ def tile_locations( :param locations: Array of locations. :param n_tiles: Number of tiles (for 'cluster') :param labels: Array of values to append to the locations + :param sorting: Array of indices to sort the locations before clustering. :return: List of arrays containing the indices of the points in each tile. """ From 584968b827b3328981b9fba084646957b0b33b68 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 19 Aug 2025 12:21:28 -0700 Subject: [PATCH 50/56] Bring pre-computing of projections for airborne EM and dcip --- simpeg_drivers/components/data.py | 5 +++++ simpeg_drivers/utils/nested.py | 29 ++++++++++++++++++++--------- simpeg_drivers/utils/surveys.py | 20 +++++++++----------- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/simpeg_drivers/components/data.py b/simpeg_drivers/components/data.py index acf0b7b4..bac0e63b 100644 --- a/simpeg_drivers/components/data.py +++ b/simpeg_drivers/components/data.py @@ -335,12 +335,17 @@ def create_survey(self): survey = survey_factory.build(data=self) survey.ordering = survey_factory.ordering survey.sorting = survey_factory.sorting + survey.locations = self.entity.vertices # Save apparent resistivity in geoh5 order if "direct current" in self.params.inversion_type: survey.apparent_resistivity = 1 / ( geometric_factor(survey)[np.argsort(survey.sorting)] + 1e-10 ) + survey.cells = self.entity.cells + + if "induced polarization" in self.params.inversion_type: + survey.cells = self.entity.cells return survey diff --git a/simpeg_drivers/utils/nested.py b/simpeg_drivers/utils/nested.py index 6c536b2c..dda4414d 100644 --- a/simpeg_drivers/utils/nested.py +++ b/simpeg_drivers/utils/nested.py @@ -20,14 +20,27 @@ from scipy.spatial.distance import cdist from simpeg import data, data_misfit, maps, meta from simpeg.electromagnetics.base_1d import BaseEM1DSimulation +from simpeg.electromagnetics.frequency_domain.simulation import BaseFDEMSimulation from simpeg.electromagnetics.frequency_domain.sources import ( LineCurrent as FEMLineCurrent, ) +from simpeg.electromagnetics.static.induced_polarization.simulation import ( + Simulation3DNodal as Simulation3DIP, +) +from simpeg.electromagnetics.static.resistivity.simulation import ( + Simulation3DNodal as Simulation3DRes, +) +from simpeg.electromagnetics.time_domain.simulation import BaseTDEMSimulation from simpeg.electromagnetics.time_domain.sources import LineCurrent as TEMLineCurrent from simpeg.simulation import BaseSimulation from simpeg.survey import BaseSurvey -from .surveys import get_intersecting_cells, get_unique_locations +from simpeg_drivers.utils.surveys import ( + compute_dc_projections, + compute_em_projections, + get_intersecting_cells, + get_unique_locations, +) def create_mesh( @@ -275,14 +288,12 @@ def create_simulation( local_sim = type(simulation)(*args, **kwargs) - # TODO bring back - # inv_type = inversion_data.params.inversion_type - # if inv_type in ["fdem", "tdem"]: - # compute_em_projections(inversion_data, local_sim) - # elif ("current" in inv_type or "polarization" in inv_type) and ( - # "2d" not in inv_type or "pseudo" in inv_type - # ): - # compute_dc_projections(inversion_data, local_sim, indices) + if isinstance(simulation, BaseFDEMSimulation | BaseTDEMSimulation): + compute_em_projections(simulation.survey.locations, local_sim) + elif isinstance(simulation, Simulation3DRes | Simulation3DIP): + compute_dc_projections( + simulation.survey.locations, simulation.survey.cells, local_sim + ) return local_sim, mapping, local_ordering diff --git a/simpeg_drivers/utils/surveys.py b/simpeg_drivers/utils/surveys.py index a1742924..613f42b6 100644 --- a/simpeg_drivers/utils/surveys.py +++ b/simpeg_drivers/utils/surveys.py @@ -145,15 +145,14 @@ def get_unique_locations(survey: BaseSurvey) -> np.ndarray: return np.unique(locations, axis=0) -def compute_em_projections(inversion_data, simulation): +def compute_em_projections(locations, simulation): """ Pre-compute projections for the receivers for efficiency. """ - rx_locs = inversion_data.entity.vertices projections = {} for component in "xyz": projections[component] = simulation.mesh.get_interpolation_matrix( - rx_locs, "faces_" + component[0] + locations, "faces_" + component[0] ) for source in simulation.survey.source_list: @@ -166,19 +165,18 @@ def compute_em_projections(inversion_data, simulation): receiver.spatialP = projection -def compute_dc_projections(inversion_data, simulation, indices): +def compute_dc_projections(locations, cells, simulation): """ Pre-compute projections for the receivers for efficiency. """ - rx_locs = inversion_data.entity.vertices - mn_pairs = inversion_data.entity.cells - projection = simulation.mesh.get_interpolation_matrix(rx_locs, "nodes") + projection = simulation.mesh.get_interpolation_matrix(locations, "nodes") - for source, ind in zip(simulation.survey.source_list, indices, strict=True): - proj_mn = projection[mn_pairs[ind, 0], :] + for source in simulation.survey.source_list: + ind = source.rx_ids + proj_mn = projection[cells[ind, 0], :] # Check if dipole receiver - if not np.all(mn_pairs[ind, 0] == mn_pairs[ind, 1]): - proj_mn -= projection[mn_pairs[ind, 1], :] + if not np.all(cells[ind, 0] == cells[ind, 1]): + proj_mn -= projection[cells[ind, 1], :] source.receiver_list[0].spatialP = proj_mn # pylint: disable=protected-access From 931e1f8b2a8b7a4a7d46e6eb91858bc98c799d87 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 19 Aug 2025 14:00:38 -0700 Subject: [PATCH 51/56] Update local index on sub survey --- simpeg_drivers/utils/nested.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/simpeg_drivers/utils/nested.py b/simpeg_drivers/utils/nested.py index dda4414d..f0c1631a 100644 --- a/simpeg_drivers/utils/nested.py +++ b/simpeg_drivers/utils/nested.py @@ -325,7 +325,6 @@ def create_survey(survey, indices, channel=None): receivers = [] for rx in src.receiver_list: - # intersect = set(rx.local_index).intersection(indices) new_rx = copy(rx) # For MT and DC surveys with multiple locations per receiver @@ -334,10 +333,12 @@ def create_survey(survey, indices, channel=None): else: new_rx.locations = rx.locations[intersect] + new_rx.local_index = indices receivers.append(new_rx) if any(receivers): new_src = copy(src) + new_src.rx_ids = indices new_src.receiver_list = receivers sources.append(new_src) From 4ac2732277b07956cc50b1def6698f7daf5671b8 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 19 Aug 2025 14:29:25 -0700 Subject: [PATCH 52/56] Re-lock --- .../py-3.10-linux-64-dev.conda.lock.yml | 12 +-- environments/py-3.10-linux-64.conda.lock.yml | 6 +- .../py-3.10-win-64-dev.conda.lock.yml | 12 +-- environments/py-3.10-win-64.conda.lock.yml | 6 +- .../py-3.11-linux-64-dev.conda.lock.yml | 12 +-- environments/py-3.11-linux-64.conda.lock.yml | 6 +- .../py-3.11-win-64-dev.conda.lock.yml | 12 +-- environments/py-3.11-win-64.conda.lock.yml | 6 +- .../py-3.12-linux-64-dev.conda.lock.yml | 12 +-- environments/py-3.12-linux-64.conda.lock.yml | 6 +- .../py-3.12-win-64-dev.conda.lock.yml | 12 +-- environments/py-3.12-win-64.conda.lock.yml | 6 +- py-3.10.conda-lock.yml | 92 +++++++++---------- py-3.11.conda-lock.yml | 92 +++++++++---------- py-3.12.conda-lock.yml | 92 +++++++++---------- 15 files changed, 192 insertions(+), 192 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 6e1c01af..5a3fd877 100644 --- a/environments/py-3.10-linux-64-dev.conda.lock.yml +++ b/environments/py-3.10-linux-64-dev.conda.lock.yml @@ -85,9 +85,9 @@ dependencies: - joblib=1.5.1=pyhd8ed1ab_0 - json5=0.12.1=pyhd8ed1ab_0 - jsonpointer=3.0.0=py310hff52083_1 - - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema=4.25.1=pyhe01879c_0 - jsonschema-specifications=2025.4.1=pyh29332c3_0 - - jsonschema-with-format-nongpl=4.25.0=he01879c_0 + - jsonschema-with-format-nongpl=4.25.1=he01879c_0 - jupyter-book=1.0.3=pyhd8ed1ab_1 - jupyter-cache=1.0.1=pyhff2d567_0 - jupyter-lsp=2.2.6=pyhe01879c_0 @@ -228,7 +228,7 @@ dependencies: - readline=8.2=h8c095d6_2 - readthedocs-sphinx-ext=2.2.5=pyhd8ed1ab_1 - referencing=0.36.2=pyh29332c3_0 - - requests=2.32.4=pyhd8ed1ab_0 + - requests=2.32.5=pyhd8ed1ab_0 - rfc3339-validator=0.1.4=pyhd8ed1ab_1 - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - rfc3987-syntax=1.1.0=pyhe01879c_1 @@ -304,10 +304,10 @@ dependencies: - zstandard=0.23.0=py310ha75aee5_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d variables: diff --git a/environments/py-3.10-linux-64.conda.lock.yml b/environments/py-3.10-linux-64.conda.lock.yml index b4c7de31..3fcb3bc3 100644 --- a/environments/py-3.10-linux-64.conda.lock.yml +++ b/environments/py-3.10-linux-64.conda.lock.yml @@ -156,10 +156,10 @@ dependencies: - zstandard=0.23.0=py310ha75aee5_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d variables: 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 d84f9d4d..394e4aa4 100644 --- a/environments/py-3.10-win-64-dev.conda.lock.yml +++ b/environments/py-3.10-win-64-dev.conda.lock.yml @@ -85,9 +85,9 @@ dependencies: - joblib=1.5.1=pyhd8ed1ab_0 - json5=0.12.1=pyhd8ed1ab_0 - jsonpointer=3.0.0=py310h5588dad_1 - - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema=4.25.1=pyhe01879c_0 - jsonschema-specifications=2025.4.1=pyh29332c3_0 - - jsonschema-with-format-nongpl=4.25.0=he01879c_0 + - jsonschema-with-format-nongpl=4.25.1=he01879c_0 - jupyter-book=1.0.3=pyhd8ed1ab_1 - jupyter-cache=1.0.1=pyhff2d567_0 - jupyter-lsp=2.2.6=pyhe01879c_0 @@ -212,7 +212,7 @@ dependencies: - pyzmq=27.0.1=py310h49f0f51_0 - readthedocs-sphinx-ext=2.2.5=pyhd8ed1ab_1 - referencing=0.36.2=pyh29332c3_0 - - requests=2.32.4=pyhd8ed1ab_0 + - requests=2.32.5=pyhd8ed1ab_0 - rfc3339-validator=0.1.4=pyhd8ed1ab_1 - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - rfc3987-syntax=1.1.0=pyhe01879c_1 @@ -294,10 +294,10 @@ dependencies: - zstandard=0.23.0=py310ha8f682b_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d variables: diff --git a/environments/py-3.10-win-64.conda.lock.yml b/environments/py-3.10-win-64.conda.lock.yml index 5ce88592..e2a7814e 100644 --- a/environments/py-3.10-win-64.conda.lock.yml +++ b/environments/py-3.10-win-64.conda.lock.yml @@ -144,10 +144,10 @@ dependencies: - zstandard=0.23.0=py310ha8f682b_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d variables: 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 df316b8c..e9929b70 100644 --- a/environments/py-3.11-linux-64-dev.conda.lock.yml +++ b/environments/py-3.11-linux-64-dev.conda.lock.yml @@ -87,9 +87,9 @@ dependencies: - joblib=1.5.1=pyhd8ed1ab_0 - json5=0.12.1=pyhd8ed1ab_0 - jsonpointer=3.0.0=py311h38be061_1 - - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema=4.25.1=pyhe01879c_0 - jsonschema-specifications=2025.4.1=pyh29332c3_0 - - jsonschema-with-format-nongpl=4.25.0=he01879c_0 + - jsonschema-with-format-nongpl=4.25.1=he01879c_0 - jupyter-book=1.0.3=pyhd8ed1ab_1 - jupyter-cache=1.0.1=pyhff2d567_0 - jupyter-lsp=2.2.6=pyhe01879c_0 @@ -230,7 +230,7 @@ dependencies: - readline=8.2=h8c095d6_2 - readthedocs-sphinx-ext=2.2.5=pyhd8ed1ab_1 - referencing=0.36.2=pyh29332c3_0 - - requests=2.32.4=pyhd8ed1ab_0 + - requests=2.32.5=pyhd8ed1ab_0 - rfc3339-validator=0.1.4=pyhd8ed1ab_1 - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - rfc3987-syntax=1.1.0=pyhe01879c_1 @@ -307,10 +307,10 @@ dependencies: - zstandard=0.23.0=py311h9ecbd09_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d variables: diff --git a/environments/py-3.11-linux-64.conda.lock.yml b/environments/py-3.11-linux-64.conda.lock.yml index 55f09b4c..4322a817 100644 --- a/environments/py-3.11-linux-64.conda.lock.yml +++ b/environments/py-3.11-linux-64.conda.lock.yml @@ -158,10 +158,10 @@ dependencies: - zstandard=0.23.0=py311h9ecbd09_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d variables: 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 d52e63c3..0f27d31c 100644 --- a/environments/py-3.11-win-64-dev.conda.lock.yml +++ b/environments/py-3.11-win-64-dev.conda.lock.yml @@ -87,9 +87,9 @@ dependencies: - joblib=1.5.1=pyhd8ed1ab_0 - json5=0.12.1=pyhd8ed1ab_0 - jsonpointer=3.0.0=py311h1ea47a8_1 - - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema=4.25.1=pyhe01879c_0 - jsonschema-specifications=2025.4.1=pyh29332c3_0 - - jsonschema-with-format-nongpl=4.25.0=he01879c_0 + - jsonschema-with-format-nongpl=4.25.1=he01879c_0 - jupyter-book=1.0.3=pyhd8ed1ab_1 - jupyter-cache=1.0.1=pyhff2d567_0 - jupyter-lsp=2.2.6=pyhe01879c_0 @@ -214,7 +214,7 @@ dependencies: - pyzmq=27.0.1=py311ha362a94_0 - readthedocs-sphinx-ext=2.2.5=pyhd8ed1ab_1 - referencing=0.36.2=pyh29332c3_0 - - requests=2.32.4=pyhd8ed1ab_0 + - requests=2.32.5=pyhd8ed1ab_0 - rfc3339-validator=0.1.4=pyhd8ed1ab_1 - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - rfc3987-syntax=1.1.0=pyhe01879c_1 @@ -297,10 +297,10 @@ dependencies: - zstandard=0.23.0=py311he736701_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d variables: diff --git a/environments/py-3.11-win-64.conda.lock.yml b/environments/py-3.11-win-64.conda.lock.yml index 6619c4ac..6a3a0795 100644 --- a/environments/py-3.11-win-64.conda.lock.yml +++ b/environments/py-3.11-win-64.conda.lock.yml @@ -146,10 +146,10 @@ dependencies: - zstandard=0.23.0=py311he736701_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d variables: 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 8eedf9b8..46b9ea30 100644 --- a/environments/py-3.12-linux-64-dev.conda.lock.yml +++ b/environments/py-3.12-linux-64-dev.conda.lock.yml @@ -87,9 +87,9 @@ dependencies: - joblib=1.5.1=pyhd8ed1ab_0 - json5=0.12.1=pyhd8ed1ab_0 - jsonpointer=3.0.0=py312h7900ff3_1 - - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema=4.25.1=pyhe01879c_0 - jsonschema-specifications=2025.4.1=pyh29332c3_0 - - jsonschema-with-format-nongpl=4.25.0=he01879c_0 + - jsonschema-with-format-nongpl=4.25.1=he01879c_0 - jupyter-book=1.0.3=pyhd8ed1ab_1 - jupyter-cache=1.0.1=pyhff2d567_0 - jupyter-lsp=2.2.6=pyhe01879c_0 @@ -230,7 +230,7 @@ dependencies: - readline=8.2=h8c095d6_2 - readthedocs-sphinx-ext=2.2.5=pyhd8ed1ab_1 - referencing=0.36.2=pyh29332c3_0 - - requests=2.32.4=pyhd8ed1ab_0 + - requests=2.32.5=pyhd8ed1ab_0 - rfc3339-validator=0.1.4=pyhd8ed1ab_1 - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - rfc3987-syntax=1.1.0=pyhe01879c_1 @@ -307,10 +307,10 @@ dependencies: - zstandard=0.23.0=py312h66e93f0_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d variables: diff --git a/environments/py-3.12-linux-64.conda.lock.yml b/environments/py-3.12-linux-64.conda.lock.yml index 8fcec162..3496e8df 100644 --- a/environments/py-3.12-linux-64.conda.lock.yml +++ b/environments/py-3.12-linux-64.conda.lock.yml @@ -158,10 +158,10 @@ dependencies: - zstandard=0.23.0=py312h66e93f0_2 - zstd=1.5.7=hb8e6e7a_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d variables: 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 78ea60cb..fbd8b395 100644 --- a/environments/py-3.12-win-64-dev.conda.lock.yml +++ b/environments/py-3.12-win-64-dev.conda.lock.yml @@ -87,9 +87,9 @@ dependencies: - joblib=1.5.1=pyhd8ed1ab_0 - json5=0.12.1=pyhd8ed1ab_0 - jsonpointer=3.0.0=py312h2e8e312_1 - - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema=4.25.1=pyhe01879c_0 - jsonschema-specifications=2025.4.1=pyh29332c3_0 - - jsonschema-with-format-nongpl=4.25.0=he01879c_0 + - jsonschema-with-format-nongpl=4.25.1=he01879c_0 - jupyter-book=1.0.3=pyhd8ed1ab_1 - jupyter-cache=1.0.1=pyhff2d567_0 - jupyter-lsp=2.2.6=pyhe01879c_0 @@ -214,7 +214,7 @@ dependencies: - pyzmq=27.0.1=py312h5b324a9_0 - readthedocs-sphinx-ext=2.2.5=pyhd8ed1ab_1 - referencing=0.36.2=pyh29332c3_0 - - requests=2.32.4=pyhd8ed1ab_0 + - requests=2.32.5=pyhd8ed1ab_0 - rfc3339-validator=0.1.4=pyhd8ed1ab_1 - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - rfc3987-syntax=1.1.0=pyhe01879c_1 @@ -297,10 +297,10 @@ dependencies: - zstandard=0.23.0=py312h4389bb4_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d variables: diff --git a/environments/py-3.12-win-64.conda.lock.yml b/environments/py-3.12-win-64.conda.lock.yml index 0b9891c9..7c59f85a 100644 --- a/environments/py-3.12-win-64.conda.lock.yml +++ b/environments/py-3.12-win-64.conda.lock.yml @@ -146,10 +146,10 @@ dependencies: - zstandard=0.23.0=py312h4389bb4_2 - zstd=1.5.7=hbeecb71_2 - pip: - - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 - - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + - geoapps-utils @ git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 + - geoh5py @ git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 - mira-simpeg @ git+https://github.com/MiraGeoscience/simpeg.git@2e61aceb15b21e896c6190b8426075e9a04cf78e - - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + - octree-creation-app @ git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac - param-sweeps @ git+https://github.com/MiraGeoscience/param-sweeps.git@cee0044fc645d73d33444cc82ce040772741dc1d variables: diff --git a/py-3.10.conda-lock.yml b/py-3.10.conda-lock.yml index e09a4f43..747b68dc 100644 --- a/py-3.10.conda-lock.yml +++ b/py-3.10.conda-lock.yml @@ -2296,7 +2296,7 @@ package: category: dev optional: true - name: jsonschema - version: 4.25.0 + version: 4.25.1 manager: conda platform: linux-64 dependencies: @@ -2305,14 +2305,14 @@ package: python: '' referencing: '>=0.28.4' rpds-py: '>=0.7.1' - url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-4.25.0-pyhe01879c_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-4.25.1-pyhe01879c_0.conda hash: - md5: c6e3fd94e058dba67d917f38a11b50ab - sha256: 87ba7cf3a65c8e8d1005368b9aee3f49e295115381b7a0b180e56f7b68b5975f + md5: 341fd940c242cf33e832c0402face56f + sha256: ac377ef7762e49cb9c4f985f1281eeff471e9adc3402526eea78e6ac6589cf1d category: dev optional: true - name: jsonschema - version: 4.25.0 + version: 4.25.1 manager: conda platform: win-64 dependencies: @@ -2321,10 +2321,10 @@ package: python: '>=3.9' referencing: '>=0.28.4' rpds-py: '>=0.7.1' - url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-4.25.0-pyhe01879c_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-4.25.1-pyhe01879c_0.conda hash: - md5: c6e3fd94e058dba67d917f38a11b50ab - sha256: 87ba7cf3a65c8e8d1005368b9aee3f49e295115381b7a0b180e56f7b68b5975f + md5: 341fd940c242cf33e832c0402face56f + sha256: ac377ef7762e49cb9c4f985f1281eeff471e9adc3402526eea78e6ac6589cf1d category: dev optional: true - name: jsonschema-specifications @@ -2354,7 +2354,7 @@ package: category: dev optional: true - name: jsonschema-with-format-nongpl - version: 4.25.0 + version: 4.25.1 manager: conda platform: linux-64 dependencies: @@ -2362,20 +2362,20 @@ package: idna: '' isoduration: '' jsonpointer: '>1.13' - jsonschema: '>=4.25.0,<4.25.1.0a0' + jsonschema: '>=4.25.1,<4.25.2.0a0' rfc3339-validator: '' rfc3986-validator: '>0.1.0' rfc3987-syntax: '>=1.1.0' uri-template: '' webcolors: '>=24.6.0' - url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-with-format-nongpl-4.25.0-he01879c_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-with-format-nongpl-4.25.1-he01879c_0.conda hash: - md5: f4c7afaf838ab5bb1c4e73eb3095fb26 - sha256: 72604d07afaddf2156e61d128256d686aee4a7bdc06e235d7be352955de7527a + md5: 13e31c573c884962318a738405ca3487 + sha256: aef6705fe1335e6472e1b6365fcdb586356b18dceff72d8d6a315fc90e900ccf category: dev optional: true - name: jsonschema-with-format-nongpl - version: 4.25.0 + version: 4.25.1 manager: conda platform: win-64 dependencies: @@ -2383,16 +2383,16 @@ package: idna: '' isoduration: '' jsonpointer: '>1.13' - jsonschema: '>=4.25.0,<4.25.1.0a0' + jsonschema: '>=4.25.1,<4.25.2.0a0' rfc3339-validator: '' rfc3986-validator: '>0.1.0' rfc3987-syntax: '>=1.1.0' uri-template: '' webcolors: '>=24.6.0' - url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-with-format-nongpl-4.25.0-he01879c_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-with-format-nongpl-4.25.1-he01879c_0.conda hash: - md5: f4c7afaf838ab5bb1c4e73eb3095fb26 - sha256: 72604d07afaddf2156e61d128256d686aee4a7bdc06e235d7be352955de7527a + md5: 13e31c573c884962318a738405ca3487 + sha256: aef6705fe1335e6472e1b6365fcdb586356b18dceff72d8d6a315fc90e900ccf category: dev optional: true - name: jupyter-book @@ -6402,7 +6402,7 @@ package: category: dev optional: true - name: requests - version: 2.32.4 + version: 2.32.5 manager: conda platform: linux-64 dependencies: @@ -6411,14 +6411,14 @@ package: idna: '>=2.5,<4' python: '>=3.9' urllib3: '>=1.21.1,<3' - url: https://repo.prefix.dev/conda-forge/noarch/requests-2.32.4-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/requests-2.32.5-pyhd8ed1ab_0.conda hash: - md5: f6082eae112814f1447b56a5e1f6ed05 - sha256: 9866aaf7a13c6cfbe665ec7b330647a0fb10a81e6f9b8fee33642232a1920e18 + md5: db0c6b99149880c8ba515cf4abe93ee4 + sha256: 8dc54e94721e9ab545d7234aa5192b74102263d3e704e6d0c8aa7008f2da2a7b category: dev optional: true - name: requests - version: 2.32.4 + version: 2.32.5 manager: conda platform: win-64 dependencies: @@ -6427,10 +6427,10 @@ package: idna: '>=2.5,<4' python: '>=3.9' urllib3: '>=1.21.1,<3' - url: https://repo.prefix.dev/conda-forge/noarch/requests-2.32.4-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/requests-2.32.5-pyhd8ed1ab_0.conda hash: - md5: f6082eae112814f1447b56a5e1f6ed05 - sha256: 9866aaf7a13c6cfbe665ec7b330647a0fb10a81e6f9b8fee33642232a1920e18 + md5: db0c6b99149880c8ba515cf4abe93ee4 + sha256: 8dc54e94721e9ab545d7234aa5192b74102263d3e704e6d0c8aa7008f2da2a7b category: dev optional: true - name: rfc3339-validator @@ -8530,12 +8530,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 hash: - sha256: 183ed8f654bc393eeafdf89b2c258a224f4b4b73 + sha256: 4bb027706ed3726d42b75d349df087dcdf8450f9 source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 category: main optional: false - name: geoapps-utils @@ -8547,12 +8547,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 hash: - sha256: 183ed8f654bc393eeafdf89b2c258a224f4b4b73 + sha256: 4bb027706ed3726d42b75d349df087dcdf8450f9 source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 category: main optional: false - name: geoh5py @@ -8564,12 +8564,12 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.5.2,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + url: git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 hash: - sha256: cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + sha256: 12bf67269934b26a307c69857c01dd3b4c4742e9 source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + url: git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 category: main optional: false - name: geoh5py @@ -8581,12 +8581,12 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.5.2,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + url: git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 hash: - sha256: cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + sha256: 12bf67269934b26a307c69857c01dd3b4c4742e9 source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + url: git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 category: main optional: false - name: mira-simpeg @@ -8632,7 +8632,7 @@ package: category: main optional: false - name: octree-creation-app - version: 0.4.0-alpha.1 + version: 0.4.0a1 manager: pip platform: linux-64 dependencies: @@ -8642,16 +8642,16 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac hash: - sha256: 47fa41aa60b8473b7333f846ff329705b8a62129 + sha256: 111d2925130201bae952ff8692bf87663f3481ac source: type: url - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac category: main optional: false - name: octree-creation-app - version: 0.4.0-alpha.1 + version: 0.4.0a1 manager: pip platform: win-64 dependencies: @@ -8661,12 +8661,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac hash: - sha256: 47fa41aa60b8473b7333f846ff329705b8a62129 + sha256: 111d2925130201bae952ff8692bf87663f3481ac source: type: url - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac category: main optional: false - name: param-sweeps diff --git a/py-3.11.conda-lock.yml b/py-3.11.conda-lock.yml index 353771d5..f990e102 100644 --- a/py-3.11.conda-lock.yml +++ b/py-3.11.conda-lock.yml @@ -2348,7 +2348,7 @@ package: category: dev optional: true - name: jsonschema - version: 4.25.0 + version: 4.25.1 manager: conda platform: linux-64 dependencies: @@ -2357,14 +2357,14 @@ package: python: '>=3.9' referencing: '>=0.28.4' rpds-py: '>=0.7.1' - url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-4.25.0-pyhe01879c_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-4.25.1-pyhe01879c_0.conda hash: - md5: c6e3fd94e058dba67d917f38a11b50ab - sha256: 87ba7cf3a65c8e8d1005368b9aee3f49e295115381b7a0b180e56f7b68b5975f + md5: 341fd940c242cf33e832c0402face56f + sha256: ac377ef7762e49cb9c4f985f1281eeff471e9adc3402526eea78e6ac6589cf1d category: dev optional: true - name: jsonschema - version: 4.25.0 + version: 4.25.1 manager: conda platform: win-64 dependencies: @@ -2373,10 +2373,10 @@ package: python: '>=3.9' referencing: '>=0.28.4' rpds-py: '>=0.7.1' - url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-4.25.0-pyhe01879c_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-4.25.1-pyhe01879c_0.conda hash: - md5: c6e3fd94e058dba67d917f38a11b50ab - sha256: 87ba7cf3a65c8e8d1005368b9aee3f49e295115381b7a0b180e56f7b68b5975f + md5: 341fd940c242cf33e832c0402face56f + sha256: ac377ef7762e49cb9c4f985f1281eeff471e9adc3402526eea78e6ac6589cf1d category: dev optional: true - name: jsonschema-specifications @@ -2406,7 +2406,7 @@ package: category: dev optional: true - name: jsonschema-with-format-nongpl - version: 4.25.0 + version: 4.25.1 manager: conda platform: linux-64 dependencies: @@ -2414,20 +2414,20 @@ package: idna: '' isoduration: '' jsonpointer: '>1.13' - jsonschema: '>=4.25.0,<4.25.1.0a0' + jsonschema: '>=4.25.1,<4.25.2.0a0' rfc3339-validator: '' rfc3986-validator: '>0.1.0' rfc3987-syntax: '>=1.1.0' uri-template: '' webcolors: '>=24.6.0' - url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-with-format-nongpl-4.25.0-he01879c_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-with-format-nongpl-4.25.1-he01879c_0.conda hash: - md5: f4c7afaf838ab5bb1c4e73eb3095fb26 - sha256: 72604d07afaddf2156e61d128256d686aee4a7bdc06e235d7be352955de7527a + md5: 13e31c573c884962318a738405ca3487 + sha256: aef6705fe1335e6472e1b6365fcdb586356b18dceff72d8d6a315fc90e900ccf category: dev optional: true - name: jsonschema-with-format-nongpl - version: 4.25.0 + version: 4.25.1 manager: conda platform: win-64 dependencies: @@ -2435,16 +2435,16 @@ package: idna: '' isoduration: '' jsonpointer: '>1.13' - jsonschema: '>=4.25.0,<4.25.1.0a0' + jsonschema: '>=4.25.1,<4.25.2.0a0' rfc3339-validator: '' rfc3986-validator: '>0.1.0' rfc3987-syntax: '>=1.1.0' uri-template: '' webcolors: '>=24.6.0' - url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-with-format-nongpl-4.25.0-he01879c_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-with-format-nongpl-4.25.1-he01879c_0.conda hash: - md5: f4c7afaf838ab5bb1c4e73eb3095fb26 - sha256: 72604d07afaddf2156e61d128256d686aee4a7bdc06e235d7be352955de7527a + md5: 13e31c573c884962318a738405ca3487 + sha256: aef6705fe1335e6472e1b6365fcdb586356b18dceff72d8d6a315fc90e900ccf category: dev optional: true - name: jupyter-book @@ -6456,7 +6456,7 @@ package: category: dev optional: true - name: requests - version: 2.32.4 + version: 2.32.5 manager: conda platform: linux-64 dependencies: @@ -6465,14 +6465,14 @@ package: idna: '>=2.5,<4' python: '>=3.9' urllib3: '>=1.21.1,<3' - url: https://repo.prefix.dev/conda-forge/noarch/requests-2.32.4-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/requests-2.32.5-pyhd8ed1ab_0.conda hash: - md5: f6082eae112814f1447b56a5e1f6ed05 - sha256: 9866aaf7a13c6cfbe665ec7b330647a0fb10a81e6f9b8fee33642232a1920e18 + md5: db0c6b99149880c8ba515cf4abe93ee4 + sha256: 8dc54e94721e9ab545d7234aa5192b74102263d3e704e6d0c8aa7008f2da2a7b category: dev optional: true - name: requests - version: 2.32.4 + version: 2.32.5 manager: conda platform: win-64 dependencies: @@ -6481,10 +6481,10 @@ package: idna: '>=2.5,<4' python: '>=3.9' urllib3: '>=1.21.1,<3' - url: https://repo.prefix.dev/conda-forge/noarch/requests-2.32.4-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/requests-2.32.5-pyhd8ed1ab_0.conda hash: - md5: f6082eae112814f1447b56a5e1f6ed05 - sha256: 9866aaf7a13c6cfbe665ec7b330647a0fb10a81e6f9b8fee33642232a1920e18 + md5: db0c6b99149880c8ba515cf4abe93ee4 + sha256: 8dc54e94721e9ab545d7234aa5192b74102263d3e704e6d0c8aa7008f2da2a7b category: dev optional: true - name: rfc3339-validator @@ -8615,12 +8615,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 hash: - sha256: 183ed8f654bc393eeafdf89b2c258a224f4b4b73 + sha256: 4bb027706ed3726d42b75d349df087dcdf8450f9 source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 category: main optional: false - name: geoapps-utils @@ -8632,12 +8632,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 hash: - sha256: 183ed8f654bc393eeafdf89b2c258a224f4b4b73 + sha256: 4bb027706ed3726d42b75d349df087dcdf8450f9 source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 category: main optional: false - name: geoh5py @@ -8649,12 +8649,12 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.5.2,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + url: git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 hash: - sha256: cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + sha256: 12bf67269934b26a307c69857c01dd3b4c4742e9 source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + url: git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 category: main optional: false - name: geoh5py @@ -8666,12 +8666,12 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.5.2,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + url: git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 hash: - sha256: cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + sha256: 12bf67269934b26a307c69857c01dd3b4c4742e9 source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + url: git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 category: main optional: false - name: mira-simpeg @@ -8717,7 +8717,7 @@ package: category: main optional: false - name: octree-creation-app - version: 0.4.0-alpha.1 + version: 0.4.0a1 manager: pip platform: linux-64 dependencies: @@ -8727,16 +8727,16 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac hash: - sha256: 47fa41aa60b8473b7333f846ff329705b8a62129 + sha256: 111d2925130201bae952ff8692bf87663f3481ac source: type: url - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac category: main optional: false - name: octree-creation-app - version: 0.4.0-alpha.1 + version: 0.4.0a1 manager: pip platform: win-64 dependencies: @@ -8746,12 +8746,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac hash: - sha256: 47fa41aa60b8473b7333f846ff329705b8a62129 + sha256: 111d2925130201bae952ff8692bf87663f3481ac source: type: url - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac category: main optional: false - name: param-sweeps diff --git a/py-3.12.conda-lock.yml b/py-3.12.conda-lock.yml index 636167ae..582866cc 100644 --- a/py-3.12.conda-lock.yml +++ b/py-3.12.conda-lock.yml @@ -2348,7 +2348,7 @@ package: category: dev optional: true - name: jsonschema - version: 4.25.0 + version: 4.25.1 manager: conda platform: linux-64 dependencies: @@ -2357,14 +2357,14 @@ package: python: '>=3.9' referencing: '>=0.28.4' rpds-py: '>=0.7.1' - url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-4.25.0-pyhe01879c_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-4.25.1-pyhe01879c_0.conda hash: - md5: c6e3fd94e058dba67d917f38a11b50ab - sha256: 87ba7cf3a65c8e8d1005368b9aee3f49e295115381b7a0b180e56f7b68b5975f + md5: 341fd940c242cf33e832c0402face56f + sha256: ac377ef7762e49cb9c4f985f1281eeff471e9adc3402526eea78e6ac6589cf1d category: dev optional: true - name: jsonschema - version: 4.25.0 + version: 4.25.1 manager: conda platform: win-64 dependencies: @@ -2373,10 +2373,10 @@ package: python: '>=3.9' referencing: '>=0.28.4' rpds-py: '>=0.7.1' - url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-4.25.0-pyhe01879c_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-4.25.1-pyhe01879c_0.conda hash: - md5: c6e3fd94e058dba67d917f38a11b50ab - sha256: 87ba7cf3a65c8e8d1005368b9aee3f49e295115381b7a0b180e56f7b68b5975f + md5: 341fd940c242cf33e832c0402face56f + sha256: ac377ef7762e49cb9c4f985f1281eeff471e9adc3402526eea78e6ac6589cf1d category: dev optional: true - name: jsonschema-specifications @@ -2406,7 +2406,7 @@ package: category: dev optional: true - name: jsonschema-with-format-nongpl - version: 4.25.0 + version: 4.25.1 manager: conda platform: linux-64 dependencies: @@ -2414,20 +2414,20 @@ package: idna: '' isoduration: '' jsonpointer: '>1.13' - jsonschema: '>=4.25.0,<4.25.1.0a0' + jsonschema: '>=4.25.1,<4.25.2.0a0' rfc3339-validator: '' rfc3986-validator: '>0.1.0' rfc3987-syntax: '>=1.1.0' uri-template: '' webcolors: '>=24.6.0' - url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-with-format-nongpl-4.25.0-he01879c_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-with-format-nongpl-4.25.1-he01879c_0.conda hash: - md5: f4c7afaf838ab5bb1c4e73eb3095fb26 - sha256: 72604d07afaddf2156e61d128256d686aee4a7bdc06e235d7be352955de7527a + md5: 13e31c573c884962318a738405ca3487 + sha256: aef6705fe1335e6472e1b6365fcdb586356b18dceff72d8d6a315fc90e900ccf category: dev optional: true - name: jsonschema-with-format-nongpl - version: 4.25.0 + version: 4.25.1 manager: conda platform: win-64 dependencies: @@ -2435,16 +2435,16 @@ package: idna: '' isoduration: '' jsonpointer: '>1.13' - jsonschema: '>=4.25.0,<4.25.1.0a0' + jsonschema: '>=4.25.1,<4.25.2.0a0' rfc3339-validator: '' rfc3986-validator: '>0.1.0' rfc3987-syntax: '>=1.1.0' uri-template: '' webcolors: '>=24.6.0' - url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-with-format-nongpl-4.25.0-he01879c_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/jsonschema-with-format-nongpl-4.25.1-he01879c_0.conda hash: - md5: f4c7afaf838ab5bb1c4e73eb3095fb26 - sha256: 72604d07afaddf2156e61d128256d686aee4a7bdc06e235d7be352955de7527a + md5: 13e31c573c884962318a738405ca3487 + sha256: aef6705fe1335e6472e1b6365fcdb586356b18dceff72d8d6a315fc90e900ccf category: dev optional: true - name: jupyter-book @@ -6456,7 +6456,7 @@ package: category: dev optional: true - name: requests - version: 2.32.4 + version: 2.32.5 manager: conda platform: linux-64 dependencies: @@ -6465,14 +6465,14 @@ package: idna: '>=2.5,<4' python: '>=3.9' urllib3: '>=1.21.1,<3' - url: https://repo.prefix.dev/conda-forge/noarch/requests-2.32.4-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/requests-2.32.5-pyhd8ed1ab_0.conda hash: - md5: f6082eae112814f1447b56a5e1f6ed05 - sha256: 9866aaf7a13c6cfbe665ec7b330647a0fb10a81e6f9b8fee33642232a1920e18 + md5: db0c6b99149880c8ba515cf4abe93ee4 + sha256: 8dc54e94721e9ab545d7234aa5192b74102263d3e704e6d0c8aa7008f2da2a7b category: dev optional: true - name: requests - version: 2.32.4 + version: 2.32.5 manager: conda platform: win-64 dependencies: @@ -6481,10 +6481,10 @@ package: idna: '>=2.5,<4' python: '>=3.9' urllib3: '>=1.21.1,<3' - url: https://repo.prefix.dev/conda-forge/noarch/requests-2.32.4-pyhd8ed1ab_0.conda + url: https://repo.prefix.dev/conda-forge/noarch/requests-2.32.5-pyhd8ed1ab_0.conda hash: - md5: f6082eae112814f1447b56a5e1f6ed05 - sha256: 9866aaf7a13c6cfbe665ec7b330647a0fb10a81e6f9b8fee33642232a1920e18 + md5: db0c6b99149880c8ba515cf4abe93ee4 + sha256: 8dc54e94721e9ab545d7234aa5192b74102263d3e704e6d0c8aa7008f2da2a7b category: dev optional: true - name: rfc3339-validator @@ -8615,12 +8615,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 hash: - sha256: 183ed8f654bc393eeafdf89b2c258a224f4b4b73 + sha256: 4bb027706ed3726d42b75d349df087dcdf8450f9 source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 category: main optional: false - name: geoapps-utils @@ -8632,12 +8632,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 hash: - sha256: 183ed8f654bc393eeafdf89b2c258a224f4b4b73 + sha256: 4bb027706ed3726d42b75d349df087dcdf8450f9 source: type: url - url: git+https://github.com/MiraGeoscience/geoapps-utils.git@183ed8f654bc393eeafdf89b2c258a224f4b4b73 + url: git+https://github.com/MiraGeoscience/geoapps-utils.git@4bb027706ed3726d42b75d349df087dcdf8450f9 category: main optional: false - name: geoh5py @@ -8649,12 +8649,12 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.5.2,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + url: git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 hash: - sha256: cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + sha256: 12bf67269934b26a307c69857c01dd3b4c4742e9 source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + url: git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 category: main optional: false - name: geoh5py @@ -8666,12 +8666,12 @@ package: numpy: '>=1.26.0,<1.27.0' pillow: '>=10.3.0,<10.4.0' pydantic: '>=2.5.2,<3.0.0' - url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + url: git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 hash: - sha256: cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + sha256: 12bf67269934b26a307c69857c01dd3b4c4742e9 source: type: url - url: git+https://github.com/MiraGeoscience/geoh5py.git@cef8a1a904ab0338cd7ecb0f762db5f7a35f02e8 + url: git+https://github.com/MiraGeoscience/geoh5py.git@12bf67269934b26a307c69857c01dd3b4c4742e9 category: main optional: false - name: mira-simpeg @@ -8717,7 +8717,7 @@ package: category: main optional: false - name: octree-creation-app - version: 0.4.0-alpha.1 + version: 0.4.0a1 manager: pip platform: linux-64 dependencies: @@ -8727,16 +8727,16 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac hash: - sha256: 47fa41aa60b8473b7333f846ff329705b8a62129 + sha256: 111d2925130201bae952ff8692bf87663f3481ac source: type: url - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac category: main optional: false - name: octree-creation-app - version: 0.4.0-alpha.1 + version: 0.4.0a1 manager: pip platform: win-64 dependencies: @@ -8746,12 +8746,12 @@ package: numpy: '>=1.26.0,<1.27.0' pydantic: '>=2.5.2,<3.0.0' scipy: '>=1.14.0,<1.15.0' - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac hash: - sha256: 47fa41aa60b8473b7333f846ff329705b8a62129 + sha256: 111d2925130201bae952ff8692bf87663f3481ac source: type: url - url: git+https://github.com/MiraGeoscience/octree-creation-app.git@47fa41aa60b8473b7333f846ff329705b8a62129 + url: git+https://github.com/MiraGeoscience/octree-creation-app.git@111d2925130201bae952ff8692bf87663f3481ac category: main optional: false - name: param-sweeps From a1211ec71e0196fad01fdfb41c7f6b9af2d6bfbd Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 19 Aug 2025 16:04:19 -0700 Subject: [PATCH 53/56] Fix changes to projection --- simpeg_drivers/utils/nested.py | 8 +++----- simpeg_drivers/utils/surveys.py | 15 ++++++++------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/simpeg_drivers/utils/nested.py b/simpeg_drivers/utils/nested.py index f0c1631a..47b9172b 100644 --- a/simpeg_drivers/utils/nested.py +++ b/simpeg_drivers/utils/nested.py @@ -291,9 +291,7 @@ def create_simulation( if isinstance(simulation, BaseFDEMSimulation | BaseTDEMSimulation): compute_em_projections(simulation.survey.locations, local_sim) elif isinstance(simulation, Simulation3DRes | Simulation3DIP): - compute_dc_projections( - simulation.survey.locations, simulation.survey.cells, local_sim - ) + compute_dc_projections(simulation.survey.locations, local_sim) return local_sim, mapping, local_ordering @@ -333,12 +331,12 @@ def create_survey(survey, indices, channel=None): else: new_rx.locations = rx.locations[intersect] - new_rx.local_index = indices + new_rx.local_index = new_rx.local_index[intersect] receivers.append(new_rx) if any(receivers): new_src = copy(src) - new_src.rx_ids = indices + new_src.rx_ids = new_src.rx_ids[intersect] new_src.receiver_list = receivers sources.append(new_src) diff --git a/simpeg_drivers/utils/surveys.py b/simpeg_drivers/utils/surveys.py index 613f42b6..314d4ea4 100644 --- a/simpeg_drivers/utils/surveys.py +++ b/simpeg_drivers/utils/surveys.py @@ -165,18 +165,19 @@ def compute_em_projections(locations, simulation): receiver.spatialP = projection -def compute_dc_projections(locations, cells, simulation): +def compute_dc_projections(locations, simulation): """ Pre-compute projections for the receivers for efficiency. """ projection = simulation.mesh.get_interpolation_matrix(locations, "nodes") for source in simulation.survey.source_list: - ind = source.rx_ids - proj_mn = projection[cells[ind, 0], :] + for receiver in source.receiver_list: + cells = receiver.local_index + proj_mn = projection[cells[:, 0], :] - # Check if dipole receiver - if not np.all(cells[ind, 0] == cells[ind, 1]): - proj_mn -= projection[cells[ind, 1], :] + # Check if dipole receiver + if not np.all(cells[:, 0] == cells[:, 1]): + proj_mn -= projection[cells[:, 1], :] - source.receiver_list[0].spatialP = proj_mn # pylint: disable=protected-access + receiver.spatialP = proj_mn # pylint: disable=protected-access From 4233b2b3b33a2026256f45a200b547db765dcf92 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 19 Aug 2025 16:50:05 -0700 Subject: [PATCH 54/56] Remove storage of indices on receivers, keep all on source --- .../components/factories/receiver_factory.py | 2 +- .../components/factories/survey_factory.py | 7 +------ simpeg_drivers/utils/nested.py | 12 ++++++++---- simpeg_drivers/utils/surveys.py | 13 +++++++------ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/simpeg_drivers/components/factories/receiver_factory.py b/simpeg_drivers/components/factories/receiver_factory.py index 97c17b18..69bbaa85 100644 --- a/simpeg_drivers/components/factories/receiver_factory.py +++ b/simpeg_drivers/components/factories/receiver_factory.py @@ -153,7 +153,7 @@ def build(self, locations=None, data=None, local_index=None, component=None): local_index=local_index, component=component, ) - receivers.local_index = local_index + if ( self.factory_type in ["tipper"] and getattr(self.params.data_object, "base_stations", None) is not None diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index 0f5b5029..50de9cea 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -270,7 +270,6 @@ def _tdem_arguments(self, data=None): data=data, component=component, ) - rx_obj.local_index = rx_ids rx_list.append(rx_obj) n_times = len(receivers.channels) n_rx = len(rx_ids) if isinstance(rx_ids, np.ndarray) else 1 @@ -312,8 +311,6 @@ def _fem_arguments(self, data=None): data=data, component=component, ) - - receiver.local_index = rx_id block_ordering.append([comp_id, rx_id]) receivers.append(receiver) @@ -329,9 +326,7 @@ def _fem_arguments(self, data=None): locations=locs, frequency=frequency, ) - tx.rx_ids = np.unique( - np.hstack([rec.local_index for rec in receivers], dtype=int) - ) + tx.rx_ids = np.r_[rx_id] sources.append(tx) ordering.append( diff --git a/simpeg_drivers/utils/nested.py b/simpeg_drivers/utils/nested.py index 47b9172b..d50dced8 100644 --- a/simpeg_drivers/utils/nested.py +++ b/simpeg_drivers/utils/nested.py @@ -24,6 +24,7 @@ from simpeg.electromagnetics.frequency_domain.sources import ( LineCurrent as FEMLineCurrent, ) +from simpeg.electromagnetics.natural_source import Simulation3DPrimarySecondary from simpeg.electromagnetics.static.induced_polarization.simulation import ( Simulation3DNodal as Simulation3DIP, ) @@ -288,10 +289,14 @@ def create_simulation( local_sim = type(simulation)(*args, **kwargs) - if isinstance(simulation, BaseFDEMSimulation | BaseTDEMSimulation): + if isinstance( + simulation, BaseFDEMSimulation | BaseTDEMSimulation + ) and not isinstance(simulation, Simulation3DPrimarySecondary): compute_em_projections(simulation.survey.locations, local_sim) elif isinstance(simulation, Simulation3DRes | Simulation3DIP): - compute_dc_projections(simulation.survey.locations, local_sim) + compute_dc_projections( + simulation.survey.locations, simulation.survey.cells, local_sim + ) return local_sim, mapping, local_ordering @@ -331,12 +336,11 @@ def create_survey(survey, indices, channel=None): else: new_rx.locations = rx.locations[intersect] - new_rx.local_index = new_rx.local_index[intersect] receivers.append(new_rx) if any(receivers): new_src = copy(src) - new_src.rx_ids = new_src.rx_ids[intersect] + new_src.rx_ids = src.rx_ids[intersect] new_src.receiver_list = receivers sources.append(new_src) diff --git a/simpeg_drivers/utils/surveys.py b/simpeg_drivers/utils/surveys.py index 314d4ea4..06815376 100644 --- a/simpeg_drivers/utils/surveys.py +++ b/simpeg_drivers/utils/surveys.py @@ -156,28 +156,29 @@ def compute_em_projections(locations, simulation): ) for source in simulation.survey.source_list: + indices = source.rx_ids for receiver in source.receiver_list: projection = 0.0 for orientation, comp in zip(receiver.orientation, "xyz", strict=True): if orientation == 0: continue - projection += orientation * projections[comp][receiver.local_index, :] + projection += orientation * projections[comp][indices, :] receiver.spatialP = projection -def compute_dc_projections(locations, simulation): +def compute_dc_projections(locations, cells, simulation): """ Pre-compute projections for the receivers for efficiency. """ projection = simulation.mesh.get_interpolation_matrix(locations, "nodes") for source in simulation.survey.source_list: + indices = source.rx_ids for receiver in source.receiver_list: - cells = receiver.local_index - proj_mn = projection[cells[:, 0], :] + proj_mn = projection[cells[indices, 0], :] # Check if dipole receiver - if not np.all(cells[:, 0] == cells[:, 1]): - proj_mn -= projection[cells[:, 1], :] + if not np.all(cells[indices, 0] == cells[indices, 1]): + proj_mn -= projection[cells[indices, 1], :] receiver.spatialP = proj_mn # pylint: disable=protected-access From 99f5062f14e19d881ca2bbefcc75f859e16e3fc9 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 19 Aug 2025 17:02:49 -0700 Subject: [PATCH 55/56] Deal with single receiver tem --- simpeg_drivers/components/factories/survey_factory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simpeg_drivers/components/factories/survey_factory.py b/simpeg_drivers/components/factories/survey_factory.py index 50de9cea..b98c47cd 100644 --- a/simpeg_drivers/components/factories/survey_factory.py +++ b/simpeg_drivers/components/factories/survey_factory.py @@ -282,7 +282,7 @@ def _tdem_arguments(self, data=None): ) tx = tx_factory.build(rx_list, locations=cur_tx_locs, waveform=waveform) - tx.rx_ids = np.asarray(rx_ids, dtype=int) + tx.rx_ids = np.r_[rx_ids].astype(int) tx_list.append(tx) self.ordering = np.vstack(ordering).astype(int) From 8742303be829599fe9617a27a96a81d1319bcb1a Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 19 Aug 2025 21:00:06 -0700 Subject: [PATCH 56/56] RE-instate solver type Mumps --- tests/run_tests/driver_ground_tem_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run_tests/driver_ground_tem_test.py b/tests/run_tests/driver_ground_tem_test.py index e3450842..9437539d 100644 --- a/tests/run_tests/driver_ground_tem_test.py +++ b/tests/run_tests/driver_ground_tem_test.py @@ -90,6 +90,7 @@ def test_tiling_ground_tem( y_channel_bool=True, z_channel_bool=True, tile_spatial=4, + solver_type="Mumps", ) fwr_driver = TDEMForwardDriver(params)