LoopStructural 1.0.9__cp38-cp38-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.
Files changed (77) hide show
  1. LoopStructural/__init__.py +36 -0
  2. LoopStructural/analysis/__init__.py +2 -0
  3. LoopStructural/analysis/_fault_displacement.py +67 -0
  4. LoopStructural/analysis/_fault_intersection.py +36 -0
  5. LoopStructural/analysis/_plane_fit.py +43 -0
  6. LoopStructural/datasets/__init__.py +12 -0
  7. LoopStructural/datasets/_base.py +65 -0
  8. LoopStructural/datasets/data/claudius.csv +21049 -0
  9. LoopStructural/datasets/data/claudiusbb.txt +2 -0
  10. LoopStructural/datasets/data/duplex.csv +126 -0
  11. LoopStructural/datasets/data/duplexbb.txt +2 -0
  12. LoopStructural/datasets/data/intrusion.csv +1017 -0
  13. LoopStructural/datasets/data/intrusionbb.txt +2 -0
  14. LoopStructural/datasets/data/onefoldbb.txt +2 -0
  15. LoopStructural/datasets/data/onefolddata.csv +2226 -0
  16. LoopStructural/datasets/data/refolded_bb.txt +2 -0
  17. LoopStructural/datasets/data/refolded_fold.csv +2126 -0
  18. LoopStructural/interpolators/__init__.py +34 -0
  19. LoopStructural/interpolators/base_structured_3d_support.py +101 -0
  20. LoopStructural/interpolators/cython/__init__.py +0 -0
  21. LoopStructural/interpolators/cython/dsi_helper.c +31046 -0
  22. LoopStructural/interpolators/cython/dsi_helper.cp38-win32.pyd +0 -0
  23. LoopStructural/interpolators/discrete_fold_interpolator.py +202 -0
  24. LoopStructural/interpolators/discrete_interpolator.py +584 -0
  25. LoopStructural/interpolators/finite_difference_interpolator.py +399 -0
  26. LoopStructural/interpolators/geological_interpolator.py +197 -0
  27. LoopStructural/interpolators/operator.py +61 -0
  28. LoopStructural/interpolators/piecewiselinear_interpolator.py +437 -0
  29. LoopStructural/interpolators/structured_grid.py +421 -0
  30. LoopStructural/interpolators/structured_tetra.py +681 -0
  31. LoopStructural/interpolators/surfe_wrapper.py +118 -0
  32. LoopStructural/modelling/__init__.py +46 -0
  33. LoopStructural/modelling/core/__init__.py +0 -0
  34. LoopStructural/modelling/core/geological_model.py +1513 -0
  35. LoopStructural/modelling/core/geological_model_graph.py +880 -0
  36. LoopStructural/modelling/core/stratigraphic_column.py +5 -0
  37. LoopStructural/modelling/fault/__init__.py +4 -0
  38. LoopStructural/modelling/fault/fault_builder.py +143 -0
  39. LoopStructural/modelling/fault/fault_function.py +188 -0
  40. LoopStructural/modelling/fault/fault_function_feature.py +76 -0
  41. LoopStructural/modelling/fault/fault_segment.py +298 -0
  42. LoopStructural/modelling/features/__init__.py +8 -0
  43. LoopStructural/modelling/features/cross_product_geological_feature.py +90 -0
  44. LoopStructural/modelling/features/geological_feature.py +252 -0
  45. LoopStructural/modelling/features/geological_feature_builder.py +414 -0
  46. LoopStructural/modelling/features/lambda_geological_feature.py +36 -0
  47. LoopStructural/modelling/features/region_feature.py +34 -0
  48. LoopStructural/modelling/features/structural_frame.py +133 -0
  49. LoopStructural/modelling/features/structural_frame_builder.py +206 -0
  50. LoopStructural/modelling/features/unconformity_feature.py +74 -0
  51. LoopStructural/modelling/fold/__init__.py +8 -0
  52. LoopStructural/modelling/fold/fold.py +143 -0
  53. LoopStructural/modelling/fold/fold_rotation_angle.py +133 -0
  54. LoopStructural/modelling/fold/fold_rotation_angle_feature.py +58 -0
  55. LoopStructural/modelling/fold/foldframe.py +193 -0
  56. LoopStructural/modelling/fold/svariogram.py +180 -0
  57. LoopStructural/utils/__init__.py +18 -0
  58. LoopStructural/utils/bounding_box.py +21 -0
  59. LoopStructural/utils/exceptions.py +10 -0
  60. LoopStructural/utils/helper.py +382 -0
  61. LoopStructural/utils/logging.py +60 -0
  62. LoopStructural/utils/map2loop.py +353 -0
  63. LoopStructural/utils/regions.py +11 -0
  64. LoopStructural/utils/utils.py +69 -0
  65. LoopStructural/visualisation/__init__.py +31 -0
  66. LoopStructural/visualisation/map_viewer.py +322 -0
  67. LoopStructural/visualisation/model_plotter.py +17 -0
  68. LoopStructural/visualisation/model_visualisation.py +1113 -0
  69. LoopStructural/visualisation/rotation_angle_plotter.py +83 -0
  70. LoopStructural/visualisation/sphinx_scraper.py +34 -0
  71. LoopStructural/visualisation/stratigraphic_column.py +60 -0
  72. LoopStructural-1.0.9.dist-info/LICENSE +21 -0
  73. LoopStructural-1.0.9.dist-info/METADATA +19 -0
  74. LoopStructural-1.0.9.dist-info/RECORD +77 -0
  75. LoopStructural-1.0.9.dist-info/WHEEL +5 -0
  76. LoopStructural-1.0.9.dist-info/top_level.txt +2 -0
  77. tests/__init__.py +0 -0
@@ -0,0 +1,5 @@
1
+ class StratigraphicColumn:
2
+ def __init__(self):
3
+ pass
4
+ def add_series(self,feature,name,maximum,minimum,colour):
5
+ pass
@@ -0,0 +1,4 @@
1
+ from .fault_function import Composite, CubicFunction, Ones, Zeros
2
+ from .fault_function_feature import FaultDisplacementFeature
3
+ from .fault_segment import FaultSegment
4
+ from .fault_builder import FaultBuilder
@@ -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