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,437 @@
1
+ """
2
+ Piecewise linear interpolator
3
+ """
4
+ import logging
5
+
6
+ import numpy as np
7
+
8
+ from LoopStructural.interpolators.discrete_interpolator import \
9
+ DiscreteInterpolator
10
+ from LoopStructural.utils.helper import get_vectors
11
+
12
+ from LoopStructural.utils import getLogger
13
+ logger = getLogger(__name__)
14
+
15
+
16
+ class PiecewiseLinearInterpolator(DiscreteInterpolator):
17
+ """
18
+
19
+ """
20
+ def __init__(self, mesh):
21
+ """
22
+ Piecewise Linear Interpolator
23
+ Approximates scalar field by finding coefficients to a piecewise linear
24
+ equation on a tetrahedral mesh. Uses constant gradient regularisation.
25
+
26
+ Parameters
27
+ ----------
28
+ mesh - TetMesh
29
+ interpolation support
30
+ """
31
+
32
+ self.shape = 'rectangular'
33
+ DiscreteInterpolator.__init__(self, mesh)
34
+ # whether to assemble a rectangular matrix or a square matrix
35
+ self.interpolator_type = 'PLI'
36
+ self.support = mesh
37
+
38
+ self.interpolation_weights = {'cgw': 0.1, 'cpw': 1., 'npw': 1.,
39
+ 'gpw': 1., 'tpw': 1., 'ipw': 1.}
40
+ self.__str = 'Piecewise Linear Interpolator with %i unknowns. \n' % \
41
+ self.nx
42
+
43
+ def __str__(self):
44
+ return self.__str
45
+
46
+ def copy(self):
47
+ return PiecewiseLinearInterpolator(self.support)
48
+
49
+ def _setup_interpolator(self, **kwargs):
50
+ """
51
+ Searches through kwargs for any interpolation weights and updates
52
+ the dictionary.
53
+ Then adds the constraints to the linear system using the
54
+ interpolation weights values
55
+ Parameters
56
+ ----------
57
+ kwargs -
58
+ interpolation weights
59
+
60
+ Returns
61
+ -------
62
+
63
+ """
64
+ # can't reset here, clears fold constraints
65
+ # self.reset()
66
+ logger.info("Setting up PLI interpolator for %s"%self.propertyname)
67
+ for key in kwargs:
68
+ if 'regularisation' in kwargs:
69
+ self.interpolation_weights['cgw'] = 0.1 * kwargs[
70
+ 'regularisation']
71
+ self.up_to_date = False
72
+ self.interpolation_weights[key] = kwargs[key]
73
+ if self.interpolation_weights['cgw'] > 0.:
74
+ self.up_to_date = False
75
+ self.add_constant_gradient(self.interpolation_weights['cgw'],
76
+ direction_feature=kwargs.get('direction_feature',None),
77
+ direction_vector=kwargs.get('direction_vector',None)
78
+ )
79
+ logger.info("Using constant gradient regularisation w = %f"
80
+ %self.interpolation_weights['cgw'])
81
+ logger.info("Added %i gradient constraints, %i normal constraints,"
82
+ "%i tangent constraints and %i value constraints"
83
+ "to %s" % (self.n_g, self.n_n,
84
+ self.n_t, self.n_i, self.propertyname))
85
+ self.add_gradient_ctr_pts(self.interpolation_weights['gpw'])
86
+ self.add_norm_ctr_pts(self.interpolation_weights['npw'])
87
+ self.add_ctr_pts(self.interpolation_weights['cpw'])
88
+ self.add_tangent_ctr_pts(self.interpolation_weights['tpw'])
89
+ self.add_interface_ctr_pts(self.interpolation_weights['ipw'])
90
+ if 'constant_norm' in kwargs:
91
+ self.add_constant_norm(w=kwargs['constant_norm'])
92
+
93
+ def add_constant_gradient(self, w= 0.1, direction_vector=None, direction_feature=None):
94
+ """
95
+ Add the constant gradient regularisation to the system
96
+
97
+ Parameters
98
+ ----------
99
+ w (double) - weighting of the cg parameter
100
+
101
+ Returns
102
+ -------
103
+
104
+ """
105
+ if direction_feature is not None:
106
+ print('dir fe')
107
+ direction_vector = direction_feature.evaluate_gradient(self.support.barycentre())
108
+ if direction_vector is not None:
109
+ if direction_vector.shape[0] == 1:
110
+ # if using a constant direction, tile array so it works for cg calc
111
+ direction_vector = np.tile(direction_vector,(self.support.barycentre().shape[0],1))
112
+
113
+
114
+ # iterate over all elements
115
+ A, idc, B = self.support.get_constant_gradient(region=self.region,direction=direction_vector)
116
+ A = np.array(A)
117
+ B = np.array(B)
118
+ idc = np.array(idc)
119
+
120
+ gi = np.zeros(self.support.n_nodes)
121
+ gi[:] = -1
122
+ gi[self.region] = np.arange(0, self.nx)
123
+ idc = gi[idc]
124
+ outside = ~np.any(idc == -1, axis=1)
125
+
126
+ # w/=A.shape[0]
127
+ self.add_constraints_to_least_squares(A[outside, :] * w,
128
+ B[outside] * w, idc[outside, :],
129
+ name='regularisation')
130
+ return
131
+
132
+ def add_direction_constant_gradient(self, w= 0.1, direction_vector=None, direction_feature=None):
133
+ """
134
+ Add the constant gradient regularisation to the system where regularisation is projected
135
+ on a vector
136
+
137
+ Parameters
138
+ ----------
139
+ w (double) - weighting of the cg parameter
140
+ direction_vector
141
+ direction_feature
142
+
143
+ Returns
144
+ -------
145
+
146
+ """
147
+ if direction_feature:
148
+ print('dir fe')
149
+ direction_vector = direction_feature.evaluate_gradient(self.support.barycentre())
150
+ if direction_vector:
151
+ if direction_vector.shape[0] == 1:
152
+ # if using a constant direction, tile array so it works for cg calc
153
+ direction_vector = np.tile(direction_vector,(self.support.barycentre().shape[0],1))
154
+
155
+
156
+ # iterate over all elements
157
+ A, idc, B = self.support.get_constant_gradient(region=self.region,direction=direction_vector)
158
+ A = np.array(A)
159
+ B = np.array(B)
160
+ idc = np.array(idc)
161
+
162
+ gi = np.zeros(self.support.n_nodes)
163
+ gi[:] = -1
164
+ gi[self.region] = np.arange(0, self.nx)
165
+ idc = gi[idc]
166
+ outside = ~np.any(idc == -1, axis=1)
167
+
168
+ # w/=A.shape[0]
169
+ self.add_constraints_to_least_squares(A[outside, :] * w,
170
+ B[outside] * w, idc[outside, :],
171
+ name='directional regularisation')
172
+ return
173
+
174
+
175
+ def add_constant_norm(self, w=0.1):
176
+ """
177
+ Add the constant gradient regularisation to the system
178
+
179
+ Parameters
180
+ ----------
181
+ w (double) - weighting of the cg parameter
182
+
183
+ Returns
184
+ -------
185
+
186
+ """
187
+ # iterate over all elements
188
+ A, idc, B = self.support.get_constant_norm(region=self.region)
189
+ A = np.array(A)
190
+ B = np.array(B)
191
+ idc = np.array(idc)
192
+
193
+ gi = np.zeros(self.support.n_nodes)
194
+ gi[:] = -1
195
+ gi[self.region] = np.arange(0, self.nx)
196
+ idc = gi[idc]
197
+ outside = ~np.any(idc == -1, axis=1)
198
+
199
+ # w/=A.shape[0]
200
+ self.add_constraints_to_least_squares(A[outside, :] * w,
201
+ B[outside] * w, idc[outside, :],
202
+ name='norm_regularisation')
203
+ return
204
+
205
+ def add_gradient_ctr_pts(self, w=1.0):
206
+ """
207
+ Adds gradient constraints to the least squares system with a weight
208
+ defined by w
209
+ Parameters
210
+ ----------
211
+ w : either numpy array of length number of
212
+
213
+ Returns
214
+ -------
215
+ Notes
216
+ -----
217
+ Gradient constraints add a constraint that the gradient of the
218
+ implicit function should
219
+ be orthogonal to the strike vector and the dip vector defined by the
220
+ normal.
221
+ This does not control the direction of the gradient and therefore
222
+ requires at least two other
223
+ value constraints OR a norm constraint for the interpolant to solve.
224
+ """
225
+
226
+ points = self.get_gradient_constraints()
227
+ if points.shape[0] > 0:
228
+ vertices, element_gradients, tetras, inside = self.support.get_tetra_gradient_for_location(points[:,:3])
229
+ #e, inside = self.support.elements_for_array(points[:, :3])
230
+ #nodes = self.support.nodes[self.support.elements[e]]
231
+ vecs = vertices[:, 1:, :] - vertices[:, 0, None, :]
232
+ vol = np.abs(np.linalg.det(vecs)) # / 6
233
+ # d_t = self.support.get_elements_gradients(e)
234
+ norm = np.linalg.norm(element_gradients, axis=2)
235
+ element_gradients /= norm[:, :, None]
236
+ # d_t *= vol[:,None,None]
237
+ strike_vector, dip_vector = get_vectors(points[:, 3:6])
238
+ A = np.einsum('ji,ijk->ik', strike_vector, element_gradients)
239
+
240
+ A *= vol[:, None]
241
+
242
+ gi = np.zeros(self.support.n_nodes).astype(int)
243
+ gi[:] = -1
244
+ gi[self.region] = np.arange(0, self.nx).astype(int)
245
+ w /= 3
246
+ idc = gi[tetras]
247
+ B = np.zeros(idc.shape[0])
248
+ outside = ~np.any(idc == -1, axis=1)
249
+ self.add_constraints_to_least_squares(A[outside, :] * w,
250
+ B[outside], idc[outside, :],
251
+ name = 'gradient')
252
+ A = np.einsum('ji,ijk->ik', dip_vector, element_gradients)
253
+ A *= vol[:, None]
254
+ # A+=A2
255
+ self.add_constraints_to_least_squares(A[outside, :] * w,
256
+ B[outside], idc[outside, :],
257
+ name='gradient')
258
+
259
+ def add_norm_ctr_pts(self, w=1.0):
260
+ """
261
+ Extracts the norm vectors from the interpolators p_n list and adds
262
+ these to the implicit
263
+ system
264
+
265
+ Parameters
266
+ ----------
267
+ w : double
268
+ weighting of the norm constraints in a least squares system
269
+
270
+ Returns
271
+ -------
272
+ Notes
273
+ -----
274
+ Controls the direction and magnitude of the norm of the scalar field
275
+ gradient.
276
+ This constraint can conflict with value constraints if the magnitude
277
+ of the vector doesn't
278
+ match with the value constraints added to the implicit system.
279
+ """
280
+
281
+ points = self.get_norm_constraints()
282
+ if points.shape[0] > 0:
283
+ vertices, element_gradients, tetras, inside = self.support.get_tetra_gradient_for_location(points[:, :3])
284
+ # e, inside = self.support.elements_for_array(points[:, :3])
285
+ # nodes = self.support.nodes[self.support.elements[e]]
286
+ vol = np.zeros(element_gradients.shape[0])
287
+ vecs = vertices[:, 1:, :] - vertices[:, 0, None, :]
288
+ vol = np.abs(np.linalg.det(vecs)) # / 6
289
+ # d_t = self.support.get_elements_gradients(e)
290
+ norm = np.zeros((element_gradients.shape[0],element_gradients.shape[1]))
291
+ norm[inside,:] = np.linalg.norm(element_gradients[inside,:,:], axis=2)
292
+ element_gradients /= norm[:, :, None]
293
+
294
+ d_t = element_gradients
295
+ d_t[inside,:,:] *= vol[inside, None, None]
296
+ # add in the element gradient matrix into the inte
297
+ idc = np.tile(tetras[:,:], (3, 1, 1))
298
+ idc = idc.swapaxes(0,1)
299
+ # idc = self.support.elements[e]
300
+ gi = np.zeros(self.support.n_nodes).astype(int)
301
+ gi[:] = -1
302
+ gi[self.region] = np.arange(0, self.nx).astype(int)
303
+ w /= 3
304
+ idc = gi[idc]
305
+ outside = ~np.any(idc == -1, axis=2)
306
+ outside = outside[:, 0]
307
+ w /= 3
308
+
309
+ self.add_constraints_to_least_squares(d_t[outside, :, :] * w,
310
+ points[outside, 3:6] * w *
311
+ vol[outside, None],
312
+ idc[outside],
313
+ name='norm')
314
+
315
+ def add_ctr_pts(self, w=1.0): # for now weight all value points the same
316
+ """
317
+ Adds value constraints to the least squares system
318
+
319
+ Parameters
320
+ ----------
321
+ w : double
322
+ weight
323
+
324
+ Returns
325
+ -------
326
+
327
+ """
328
+
329
+ # get elements for points
330
+ points = self.get_value_constraints()
331
+ if points.shape[0] > 1:
332
+ vertices, c, tetras, inside = self.support.get_tetra_for_location(points[:,:3])
333
+ # calculate volume of tetras
334
+ vecs = vertices[inside, 1:, :] - vertices[inside, 0, None, :]
335
+ vol = np.abs(np.linalg.det(vecs)) / 6
336
+ A = c[inside]
337
+ A *= vol[:,None]
338
+ idc = tetras[inside,:]
339
+ # now map the index from global to region create array size of mesh
340
+ # initialise as np.nan, then map points inside region to 0->nx
341
+ gi = np.zeros(self.support.n_nodes).astype(int)
342
+ gi[:] = -1
343
+
344
+ gi[self.region] = np.arange(0, self.nx)
345
+ idc = gi[idc]
346
+ outside = ~np.any(idc == -1, axis=1)
347
+ self.add_constraints_to_least_squares(A[outside,:] * w,
348
+ points[inside,:][outside, 3] * w * vol[outside],
349
+ idc[outside, :], name='value')
350
+
351
+ def add_interface_ctr_pts(self, w=1.0): # for now weight all value points the same
352
+ """
353
+ Adds a constraint that defines all points with the same 'id' to be the same value
354
+ Sets all P1-P2 = 0 for all pairs of points
355
+
356
+ Parameters
357
+ ----------
358
+ w : double
359
+ weight
360
+
361
+ Returns
362
+ -------
363
+
364
+ """
365
+
366
+ # get elements for points
367
+ points = self.get_interface_constraints()
368
+ if points.shape[0] > 1:
369
+ vertices, c, tetras, inside = self.support.get_tetra_for_location(points[:,:3])
370
+ # calculate volume of tetras
371
+ vecs = vertices[inside, 1:, :] - vertices[inside, 0, None, :]
372
+ vol = np.abs(np.linalg.det(vecs)) / 6
373
+ A = c[inside]
374
+ A *= vol[:,None]
375
+ idc = tetras[inside,:]
376
+ for id in np.unique(points[np.logical_and(~np.isnan(points[:,3]),inside),3]):
377
+ mask = points[inside,3] == id
378
+ interface_A = A[None,mask,:] - A[mask,None,:]
379
+ interface_A = np.sum(interface_A,axis=0)
380
+ # interface_A = interface_A.reshape((interface_A.shape[0]*interface_A.shape[0],A.shape[1]))
381
+ interface_idc = idc[mask,:]
382
+
383
+ # now map the index from global to region create array size of mesh
384
+ # initialise as np.nan, then map points inside region to 0->nx
385
+ gi = np.zeros(self.support.n_nodes).astype(int)
386
+ gi[:] = -1
387
+
388
+ gi[self.region] = np.arange(0, self.nx)
389
+ interface_idc = gi[interface_idc]
390
+ # interface_idc = np.tile(interface_idc,(interface_idc.shape[0],1)).reshape(interface_A.shape)#flatten()
391
+ outside = ~np.any(interface_idc == -1, axis=1)
392
+ self.add_constraints_to_least_squares(interface_A[outside,:] * w,
393
+ np.zeros(interface_A[outside,:].shape[0]),
394
+ interface_idc[outside, :], name='interface')
395
+
396
+ def add_gradient_orthogonal_constraint(self, points, vector, w=1.0,
397
+ B=0):
398
+ """
399
+ constraints scalar field to be orthogonal to a given vector
400
+
401
+ Parameters
402
+ ----------
403
+ position
404
+ normals
405
+ w
406
+ B
407
+
408
+ Returns
409
+ -------
410
+
411
+ """
412
+ if points.shape[0] > 0:
413
+ vertices, element_gradients, tetras, inside = self.support.get_tetra_gradient_for_location(points[:,:3])
414
+ #e, inside = self.support.elements_for_array(points[:, :3])
415
+ #nodes = self.support.nodes[self.support.elements[e]]
416
+ vector /= np.linalg.norm(vector,axis=1)[:,None]
417
+ vecs = vertices[:, 1:, :] - vertices[:, 0, None, :]
418
+ vol = np.abs(np.linalg.det(vecs)) # / 6
419
+ # d_t = self.support.get_elements_gradients(e)
420
+ norm = np.linalg.norm(element_gradients, axis=2)
421
+ element_gradients /= norm[:, :, None]
422
+
423
+ A = np.einsum('ij,ijk->ik', vector, element_gradients)
424
+
425
+ A *= vol[:, None]
426
+
427
+ gi = np.zeros(self.support.n_nodes).astype(int)
428
+ gi[:] = -1
429
+ gi[self.region] = np.arange(0, self.nx).astype(int)
430
+ w /= 3
431
+ idc = gi[tetras]
432
+ B = np.zeros(idc.shape[0])+B
433
+ outside = ~np.any(idc == -1, axis=1)
434
+ self.add_constraints_to_least_squares(A[outside, :] * w,
435
+ B[outside], idc[outside, :], name='gradient_orthogonal')
436
+
437
+