Skip to content

Commit 39d7935

Browse files
committed
Merge branch 'fault-anisotropy-fix' into inequality-refresh
2 parents 6d7264c + 064ae65 commit 39d7935

File tree

6 files changed

+63
-65
lines changed

6 files changed

+63
-65
lines changed

LoopStructural/interpolators/_p1interpolator.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,12 @@ def setup_interpolator(self, **kwargs):
175175
# self.add_interface_constraints(self.interpolation_weights["ipw"])
176176

177177
def add_gradient_orthogonal_constraints(
178-
self, points: np.ndarray, vector: np.ndarray, w: float = 1.0, B: float = 0
178+
self,
179+
points: np.ndarray,
180+
vector: np.ndarray,
181+
w: float = 1.0,
182+
B: float = 0,
183+
name='undefined gradient orthogonal constraint',
179184
):
180185
"""
181186
constraints scalar field to be orthogonal to a given vector

LoopStructural/modelling/core/geological_model.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1470,7 +1470,6 @@ def regular_grid(self, nsteps=None, shuffle=True, rescale=False, order="C"):
14701470
locations of points in regular grid
14711471
"""
14721472
return self.bounding_box.regular_grid(nsteps=nsteps, shuffle=shuffle, order=order)
1473-
14741473

14751474
def evaluate_model(self, xyz: np.ndarray, scale: bool = True) -> np.ndarray:
14761475
"""Evaluate the stratigraphic id at each location

LoopStructural/modelling/features/builders/_fault_builder.py

Lines changed: 50 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
from typing import Union
2+
3+
from LoopStructural.utils.maths import rotation
24
from ._structural_frame_builder import StructuralFrameBuilder
35
from .. import AnalyticalGeologicalFeature
46
from LoopStructural.utils import get_vectors
@@ -135,9 +137,9 @@ def create_data_from_geometry(
135137
)
136138

137139
if len(vector_data) == 0:
138-
logger.error(
139-
"You cannot model a fault without defining the orientation of the fault\n\
140-
Defaulting to a vertical fault"
140+
logger.warning(
141+
f"No orientation data for fault\n\
142+
Defaulting to a dip of {fault_dip}vertical fault"
141143
)
142144
if fault_frame_data.loc[trace_mask, :].shape[0] > 3:
143145

@@ -149,20 +151,22 @@ def create_data_from_geometry(
149151
slope, intercept = coefficients
150152

151153
# Create a direction vector using the slope
152-
direction_vector = np.array([1, slope])
154+
direction_vector = np.array([1, slope, 0])
153155
direction_vector /= np.linalg.norm(direction_vector)
154-
print(f"Fault dip: {fault_dip}")
156+
rotation_matrix = rotation(direction_vector[None, :], [90 - fault_dip])
155157
vector_data = np.array(
156158
[
157159
[
158160
direction_vector[1],
159161
-direction_vector[0],
160-
np.sin(np.deg2rad(fault_dip)),
162+
0,
161163
]
162164
]
163165
)
164-
vector_data /= np.linalg.norm(vector_data, axis=1)[:, None]
166+
vector_data /= np.linalg.norm(vector_data, axis=1)
167+
vector_data = np.einsum("ijk,ik->ij", rotation_matrix, vector_data)
165168

169+
vector_data /= np.linalg.norm(vector_data, axis=1)
166170
fault_normal_vector = np.mean(vector_data, axis=0)
167171

168172
logger.info(f"Fault normal vector: {fault_normal_vector}")
@@ -221,11 +225,11 @@ def create_data_from_geometry(
221225
self.fault_minor_axis = minor_axis
222226
self.fault_major_axis = major_axis
223227
self.fault_intermediate_axis = intermediate_axis
224-
fault_normal_vector /= np.linalg.norm(fault_normal_vector)
228+
self.fault_normal_vector /= np.linalg.norm(self.fault_normal_vector)
225229
fault_slip_vector /= np.linalg.norm(fault_slip_vector)
226230
# check if slip vector is inside fault plane, if not project onto fault plane
227231
# if not np.isclose(normal_vector @ slip_vector, 0):
228-
strike_vector = np.cross(fault_normal_vector, fault_slip_vector)
232+
strike_vector = np.cross(self.fault_normal_vector, fault_slip_vector)
229233
self.fault_strike_vector = strike_vector
230234

231235
fault_edges = np.zeros((2, 3))
@@ -252,8 +256,8 @@ def create_data_from_geometry(
252256
)
253257
if fault_center is not None:
254258
if minor_axis is not None:
255-
fault_edges[0, :] = fault_center[:3] + fault_normal_vector * minor_axis
256-
fault_edges[1, :] = fault_center[:3] - fault_normal_vector * minor_axis
259+
fault_edges[0, :] = fault_center[:3] + self.fault_normal_vector * minor_axis
260+
fault_edges[1, :] = fault_center[:3] - self.fault_normal_vector * minor_axis
257261
self.update_geometry(fault_edges)
258262

259263
# choose whether to add points -1,1 to constrain fault frame or a scaled
@@ -342,9 +346,9 @@ def create_data_from_geometry(
342346
fault_center[1],
343347
fault_center[2],
344348
self.name,
345-
fault_normal_vector[0] / minor_axis * 0.5,
346-
fault_normal_vector[1] / minor_axis * 0.5,
347-
fault_normal_vector[2] / minor_axis * 0.5,
349+
self.fault_normal_vector[0] / minor_axis * 0.5,
350+
self.fault_normal_vector[1] / minor_axis * 0.5,
351+
self.fault_normal_vector[2] / minor_axis * 0.5,
348352
np.nan,
349353
0,
350354
w,
@@ -439,9 +443,9 @@ def create_data_from_geometry(
439443

440444
self.add_data_from_data_frame(fault_frame_data)
441445
if fault_trace_anisotropy > 0:
442-
self.add_fault_trace_anisotropy(fault_trace_anisotropy)
446+
self.add_fault_trace_anisotropy(w=fault_trace_anisotropy)
443447
if fault_dip_anisotropy > 0:
444-
self.add_fault_dip_anisotropy(fault_dip_anisotropy)
448+
self.add_fault_dip_anisotropy(w=fault_dip_anisotropy)
445449
if force_mesh_geometry:
446450
self.set_mesh_geometry(fault_buffer, None)
447451
self.update_geometry(fault_frame_data[["X", "Y", "Z"]].to_numpy())
@@ -501,29 +505,24 @@ def add_fault_trace_anisotropy(self, w: float = 1.0):
501505
w : float, optional
502506
_description_, by default 1.0
503507
"""
504-
trace_data = self.builders[0].data.loc[self.builders[0].data["val"] == 0, :]
505-
if trace_data.shape[0] < 2:
506-
logger.warning(
507-
f"Only {trace_data.shape[0]} point on fault trace, cannot add fault trace anisotropy. Need at least 3 points"
508+
if w > 0:
509+
510+
plane = np.array([0, 0, 1])
511+
strike_vector = (
512+
self.fault_normal_vector - np.dot(self.fault_normal_vector, plane) * plane
513+
)
514+
strike_vector /= np.linalg.norm(strike_vector)
515+
strike_vector = np.array([strike_vector[1], -strike_vector[0], 0])
516+
517+
anisotropy_feature = AnalyticalGeologicalFeature(
518+
vector=strike_vector, origin=[0, 0, 0], name="fault_trace_anisotropy"
519+
)
520+
print('adding fault trace anisotropy')
521+
self.builders[0].add_orthogonal_feature(
522+
anisotropy_feature, w=w, region=None, step=1, B=0
508523
)
509-
return
510-
coefficients = np.polyfit(
511-
trace_data["X"],
512-
trace_data["Y"],
513-
1,
514-
)
515-
slope, intercept = coefficients
516-
517-
# Create a direction vector using the slope
518-
direction_vector = np.array([1, slope])
519-
direction_vector /= np.linalg.norm(direction_vector)
520-
vector_data = np.array([[direction_vector[1], -direction_vector[0], 0]])
521-
anisotropy_feature = AnalyticalGeologicalFeature(
522-
vector=vector_data, origin=[0, 0, 0], name="fault_trace_anisotropy"
523-
)
524-
self.builders[0].add_orthogonal_feature(anisotropy_feature, w=w, region=None, step=1, B=0)
525524

526-
def add_fault_dip_anisotropy(self, dip: np.ndarray, w: float = 1.0):
525+
def add_fault_dip_anisotropy(self, w: float = 1.0):
527526
"""_summary_
528527
529528
Parameters
@@ -533,32 +532,23 @@ def add_fault_dip_anisotropy(self, dip: np.ndarray, w: float = 1.0):
533532
w : float, optional
534533
_description_, by default 1.0
535534
"""
536-
537-
trace_data = self.builders[0].data.loc[self.builders[0].data["val"] == 0, :]
538-
if trace_data.shape[0] < 2:
539-
logger.warning(
540-
f'Only {trace_data.shape[0]} point on fault trace, cannot add fault trace anisotropy. Need at least 3 points'
535+
if w > 0:
536+
plane = np.array([0, 0, 1])
537+
strike_vector = (
538+
self.fault_normal_vector - np.dot(self.fault_normal_vector, plane) * plane
541539
)
542-
return
543-
coefficients = np.polyfit(
544-
trace_data["X"],
545-
trace_data["Y"],
546-
1,
547-
)
548-
slope, intercept = coefficients
540+
strike_vector /= np.linalg.norm(strike_vector)
541+
strike_vector = np.array([strike_vector[1], -strike_vector[0], 0])
549542

550-
# Create a direction vector using the slope
551-
direction_vector = np.array([1, slope])
552-
direction_vector /= np.linalg.norm(direction_vector)
553-
vector_data = np.array([[direction_vector[0], direction_vector[1], 0]])
543+
dip_vector = np.cross(strike_vector, self.fault_normal_vector)
554544

555-
vector_data = np.array(
556-
[[direction_vector[1], -direction_vector[0], np.sin(np.deg2rad(dip))]]
557-
)
558-
anisotropy_feature = AnalyticalGeologicalFeature(
559-
vector=vector_data, origin=[0, 0, 0], name="fault_dip_anisotropy"
560-
)
561-
self.builders[0].add_orthogonal_feature(anisotropy_feature, w=w, region=None, step=1, B=0)
545+
anisotropy_feature = AnalyticalGeologicalFeature(
546+
vector=dip_vector, origin=[0, 0, 0], name="fault_dip_anisotropy"
547+
)
548+
print(f'adding fault dip anisotropy {anisotropy_feature.name}')
549+
self.builders[0].add_orthogonal_feature(
550+
anisotropy_feature, w=w, region=None, step=1, B=0
551+
)
562552

563553
def update(self):
564554
for i in range(3):

LoopStructural/modelling/features/builders/_geological_feature_builder.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ def install_gradient_constraint(self):
304304
vector[element_idx[::step], :],
305305
w=w,
306306
B=B,
307+
name=f'{feature.name}_orthogonal',
307308
)
308309

309310
def add_equality_constraints(self, feature, region, scalefactor=1.0):
@@ -506,9 +507,9 @@ def build(self, fold=None, fold_weights={}, data_region=None, **kwargs):
506507
self.interpolator.support.maximum = newmax
507508
self.interpolator.set_region(region=region)
508509

510+
self.interpolator.setup_interpolator(**kwargs)
509511
self.install_gradient_constraint()
510512
self.install_equality_constraints()
511-
self.interpolator.setup_interpolator(**kwargs)
512513
self.interpolator.solve_system(**kwargs)
513514
self._up_to_date = True
514515
return self._feature

LoopStructural/modelling/features/fault/_fault_function_feature.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from ....modelling.features import BaseFeature, StructuralFrame
2-
2+
from typing import Optional
33
from ....utils import getLogger
44

55
logger = getLogger(__name__)
@@ -77,3 +77,6 @@ def evaluate_on_surface(self, location):
7777
fault_strike = self.fault_frame.features[2].evaluate_value(location)
7878
d = self.displacement.evaluate(fault_displacement, fault_strike)
7979
return d
80+
81+
def get_data(self, value_map: Optional[dict] = None):
82+
pass

LoopStructural/modelling/features/fault/_fault_segment.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ def apply_to_vectors(self, vector: np.ndarray, scale_parameter: float = 1.0) ->
423423

424424
element_gradients = element_gradients.swapaxes(1, 2)
425425
element_gradients = element_gradients @ I
426-
v = np.sum(element_gradients * corners, axis=2)
426+
v = np.sum(element_gradients * corners[:, None, :], axis=2)
427427
return v
428428

429429
def add_abutting_fault(self, abutting_fault_feature, positive=None):

0 commit comments

Comments
 (0)