LoopStructural 1.6.1__py3-none-any.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.

Potentially problematic release.


This version of LoopStructural might be problematic. Click here for more details.

Files changed (129) hide show
  1. LoopStructural/__init__.py +52 -0
  2. LoopStructural/datasets/__init__.py +23 -0
  3. LoopStructural/datasets/_base.py +301 -0
  4. LoopStructural/datasets/_example_models.py +10 -0
  5. LoopStructural/datasets/data/claudius.csv +21049 -0
  6. LoopStructural/datasets/data/claudiusbb.txt +2 -0
  7. LoopStructural/datasets/data/duplex.csv +126 -0
  8. LoopStructural/datasets/data/duplexbb.txt +2 -0
  9. LoopStructural/datasets/data/fault_trace/fault_trace.cpg +1 -0
  10. LoopStructural/datasets/data/fault_trace/fault_trace.dbf +0 -0
  11. LoopStructural/datasets/data/fault_trace/fault_trace.prj +1 -0
  12. LoopStructural/datasets/data/fault_trace/fault_trace.shp +0 -0
  13. LoopStructural/datasets/data/fault_trace/fault_trace.shx +0 -0
  14. LoopStructural/datasets/data/geological_map_data/bbox.csv +2 -0
  15. LoopStructural/datasets/data/geological_map_data/contacts.csv +657 -0
  16. LoopStructural/datasets/data/geological_map_data/fault_displacement.csv +7 -0
  17. LoopStructural/datasets/data/geological_map_data/fault_edges.txt +2 -0
  18. LoopStructural/datasets/data/geological_map_data/fault_locations.csv +79 -0
  19. LoopStructural/datasets/data/geological_map_data/fault_orientations.csv +19 -0
  20. LoopStructural/datasets/data/geological_map_data/stratigraphic_order.csv +13 -0
  21. LoopStructural/datasets/data/geological_map_data/stratigraphic_orientations.csv +207 -0
  22. LoopStructural/datasets/data/geological_map_data/stratigraphic_thickness.csv +13 -0
  23. LoopStructural/datasets/data/intrusion.csv +1017 -0
  24. LoopStructural/datasets/data/intrusionbb.txt +2 -0
  25. LoopStructural/datasets/data/onefoldbb.txt +2 -0
  26. LoopStructural/datasets/data/onefolddata.csv +2226 -0
  27. LoopStructural/datasets/data/refolded_bb.txt +2 -0
  28. LoopStructural/datasets/data/refolded_fold.csv +205 -0
  29. LoopStructural/datasets/data/tabular_intrusion.csv +23 -0
  30. LoopStructural/datatypes/__init__.py +4 -0
  31. LoopStructural/datatypes/_bounding_box.py +422 -0
  32. LoopStructural/datatypes/_point.py +166 -0
  33. LoopStructural/datatypes/_structured_grid.py +94 -0
  34. LoopStructural/datatypes/_surface.py +184 -0
  35. LoopStructural/export/exporters.py +554 -0
  36. LoopStructural/export/file_formats.py +15 -0
  37. LoopStructural/export/geoh5.py +100 -0
  38. LoopStructural/export/gocad.py +126 -0
  39. LoopStructural/export/omf_wrapper.py +88 -0
  40. LoopStructural/interpolators/__init__.py +105 -0
  41. LoopStructural/interpolators/_api.py +143 -0
  42. LoopStructural/interpolators/_builders.py +149 -0
  43. LoopStructural/interpolators/_cython/__init__.py +0 -0
  44. LoopStructural/interpolators/_discrete_fold_interpolator.py +183 -0
  45. LoopStructural/interpolators/_discrete_interpolator.py +692 -0
  46. LoopStructural/interpolators/_finite_difference_interpolator.py +470 -0
  47. LoopStructural/interpolators/_geological_interpolator.py +380 -0
  48. LoopStructural/interpolators/_interpolator_factory.py +89 -0
  49. LoopStructural/interpolators/_non_linear_discrete_interpolator.py +0 -0
  50. LoopStructural/interpolators/_operator.py +38 -0
  51. LoopStructural/interpolators/_p1interpolator.py +228 -0
  52. LoopStructural/interpolators/_p2interpolator.py +277 -0
  53. LoopStructural/interpolators/_surfe_wrapper.py +174 -0
  54. LoopStructural/interpolators/supports/_2d_base_unstructured.py +340 -0
  55. LoopStructural/interpolators/supports/_2d_p1_unstructured.py +68 -0
  56. LoopStructural/interpolators/supports/_2d_p2_unstructured.py +288 -0
  57. LoopStructural/interpolators/supports/_2d_structured_grid.py +462 -0
  58. LoopStructural/interpolators/supports/_2d_structured_tetra.py +0 -0
  59. LoopStructural/interpolators/supports/_3d_base_structured.py +467 -0
  60. LoopStructural/interpolators/supports/_3d_p2_tetra.py +331 -0
  61. LoopStructural/interpolators/supports/_3d_structured_grid.py +470 -0
  62. LoopStructural/interpolators/supports/_3d_structured_tetra.py +746 -0
  63. LoopStructural/interpolators/supports/_3d_unstructured_tetra.py +637 -0
  64. LoopStructural/interpolators/supports/__init__.py +55 -0
  65. LoopStructural/interpolators/supports/_aabb.py +77 -0
  66. LoopStructural/interpolators/supports/_base_support.py +114 -0
  67. LoopStructural/interpolators/supports/_face_table.py +70 -0
  68. LoopStructural/interpolators/supports/_support_factory.py +32 -0
  69. LoopStructural/modelling/__init__.py +29 -0
  70. LoopStructural/modelling/core/__init__.py +0 -0
  71. LoopStructural/modelling/core/geological_model.py +1867 -0
  72. LoopStructural/modelling/features/__init__.py +32 -0
  73. LoopStructural/modelling/features/_analytical_feature.py +79 -0
  74. LoopStructural/modelling/features/_base_geological_feature.py +364 -0
  75. LoopStructural/modelling/features/_cross_product_geological_feature.py +100 -0
  76. LoopStructural/modelling/features/_geological_feature.py +288 -0
  77. LoopStructural/modelling/features/_lambda_geological_feature.py +93 -0
  78. LoopStructural/modelling/features/_region.py +18 -0
  79. LoopStructural/modelling/features/_structural_frame.py +186 -0
  80. LoopStructural/modelling/features/_unconformity_feature.py +83 -0
  81. LoopStructural/modelling/features/builders/__init__.py +5 -0
  82. LoopStructural/modelling/features/builders/_base_builder.py +111 -0
  83. LoopStructural/modelling/features/builders/_fault_builder.py +590 -0
  84. LoopStructural/modelling/features/builders/_folded_feature_builder.py +129 -0
  85. LoopStructural/modelling/features/builders/_geological_feature_builder.py +543 -0
  86. LoopStructural/modelling/features/builders/_structural_frame_builder.py +237 -0
  87. LoopStructural/modelling/features/fault/__init__.py +3 -0
  88. LoopStructural/modelling/features/fault/_fault_function.py +444 -0
  89. LoopStructural/modelling/features/fault/_fault_function_feature.py +82 -0
  90. LoopStructural/modelling/features/fault/_fault_segment.py +505 -0
  91. LoopStructural/modelling/features/fold/__init__.py +9 -0
  92. LoopStructural/modelling/features/fold/_fold.py +167 -0
  93. LoopStructural/modelling/features/fold/_fold_rotation_angle.py +149 -0
  94. LoopStructural/modelling/features/fold/_fold_rotation_angle_feature.py +67 -0
  95. LoopStructural/modelling/features/fold/_foldframe.py +194 -0
  96. LoopStructural/modelling/features/fold/_svariogram.py +188 -0
  97. LoopStructural/modelling/input/__init__.py +2 -0
  98. LoopStructural/modelling/input/fault_network.py +80 -0
  99. LoopStructural/modelling/input/map2loop_processor.py +165 -0
  100. LoopStructural/modelling/input/process_data.py +650 -0
  101. LoopStructural/modelling/input/project_file.py +84 -0
  102. LoopStructural/modelling/intrusions/__init__.py +25 -0
  103. LoopStructural/modelling/intrusions/geom_conceptual_models.py +142 -0
  104. LoopStructural/modelling/intrusions/geometric_scaling_functions.py +123 -0
  105. LoopStructural/modelling/intrusions/intrusion_builder.py +672 -0
  106. LoopStructural/modelling/intrusions/intrusion_feature.py +410 -0
  107. LoopStructural/modelling/intrusions/intrusion_frame_builder.py +971 -0
  108. LoopStructural/modelling/intrusions/intrusion_support_functions.py +460 -0
  109. LoopStructural/utils/__init__.py +38 -0
  110. LoopStructural/utils/_surface.py +143 -0
  111. LoopStructural/utils/_transformation.py +76 -0
  112. LoopStructural/utils/config.py +18 -0
  113. LoopStructural/utils/dtm_creator.py +17 -0
  114. LoopStructural/utils/exceptions.py +31 -0
  115. LoopStructural/utils/helper.py +292 -0
  116. LoopStructural/utils/json_encoder.py +18 -0
  117. LoopStructural/utils/linalg.py +8 -0
  118. LoopStructural/utils/logging.py +79 -0
  119. LoopStructural/utils/maths.py +245 -0
  120. LoopStructural/utils/regions.py +103 -0
  121. LoopStructural/utils/typing.py +7 -0
  122. LoopStructural/utils/utils.py +68 -0
  123. LoopStructural/version.py +1 -0
  124. LoopStructural/visualisation/__init__.py +11 -0
  125. LoopStructural-1.6.1.dist-info/LICENSE +21 -0
  126. LoopStructural-1.6.1.dist-info/METADATA +81 -0
  127. LoopStructural-1.6.1.dist-info/RECORD +129 -0
  128. LoopStructural-1.6.1.dist-info/WHEEL +5 -0
  129. LoopStructural-1.6.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,410 @@
