LoopStructural 1.6.14__py3-none-any.whl → 1.6.16__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 (30) hide show
  1. LoopStructural/__init__.py +30 -12
  2. LoopStructural/datatypes/_bounding_box.py +22 -13
  3. LoopStructural/datatypes/_point.py +0 -1
  4. LoopStructural/export/exporters.py +2 -2
  5. LoopStructural/interpolators/__init__.py +33 -30
  6. LoopStructural/interpolators/_constant_norm.py +205 -0
  7. LoopStructural/interpolators/_discrete_interpolator.py +15 -14
  8. LoopStructural/interpolators/_finite_difference_interpolator.py +10 -10
  9. LoopStructural/interpolators/_geological_interpolator.py +9 -3
  10. LoopStructural/interpolators/_interpolatortype.py +22 -0
  11. LoopStructural/interpolators/_p1interpolator.py +6 -2
  12. LoopStructural/interpolators/_surfe_wrapper.py +4 -1
  13. LoopStructural/interpolators/supports/_2d_base_unstructured.py +1 -1
  14. LoopStructural/interpolators/supports/_2d_structured_grid.py +16 -0
  15. LoopStructural/interpolators/supports/_3d_base_structured.py +16 -0
  16. LoopStructural/interpolators/supports/_3d_structured_tetra.py +7 -3
  17. LoopStructural/modelling/core/geological_model.py +250 -312
  18. LoopStructural/modelling/core/stratigraphic_column.py +473 -0
  19. LoopStructural/modelling/features/_base_geological_feature.py +38 -2
  20. LoopStructural/modelling/features/builders/_fault_builder.py +1 -0
  21. LoopStructural/modelling/features/builders/_geological_feature_builder.py +1 -1
  22. LoopStructural/modelling/features/fault/_fault_segment.py +1 -1
  23. LoopStructural/modelling/intrusions/intrusion_builder.py +1 -1
  24. LoopStructural/modelling/intrusions/intrusion_frame_builder.py +1 -1
  25. LoopStructural/version.py +1 -1
  26. {loopstructural-1.6.14.dist-info → loopstructural-1.6.16.dist-info}/METADATA +2 -2
  27. {loopstructural-1.6.14.dist-info → loopstructural-1.6.16.dist-info}/RECORD +30 -27
  28. {loopstructural-1.6.14.dist-info → loopstructural-1.6.16.dist-info}/WHEEL +0 -0
  29. {loopstructural-1.6.14.dist-info → loopstructural-1.6.16.dist-info}/licenses/LICENSE +0 -0
  30. {loopstructural-1.6.14.dist-info → loopstructural-1.6.16.dist-info}/top_level.txt +0 -0
@@ -160,7 +160,7 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
160
160
  # print(points[inside,:].shape)
161
161
  gi = np.zeros(self.support.n_nodes, dtype=int)
162
162
  gi[:] = -1
163
- gi[self.region] = np.arange(0, self.nx, dtype=int)
163
+ gi[self.region] = np.arange(0, self.dof, dtype=int)
164
164
  idc = np.zeros(node_idx.shape)
165
165
  idc[:] = -1
166
166
  idc[inside, :] = gi[node_idx[inside, :]]
@@ -204,7 +204,7 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
204
204
  )
205
205
  gi = np.zeros(self.support.n_nodes, dtype=int)
206
206
  gi[:] = -1
207
- gi[self.region] = np.arange(0, self.nx, dtype=int)
207
+ gi[self.region] = np.arange(0, self.dof, dtype=int)
208
208
  idc = np.zeros(node_idx.shape).astype(int)
209
209
  idc[:] = -1
210
210
  idc[inside, :] = gi[node_idx[inside, :]]
@@ -227,11 +227,11 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
227
227
  interface_A = np.hstack([A[mask, :][ij[:, 0], :], -A[mask, :][ij[:, 1], :]])
228
228
  interface_idc = np.hstack([idc[mask, :][ij[:, 0], :], idc[mask, :][ij[:, 1], :]])
