LoopStructural 1.0.9__cp39-cp39-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- LoopStructural/__init__.py +36 -0
- LoopStructural/analysis/__init__.py +2 -0
- LoopStructural/analysis/_fault_displacement.py +67 -0
- LoopStructural/analysis/_fault_intersection.py +36 -0
- LoopStructural/analysis/_plane_fit.py +43 -0
- LoopStructural/datasets/__init__.py +12 -0
- LoopStructural/datasets/_base.py +65 -0
- LoopStructural/datasets/data/claudius.csv +21049 -0
- LoopStructural/datasets/data/claudiusbb.txt +2 -0
- LoopStructural/datasets/data/duplex.csv +126 -0
- LoopStructural/datasets/data/duplexbb.txt +2 -0
- LoopStructural/datasets/data/intrusion.csv +1017 -0
- LoopStructural/datasets/data/intrusionbb.txt +2 -0
- LoopStructural/datasets/data/onefoldbb.txt +2 -0
- LoopStructural/datasets/data/onefolddata.csv +2226 -0
- LoopStructural/datasets/data/refolded_bb.txt +2 -0
- LoopStructural/datasets/data/refolded_fold.csv +2126 -0
- LoopStructural/interpolators/__init__.py +34 -0
- LoopStructural/interpolators/base_structured_3d_support.py +101 -0
- LoopStructural/interpolators/cython/__init__.py +0 -0
- LoopStructural/interpolators/cython/dsi_helper.c +31046 -0
- LoopStructural/interpolators/cython/dsi_helper.cp39-win32.pyd +0 -0
- LoopStructural/interpolators/discrete_fold_interpolator.py +202 -0
- LoopStructural/interpolators/discrete_interpolator.py +584 -0
- LoopStructural/interpolators/finite_difference_interpolator.py +399 -0
- LoopStructural/interpolators/geological_interpolator.py +197 -0
- LoopStructural/interpolators/operator.py +61 -0
- LoopStructural/interpolators/piecewiselinear_interpolator.py +437 -0
- LoopStructural/interpolators/structured_grid.py +421 -0
- LoopStructural/interpolators/structured_tetra.py +681 -0
- LoopStructural/interpolators/surfe_wrapper.py +118 -0
- LoopStructural/modelling/__init__.py +46 -0
- LoopStructural/modelling/core/__init__.py +0 -0
- LoopStructural/modelling/core/geological_model.py +1513 -0
- LoopStructural/modelling/core/geological_model_graph.py +880 -0
- LoopStructural/modelling/core/stratigraphic_column.py +5 -0
- LoopStructural/modelling/fault/__init__.py +4 -0
- LoopStructural/modelling/fault/fault_builder.py +143 -0
- LoopStructural/modelling/fault/fault_function.py +188 -0
- LoopStructural/modelling/fault/fault_function_feature.py +76 -0
- LoopStructural/modelling/fault/fault_segment.py +298 -0
- LoopStructural/modelling/features/__init__.py +8 -0
- LoopStructural/modelling/features/cross_product_geological_feature.py +90 -0
- LoopStructural/modelling/features/geological_feature.py +252 -0
- LoopStructural/modelling/features/geological_feature_builder.py +414 -0
- LoopStructural/modelling/features/lambda_geological_feature.py +36 -0
- LoopStructural/modelling/features/region_feature.py +34 -0
- LoopStructural/modelling/features/structural_frame.py +133 -0
- LoopStructural/modelling/features/structural_frame_builder.py +206 -0
- LoopStructural/modelling/features/unconformity_feature.py +74 -0
- LoopStructural/modelling/fold/__init__.py +8 -0
- LoopStructural/modelling/fold/fold.py +143 -0
- LoopStructural/modelling/fold/fold_rotation_angle.py +133 -0
- LoopStructural/modelling/fold/fold_rotation_angle_feature.py +58 -0
- LoopStructural/modelling/fold/foldframe.py +193 -0
- LoopStructural/modelling/fold/svariogram.py +180 -0
- LoopStructural/utils/__init__.py +18 -0
- LoopStructural/utils/bounding_box.py +21 -0
- LoopStructural/utils/exceptions.py +10 -0
- LoopStructural/utils/helper.py +382 -0
- LoopStructural/utils/logging.py +60 -0
- LoopStructural/utils/map2loop.py +353 -0
- LoopStructural/utils/regions.py +11 -0
- LoopStructural/utils/utils.py +69 -0
- LoopStructural/visualisation/__init__.py +31 -0
- LoopStructural/visualisation/map_viewer.py +322 -0
- LoopStructural/visualisation/model_plotter.py +17 -0
- LoopStructural/visualisation/model_visualisation.py +1113 -0
- LoopStructural/visualisation/rotation_angle_plotter.py +83 -0
- LoopStructural/visualisation/sphinx_scraper.py +34 -0
- LoopStructural/visualisation/stratigraphic_column.py +60 -0
- LoopStructural-1.0.9.dist-info/LICENSE +21 -0
- LoopStructural-1.0.9.dist-info/METADATA +19 -0
- LoopStructural-1.0.9.dist-info/RECORD +77 -0
- LoopStructural-1.0.9.dist-info/WHEEL +5 -0
- LoopStructural-1.0.9.dist-info/top_level.txt +2 -0
- tests/__init__.py +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
from ..features.structural_frame_builder import StructuralFrameBuilder
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
class FaultBuilder(StructuralFrameBuilder):
|
|
5
|
+
def __init__(self,interpolator=None,interpolators=None,model=None,fault_bounding_box_buffer=0.2,**kwargs):
|
|
6
|
+
"""A specialised structural frame builder for building a fault
|
|
7
|
+
|
|
8
|
+
Parameters
|
|
9
|
+
----------
|
|
10
|
+
interpolator : GeologicalInterpolator, optional
|
|
11
|
+
the interpolator to use for building the fault frame, by default None
|
|
12
|
+
interpolators : [GeologicalInterpolator, GeologicalInterpolator, GeologicalInterpolator], optional
|
|
13
|
+
a list of interpolators to use for building the fault frame, by default None
|
|
14
|
+
model : GeologicalModel
|
|
15
|
+
reference to the model containing the fault
|
|
16
|
+
fault_bounding_box_buffer: float, default 0.2
|
|
17
|
+
the maximum area around the model domain that a fault is modelled. For high displacement faults this
|
|
18
|
+
may need to be large, smaller values will be result in fewer degrees of freedom = quicker interpolation
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
StructuralFrameBuilder.__init__(self,interpolator,interpolators,**kwargs)
|
|
22
|
+
self.origin = np.array([np.nan,np.nan,np.nan])
|
|
23
|
+
self.maximum = np.array([np.nan,np.nan,np.nan])
|
|
24
|
+
self.model = model
|
|
25
|
+
# define a maximum area to mesh adding buffer to model
|
|
26
|
+
buffer = .2
|
|
27
|
+
self.minimum_origin = self.model.bounding_box[0,:] - buffer*(self.model.bounding_box[1,:]-self.model.bounding_box[0,:])
|
|
28
|
+
self.maximum_maximum = self.model.bounding_box[1,:] + buffer*(self.model.bounding_box[1,:]-self.model.bounding_box[0,:])
|
|
29
|
+
|
|
30
|
+
def update_geometry(self,points):
|
|
31
|
+
|
|
32
|
+
self.origin = np.nanmin(np.array([np.min(points,axis=0),self.origin]),axis=0)
|
|
33
|
+
self.maximum = np.nanmax(np.array([np.max(points,axis=0),self.maximum]),axis=0)
|
|
34
|
+
self.origin[self.origin<self.minimum_origin] = self.minimum_origin[self.origin<self.minimum_origin]
|
|
35
|
+
self.maximum[self.maximum>self.maximum_maximum] = self.maximum_maximum[self.maximum>self.maximum_maximum]
|
|
36
|
+
|
|
37
|
+
def create_data_from_geometry(self,
|
|
38
|
+
data,
|
|
39
|
+
fault_center,
|
|
40
|
+
normal_vector,
|
|
41
|
+
slip_vector,
|
|
42
|
+
influence_distance = None,
|
|
43
|
+
horizontal_radius = None,
|
|
44
|
+
vertical_radius = None):
|
|
45
|
+
"""Generate the required data for building a fault frame for a fault with the
|
|
46
|
+
specified parameters
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
data : DataFrame,
|
|
51
|
+
model data
|
|
52
|
+
fault_center : np.array(3)
|
|
53
|
+
x,y,z coordinates of the fault center
|
|
54
|
+
normal_vector : np.array(3)
|
|
55
|
+
x,y,z components of normal vector to fault, single observation usually
|
|
56
|
+
average direction
|
|
57
|
+
slip_vector : np.array(3)
|
|
58
|
+
x,y,z components of slip vector for the fault, single observation usually
|
|
59
|
+
average direction
|
|
60
|
+
influence_distance : double
|
|
61
|
+
distance away from fault for the fault volume
|
|
62
|
+
horizontal_radius : double
|
|
63
|
+
fault extent
|
|
64
|
+
vertical_radius : double
|
|
65
|
+
fault volume radius in the slip direction
|
|
66
|
+
"""
|
|
67
|
+
normal_vector/=np.linalg.norm(normal_vector)
|
|
68
|
+
slip_vector/=np.linalg.norm(slip_vector)
|
|
69
|
+
strike_vector = np.cross(normal_vector,slip_vector)
|
|
70
|
+
fault_edges = np.zeros((2,3))
|
|
71
|
+
fault_tips = np.zeros((2,3))
|
|
72
|
+
fault_depth = np.zeros((2,3))
|
|
73
|
+
if fault_center is not None:
|
|
74
|
+
if influence_distance is not None:
|
|
75
|
+
fault_edges[0,:] = fault_center[:3]+normal_vector*influence_distance
|
|
76
|
+
fault_edges[1,:] = fault_center[:3]-normal_vector*influence_distance
|
|
77
|
+
self.update_geometry(fault_edges)
|
|
78
|
+
data.loc[len(data),['X','Y','Z','feature_name','val','coord']] = \
|
|
79
|
+
[fault_edges[0,0],fault_edges[0,1],fault_edges[0,2],self.name,1,0]
|
|
80
|
+
data.loc[len(data),['X','Y','Z','feature_name','val','coord']] = \
|
|
81
|
+
[fault_edges[1,0],fault_edges[1,1],fault_edges[1,2],self.name,-1,0]
|
|
82
|
+
if horizontal_radius is not None:
|
|
83
|
+
fault_tips[0,:] = fault_center[:3]+strike_vector*horizontal_radius
|
|
84
|
+
fault_tips[1,:] = fault_center[:3]-strike_vector*horizontal_radius
|
|
85
|
+
self.update_geometry(fault_tips)
|
|
86
|
+
data.loc[len(data),['X','Y','Z','feature_name','val','coord']] = \
|
|
87
|
+
[fault_center[0],fault_center[1],fault_center[2],self.name,0,2]
|
|
88
|
+
# data.loc[len(data),['X','Y','Z','feature_name','val','coord']] = \
|
|
89
|
+
# [fault_tips[1,0],fault_tips[1,1],fault_tips[1,2],self.name,-1,2]
|
|
90
|
+
strike_vector /= horizontal_radius
|
|
91
|
+
if vertical_radius is not None:
|
|
92
|
+
fault_depth[0,:] = fault_center[:3]+slip_vector*vertical_radius
|
|
93
|
+
fault_depth[1,:] = fault_center[:3]-slip_vector*vertical_radius
|
|
94
|
+
data.loc[len(data),['X','Y','Z','feature_name','val','coord']] = \
|
|
95
|
+
[fault_center[0],fault_center[1],fault_center[2],self.name,0,1]
|
|
96
|
+
# data.loc[len(data),['X','Y','Z','feature_name','val','coord']] = \
|
|
97
|
+
# [fault_depth[1,0],fault_depth[1,1],fault_depth[1,2],self.name,-1,1]
|
|
98
|
+
self.update_geometry(fault_depth)
|
|
99
|
+
#TODO need to add data here
|
|
100
|
+
slip_vector /= vertical_radius
|
|
101
|
+
|
|
102
|
+
data.loc[len(data),['X','Y','Z','feature_name','nx','ny','nz','val','coord']] =\
|
|
103
|
+
[fault_center[0],fault_center[1],fault_center[2],self.name,slip_vector[0],slip_vector[1],slip_vector[2],0,1]
|
|
104
|
+
# add strike vector to constraint fault extent
|
|
105
|
+
data.loc[len(data),['X','Y','Z','feature_name','nx','ny','nz','coord']] = [fault_center[0],fault_center[1],fault_center[2],\
|
|
106
|
+
self.name, strike_vector[0], strike_vector[1], strike_vector[2], 2]
|
|
107
|
+
self.add_data_from_data_frame(data)
|
|
108
|
+
def set_mesh_geometry(self,buffer):
|
|
109
|
+
"""set the mesh geometry
|
|
110
|
+
|
|
111
|
+
Parameters
|
|
112
|
+
----------
|
|
113
|
+
buffer : double
|
|
114
|
+
percentage of length to add to edges
|
|
115
|
+
"""
|
|
116
|
+
length = self.maximum-self.origin
|
|
117
|
+
# origin = self.builders[0].interpolator.support.origin
|
|
118
|
+
# maximum = self.builders[0].interpolator.support.maximum#set_interpolation_geometry
|
|
119
|
+
# if origin[2]>self.origin[2]:
|
|
120
|
+
# origin[2]=self.origin[2]
|
|
121
|
+
# if maximum[2]<self.maximum[2]:
|
|
122
|
+
# maximum[2]=self.maximum[2]
|
|
123
|
+
# self.builders[0].set_interpolation_geometry(origin,maximum)
|
|
124
|
+
# for builder in self.builders:
|
|
125
|
+
# all three coordinates share the same support
|
|
126
|
+
self.builders[0].set_interpolation_geometry(self.origin-length*buffer,self.maximum+length*buffer)
|
|
127
|
+
|
|
128
|
+
def add_splay(self,splayregion,splay):
|
|
129
|
+
# for i in range(3):
|
|
130
|
+
# # work out the values of the nodes where we want hard
|
|
131
|
+
# # constraints
|
|
132
|
+
# idc = np.arange(0, interpolator.support.n_nodes)[
|
|
133
|
+
# kwargs['splayregion'](interpolator.support.nodes)]
|
|
134
|
+
# val = kwargs['splay'][i].evaluate_value(
|
|
135
|
+
# interpolator.support.nodes[
|
|
136
|
+
# kwargs['splayregion'](interpolator.support.nodes), :])
|
|
137
|
+
# mask = ~np.isnan(val)
|
|
138
|
+
# fault_frame_builder[i].interpolator.add_equality_constraints(
|
|
139
|
+
# idc[mask], val[mask])
|
|
140
|
+
pass
|
|
141
|
+
def update(self):
|
|
142
|
+
for i in range(3):
|
|
143
|
+
self.builders[i].update()
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from LoopStructural.utils import getLogger
|
|
6
|
+
logger = getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CubicFunction:
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
def __init__(self):
|
|
14
|
+
"""
|
|
15
|
+
Class to represent a cubic function
|
|
16
|
+
"""
|
|
17
|
+
self.A = [] # np.zeros((4,4))
|
|
18
|
+
self.B = [] # np.zeros((4))
|
|
19
|
+
self.max_v = 999999
|
|
20
|
+
self.min_v = -99999
|
|
21
|
+
self.w = None
|
|
22
|
+
|
|
23
|
+
def add_cstr(self, x, y):
|
|
24
|
+
self.A.append([x ** 3, x ** 2, x, 1.])
|
|
25
|
+
self.B.append(y)
|
|
26
|
+
|
|
27
|
+
def add_grad(self, x, g):
|
|
28
|
+
self.A.append([3 * x ** 2, 2 * x, 1., 0.])
|
|
29
|
+
self.B.append(g)
|
|
30
|
+
|
|
31
|
+
def add_max(self, max_v):
|
|
32
|
+
self.max_v = max_v
|
|
33
|
+
|
|
34
|
+
def add_min(self, min_v):
|
|
35
|
+
self.min_v = min_v
|
|
36
|
+
|
|
37
|
+
def __call__(self, v):
|
|
38
|
+
if len(self.B) < 3:
|
|
39
|
+
print("underdetermined")
|
|
40
|
+
return
|
|
41
|
+
if self.w is None:
|
|
42
|
+
A = np.array(self.A)
|
|
43
|
+
B = np.array(self.B)
|
|
44
|
+
ATA = A.T @ A
|
|
45
|
+
ATB = A.T @ B
|
|
46
|
+
self.w = np.linalg.lstsq(ATA, ATB, rcond=None)[0]
|
|
47
|
+
eva = self.w[0] * v ** 3 + self.w[1] * v ** 2 + self.w[2] * v + self.w[
|
|
48
|
+
3]
|
|
49
|
+
eva[v > self.max_v] = self.w[0] * self.max_v ** 3 + \
|
|
50
|
+
self.w[1] * self.max_v ** 2 + self.w[
|
|
51
|
+
2] * self.max_v + self.w[3]
|
|
52
|
+
eva[v < self.min_v] = self.w[0] * self.min_v ** 3 + \
|
|
53
|
+
self.w[1] * self.min_v ** 2 + self.w[
|
|
54
|
+
2] * self.min_v + self.w[3]
|
|
55
|
+
return eva
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class Composite():
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
"""
|
|
62
|
+
def __init__(self, positive, negative):
|
|
63
|
+
self.positive = positive
|
|
64
|
+
self.negative = negative
|
|
65
|
+
|
|
66
|
+
def __call__(self, v):
|
|
67
|
+
v = np.array(v)
|
|
68
|
+
r = np.zeros(v.shape)
|
|
69
|
+
r[v > 0] = self.positive(v[v > 0])
|
|
70
|
+
r[v < 0] = self.negative(v[v < 0])
|
|
71
|
+
return r
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class Ones:
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
"""
|
|
78
|
+
def __init__(self):
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
def __call__(self, v):
|
|
82
|
+
v = np.array(v)
|
|
83
|
+
return np.ones(v.shape)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class Zeros:
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
"""
|
|
90
|
+
def __init__(self):
|
|
91
|
+
pass
|
|
92
|
+
|
|
93
|
+
def __call__(self, v):
|
|
94
|
+
v = np.array(v)
|
|
95
|
+
return np.zeros(v.shape)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class FaultDisplacement:
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
"""
|
|
102
|
+
def __init__(self, hw=None, fw=None, gx=None, gy=None, gz=None, **kwargs):
|
|
103
|
+
self.gx = gx
|
|
104
|
+
if hw is not None and fw is not None:
|
|
105
|
+
self.__gx = Composite(hw, fw)
|
|
106
|
+
self.gy = gy
|
|
107
|
+
self.gz = gz
|
|
108
|
+
self.gx_bounds = None
|
|
109
|
+
self.gy_bounds = None
|
|
110
|
+
self.gz_bounds = None
|
|
111
|
+
|
|
112
|
+
if self.gx == None:
|
|
113
|
+
print('Gx function none setting to ones')
|
|
114
|
+
self.gx = Ones()
|
|
115
|
+
if self.gy == None:
|
|
116
|
+
print('Gy function none setting to ones')
|
|
117
|
+
self.gy = Ones()
|
|
118
|
+
if self.gz == None:
|
|
119
|
+
print('Gz function none setting to ones')
|
|
120
|
+
self.gz = Ones()
|
|
121
|
+
if 'gxmax' in kwargs and 'gxmin' in kwargs:
|
|
122
|
+
self.gx_bounds = (kwargs['gxmin'], kwargs['gxmax'])
|
|
123
|
+
|
|
124
|
+
if 'gymax' in kwargs and 'gymin' in kwargs:
|
|
125
|
+
self.gy_bounds = (kwargs['gymin'], kwargs['gymax'])
|
|
126
|
+
|
|
127
|
+
if 'gzmax' in kwargs and 'gzmin' in kwargs:
|
|
128
|
+
self.gz_bounds = (kwargs['gzmin'], kwargs['gzmax'])
|
|
129
|
+
|
|
130
|
+
def __call__(self, gx, gy, gz):
|
|
131
|
+
if self.gx_bounds is not None:
|
|
132
|
+
mid =(self.gx_bounds[1]+self.gx_bounds[0])/2.
|
|
133
|
+
gx = (gx -mid) / (self.gx_bounds[1]-self.gx_bounds[0])
|
|
134
|
+
if self.gy_bounds is not None:
|
|
135
|
+
mid = (self.gy_bounds[1]+self.gy_bounds[0])/2.
|
|
136
|
+
gy = (gy -mid) / (self.gy_bounds[1]-self.gy_bounds[0])
|
|
137
|
+
if self.gz_bounds is not None:
|
|
138
|
+
mid =(self.gz_bounds[1]+self.gz_bounds[0])/2.
|
|
139
|
+
gz = (gz -mid) / (self.gz_bounds[1]-self.gz_bounds[0])
|
|
140
|
+
return self.gx(gx)*self.gy(gy)*self.gz(gz)
|
|
141
|
+
|
|
142
|
+
def evaluate(self, gy, gz):
|
|
143
|
+
if self.gy_bounds is not None:
|
|
144
|
+
mid = (self.gy_bounds[1]+self.gy_bounds[0])/2.
|
|
145
|
+
gy = (gy -mid) / (self.gy_bounds[1]-self.gy_bounds[0])
|
|
146
|
+
if self.gz_bounds is not None:
|
|
147
|
+
mid =(self.gz_bounds[1]+self.gz_bounds[0])/2.
|
|
148
|
+
gz = (gz -mid) / (self.gz_bounds[1]-self.gz_bounds[0])
|
|
149
|
+
return self.gy(gy)*self.gz(gz)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class BaseFault(object):
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
"""
|
|
156
|
+
hw = CubicFunction()
|
|
157
|
+
hw.add_cstr(0, 1)
|
|
158
|
+
hw.add_grad(0, 0)
|
|
159
|
+
hw.add_cstr(1, 0)
|
|
160
|
+
# hw.add_cstr(1,1)
|
|
161
|
+
|
|
162
|
+
hw.add_grad(1, 0)
|
|
163
|
+
hw.add_max(1)
|
|
164
|
+
fw = CubicFunction()
|
|
165
|
+
fw.add_cstr(0, -1)
|
|
166
|
+
fw.add_grad(0, 0)
|
|
167
|
+
fw.add_cstr(-1, 0)
|
|
168
|
+
fw.add_grad(-1, 0)
|
|
169
|
+
fw.add_min(-1)
|
|
170
|
+
# gyf = CubicFunction()
|
|
171
|
+
# gyf.add_cstr(-1, 0)
|
|
172
|
+
# gyf.add_cstr(1, 0)
|
|
173
|
+
# gyf.add_cstr(-0.2, 1)
|
|
174
|
+
# gyf.add_cstr(0.2, 1)
|
|
175
|
+
# gyf.add_grad(0, 0)
|
|
176
|
+
# gyf.add_min(-1)
|
|
177
|
+
# gyf.add_max(1)
|
|
178
|
+
gyf = Ones()
|
|
179
|
+
gzf = CubicFunction()
|
|
180
|
+
gzf.add_cstr(-1, 0)
|
|
181
|
+
gzf.add_cstr(1, 0)
|
|
182
|
+
gzf.add_cstr(-0.2, 1)
|
|
183
|
+
gzf.add_cstr(0.2, 1)
|
|
184
|
+
gzf.add_grad(0, 0)
|
|
185
|
+
gzf.add_min(-1)
|
|
186
|
+
gzf.add_max(1)
|
|
187
|
+
gxf = Composite(hw, fw)
|
|
188
|
+
fault_displacement = FaultDisplacement(gx=gxf, gy=gyf, gz=gzf)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from LoopStructural.utils import getLogger
|
|
4
|
+
logger = getLogger(__name__)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FaultDisplacementFeature:
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
def __init__(self, fault_frame, displacement, name = 'fault_displacement'):
|
|
12
|
+
"""
|
|
13
|
+
Geological feature representing the fault displacement
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
fault_frame - geometry of the fault
|
|
18
|
+
displacement - function defining fault displacement
|
|
19
|
+
"""
|
|
20
|
+
self.fault_frame = fault_frame
|
|
21
|
+
self.displacement = displacement
|
|
22
|
+
self.name = name +'_displacement'
|
|
23
|
+
|
|
24
|
+
def evaluate_value(self, location):
|
|
25
|
+
"""
|
|
26
|
+
Return the value of the fault displacement
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
location
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
|
|
35
|
+
"""
|
|
36
|
+
fault_suface = self.fault_frame.features[0].evaluate_value(location)
|
|
37
|
+
fault_displacement = self.fault_frame.features[1].evaluate_value(
|
|
38
|
+
location)
|
|
39
|
+
fault_strike = self.fault_frame.features[2].evaluate_value(location)
|
|
40
|
+
d = self.displacement(fault_suface, fault_displacement, fault_strike)
|
|
41
|
+
return d
|
|
42
|
+
|
|
43
|
+
def evaluate_gradient(self, location):
|
|
44
|
+
"""
|
|
45
|
+
get the scaled displacement
|
|
46
|
+
|
|
47
|
+
Parameters
|
|
48
|
+
----------
|
|
49
|
+
location
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
fault_suface = self.fault_frame.features[0].evaluate_value(location)
|
|
56
|
+
fault_displacement = self.fault_frame.features[1].evaluate_value(
|
|
57
|
+
location)
|
|
58
|
+
fault_strike = self.fault_frame.features[2].evaluate_value(location)
|
|
59
|
+
d = self.displacement(fault_suface, fault_displacement, fault_strike)
|
|
60
|
+
return d
|
|
61
|
+
|
|
62
|
+
def min(self):
|
|
63
|
+
return -1
|
|
64
|
+
|
|
65
|
+
def max(self):
|
|
66
|
+
return 1
|
|
67
|
+
|
|
68
|
+
def evaluate_on_surface(self, location):
|
|
69
|
+
fault_displacement = self.fault_frame.features[1].evaluate_value(
|
|
70
|
+
location)
|
|
71
|
+
fault_strike = self.fault_frame.features[2].evaluate_value(location)
|
|
72
|
+
d = self.displacement.evaluate(fault_displacement, fault_strike)
|
|
73
|
+
return d
|
|
74
|
+
|
|
75
|
+
def mean(self):
|
|
76
|
+
return 0
|