1
+ from typing import Optional
2
+ import numpy as np
3
+ import pandas as pd
4
+ from LoopStructural.modelling.features import BaseFeature
5
+ from LoopStructural.modelling.features import FeatureType
6
+
7
+ # import logging
8
+ from ...utils import getLogger
9
+ from scipy.interpolate import Rbf
10
+
11
+ logger = getLogger(__name__)
12
+
13
+
14
+ class IntrusionFeature(BaseFeature):
15
+ """
16
+ Intrusion feature is a class to represent an intrusion, using a distance scalar field to the intrusion contact.
17
+ Threshold distances are simulated along the intrusion frame coordinates, and simulation are constrained
18
+ with conceptual geometrical model of the lateral and vertical intrusion extent.
19
+
20
+ """
21
+
22
+ def __init__(
23
+ self,
24
+ frame,
25
+ builder,
26
+ # faults=[],
27
+ name="UnnamedIntrusion",
28
+ model=None,
29
+ ):
30
+ """
31
+ Parameters
32
+ ----------
33
+ name: string
34
+
35
+ model: GeologicalModel
36
+
37
+ Returns
38
+ ----------
39
+ intrusion_feature : IntrusionFeature
40
+
41
+ """
42
+
43
+ BaseFeature.__init__(self, name=name, builder=builder, model=model)
44
+
45
+ self.intrusion_frame = frame
46
+ self.type = FeatureType.INTRUSION
47
+ self.assisting_faults = {}
48
+
49
+ def set_intrusion_frame(self, intrusion_frame):
50
+ self.intrusion_feature_frame = intrusion_frame
51
+
52
+ def set_model(self, model):
53
+ self.model = model
54
+
55
+ def add_assisting_faults(self, faults_dictionary):
56
+
57
+ self.assisting_faults = faults_dictionary
58
+
59
+ def interpolate_lateral_thresholds(self, points_coord1):
60
+
61
+ conceptual_model = self.builder.lateral_extent_model
62
+ inputsimdata_minL = self.builder.data_for_lateral_extent_calculation[0]
63
+ inputsimdata_maxL = self.builder.data_for_lateral_extent_calculation[1]
64
+
65
+ minL_inputdata_coord1 = inputsimdata_minL.coord1.to_numpy()
66
+ # minL_inputdata_coord2 = inputsimdata_minL.coord2.to_numpy()
67
+ minL_inputdata_residual = inputsimdata_minL.l_residual.to_numpy()
68
+ # minL_inputdata_conceptual = inputsimdata_minL.l_conceptual.to_numpy()
69
+
70
+ maxL_inputdata_coord1 = inputsimdata_maxL.coord1.to_numpy()
71
+ # maxL_inputdata_coord2 = inputsimdata_maxL.coord2.to_numpy()
72
+ maxL_inputdata_residual = inputsimdata_maxL.l_residual.to_numpy()
73
+ # maxL_inputdata_conceptual = inputsimdata_maxL.l_conceptual.to_numpy()
74
+
75
+ # min,max P and L should be the same as in conceptual models
76
+ minP = self.builder.conceptual_model_parameters.get("minP")
77
+ maxP = self.builder.conceptual_model_parameters.get("maxP")
78
+ minL = self.builder.conceptual_model_parameters.get("minL")
79
+ maxL = self.builder.conceptual_model_parameters.get("maxL")
80
+
81
+ points_coord_df = pd.DataFrame(points_coord1, columns=["coord1"])
82
+ residual_values = []
83
+ thresholds_values = []
84
+ conceptual_values = []
85
+
86
+ # min side
87
+ minL_residual_interpolator = Rbf(
88
+ minL_inputdata_coord1, minL_inputdata_residual, function="linear"
89
+ )
90
+ minL_conceptual_model = conceptual_model(
91
+ points_coord_df, minP=minP, maxP=maxP, minS=minL, maxS=maxL
92
+ )[:, 1]
93
+
94
+ minL_minP = np.min(minL_inputdata_coord1)
95
+ minL_minP_val = minL_residual_interpolator(minL_minP)
96
+ minL_maxP = np.max(minL_inputdata_coord1)
97
+ minL_maxP_val = minL_residual_interpolator(minL_maxP)
98
+
99
+ residuals = minL_residual_interpolator(points_coord1)
100
+ residuals[points_coord1 > minL_maxP] = minL_maxP_val
101
+ residuals[points_coord1 < minL_minP] = minL_minP_val
102
+
103
+ values = minL_conceptual_model - residuals
104
+ values[points_coord1 < minP] = 0
105
+ values[points_coord1 > maxP] = 0
106
+
107
+ residual_values.append(residuals)
108
+ thresholds_values.append(values)
109
+ conceptual_values.append(minL_conceptual_model)
110
+
111
+ # max side
112
+ maxL_residual_interpolator = Rbf(
113
+ maxL_inputdata_coord1, maxL_inputdata_residual, function="linear"
114
+ )
115
+ maxL_conceptual_model = conceptual_model(
116
+ points_coord_df, minP=minP, maxP=maxP, minS=minL, maxS=maxL
117
+ )[:, 0]
118
+
119
+ maxL_minP = np.min(maxL_inputdata_coord1)
120
+ maxL_minP_val = maxL_residual_interpolator(maxL_minP)
121
+ maxL_maxP = np.max(maxL_inputdata_coord1)
122
+ maxL_maxP_val = maxL_residual_interpolator(maxL_maxP)
123
+
124
+ residuals = maxL_residual_interpolator(points_coord1)
125
+ residuals[points_coord1 > maxL_maxP] = maxL_maxP_val
126
+ residuals[points_coord1 < maxL_minP] = maxL_minP_val
127
+
128
+ values = maxL_conceptual_model - residuals
129
+ values[points_coord1 < minP] = 0
130
+ values[points_coord1 > maxP] = 0
131
+
132
+ residual_values.append(residuals)
133
+ thresholds_values.append(values)
134
+ conceptual_values.append(maxL_conceptual_model)
135
+
136
+ return thresholds_values, residual_values, conceptual_values
137
+
138
+ def interpolate_vertical_thresholds(self, points_coord1, points_coord2):
139
+
140
+ function_rbf = "linear"
141
+
142
+ conceptual_model = self.builder.vertical_extent_model
143
+ inputsimdata_maxG = self.builder.data_for_vertical_extent_calculation[0]
144
+ inputsimdata_minG = self.builder.data_for_vertical_extent_calculation[1]
145
+
146
+ minG_inputdata_coord0 = inputsimdata_minG.coord0.to_numpy()
147
+ minG_inputdata_coord1 = inputsimdata_minG.coord1.to_numpy()
148
+ minG_inputdata_coord2 = inputsimdata_minG.coord2.to_numpy()
149
+ # inputsimdata_minG.coord0.to_numpy()
150
+
151
+ # inputsimdata_maxG.coord0.to_numpy()
152
+ maxG_inputdata_coord1 = inputsimdata_maxG.coord1.to_numpy()
153
+ maxG_inputdata_coord2 = inputsimdata_maxG.coord2.to_numpy()
154
+ maxG_inputdata_residual = inputsimdata_maxG.g_residual.to_numpy()
155
+ # inputsimdata_maxG.g_conceptual.to_numpy()
156
+
157
+ # min,max P and L should be the same as in conceptual models
158
+ minP = self.builder.conceptual_model_parameters.get("minP")
159
+ maxP = self.builder.conceptual_model_parameters.get("maxP")
160
+ minL = self.builder.conceptual_model_parameters.get("minL")
161
+ maxL = self.builder.conceptual_model_parameters.get("maxL")
162
+ mean_G = self.builder.conceptual_model_parameters.get("mean_growth")
163
+ vertex = self.builder.conceptual_model_parameters.get("vertex")
164
+
165
+ points_df = pd.DataFrame()
166
+ points_df["coord1"] = points_coord1
167
+ points_df["coord2"] = points_coord2
168
+ residual_values = []
169
+ threshold_values = []
170
+ conceptual_values = []
171
+
172
+ # max growth
173
+ maxG_residual_interpolator = Rbf(
174
+ maxG_inputdata_coord1,
175
+ maxG_inputdata_coord2,
176
+ maxG_inputdata_residual,
177
+ function=function_rbf,
178
+ )
179
+ maxG_conceptual_model = conceptual_model(
180
+ points_df,
181
+ minP=minP,
182
+ maxP=maxP,
183
+ minS=minL,
184
+ maxS=maxL,
185
+ mean_growth=mean_G,
186
+ vertex=vertex,
187
+ )[:, 1]
188
+
189
+ # maxG_minP = np.min(maxG_inputdata_coord1)
190
+ # maxG_residual_interpolator(
191
+ # maxG_minP,
192
+ # maxG_inputdata_coord2[np.where(maxG_inputdata_coord1 == maxG_minP)][0],
193
+ # )
194
+ # maxG_maxP = np.max(maxG_inputdata_coord1)
195
+ # maxG_residual_interpolator(
196
+ # maxG_maxP,
197
+ # maxG_inputdata_coord2[np.where(maxG_inputdata_coord1 == maxG_maxP)][0],
198
+ # )
199
+ # maxG_minL = np.min(maxG_inputdata_coord2)
200
+ # maxG_residual_interpolator(
201
+ # maxG_inputdata_coord1[np.where(maxG_inputdata_coord2 == maxG_minL)][0],
202
+ # maxG_minL,
203
+ # )
204
+ # maxG_maxL = np.max(maxG_inputdata_coord2)
205
+ # maxG_residual_interpolator(
206
+ # maxG_inputdata_coord1[np.where(maxG_inputdata_coord2 == maxG_maxL)][0],
207
+ # maxG_maxL,
208
+ # )
209
+
210
+ residuals = maxG_residual_interpolator(points_coord1, points_coord2)
211
+ thresholds = maxG_conceptual_model - residuals
212
+
213
+ residual_values.append(residuals)
214
+ threshold_values.append(thresholds)
215
+ conceptual_values.append(maxG_conceptual_model)
216
+
217
+ # intrusion reference contact, conditioning to data
218
+ minG_interpolator = Rbf(
219
+ minG_inputdata_coord1,
220
+ minG_inputdata_coord2,
221
+ minG_inputdata_coord0,
222
+ function=function_rbf,
223
+ )
224
+ thresholds = minG_interpolator(points_coord1, points_coord2)
225
+ minG_conceptual_model = np.zeros(len(points_coord1))
226
+
227
+ threshold_values.append(thresholds)
228
+ conceptual_values.append(minG_conceptual_model)
229
+
230
+ return threshold_values, residual_values, conceptual_values
231
+
232
+ def evaluate_gradient(self, pos):
233
+ ## LG TODO check whether it can be implemented
234
+ raise NotImplementedError("Cannot calculate gradient of Intrusion")
235
+
236
+ def evaluate_value(self, pos):
237
+ """
238
+ Computes a distance scalar field to the intrusion contact (isovalue = 0).
239
+
240
+ Parameters
241
+ ------------
242
+ points : numpy array (x,y,z), points where the IntrusionFeature is evaluated.
243
+
244
+ Returns
245
+ ------------
246
+ intrusion_sf : numpy array, contains distance to intrusion contact
247
+
248
+ """
249
+ self.builder.up_to_date()
250
+
251
+ # compute coordinates values for each evaluated point
252
+ intrusion_coord0_pts = self.intrusion_frame[0].evaluate_value(pos)
253
+ intrusion_coord1_pts = self.intrusion_frame[1].evaluate_value(pos)
254
+ intrusion_coord2_pts = self.intrusion_frame[2].evaluate_value(pos)
255
+
256
+ self.evaluated_points = [
257
+ pos,
258
+ intrusion_coord0_pts,
259
+ intrusion_coord1_pts,
260
+ intrusion_coord2_pts,
261
+ ]
262
+
263
+ thresholds, residuals, conceptual = self.interpolate_lateral_thresholds(
264
+ intrusion_coord1_pts
265
+ )
266
+
267
+ if self.intrusion_frame.builder.marginal_faults is not None:
268
+ c2_minside_threshold = thresholds[0] # np.zeros_like(intrusion_coord2_pts)
269
+ c2_maxside_threshold = thresholds[1]
270
+
271
+ else:
272
+ c2_minside_threshold = thresholds[0]
273
+ c2_maxside_threshold = thresholds[1]
274
+
275
+ thresholds, residuals, conceptual = self.interpolate_vertical_thresholds(
276
+ intrusion_coord1_pts, intrusion_coord2_pts
277
+ )
278
+ c0_minside_threshold = thresholds[1]
279
+ c0_maxside_threshold = thresholds[0]
280
+
281
+ if len(self.assisting_faults) > 0:
282
+ fault = self.assisting_faults.get("structure")
283
+ weight = self.assisting_faults.get("asymmetry_weight", 1)
284
+ evaluation_points_in_fault = fault[0].evaluate_value(pos)
285
+ c0_maxside_threshold[evaluation_points_in_fault >= 0] = (
286
+ c0_maxside_threshold[evaluation_points_in_fault >= 0] * weight
287
+ )
288
+
289
+ mid_point = c0_minside_threshold + ((c0_maxside_threshold - c0_minside_threshold) / 2)
290
+
291
+ a = intrusion_coord2_pts >= c2_maxside_threshold
292
+ b = intrusion_coord2_pts <= c2_minside_threshold
293
+ c = (
294
+ (c2_minside_threshold < intrusion_coord2_pts)
295
+ * (intrusion_coord2_pts < c2_maxside_threshold)
296
+ * (intrusion_coord0_pts <= c0_minside_threshold)
297
+ )
298
+ d = (
299
+ (c2_minside_threshold < intrusion_coord2_pts)
300
+ * (intrusion_coord2_pts < c2_maxside_threshold)
301
+ * (intrusion_coord0_pts >= c0_maxside_threshold)
302
+ )
303
+ e = (
304
+ (c2_minside_threshold < intrusion_coord2_pts)
305
+ * (intrusion_coord2_pts < c2_maxside_threshold)
306
+ * (mid_point >= intrusion_coord0_pts)
307
+ * (intrusion_coord0_pts > c0_minside_threshold)
308
+ )
309
+ f = (
310
+ (c2_minside_threshold < intrusion_coord2_pts)
311
+ * (intrusion_coord2_pts < c2_maxside_threshold)
312
+ * (mid_point < intrusion_coord0_pts)
313
+ * (intrusion_coord0_pts < c0_maxside_threshold)
314
+ )
315
+
316
+ mod_Smin_thresholds = intrusion_coord2_pts - c2_minside_threshold
317
+ mod_Smax_thresholds = intrusion_coord2_pts - c2_maxside_threshold
318
+ mod_Gmin_thresholds = intrusion_coord0_pts - c0_minside_threshold
319
+ mod_Gmax_thresholds = intrusion_coord0_pts - c0_maxside_threshold
320
+
321
+ intrusion_sf = (
322
+ a * mod_Smax_thresholds
323
+ + b * abs(mod_Smin_thresholds)
324
+ + c * abs(mod_Gmin_thresholds)
325
+ + d * mod_Gmax_thresholds
326
+ - e * mod_Gmin_thresholds
327
+ + f * mod_Gmax_thresholds
328
+ ) * (
329
+ -1
330
+ ) # multiply by (-1) so intrusions can be used as unconformities
331
+
332
+ return intrusion_sf
333
+
334
+ def evaluate_value_test(self, points):
335
+ """
336
+ Computes a distance scalar field to the intrusion contact (isovalue = 0).
337
+
338
+ Parameters
339
+ ------------
340
+ points : numpy array (x,y,z), points where the IntrusionFeature is evaluated.
341
+
342
+ Returns
343
+ ------------
344
+ intrusion_sf : numpy array, contains distance to intrusion contact
345
+
346
+ """
347
+ self.builder.up_to_date()
348
+
349
+ # compute coordinates values for each evaluated point
350
+ intrusion_coord0_pts = self.intrusion_frame[0].evaluate_value(points)
351
+ intrusion_coord1_pts = self.intrusion_frame[1].evaluate_value(points)
352
+ intrusion_coord2_pts = self.intrusion_frame[2].evaluate_value(points)
353
+
354
+ self.evaluated_points = [
355
+ points,
356
+ intrusion_coord0_pts,
357
+ intrusion_coord1_pts,
358
+ intrusion_coord2_pts,
359
+ ]
360
+
361
+ thresholds, residuals, conceptual = self.interpolate_lateral_thresholds(
362
+ intrusion_coord1_pts
363
+ )
364
+
365
+ if self.intrusion_frame.builder.marginal_faults is not None:
366
+ c2_minside_threshold = np.zeros_like(intrusion_coord2_pts)
367
+ c2_maxside_threshold = thresholds[1]
368
+
369
+ else:
370
+ c2_minside_threshold = thresholds[0]
371
+ c2_maxside_threshold = thresholds[1]
372
+
373
+ thresholds, residuals, conceptual = self.interpolate_vertical_thresholds(
374
+ intrusion_coord1_pts, intrusion_coord2_pts
375
+ )
376
+ c0_minside_threshold = thresholds[1]
377
+ c0_maxside_threshold = thresholds[0]
378
+
379
+ mid_point = c0_minside_threshold + ((c0_maxside_threshold - c0_minside_threshold) / 2)
380
+
381
+ mod_intrusion_coord0_pts = intrusion_coord0_pts - mid_point
382
+ mod_c0_minside_threshold = c0_minside_threshold - mid_point
383
+ mod_c0_maxside_threshold = c0_maxside_threshold + mid_point
384
+
385
+ a = (
386
+ (mod_intrusion_coord0_pts >= mid_point)
387
+ * (c2_minside_threshold < intrusion_coord2_pts)
388
+ * (intrusion_coord2_pts < c2_maxside_threshold)
389
+ )
390
+ b = (
391
+ (mod_intrusion_coord0_pts <= mid_point)
392
+ * (c2_minside_threshold < intrusion_coord2_pts)
393
+ * (intrusion_coord2_pts < c2_maxside_threshold)
394
+ )
395
+ c = (
396
+ (mod_intrusion_coord0_pts <= mid_point)
397
+ * (mod_intrusion_coord0_pts >= mod_c0_minside_threshold)
398
+ * (c2_minside_threshold < intrusion_coord2_pts)
399
+ * (intrusion_coord2_pts < c2_maxside_threshold)
400
+ )
401
+
402
+ intrusion_sf = mod_intrusion_coord0_pts
403
+ intrusion_sf[a] = mod_intrusion_coord0_pts[a] - mod_c0_maxside_threshold[a]
404
+ intrusion_sf[b] = abs(mod_c0_minside_threshold[b] + mod_intrusion_coord0_pts[b])
405
+ intrusion_sf[c] = mod_intrusion_coord0_pts[c] - mod_c0_minside_threshold[c]
406
+
407
+ return intrusion_sf
408
+
409
+ def get_data(self, value_map: Optional[dict] = None):
410
+ pass