Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
843a029
PlateOptions composed of PlateModel
benk-mira Mar 25, 2026
7a36da5
fix tests
benk-mira Mar 31, 2026
19342da
refactor
benk-mira Apr 1, 2026
ce6b151
copilot suggestions
benk-mira Apr 1, 2026
4178c1f
padding_distance back to 1000.0
benk-mira Apr 2, 2026
2ecd649
nope, revert
benk-mira Apr 2, 2026
0b5b55e
diagonal balance true, topo not a horizon, minimal plate refinement
benk-mira Apr 2, 2026
ba7c0c8
handle naming changes in ui.json files with aliases
benk-mira Apr 2, 2026
fee12c3
cleanup
benk-mira Apr 2, 2026
fb5afb4
another cleanup
benk-mira Apr 2, 2026
d97eba2
update docstrings
benk-mira Apr 2, 2026
e42b10e
more docstring updates
benk-mira Apr 2, 2026
db56325
Set old default cell sizes in runtests where it isn't passed through …
benk-mira Apr 2, 2026
aab91f4
Update simpeg_drivers/utils/synthetics/meshes.py
benk-mira Apr 2, 2026
d2a579c
Merge branch 'develop' into GEOPY-2770
benk-mira Apr 2, 2026
51ee9b7
create plate on demand
benk-mira Apr 2, 2026
44af353
Merge branch 'GEOPY-2770' of github.com:MiraGeoscience/simpeg-drivers…
benk-mira Apr 2, 2026
6160b7f
remove aliasing as it breaks tests since collect_from_dict recurses a…
benk-mira Apr 2, 2026
1cf8dc3
alias plate_property and overburden_property
benk-mira Apr 6, 2026
0dddd0b
relock
benk-mira Apr 6, 2026
e347434
add name to PlateModelOptions
benk-mira Apr 6, 2026
ea78021
handle caplog assertion for extra logging
benk-mira Apr 6, 2026
7ae05ff
update targets
benk-mira Apr 6, 2026
8f563c6
cell_size as argument for all forward tests
benk-mira Apr 7, 2026
c601508
mvi used to use 5m cells
benk-mira Apr 7, 2026
d987725
Merge branch 'develop' into GEOPY-2770
domfournier Apr 7, 2026
61d9120
Update MVI test
domfournier Apr 7, 2026
e431369
Refine test mesh to stabilize test
domfournier Apr 8, 2026
2b8e643
Refine MT test again
domfournier Apr 8, 2026
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
4 changes: 2 additions & 2 deletions simpeg_drivers-assets/uijson/plate_simulation.ui.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"tooltip": "Value of the basement resisitivity (ohm-m), density (g/cc) or susceptibility (SI)",
"enabled": true
},
"overburden": {
"overburden_property": {
"main": true,
"group": "Overburden",
"label": "Physical property (SI)",
Expand Down Expand Up @@ -65,7 +65,7 @@
"enabled": true,
"tooltip": "Spacing between plates"
},
"plate": {
"plate_property": {
"main": true,
"group": "Plate",
"label": "Physical property (SI)",
Expand Down
73 changes: 47 additions & 26 deletions simpeg_drivers/plate_simulation/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
import numpy as np
from dask.distributed import Client
from geoapps_utils.base import Driver, get_logger
from geoapps_utils.modelling.plates import Plate
from geoapps_utils.utils.transformations import azimuth_to_unit_vector
from geoh5py.data import FloatData, ReferencedData
from geoh5py.objects import Octree, Points, Surface
from geoh5py.shared.utils import fetch_active_workspace
from grid_apps.octree_creation.driver import OctreeDriver

from simpeg_drivers.driver import (
InversionDriver,
Expand All @@ -30,9 +30,9 @@
)
from simpeg_drivers.options import BaseForwardOptions, ModelTypeEnum
from simpeg_drivers.plate_simulation.models.events import Anomaly, Erosion, Overburden
from simpeg_drivers.plate_simulation.models.parametric import Plate
from simpeg_drivers.plate_simulation.models.series import DikeSwarm, Geology
from simpeg_drivers.plate_simulation.options import PlateSimulationOptions
from simpeg_drivers.utils.synthetics.meshes import get_octree_mesh
from simpeg_drivers.utils.utils import validate_out_group


Expand Down Expand Up @@ -131,24 +131,29 @@ def plates(self) -> list[Plate]:
"""Generate sequence of plates."""
if self._plates is None:
offset = (
self.params.model.overburden_model.thickness
if self.params.model.plate_model.reference_surface == "overburden"
self.params.model.overburden.thickness
if self.params.model.plate.reference_surface == "overburden"
else 0.0
)
center = self.params.model.plate_model.center(
center = self.params.model.plate.center(
self.survey,
self.topography,
depth_offset=-1 * offset,
)
plate = Plate(
self.params.model.plate_model,
center,
self.params.model.plate.geometry.model_copy(
update={
"easting": center[0],
"northing": center[1],
"elevation": center[2],
}
),
Comment thread
benk-mira marked this conversation as resolved.
)
self._plates = self.replicate(
plate,
self.params.model.plate_model.number,
self.params.model.plate_model.spacing,
self.params.model.plate_model.dip_direction,
self.params.model.plate.number,
self.params.model.plate.spacing,
self.params.model.plate.geometry.direction,
)
return self._plates

Expand Down Expand Up @@ -180,13 +185,16 @@ def make_mesh(self) -> Octree:
"""

logger.info("making the mesh...")
octree_params = self.params.mesh.octree_params(
self.survey,
self.simulation_parameters.active_cells.topography_object,
[p.surface.copy(parent=self._out_group) for p in self.plates],
)
octree_driver = OctreeDriver(octree_params)
mesh = octree_driver.run()
with fetch_active_workspace(self.params.geoh5, mode="r+") as geoh5:
surfaces = [p.surface(geoh5) for p in self.plates]
mesh = get_octree_mesh(
opts=self.params.mesh,
survey=self.survey,
topography=self.simulation_parameters.active_cells.topography_object,
plates=surfaces,
Comment thread
benk-mira marked this conversation as resolved.
name=self.params.mesh.name,
)

mesh.parent = self._out_group

return mesh
Expand All @@ -198,12 +206,15 @@ def make_model(self) -> FloatData:

overburden = Overburden(
topography=self.simulation_parameters.active_cells.topography_object,
thickness=self.params.model.overburden_model.thickness,
value=self.params.model.overburden_model.overburden,
thickness=self.params.model.overburden.thickness,
value=self.params.model.overburden.overburden_property,
)

dikes = DikeSwarm(
[Anomaly(plate, plate.params.plate) for plate in self.plates],
[
Anomaly(plate, self.params.model.plate.plate_property)
for plate in self.plates
],
name="plates",
)

Expand Down Expand Up @@ -261,8 +272,6 @@ def replicate(
"""
Replicate a plate n times along an azimuth centered at origin.

Plate names will be indexed.

:param plate: models.parametric.Plate to be replicated.
:param number: Number of plates returned.
:param spacing: Spacing between plates.
Expand All @@ -272,10 +281,22 @@ def replicate(

plates = []
for i in range(number):
center = np.r_[plate.center] + azimuth_to_unit_vector(azimuth) * offsets[i]
new = Plate(plate.params.model_copy(), center)
new.params.name = f"{plate.params.name} offset {i + 1}"
plates.append(new)
center = (
np.r_[plate.params.origin]
+ azimuth_to_unit_vector(azimuth) * offsets[i]
)
new_plate = Plate(
plate.params.model_copy(
Comment thread
benk-mira marked this conversation as resolved.
update={
"easting": center[0],
"northing": center[1],
"elevation": center[2],
}
)
)

plates.append(new_plate)

return plates


Expand Down
10 changes: 5 additions & 5 deletions simpeg_drivers/plate_simulation/match/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ def _create_plate_from_parameters(
"""
center = self.params.survey.vertices[index_center]
center[2] = (
self._drape_heights[index_center] - model_options.overburden_model.thickness
self._drape_heights[index_center] - model_options.overburden.thickness
)
indices = self.params.survey.get_segment_indices(
index_center, self.params.max_distance
Expand All @@ -208,10 +208,10 @@ def _create_plate_from_parameters(
"y": center[1],
"z": center[2],
},
"width": model_options.plate_model.dip_length,
"thickness": model_options.plate_model.width,
"length": model_options.plate_model.strike_length,
"dip": model_options.plate_model.dip,
"width": model_options.plate.geometry.dip_length,
"thickness": model_options.plate.geometry.width,
"length": model_options.plate.geometry.strike_length,
"dip": model_options.plate.geometry.dip,
"dip_direction": (azimuth + strike_angle) % 360,
}
)
Expand Down
47 changes: 17 additions & 30 deletions simpeg_drivers/plate_simulation/models/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
from typing import TypeVar

import numpy as np
from geoapps_utils.modelling.plates import PlateModel
from geoh5py.objects import Points
from pydantic import (
BaseModel,
ConfigDict,
Field,
ValidationInfo,
field_validator,
model_validator,
Expand All @@ -28,21 +30,13 @@ class PlateOptions(BaseModel):
"""
Parameters describing an anomalous plate.

:param plate: Value given to the plate(s).
:param width: V-size of the plate.
:param strike_length: U-size of the plate.
:param dip_length: W-size of the plate.
:param dip: Orientation of the v-axis in degree from horizontal.
:param dip_direction: Orientation of the u axis in degree from north.
:param reference: Point of rotation to be 'center' or 'top'.
:param name: Name given to the plate.
:param plate_property: Value given to the plate(s).
:param geometry: Parameters describing the plate geometry.
:param number: Number of offset plates to be created.
:param spacing: Spacing between plates.
:param relative_locations: If True locations are relative to survey in xy and
mean topography in z.
:param easting: Easting offset relative to survey.
:param northing: Northing offset relative to survey.
:param elevation: plate(s) elevation. May be true elevation or relative to
overburden or topography.
:param reference_surface: Switches between using topography and overburden as
elevation reference of the plate.
:param reference_type: Type of reference for plate elevation. Can be 'mean'
Expand All @@ -53,18 +47,11 @@ class PlateOptions(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)

name: str = "Plate"
plate: float
width: float
strike_length: float
dip_length: float
dip: float = 90.0
dip_direction: float = 90.0
plate_property: float = Field(validation_alias="plate")
geometry: PlateModel
number: int = 1
spacing: float = 0.0
relative_locations: bool = False
easting: float = 0.0
northing: float = 0.0
elevation: float
reference_surface: str = "topography"
reference_type: str = "mean"

Expand All @@ -82,7 +69,7 @@ def single_plate(self):
@property
def halfplate(self):
"""Compute half the z-projection length of the plate."""
return 0.5 * self.dip_length * np.sin(np.deg2rad(self.dip))
return 0.5 * self.geometry.dip_length * np.sin(np.deg2rad(self.geometry.dip))

def center(
self,
Expand All @@ -104,11 +91,11 @@ def _get_xy(self, survey: Points) -> tuple[float, float]:

if self.relative_locations:
return (
survey.vertices[:, 0].mean() + self.easting,
survey.vertices[:, 1].mean() + self.northing,
survey.vertices[:, 0].mean() + self.geometry.origin[0],
survey.vertices[:, 1].mean() + self.geometry.origin[1],
)

return self.easting, self.northing
return self.geometry.origin[0], self.geometry.origin[1]

def _get_z(self, surface: Points, offset: float = 0.0) -> float:
"""
Expand All @@ -122,9 +109,9 @@ def _get_z(self, surface: Points, offset: float = 0.0) -> float:
raise ValueError("Topography object has no vertices.")
if self.relative_locations:
z = getattr(surface.vertices[:, 2], self.reference_type)()
z += offset + self.elevation - self.halfplate
z += offset + self.geometry.elevation - self.halfplate
else:
z = self.elevation
z = self.geometry.elevation

return z

Expand All @@ -134,11 +121,11 @@ class OverburdenOptions(BaseModel):
Parameters for the overburden layer.

:param thickness: Thickness of the overburden layer.
:param overburden: Value given to the overburden layer.
:param overburden_property: Value given to the overburden layer.
"""

thickness: float
overburden: float
overburden_property: float = Field(validation_alias="overburden")


class ModelOptions(BaseModel):
Expand All @@ -153,5 +140,5 @@ class ModelOptions(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)

background: float
overburden_model: OverburdenOptions
plate_model: PlateOptions
overburden: OverburdenOptions
plate: PlateOptions
Loading
Loading