229
229
  # now map the index from global to region create array size of mesh
230
- # initialise as np.nan, then map points inside region to 0->nx
230
+ # initialise as np.nan, then map points inside region to 0->dof
231
231
  gi = np.zeros(self.support.n_nodes).astype(int)
232
232
  gi[:] = -1
233
233
 
234
- gi[self.region] = np.arange(0, self.nx)
234
+ gi[self.region] = np.arange(0, self.dof)
235
235
  interface_idc = gi[interface_idc]
236
236
  outside = ~np.any(interface_idc == -1, axis=1)
237
237
  self.add_constraints_to_least_squares(
@@ -266,7 +266,7 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
266
266
  # magnitude
267
267
  gi = np.zeros(self.support.n_nodes)
268
268
  gi[:] = -1
269
- gi[self.region] = np.arange(0, self.nx)
269
+ gi[self.region] = np.arange(0, self.dof)
270
270
  idc = np.zeros(node_idx.shape)
271
271
  idc[:] = -1
272
272
  idc[inside, :] = gi[node_idx[inside, :]]
@@ -331,7 +331,7 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
331
331
  )
332
332
  gi = np.zeros(self.support.n_nodes)
333
333
  gi[:] = -1
334
- gi[self.region] = np.arange(0, self.nx)
334
+ gi[self.region] = np.arange(0, self.dof)
335
335
  idc = np.zeros(node_idx.shape)
336
336
  idc[:] = -1
337
337
  idc[inside, :] = gi[node_idx[inside, :]]
@@ -421,7 +421,7 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
421
421
  # magnitude
422
422
  gi = np.zeros(self.support.n_nodes)
423
423
  gi[:] = -1
424
- gi[self.region] = np.arange(0, self.nx)
424
+ gi[self.region] = np.arange(0, self.dof)
425
425
  idc = np.zeros(node_idx.shape)
426
426
  idc[:] = -1
427
427
 
@@ -472,7 +472,7 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
472
472
 
473
473
  # """
474
474
  # # First get the global indicies of the pairs of neighbours this should be an
475
- # # Nx27 array for 3d and an Nx9 array for 2d
475
+ # # N*27 array for 3d and an N*9 array for 2d
476
476
 
477
477
  # global_indexes = self.support.neighbour_global_indexes()
478
478
 
@@ -490,7 +490,7 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
490
490
 
491
491
  """
492
492
  # First get the global indicies of the pairs of neighbours this should be an
493
- # Nx27 array for 3d and an Nx9 array for 2d
493
+ # N*27 array for 3d and an N*9 array for 2d
494
494
 
495
495
  global_indexes = self.support.neighbour_global_indexes() # np.array([ii,jj]))
496
496
 
@@ -499,7 +499,7 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
499
499
 
500
500
  gi = np.zeros(self.support.n_nodes)
501
501
  gi[:] = -1
502
- gi[self.region] = np.arange(0, self.nx)
502
+ gi[self.region] = np.arange(0, self.dof)
503
503
  idc = gi[idc]
504
504
  inside = ~np.any(idc == -1, axis=1) # np.ones(a.shape[0],dtype=bool)#
505
505
  # a[idc==-1] = 0
@@ -96,7 +96,7 @@ class GeologicalInterpolator(metaclass=ABCMeta):
96
96
  json["constraints"] = self.constraints
97
97
  json["data"] = self.data
98
98
  json["type"] = self.type
99
- # json["dof"] = self.nx
99
+ # json["dof"] = self.dof
100
100
  json["up_to_date"] = self.up_to_date
101
101
  return json
102
102
 
@@ -154,16 +154,22 @@ class GeologicalInterpolator(metaclass=ABCMeta):
154
154
  ----------
155
155
  points : np.ndarray
156
156
  array containing the value constraints usually 7-8 columns.
157
- X,Y,Z,nx,ny,nz,weight
157
+ X,Y,Z,nx,ny,nz,(weight, default : 1 for each row)
158
158
 
159
159
  Returns
160
160
  -------
161
161
 
162
+ Notes
163
+ -------
164
+ If no weights are provided, w = 1 is assigned to each normal constraint.
165
+
162
166
  """
