Skip to content

Commit 2e304a5

Browse files
authored
New displacement example (#179)
* fix: check fault trace length before fitting polyline * fix: set feature faults to builder faults before building * refactor: 🎨 adding abc and type hints to fault functions Added plot, to_dict, from_dict methods to the fault functions. * fix: expose rng in loopstructur * docs: adding new example for fault displacement profile * fix: reverting back to cropping fault function outside bounds
1 parent 145c274 commit 2e304a5

File tree

3 files changed

+144
-1
lines changed

3 files changed

+144
-1
lines changed

LoopStructural/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from .modelling.core.geological_model import GeologicalModel
2222
from .interpolators._api import LoopInterpolator
2323
from .datatypes import BoundingBox
24-
from .utils import log_to_console, log_to_file, getLogger
24+
from .utils import log_to_console, log_to_file, getLogger, rng
2525

2626
logger = getLogger(__name__)
2727
logger.info("Imported LoopStructural")

LoopStructural/modelling/features/fault/_fault_function.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,27 @@ def solve(self):
124124
def __call__(self, v):
125125
self.solve()
126126
eva = self.w[0] * v**3 + self.w[1] * v**2 + self.w[2] * v + self.w[3]
127+
eva[v > self.lim[1]] = (
128+
self.w[0] * self.lim[1] ** 3
129+
+ self.w[1] * self.lim[1] ** 2
130+
+ self.w[2] * self.lim[1]
131+
+ self.w[3]
132+
)
133+
eva[v < self.lim[0]] = (
134+
self.w[0] * self.lim[0] ** 3
135+
+ self.w[1] * self.lim[0] ** 2
136+
+ self.w[2] * self.lim[0]
137+
+ self.w[3]
138+
)
127139
eva[eva > self.max_v] = self.max_v
128140
eva[eva < self.min_v] = self.min_v
141+
129142
return eva
130143

131144
def to_dict(self) -> dict:
132145
"""Export the function to a dictionary
133146
147+
134148
Returns
135149
-------
136150
dict
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
"""
2+
3c. Defining the fault displacement function
3+
============================================
4+
5+
"""
6+
7+
import numpy as np
8+
import pandas as pd
9+
import LoopStructural as LS
10+
11+
# Define a dataset for a fault
12+
13+
origin = [0, 0, 0]
14+
extent = [10, 10, 10]
15+
16+
data = pd.DataFrame(
17+
[
18+
[5, 5, 5, 0, 0.70710678, 0.0, 0.70710678, 0, "fault"],
19+
[5, 5, 5, 0, -0.70710678, 0.0, 0.70710678, 1, "fault"],
20+
[8, 5, 5, 0, 0, 0, 1, np.nan, "strati"],
21+
],
22+
columns=["X", "Y", "Z", "val", "nx", "ny", "nz", "coord", "feature_name"],
23+
)
24+
25+
data
26+
27+
######################################################################
28+
# Create model using the standard fault displacement model
29+
30+
model = LS.GeologicalModel(origin, extent)
31+
model.data = data
32+
model.create_and_add_fault(
33+
"fault",
34+
1,
35+
nelements=1000,
36+
interpolator_type="PLI",
37+
buffer=0.5,
38+
major_axis=10,
39+
minor_axis=3,
40+
intermediate_axis=10,
41+
)
42+
model.create_and_add_foliation(
43+
"strati", nelements=1000, interpolator_type="PLI", faults=[model["fault"]]
44+
)
45+
46+
47+
import LoopStructural.visualisation as vis
48+
49+
view = vis.LavaVuModelViewer(model)
50+
view.add_isosurface(model.features[0], slices=[0])
51+
view.add_isosurface(model.features[1], nslices=5, paint_with=model.features[1])
52+
# view.add_vector_field(model["fault"][1], locations=model.regular_grid()[::100])
53+
view.camera = {
54+
'translate': [0.0, 0.0, -17.321],
55+
'rotate': [-0.703, -0.055, -0.043, 0.708],
56+
'xyzrotate': [-89.604, -8.007, 0.933],
57+
'fov': 45.0,
58+
}
59+
view.display()
60+
61+
######################################################################
62+
# Define a fault displacement profile which
63+
# is a drag fault only on the footwall side.
64+
# In LoopStructural the displacement is defined by a function of the three
65+
# coordinates of the fault frame.
66+
# The fault profile in the fault surface field
67+
68+
model['fault'].faultfunction.gx.plot()
69+
70+
######################################################################
71+
# The fault profile in the fault extent
72+
model['fault'].faultfunction.gy.plot()
73+
74+
75+
######################################################################
76+
# The fault profile down dip is kept constant.
77+
# We will modify this profile so that the hanging wall is displaced by a constant value
78+
79+
from LoopStructural.modelling.features.fault._fault_function import (
80+
FaultDisplacement,
81+
CubicFunction,
82+
Ones,
83+
)
84+
85+
fw = CubicFunction()
86+
fw.add_cstr(0, -1)
87+
fw.add_grad(0, 0)
88+
fw.add_cstr(-1, 0)
89+
fw.add_grad(-1, 0)
90+
fw.add_min(-1)
91+
hw = Ones()
92+
drag_fault = FaultDisplacement(hw=hw, fw=fw)
93+
94+
drag_fault.gx.plot()
95+
drag_fault.gy.plot()
96+
drag_fault.gz.plot()
97+
98+
model = LS.GeologicalModel(origin, extent)
99+
model.data = data
100+
model.create_and_add_fault(
101+
"fault",
102+
-1,
103+
nelements=1000,
104+
interpolator_type="PLI",
105+
buffer=0.5,
106+
major_axis=10,
107+
minor_axis=6,
108+
intermediate_axis=10,
109+
faultfunction=drag_fault,
110+
)
111+
model.create_and_add_foliation(
112+
"strati", nelements=1000, interpolator_type="PLI", faults=[model["fault"]]
113+
)
114+
115+
116+
view = vis.LavaVuModelViewer(model)
117+
view.nelements = 1e5
118+
view.add_isosurface(model.features[0], slices=[0])
119+
view.add_isosurface(model['strati'], nslices=5)
120+
# view.add_scalar_field(model['strati'], cmap='tab20')
121+
# view.add_vector_field(model["fault"][1], locations=model.regular_grid()[::100])
122+
view.camera = {
123+
'translate': [0.0, 0.0, -17.321],
124+
'rotate': [-0.703, -0.055, -0.043, 0.708],
125+
'xyzrotate': [-89.604, -8.007, 0.933],
126+
'fov': 45.0,
127+
}
128+
129+
view.display()

0 commit comments

Comments
 (0)