Skip to content

Commit 48e6261

Browse files
committed
fix: return axis and angle for movement of fault points
1 parent 322c0fb commit 48e6261

File tree

2 files changed

+39
-27
lines changed

2 files changed

+39
-27
lines changed

LoopStructural/modelling/features/_geological_feature.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
"""
22
Geological features
33
"""
4+
45
from ...modelling.features import BaseFeature
56
from ...utils import getLogger
67
from ...modelling.features import FeatureType
78
from ...interpolators import GeologicalInterpolator
89
import numpy as np
910

10-
from ...utils import getLogger, LoopValueError
11+
from ...utils import getLogger, LoopValueError, rotate
1112

1213
logger = getLogger(__name__)
1314

@@ -114,14 +115,14 @@ def evaluate_value(self, evaluation_points: np.ndarray) -> np.ndarray:
114115
v = np.zeros(evaluation_points.shape[0])
115116
v[:] = np.nan
116117
mask = self._calculate_mask(evaluation_points)
117-
evaluation_points = self._apply_faults(evaluation_points)
118+
evaluation_points, axis, angle = self._apply_faults(evaluation_points)
118119
if mask.dtype not in [int, bool]:
119120
logger.error(f"Unable to evaluate value for {self.name}")
120121
else:
121122
v[mask] = self.interpolator.evaluate_value(evaluation_points[mask, :])
122123
return v
123124

124-
def evaluate_gradient(self, evaluation_points: np.ndarray) -> np.ndarray:
125+
def evaluate_gradient(self, pos: np.ndarray) -> np.ndarray:
125126
"""
126127
127128
Parameters
@@ -134,18 +135,24 @@ def evaluate_gradient(self, evaluation_points: np.ndarray) -> np.ndarray:
134135
135136
136137
"""
137-
if evaluation_points.shape[1] != 3:
138+
if pos.shape[1] != 3:
138139
raise LoopValueError("Need Nx3 array of xyz points to evaluate gradient")
139140
self.builder.up_to_date()
140-
v = np.zeros(evaluation_points.shape)
141+
v = np.zeros(pos.shape)
141142
v[:] = np.nan
142-
mask = self._calculate_mask(evaluation_points)
143-
evaluation_points = self._apply_faults(evaluation_points)
143+
mask = self._calculate_mask(pos)
144+
original_pos = pos.copy()
145+
pos, axis, angle = self._apply_faults(pos)
144146
if mask.dtype not in [int, bool]:
145147
logger.error(f"Unable to evaluate gradient for {self.name}")
146148
else:
147-
v[mask, :] = self.interpolator.evaluate_gradient(evaluation_points[mask, :])
148-
149+
v[mask, :] = self.interpolator.evaluate_gradient(pos[mask, :])
150+
v_norm = np.linalg.norm(v[mask, :], axis=1)
151+
v[mask, :] /= v_norm[:, None]
152+
if axis is not None:
153+
for i in reversed(range(axis.shape[1])):
154+
v[mask, :] = rotate(v[mask, :], axis[:, i, :], angle[:, i])
155+
v[mask, :] *= v_norm[:, None]
149156
return v
150157

151158
def evaluate_gradient_misfit(self):

LoopStructural/modelling/features/fault/_fault_segment.py

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ class FaultSegment(StructuralFrame):
1919
Class for representing a slip event of a fault
2020
"""
2121

22-
def __init__(
23-
self, features, name, faultfunction=None, steps=3, displacement=1.0, fold=None
24-
):
22+
def __init__(self, features, name, faultfunction=None, steps=10, displacement=1.0, fold=None):
2523
"""
2624
A slip event of a fault
2725
@@ -263,7 +261,7 @@ def evaluate_displacement(self, points):
263261
d[mask] = self.faultfunction(gx[mask], gy[mask], gz[mask])
264262
return d * self.displacement
265263

266-
def apply_to_points(self, points):
264+
def apply_to_points(self, points, reverse=False):
267265
"""
268266
Unfault the array of points
269267
@@ -308,6 +306,13 @@ def apply_to_points(self, points):
308306
mask = np.abs(d) > 0.0
309307

310308
d *= self.displacement
309+
if reverse:
310+
d *= -1.0
311+
# calculate the anglee and vector to rotate the points
312+
axis = np.zeros((points.shape[0], steps, 3))
313+
axis[:] = np.nan
314+
angle = np.zeros((points.shape[0], steps))
315+
angle[:] = np.nan
311316
# calculate the fault frame for the evaluation points
312317
for i in range(steps):
313318
gx = None
@@ -318,18 +323,10 @@ def apply_to_points(self, points):
318323
with ThreadPoolExecutor(max_workers=8) as executor:
319324
# all of these operations should be
320325
# independent so just run as different threads
321-
gx_future = executor.submit(
322-
self.__getitem__(0).evaluate_value, newp[mask, :]
323-
)
324-
g_future = executor.submit(
325-
self.__getitem__(1).evaluate_gradient, newp[mask, :]
326-
)
327-
gy_future = executor.submit(
328-
self.__getitem__(1).evaluate_value, newp[mask, :]
329-
)
330-
gz_future = executor.submit(
331-
self.__getitem__(2).evaluate_value, newp[mask, :]
332-
)
326+
gx_future = executor.submit(self.__getitem__(0).evaluate_value, newp[mask, :])
327+
g_future = executor.submit(self.__getitem__(1).evaluate_gradient, newp[mask, :])
328+
gy_future = executor.submit(self.__getitem__(1).evaluate_value, newp[mask, :])
329+
gz_future = executor.submit(self.__getitem__(2).evaluate_value, newp[mask, :])
333330
gx = gx_future.result()
334331
g = g_future.result()
335332
gy = gy_future.result()
@@ -363,10 +360,18 @@ def apply_to_points(self, points):
363360
# multiply displacement vector by the displacement magnitude for
364361
# step
365362
g *= (1.0 / steps) * d[:, None]
366-
363+
prev_p = newp[mask, :].copy()
367364
# apply displacement
368365
newp[mask, :] += g
369-
return newp
366+
# axis[mask, i, :] = np.cross(prev_p, newp[mask, :], axisa=1, axisb=1)
367+
# angle[mask, i] = 2 * np.arctan(
368+
# 0.5 * (np.linalg.norm(prev_p - newp[mask, :], axis=1))
369+
# )
370+
# calculate the angle between the previous and new points
371+
# and the axis of rotation
372+
# g /= np.linalg.norm(g, axis=1)[:, None]
373+
axis[mask, i, :] /= np.linalg.norm(axis[mask, i, :], axis=1)[:, None]
374+
return newp, axis, angle
370375

371376
def add_abutting_fault(self, abutting_fault_feature, positive=None):
372377

0 commit comments

Comments
 (0)