LoopStructural 1.0.9__cp36-cp36m-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.cp36-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,298 @@
1
+ import logging
2
+
3
+ from LoopStructural.modelling.fault.fault_function_feature import FaultDisplacementFeature
4
+ from LoopStructural.modelling.fault.fault_function import BaseFault
5
+ from LoopStructural.utils import getLogger
6
+ logger = getLogger(__name__)
7
+ from concurrent.futures import ThreadPoolExecutor
8
+ import numpy as np
9
+
10
+
11
+ class FaultSegment:
12
+ """
13
+ Class for representing a slip event of a fault
14
+ """
15
+
16
+ def __init__(self, faultframe,
17
+ faultfunction = None,
18
+ steps = 3,
19
+ displacement=1.,
20
+ **kwargs):
21
+ """
22
+ A slip event of a fault
23
+
24
+ Parameters
25
+ ----------
26
+ faultframe : FaultFrame
27
+ the fault frame defining the faut geometry
28
+ faultfunction : function/lambda function
29
+ optional displacement function for spatially variable fault displacement
30
+ steps : int
31
+ how many integration steps for faults
32
+ kwargs
33
+ """
34
+ self.faultframe = faultframe
35
+ self.type = 'fault'
36
+ self.name = kwargs.get('name', self.faultframe.name)
37
+ self.displacement = displacement
38
+ self.faultfunction = faultfunction
39
+ if faultfunction == 'BaseFault':
40
+ self.faultfunction = BaseFault.fault_displacement
41
+ self.steps = steps
42
+ self.regions = []
43
+ self.faults_enabled = True
44
+ self.displacementfeature = None
45
+ self.model = None
46
+ if self.faultframe is not None:
47
+ self.displacementfeature = FaultDisplacementFeature(
48
+ self.faultframe, self.faultfunction, name = self.name)
49
+ self.builder = None
50
+
51
+ def __getitem__(self, item):
52
+ """
53
+
54
+ Parameters
55
+ ----------
56
+ item
57
+
58
+ Returns
59
+ -------
60
+
61
+ """
62
+ return self.faultframe[item]
63
+
64
+ def set_model(self, model):
65
+ """
66
+ Link a geological model to the feature
67
+
68
+ Parameters
69
+ ----------
70
+ model - GeologicalModel
71
+
72
+ Returns
73
+ -------
74
+
75
+ """
76
+ self.model = model
77
+
78
+ def set_displacement(self, displacement, scale = True):
79
+ """
80
+ Set the fault displacement to a new value
81
+
82
+ Parameters
83
+ ----------
84
+ displacement - double
85
+ scale - boolean
86
+
87
+ Returns
88
+ -------
89
+
90
+ """
91
+ if scale and self.model is not None:
92
+ self.displacement = displacement / self.model.scale_factor
93
+ elif not scale:
94
+ self.displacement = displacement
95
+ else:
96
+ logger.warning("Displacement not updated")
97
+
98
+ def toggle_faults(self):
99
+ """
100
+ Toggle faults that affect this fault segment
101
+
102
+ Returns
103
+ -------
104
+
105
+ """
106
+ self.faults_enabled = ~self.faults_enabled
107
+ for i in range(3):
108
+ self.faultframe[i].toggle_faults()
109
+
110
+ def add_region(self, region):
111
+ """
112
+
113
+ Parameters
114
+ ----------
115
+ region : boolean function(x,y,z)
116
+ A function that returns true if inside region, false if outside
117
+ can be passed as a lambda function e.g.
118
+ lambda pos : feature.evaluate_value(pos) > 0
119
+ Returns
120
+ -------
121
+
122
+ """
123
+
124
+ self.regions.append(region)
125
+
126
+ def evaluate(self, locations):
127
+ """
128
+ Evaluate which side of fault
129
+
130
+ Parameters
131
+ ----------
132
+ locations numpy array
133
+ location to evaluate
134
+
135
+ Returns
136
+ -------
137
+ boolean array true if on hanging wall, false if on footwall
138
+
139
+ """
140
+
141
+ return self.faultframe.features[0].evaluate_value(locations) > 0
142
+
143
+ def inside_volume(self,locations):
144
+ v = self.faultframe.evaluate_value(locations)
145
+ return np.all(np.logical_and(v > -1,v<1),axis=1)
146
+
147
+ def evaluate_value(self, locations):
148
+ """
149
+ Return the value of the fault surface scalar field
150
+
151
+ Parameters
152
+ ----------
153
+ locations - numpy array
154
+ location to evaluate scalar field
155
+
156
+ Returns
157
+ -------
158
+
159
+ """
160
+ v = np.zeros(locations.shape[0])
161
+ v[:] = np.nan
162
+ mask = np.zeros(locations.shape[0]).astype(bool)
163
+ mask[:] = True
164
+ # check regions
165
+ for r in self.regions:
166
+ mask = np.logical_and(mask, r(locations))
167
+ v[mask]=self.faultframe[0].evaluate_value(locations[mask, :])
168
+ return v
169
+
170
+ def mean(self):
171
+ return self.faultframe[0].mean()
172
+
173
+ def max(self):
174
+ return self.faultframe[0].max()
175
+
176
+ def min(self):
177
+ return self.faultframe[0].min()
178
+
179
+ def evaluate_gradient(self, locations):
180
+ """
181
+ Return the fault slip direction at the location
182
+
183
+ Parameters
184
+ ----------
185
+ locations - numpy array Nx3
186
+
187
+
188
+ Returns
189
+ -------
190
+
191
+ """
192
+ v = np.zeros(locations.shape)
193
+ v[:,:] = np.nan
194
+ mask = np.zeros(locations.shape[0]).astype(bool)
195
+ mask[:] = True
196
+ # check regions
197
+ for r in self.regions:
198
+ mask = np.logical_and(mask, r(locations))
199
+ # need to scale with fault displacement
200
+ v[mask,:] = self.faultframe[1].evaluate_gradient(locations[mask, :])
201
+ return v
202
+
203
+ def evaluate_displacement(self, points):
204
+ newp = np.copy(points).astype(float)
205
+ # evaluate fault function for all points then define mask for only points affected by fault
206
+ with ThreadPoolExecutor(max_workers=8) as executor:
207
+ # all of these operations should be independent so just run as different threads
208
+ gx_future = executor.submit(self.faultframe.features[0].evaluate_value, newp)
209
+ gy_future = executor.submit(self.faultframe.features[1].evaluate_value, newp)
210
+ gz_future = executor.submit(self.faultframe.features[2].evaluate_value, newp)
211
+ gx = gx_future.result()
212
+ gy = gy_future.result()
213
+ gz = gz_future.result()
214
+ d = np.zeros(gx.shape)
215
+ mask = np.logical_and(~np.isnan(gx),~np.isnan(gy))
216
+ mask = np.logical_and(mask,~np.isnan(gz))
217
+ d[~mask] = 0
218
+ gx_mask = np.zeros_like(mask,dtype=bool)
219
+ gx_mask[mask] = gx[mask] > 0
220
+ d[gx_mask] = 1.
221
+ if self.faultfunction is not None:
222
+ d[mask] = self.faultfunction(gx[mask], gy[mask], gz[mask])
223
+ return d
224
+ def apply_to_points(self, points):
225
+ """
226
+ Unfault the array of points
227
+
228
+ Parameters
229
+ ----------
230
+ points - numpy array Nx3
231
+
232
+ Returns
233
+ -------
234
+
235
+ """
236
+ steps = self.steps
237
+ newp = np.copy(points).astype(float)
238
+ # evaluate fault function for all points then define mask for only points affected by fault
239
+ with ThreadPoolExecutor(max_workers=8) as executor:
240
+ # all of these operations should be independent so just run as different threads
241
+ gx_future = executor.submit(self.faultframe.features[0].evaluate_value, newp)
242
+ gy_future = executor.submit(self.faultframe.features[1].evaluate_value, newp)
243
+ gz_future = executor.submit(self.faultframe.features[2].evaluate_value, newp)
244
+ gx = gx_future.result()
245
+ gy = gy_future.result()
246
+ gz = gz_future.result()
247
+ d = np.zeros(gx.shape)
248
+ mask = np.logical_and(~np.isnan(gx),~np.isnan(gy))
249
+ mask = np.logical_and(mask,~np.isnan(gz))
250
+ d[~mask] = 0
251
+ gx_mask = np.zeros_like(mask,dtype=bool)
252
+ gx_mask[mask] = gx[mask] > 0
253
+ d[gx_mask] = 1.
254
+ if self.faultfunction is not None:
255
+ d[mask] = self.faultfunction(gx[mask], gy[mask], gz[mask])
256
+ mask = np.abs(d) > 0.
257
+
258
+ d *= self.displacement
259
+ # calculate the fault frame for the evaluation points
260
+ for i in range(steps):
261
+ with ThreadPoolExecutor(max_workers=8) as executor:
262
+ # all of these operations should be independent so just run as different threads
263
+ gx_future = executor.submit(self.faultframe.features[0].evaluate_value, newp[mask, :])
264
+ g_future = executor.submit(self.faultframe.features[1].evaluate_gradient, newp[mask, :])
265
+ gy_future = executor.submit(self.faultframe.features[1].evaluate_value, newp[mask, :])
266
+ gz_future = executor.submit(self.faultframe.features[2].evaluate_value, newp[mask, :])
267
+ gx = gx_future.result()
268
+ g = g_future.result()
269
+ gy = gy_future.result()
270
+ gz = gz_future.result()
271
+ # # get the fault frame val/grad for the points
272
+ # determine displacement magnitude, for constant displacement
273
+ # hanging wall should be > 0
274
+ d = np.zeros(gx.shape)
275
+ mask2 = np.logical_and(~np.isnan(gx), ~np.isnan(gy))
276
+ mask2 = np.logical_and(mask2, ~np.isnan(gz))
277
+ d[~mask2] = 0
278
+ gx_mask2 = np.zeros_like(mask2,dtype=bool)
279
+ gx_mask2[mask2] = gx[mask2] > 0
280
+ # d[~np.isnan(gx)][gx[~np.isnan(gx)]>0] = 1
281
+ d[gx_mask2] = 1.
282
+ # d[mask2][gx[mask2] < 0] = 0.
283
+ # d[gx < 0] = 0.
284
+ if self.faultfunction is not None:
285
+ d[mask2] = self.faultfunction(gx[mask2], gy[mask2], gz[mask2])
286
+ d *= self.displacement
287
+ # normalise when length is >0
288
+ g_mag = np.zeros(g.shape[0])
289
+ g_mag[mask2] = np.linalg.norm(g[mask2], axis=1)
290
+ # g_mag = np.linalg.norm(g[mask2], axis=1)
291
+ g[g_mag > 0.] /= g_mag[g_mag > 0, None]
292
+ # multiply displacement vector by the displacement magnitude for
293
+ # step
294
+ g *= (1. / steps) * d[:, None]
295
+
296
+ # apply displacement
297
+ newp[mask, :] += g
298
+ return newp
@@ -0,0 +1,8 @@
1
+ # from .faulted_geological_feature import FaultedGeologicalFeature
2
+ from .geological_feature import GeologicalFeature
3
+ from .lambda_geological_feature import LambdaGeologicalFeature
4
+ from .geological_feature_builder import GeologicalFeatureInterpolator
5
+ from .region_feature import RegionFeature
6
+ from .structural_frame import StructuralFrame
7
+ from .structural_frame_builder import StructuralFrameBuilder
8
+ from .unconformity_feature import UnconformityFeature
@@ -0,0 +1,90 @@
1
+ """
2
+ """
3
+ import logging
4
+
5
+ import numpy as np
6
+
7
+ from LoopStructural.modelling.features.geological_feature import \
8
+ GeologicalFeature
9
+
10
+ from LoopStructural.utils import getLogger
11
+ logger = getLogger(__name__)
12
+
13
+
14
+ class CrossProductGeologicalFeature(GeologicalFeature):
15
+ """[summary]
16
+
17
+ [extended_summary]
18
+
19
+ Parameters
20
+ ----------
21
+ GeologicalFeature : [type]
22
+ [description]
23
+ """
24
+ def __init__(self, name, geological_feature_a, geological_feature_b):
25
+ """
26
+ Create a geological feature for a vector field using the cross
27
+ product between
28
+ two existing features
29
+ Parameters
30
+ ----------
31
+ name: feature name
32
+ geological_feature_a: first feature
33
+ geological_feature_b: second feature
34
+ """
35
+ super().__init__(name, None)
36
+ self.geological_feature_a = geological_feature_a
37
+ self.geological_feature_b = geological_feature_b
38
+ self.value_feature = None
39
+ def evaluate_gradient(self, locations):
40
+ """
41
+ Calculate the gradient of the geological feature by using numpy to
42
+ calculate the cross
43
+ product between the two existing feature gradients.
44
+ This means both features have to be evaluated for the locations
45
+ Parameters
46
+ ----------
47
+ locations
48
+
49
+ Returns
50
+ -------
51
+
52
+ """
53
+ v1 = self.geological_feature_a.evaluate_gradient(locations)
54
+ # v1 /= np.linalg.norm(v1,axis=1)[:,None]
55
+ v2 = self.geological_feature_b.evaluate_gradient(locations)
56
+ # v2 /= np.linalg.norm(v2,axis=1)[:,None]
57
+ return np.cross(v1,v2,
58
+ axisa=1,
59
+ axisb=1)
60
+
61
+ def evaluate_value(self, evaluation_points):
62
+ """
63
+ Return 0 because there is no value for this feature
64
+ Parameters
65
+ ----------
66
+ evaluation_points
67
+
68
+ Returns
69
+ -------
70
+
71
+ """
72
+ values = np.zeros(evaluation_points.shape[0])
73
+ if self.value_feature is not None:
74
+ values[:] = self.value_feature.evaluate_value(evaluation_points)
75
+ return values
76
+
77
+ def mean(self):
78
+ if self.value_feature:
79
+ return self.value_feature.mean()
80
+ return 0.
81
+
82
+ def min(self):
83
+ if self.value_feature:
84
+ return self.value_feature.min()
85
+ return 0.
86
+
87
+ def max(self):
88
+ if self.value_feature:
89
+ return self.value_feature.max()
90
+ return 0.
@@ -0,0 +1,252 @@
1
+ """
2
+ Geological features
3
+ """
4
+ import logging
5
+
6
+ import numpy as np
7
+
8
+ from LoopStructural.utils import getLogger
9
+ logger = getLogger(__name__)
10
+
11
+
12
+ class GeologicalFeature:
13
+ """
14
+ Geological feature is class that is used to represent a geometrical element in a geological
15
+ model. For example foliations, fault planes, fold rotation angles etc.
16
+
17
+ Attributes
18
+ ----------
19
+ name : string
20
+ should be a unique name for the geological feature
21
+ support : a ScalarField
22
+ holds the property values for the feature and links to the
23
+ support geometry
24
+ data : list
25
+ list containing geological data
26
+ region : list
27
+ list of boolean functions defining whether the feature is
28
+ active
29
+ faults : list
30
+ list of FaultSegments that affect this feature
31
+ """
32
+ def __init__(self, name, interpolator, builder=None, data=None, region=None, type=None,
33
+ faults=[], fold = None):
34
+ """Default constructor for geological feature
35
+
36
+ Parameters
37
+ ----------
38
+ name: string
39
+ interpolator : GeologicalInterpolator
40
+ builder : GeologicalFeatureBuilder
41
+ data :
42
+ region :
43
+ type :
44
+ faults : list
45
+
46
+
47
+ """
48
+ self.name = name
49
+ self.interpolator = interpolator
50
+ self.ndim = 1
51
+ self.builder = builder
52
+ self.region = region
53
+ self.regions = []
54
+ self.type = type
55
+ self.faults = faults
56
+ self.faults_enabled = True
57
+ self.fold=fold
58
+ self._attributes = {}
59
+ self._attributes['feature'] = self
60
+ self._attributes['builder'] = self.builder
61
+ self._attributes['faults'] = self.faults
62
+ if region is None:
63
+ self.region = 'everywhere'
64
+ self.model = None
65
+
66
+ def __str__(self):
67
+ return self.name
68
+
69
+ def __getitem__(self,key):
70
+ return self._attributes[key]
71
+
72
+ def __setitem__(self, key, item):
73
+ self._attributes[key] = item
74
+
75
+ def set_model(self, model):
76
+ self.model = model
77
+
78
+ def toggle_faults(self):
79
+ """
80
+ Turn the fault off for a feature
81
+ This function is only really used for debugging or creating methods
82
+ explanation figures
83
+
84
+ Returns
85
+ -------
86
+
87
+ """
88
+ self.faults_enabled = ~self.faults_enabled
89
+
90
+ def add_region(self, region):
91
+ """
92
+ Adds a region where the geological feature is active to the model.
93
+
94
+ Parameters
95
+ ----------
96
+ region : boolean function(x,y,z)
97
+ returns true if inside region, false if outside
98
+ can be passed as a lambda function e.g.
99
+ lambda pos : feature.evaluate_value(pos) > 0
100
+
101
+ Returns
102
+ -------
103
+
104
+ """
105
+ self.regions.append(region)
106
+
107
+ def evaluate_value(self, evaluation_points):
108
+ """
109
+ Evaluate the scalar field value of the geological feature at the locations
110
+ specified
111
+
112
+ Parameters
113
+ ----------
114
+ evaluation_points : numpy array
115
+ location to evaluate the scalar value
116
+
117
+ Returns
118
+ -------
119
+ values : numpy array
120
+ numpy array containing evaluated values
121
+
122
+ """
123
+ #TODO need to add a generic type checker for all methods
124
+ #if evaluation_points is not a numpy array try and convert
125
+ #otherwise error
126
+ self.builder.up_to_date()
127
+ # check if the points are within the display region
128
+ v = np.zeros(evaluation_points.shape[0])
129
+ v[:] = np.nan
130
+ mask = np.zeros(evaluation_points.shape[0]).astype(bool)
131
+ mask[:] = True
132
+ # check regions
133
+ for r in self.regions:
134
+ mask = np.logical_and(mask, r(evaluation_points))
135
+ # apply faulting after working out which regions are visible
136
+ if self.faults_enabled:
137
+ for f in self.faults:
138
+ evaluation_points = f.apply_to_points(evaluation_points)
139
+ v[mask] = self.interpolator.evaluate_value(evaluation_points[mask, :])
140
+ return v
141
+
142
+ def evaluate_gradient(self, evaluation_points):
143
+ """
144
+
145
+ Parameters
146
+ ----------
147
+ locations : numpy array
148
+ location where the gradient is being evaluated
149
+
150
+ Returns
151
+ -------
152
+
153
+ """
154
+ self.builder.up_to_date()
155
+ v = np.zeros(evaluation_points.shape)
156
+ v[:] = np.nan
157
+ mask = np.zeros(evaluation_points.shape[0]).astype(bool)
158
+ mask[:] = True
159
+ # check regions
160
+ for r in self.regions:
161
+ mask = np.logical_and(mask, r(evaluation_points))
162
+
163
+ # apply faulting after working out which regions are visible
164
+ if self.faults_enabled:
165
+ for f in self.faults:
166
+ evaluation_points = f.apply_to_points(evaluation_points)
167
+ v[mask, :] = self.interpolator.evaluate_gradient(evaluation_points)
168
+
169
+ return v
170
+
171
+ def evaluate_gradient_misfit(self):
172
+ """
173
+
174
+ Returns
175
+ -------
176
+ misfit : np.array(N,dtype=double)
177
+ dot product between interpolated gradient and constraints
178
+ """
179
+ self.builder.up_to_date()
180
+ grad = self.interpolator.get_gradient_constraints()
181
+ norm = self.interpolator.get_norm_constraints()
182
+
183
+ dot = []
184
+ if grad.shape[0] > 0:
185
+ grad /=np.linalg.norm(grad,axis=1)[:,None]
186
+ model_grad = self.evaluate_gradient(grad[:,:3])
187
+ dot.append(np.einsum('ij,ij->i',model_grad,grad[:,:3:6]).tolist())
188
+
189
+ if norm.shape[0] > 0:
190
+ norm /=np.linalg.norm(norm,axis=1)[:,None]
191
+ model_norm = self.evaluate_gradient(norm[:, :3])
192
+ dot.append(np.einsum('ij,ij->i', model_norm, norm[:,:3:6]))
193
+
194
+ return np.array(dot)
195
+
196
+ def evaluate_value_misfit(self):
197
+ """
198
+
199
+ Returns
200
+ -------
201
+ misfit : np.array(N,dtype=double)
202
+ difference between interpolated scalar field and value constraints
203
+ """
204
+ self.builder.up_to_date()
205
+
206
+ locations = self.interpolator.get_value_constraints()
207
+ diff = np.abs(locations[:, 3] - self.evaluate_value(locations[:, :3]))
208
+ diff/=(self.max()-self.min())
209
+ return diff
210
+
211
+ def mean(self):
212
+ """
213
+ Calculate average of the support values
214
+
215
+ Returns
216
+ -------
217
+ mean : double
218
+ average value of the feature evaluated on a (10,10,10) grid in model area
219
+
220
+ """
221
+ if self.model is None:
222
+ return 0
223
+ return np.mean(self.evaluate_value(self.model.regular_grid((10,10,10))))
224
+
225
+ def min(self):
226
+ """
227
+
228
+ Returns
229
+ -------
230
+ min : double
231
+ min value of the feature evaluated on a (10,10,10) grid in model area
232
+ """
233
+ if self.model is None:
234
+ return 0
235
+ return np.nanmin(
236
+ self.evaluate_value(self.model.regular_grid((10, 10, 10))))
237
+
238
+ def max(self):
239
+ """
240
+ Calculate average of the support values
241
+
242
+ Returns
243
+ -------
244
+ max : double
245
+ max value of the feature evaluated on a (10,10,10) grid in model area
246
+ """
247
+ if self.model is None:
248
+ return 0
249
+ return np.nanmax(
250
+ self.evaluate_value(self.model.regular_grid((10, 10, 10))))
251
+
252
+