163
167
  if points.shape[1] == self.dimensions * 2:
164
168
  points = np.hstack([points, np.ones((points.shape[0], 1))])
169
+ logger.warning(f"No weight provided for normal constraints, all weights are set to 1")
170
+ raise Warning
165
171
  if points.shape[1] < self.dimensions * 2 + 1:
166
- raise ValueError("Nonrmal constraints must at least have X,Y,Z,nx,ny,nz")
172
+ raise ValueError("Normal constraints must at least have X,Y,Z,nx,ny,nz")
167
173
  self.n_n = points.shape[0]
168
174
  self.data["normal"] = points
169
175
  self.up_to_date = False
@@ -0,0 +1,22 @@
1
+ from enum import Enum
2
+
3
+ class InterpolatorType(Enum):
4
+ """
5
+ Enum for the different interpolator types
6
+
7
+ Each value is a unique identifier.
8
+ """
9
+
10
+ BASE = "BASE"
11
+ BASE_DISCRETE = "BASE_DISCRETE"
12
+ FINITE_DIFFERENCE = "FINITE_DIFFERENCE"
13
+ DISCRETE_FOLD = "DISCRETE_FOLD"
14
+ PIECEWISE_LINEAR = "PIECEWISE_LINEAR"
15
+ PIECEWISE_QUADRATIC = "PIECEWISE_QUADRATIC"
16
+ BASE_DATA_SUPPORTED = "BASE_DATA_SUPPORTED"
17
+ SURFE = "SURFE"
18
+ PIECEWISE_LINEAR_CONSTANT_NORM = "PIECEWISE_LINEAR_CONSTANT_NORM"
19
+ FINITE_DIFFERENCE_CONSTANT_NORM = "FINITE_DIFFERENCE_CONSTANT_NORM"
20
+
21
+
22
+
@@ -45,7 +45,7 @@ class P1Interpolator(DiscreteInterpolator):
45
45
  points = self.get_norm_constraints()
46
46
  if points.shape[0] > 0:
47
47
  grad, elements, inside = self.support.evaluate_shape_derivatives(points[:, :3])
48
- size = self.support.element_size[elements[inside]]
48
+ size = self.support.element_scale[elements[inside]]
49
49
  wt = np.ones(size.shape[0])
50
50
  wt *= w # s* size
51
51
  elements = np.tile(self.support.elements[elements[inside]], (3, 1, 1))
@@ -70,6 +70,7 @@ class P1Interpolator(DiscreteInterpolator):
70
70
  if points.shape[0] > 1:
71
71
  N, elements, inside = self.support.evaluate_shape(points[:, :3])
72
72
  size = self.support.element_size[elements[inside]]
73
+
73
74
  wt = np.ones(size.shape[0])
74
75
  wt *= w # * size
