Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
ef5e36a
Start implementing ProcessPoolExecutor for building sub-misfits.
domfournier Aug 8, 2025
3459408
Continue refactoring
domfournier Aug 11, 2025
d1dfdaa
Fix for PF
domfournier Aug 11, 2025
212f0ef
Full run through gravity
domfournier Aug 12, 2025
301d199
Run-through ATEM
domfournier Aug 12, 2025
a01aedb
MT almost through
domfournier Aug 12, 2025
34fc52c
Combine EM and MT data parsing without looping
domfournier Aug 13, 2025
1bba32b
Fixes for DC and PF
domfournier Aug 13, 2025
08c152c
Change ordering for FEM methods
domfournier Aug 13, 2025
938daf5
Full run through NS tests
domfournier Aug 13, 2025
bfb339c
Line up PF with the rest
domfournier Aug 13, 2025
cf77def
Work through kinks for DC
domfournier Aug 13, 2025
787d9c7
Clean out commented code
domfournier Aug 14, 2025
2f1268c
Merge branch 'develop' into GEOPY-2389
domfournier Aug 14, 2025
a529ccb
Move functions under utils/nested
domfournier Aug 14, 2025
b6fed5c
Rename functions
domfournier Aug 14, 2025
e44c9a3
Start removing ordering as tensor array. Only reference to the rx loc…
domfournier Aug 14, 2025
303f164
Fix TEM
domfournier Aug 14, 2025
25e2a96
Merge branch 'develop' into GEOPY-2389
domfournier Aug 14, 2025
0adbbcb
Re-lock
domfournier Aug 14, 2025
b45ff34
Merge branch 'GEOPY-2389' of https://github.com/MiraGeoscience/simpeg…
domfournier Aug 14, 2025
ebba709
Fix imports in test
domfournier Aug 14, 2025
f64cc53
Order of operation for 2D
domfournier Aug 15, 2025
7cc7430
Skip nesting for 2D problems
domfournier Aug 15, 2025
2418825
Clean up
domfournier Aug 15, 2025
2bd95d1
Continue work on FEM sorting
domfournier Aug 15, 2025
5c7858e
Add MT_fwr_example
domfournier Aug 15, 2025
2e74af8
Continue work on 1D
domfournier Aug 15, 2025
45827d3
Fix tem 1D and IP
domfournier Aug 15, 2025
1337c3e
Proper handling of reshape for various EMs
domfournier Aug 15, 2025
3a0a059
Fix FEM3D
domfournier Aug 15, 2025
e987227
Fix joints
domfournier Aug 15, 2025
5d1f69f
Revert back to ordering per type
domfournier Aug 16, 2025
a0aae26
Review sorting array
domfournier Aug 17, 2025
f92dd1b
Apply tile sorting to survey sorting
domfournier Aug 17, 2025
3fc6e6f
Fix sorting of app res
domfournier Aug 17, 2025
acb043b
Adjust data_tests
domfournier Aug 17, 2025
723dc54
Remove special sorting for 1D driver
domfournier Aug 17, 2025
297d870
Fix FEM 1D again
domfournier Aug 17, 2025
8e97ac1
Attach receiver indices to the source for reference in create_survey.…
domfournier Aug 18, 2025
ddfc83d
Adjust tile estimator
domfournier Aug 18, 2025
e7b0f9a
Clean up SaveData directive
domfournier Aug 18, 2025
071dc2e
Adjust naming in IP tests
domfournier Aug 18, 2025
ec864b7
Fix naming of dc tests
domfournier Aug 18, 2025
ac3d7a6
Clean up attribute sorting of driver and MisfitFactory
domfournier Aug 18, 2025
c6b3796
Use divide for normalizations
domfournier Aug 18, 2025
959755b
Re-lock
domfournier Aug 18, 2025
2968a6c
Revert back to Pardiso?
domfournier Aug 18, 2025
e48dfb5
Remove check for Mumps
domfournier Aug 18, 2025
54ffd47
Revert "Remove check for Mumps"
domfournier Aug 18, 2025
bee387e
Set Mumps in test
domfournier Aug 18, 2025
c4ba10b
Beef up docstrings in nested
domfournier Aug 19, 2025
584968b
Bring pre-computing of projections for airborne EM and dcip
domfournier Aug 19, 2025
931e1f8
Update local index on sub survey
domfournier Aug 19, 2025
0b341f2
Merge branch 'develop' into GEOPY-2389
domfournier Aug 19, 2025
4ac2732
Re-lock
domfournier Aug 19, 2025
a23ac17
Merge branch 'develop' into GEOPY-2389
domfournier Aug 19, 2025
a1211ec
Fix changes to projection
domfournier Aug 19, 2025
4233b2b
Remove storage of indices on receivers, keep all on source
domfournier Aug 19, 2025
99f5062
Deal with single receiver tem
domfournier Aug 20, 2025
8742303
RE-instate solver type Mumps
domfournier Aug 20, 2025
4445cae
Merge branch 'develop' into GEOPY-2389
domfournier Aug 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions simpeg_drivers-assets/MT_fwr_UBC_example.geoh5
Git LFS file not shown
139 changes: 17 additions & 122 deletions simpeg_drivers/components/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 geoh5py.objects import LargeLoopGroundTEMReceivers, 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
Expand All @@ -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 :
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -160,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:
Expand Down Expand Up @@ -232,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:
Expand Down Expand Up @@ -333,126 +323,31 @@ 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)
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(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,
geometric_factor(survey)[np.argsort(survey.sorting)] + 1e-10
)
survey.cells = self.entity.cells

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)
if "induced polarization" in self.params.inversion_type:
survey.cells = self.entity.cells

inverse_problem.dpred = dpred
return survey

@property
def observed_data_types(self):
Expand Down Expand Up @@ -495,7 +390,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

Expand Down
Loading
Loading