LoopStructural 1.6.13__py3-none-any.whl → 1.6.15__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.
- LoopStructural/datatypes/_bounding_box.py +23 -13
- LoopStructural/datatypes/_point.py +0 -1
- LoopStructural/export/exporters.py +2 -2
- LoopStructural/interpolators/__init__.py +43 -32
- LoopStructural/interpolators/_constant_norm.py +205 -0
- LoopStructural/interpolators/_discrete_interpolator.py +15 -14
- LoopStructural/interpolators/_finite_difference_interpolator.py +27 -21
- LoopStructural/interpolators/_geological_interpolator.py +1 -1
- LoopStructural/interpolators/_interpolatortype.py +22 -0
- LoopStructural/interpolators/_p1interpolator.py +7 -3
- LoopStructural/interpolators/_surfe_wrapper.py +4 -1
- LoopStructural/interpolators/supports/_2d_base_unstructured.py +1 -1
- LoopStructural/interpolators/supports/_2d_structured_grid.py +16 -0
- LoopStructural/interpolators/supports/_3d_base_structured.py +16 -0
- LoopStructural/interpolators/supports/_3d_structured_grid.py +3 -2
- LoopStructural/interpolators/supports/_3d_structured_tetra.py +7 -3
- LoopStructural/modelling/__init__.py +11 -3
- LoopStructural/modelling/core/geological_model.py +187 -234
- LoopStructural/modelling/features/_base_geological_feature.py +38 -2
- LoopStructural/modelling/features/builders/_geological_feature_builder.py +2 -2
- LoopStructural/modelling/features/fault/_fault_function.py +1 -1
- LoopStructural/modelling/intrusions/intrusion_builder.py +1 -1
- LoopStructural/modelling/intrusions/intrusion_frame_builder.py +1 -1
- LoopStructural/utils/__init__.py +1 -0
- LoopStructural/utils/helper.py +1 -24
- LoopStructural/utils/maths.py +74 -17
- LoopStructural/version.py +1 -1
- {loopstructural-1.6.13.dist-info → loopstructural-1.6.15.dist-info}/METADATA +2 -2
- {loopstructural-1.6.13.dist-info → loopstructural-1.6.15.dist-info}/RECORD +32 -30
- {loopstructural-1.6.13.dist-info → loopstructural-1.6.15.dist-info}/WHEEL +1 -1
- {loopstructural-1.6.13.dist-info → loopstructural-1.6.15.dist-info}/licenses/LICENSE +0 -0
- {loopstructural-1.6.13.dist-info → loopstructural-1.6.15.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.
|
|
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.
|
|
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->
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
424
|
+
gi[self.region] = np.arange(0, self.dof)
|
|
425
425
|
idc = np.zeros(node_idx.shape)
|
|
426
426
|
idc[:] = -1
|
|
427
427
|
|
|
@@ -454,22 +454,28 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
|
|
|
454
454
|
)
|
|
455
455
|
self.up_to_date = False
|
|
456
456
|
|
|
457
|
-
def add_regularisation(self, operator, w=0.1):
|
|
458
|
-
"""
|
|
459
457
|
|
|
460
|
-
Parameters
|
|
461
|
-
----------
|
|
462
|
-
operator
|
|
463
|
-
w
|
|
464
458
|
|
|
465
|
-
|
|
466
|
-
|
|
459
|
+
# def assemble_borders(self, operator, w, name='regularisation'):
|
|
460
|
+
# """
|
|
461
|
+
# Adds a constraint to the border of the model to force the value to be equal to the value at the border
|
|
467
462
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
463
|
+
# Parameters
|
|
464
|
+
# ----------
|
|
465
|
+
# operator : Operator
|
|
466
|
+
# operator to use for the regularisation
|
|
467
|
+
# w : double
|
|
468
|
+
# weight of the regularisation
|
|
469
|
+
|
|
470
|
+
# Returns
|
|
471
|
+
# -------
|
|
472
|
+
|
|
473
|
+
# """
|
|
474
|
+
# # First get the global indicies of the pairs of neighbours this should be an
|
|
475
|
+
# # N*27 array for 3d and an N*9 array for 2d
|
|
476
|
+
|
|
477
|
+
# global_indexes = self.support.neighbour_global_indexes()
|
|
471
478
|
|
|
472
|
-
# def assemble_borders(self, operator, w):
|
|
473
479
|
|
|
474
480
|
def assemble_inner(self, operator, w, name='regularisation'):
|
|
475
481
|
"""
|
|
@@ -484,7 +490,7 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
|
|
|
484
490
|
|
|
485
491
|
"""
|
|
486
492
|
# First get the global indicies of the pairs of neighbours this should be an
|
|
487
|
-
#
|
|
493
|
+
# N*27 array for 3d and an N*9 array for 2d
|
|
488
494
|
|
|
489
495
|
global_indexes = self.support.neighbour_global_indexes() # np.array([ii,jj]))
|
|
490
496
|
|
|
@@ -493,7 +499,7 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
|
|
|
493
499
|
|
|
494
500
|
gi = np.zeros(self.support.n_nodes)
|
|
495
501
|
gi[:] = -1
|
|
496
|
-
gi[self.region] = np.arange(0, self.
|
|
502
|
+
gi[self.region] = np.arange(0, self.dof)
|
|
497
503
|
idc = gi[idc]
|
|
498
504
|
inside = ~np.any(idc == -1, axis=1) # np.ones(a.shape[0],dtype=bool)#
|
|
499
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.
|
|
99
|
+
# json["dof"] = self.dof
|
|
100
100
|
json["up_to_date"] = self.up_to_date
|
|
101
101
|
return json
|
|
102
102
|
|
|
@@ -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.
|
|
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]),
|
|
@@ -146,7 +150,7 @@ class P1Interpolator(DiscreteInterpolator):
|
|
|
146
150
|
self.reset()
|
|
147
151
|
for key in kwargs:
|
|
148
152
|
if "regularisation" in kwargs:
|
|
149
|
-
self.interpolation_weights["cgw"] =
|
|
153
|
+
self.interpolation_weights["cgw"] = kwargs["regularisation"]
|
|
150
154
|
self.up_to_date = False
|
|
151
155
|
self.interpolation_weights[key] = kwargs[key]
|
|
152
156
|
if self.interpolation_weights["cgw"] > 0.0:
|
|
@@ -203,5 +203,8 @@ class SurfeRBFInterpolator(GeologicalInterpolator):
|
|
|
203
203
|
return
|
|
204
204
|
|
|
205
205
|
@property
|
|
206
|
-
def
|
|
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.
|
|
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)
|
|
@@ -437,8 +437,9 @@ class StructuredGrid(BaseStructuredSupport):
|
|
|
437
437
|
T[:, 2, 6] = (1 - local_coords[:, 0]) * local_coords[:, 1]
|
|
438
438
|
T[:, 2, 3] = -local_coords[:, 0] * local_coords[:, 1]
|
|
439
439
|
T[:, 2, 7] = local_coords[:, 0] * local_coords[:, 1]
|
|
440
|
-
T /= self.step_vector[0]
|
|
441
|
-
|
|
440
|
+
T[:, 0, :] /= self.step_vector[None, 0]
|
|
441
|
+
T[:, 1, :] /= self.step_vector[None, 1]
|
|
442
|
+
T[:, 2, :] /= self.step_vector[None, 2]
|
|
442
443
|
return vertices, T, elements, inside
|
|
443
444
|
|
|
444
445
|
def get_element_for_location(self, pos: np.ndarray):
|
|
@@ -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
|
-
|
|
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)
|
|
@@ -22,6 +22,14 @@ from ..modelling.input import (
|
|
|
22
22
|
try:
|
|
23
23
|
from ..modelling.input.project_file import LoopProjectfileProcessor
|
|
24
24
|
except (LoopImportError, ImportError):
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
|
|
25
|
+
class LoopProjectfileProcessor(ProcessInputData):
|
|
26
|
+
"""
|
|
27
|
+
Dummy class to handle the case where LoopProjectFile is not installed.
|
|
28
|
+
This will raise a warning when used.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, *args, **kwargs):
|
|
32
|
+
raise LoopImportError(
|
|
33
|
+
"LoopProjectFile cannot be imported. Please install LoopProjectFile."
|
|
34
|
+
)
|
|
35
|
+
|