75
76
  self.add_constraints_to_least_squares(
@@ -110,13 +111,16 @@ class P1Interpolator(DiscreteInterpolator):
110
111
  const_n = -np.einsum("ij,ijk->ik", norm, Dn)
111
112
  # const_t_cp2 = np.einsum('ij,ikj->ik',normal,cp2_Dt)
112
113
  # const_n_cp2 = -np.einsum('ij,ikj->ik',normal,cp2_Dn)
113
-
114
+ # shared_element_size = self.support.shared_element_size
115
+ # const_t /= shared_element_size[:, None] # normalise by element size
116
+ # const_n /= shared_element_size[:, None] # normalise by element size
114
117
  const = np.hstack([const_t, const_n])
115
118
 
116
119
  # get vertex indexes
117
120
  tri_cp1 = np.hstack([self.support.elements[tri1], self.support.elements[tri2]])
118
121
  # tri_cp2 = np.hstack([self.support.elements[cp2_tri1],self.support.elements[tri2]])
119
122
  # add cp1 and cp2 to the least squares system
123
+
120
124
  self.add_constraints_to_least_squares(
121
125
  const,
122
126
  np.zeros(const.shape[0]),
@@ -203,5 +203,8 @@ class SurfeRBFInterpolator(GeologicalInterpolator):
203
203
  return
204
204
 
205
205
  @property
206
- def nx(self):
206
+ def dof(self):
207
207
  return self.get_data_locations().shape[0]
208
+ @property
209
+ def n_elements(self)->int:
210
+ return self.get_data_locations().shape[0]
@@ -30,7 +30,7 @@ class BaseUnstructured2d(BaseSupport):
30
30
  self.order = 1
31
31
  elif self.elements.shape[1] == 6:
32
32
  self.order = 2
33
- self.nx = self.vertices.shape[0]
33
+ self.dof = self.vertices.shape[0]
34
34
  self.neighbours = neighbours
35
35
  self.minimum = np.min(self.nodes, axis=0)
36
36
  self.maximum = np.max(self.nodes, axis=0)
@@ -372,6 +372,22 @@ class StructuredGrid2D(BaseSupport):
372
372
  return xy
373
373
 
374
374
  def position_to_cell_corners(self, pos):
375
+ """Get the global indices of the vertices (corner) nodes of the cell containing each point.
376
+
377
+ Parameters
378
+ ----------
379
+ pos : np.array
380
+ (N, 2) array of xy coordinates representing the positions of N points.
381
+
382
+ Returns
383
+ -------
384
+ globalidx : np.array
385
+ (N, 4) array of global indices corresponding to the 4 corner nodes of the cell
386
+ each point lies in. If a point lies outside the support, its corresponding entry
387
+ will be set to -1.
388
+ inside : np.array
389
+ (N,) boolean array indicating whether each point is inside the support domain.
390
+ """
375
391
  corner_index, inside = self.position_to_cell_index(pos)
376
392
  corners = self.cell_corner_indexes(corner_index)
377
393
  globalidx = self.global_node_indices(corners)
@@ -373,6 +373,22 @@ class BaseStructuredSupport(BaseSupport):
373
373
  return corner_indexes
374
374
 
375
375
  def position_to_cell_corners(self, pos):
376
+ """Get the global indices of the vertices (corners) of the cell containing each point.
377
+
378
+ Parameters
379
+ ----------
380
+ pos : np.array
381
+ (N, 3) array of xyz coordinates representing the positions of N points.
382
+
383
+ Returns
384
+ -------
385
+ globalidx : np.array
386
+ (N, 8) array of global indices corresponding to the 8 corner nodes of the cell
387
+ each point lies in. If a point lies outside the support, its corresponding entry
388
+ will be set to -1.
389
+ inside : np.array
390
+ (N,) boolean array indicating whether each point is inside the support domain.
391
+ """
376
392
  cell_indexes, inside = self.position_to_cell_index(pos)
377
393
  corner_indexes = self.cell_corner_indexes(cell_indexes)
378
394
  globalidx = self.global_node_indices(corner_indexes)
@@ -85,10 +85,14 @@ class TetMesh(BaseStructuredSupport):
85
85
  )
86
86
 
87
87
  return np.abs(np.linalg.det(vecs)) / 6
88
-
88
+
89
89
  @property
90
90
  def element_scale(self):
91
- return self.element_size / np.mean(self.element_size)
91
+ size = self.element_size
92
+ size-= np.min(size)
93
+ size/= np.max(size)
94
+ size+=1.
95
+ return size
92
96
 
93
97
  @property
94
98
  def barycentre(self) -> np.ndarray:
@@ -189,7 +193,7 @@ class TetMesh(BaseStructuredSupport):
189
193
  """
190
194
  norm = self.shared_element_norm
191
195
  return 0.5 * np.linalg.norm(norm, axis=1)
192
-
196
+
193
197
  @property
194
198
  def shared_element_scale(self):
195
199
  return self.shared_element_size / np.mean(self.shared_element_size)