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,77 @@
1
+ import numpy as np
2
+ from scipy import sparse
3
+
4
+
5
+ def _initialise_aabb(grid):
6
+ """assigns the tetras to the grid cells where the bounding box
7
+ of the tetra element overlaps the grid cell.
8
+ It could be changed to use the separating axis theorem, however this would require
9
+ significantly more calculations. (12 more I think).. #TODO test timing
10
+ """
11
+ # calculate the bounding box for all tetraherdon in the mesh
12
+ # find the min/max extents for xyz
13
+ # tetra_bb = np.zeros((grid.elements.shape[0], 19, 3))
14
+ minx = np.min(grid.nodes[grid.elements[:, :4], 0], axis=1)
15
+ maxx = np.max(grid.nodes[grid.elements[:, :4], 0], axis=1)
16
+ miny = np.min(grid.nodes[grid.elements[:, :4], 1], axis=1)
17
+ maxy = np.max(grid.nodes[grid.elements[:, :4], 1], axis=1)
18
+
19
+ cell_indexes = grid.aabb_grid.global_index_to_cell_index(np.arange(grid.aabb_grid.n_elements))
20
+ corners = grid.aabb_grid.cell_corner_indexes(cell_indexes)
21
+ positions = grid.aabb_grid.node_indexes_to_position(corners)
22
+ ## Because we known the node orders just select min/max from each
23
+ # coordinate. Use these to check whether the tetra is in the cell
24
+ x_boundary = positions[:, [0, 1], 0]
25
+ y_boundary = positions[:, [0, 2], 1]
26
+ a = np.logical_and(
27
+ minx[None, :] > x_boundary[:, None, 0],
28
+ minx[None, :] < x_boundary[:, None, 1],
29
+ ) # min point between cell
30
+ b = np.logical_and(
31
+ maxx[None, :] < x_boundary[:, None, 1],
32
+ maxx[None, :] > x_boundary[:, None, 0],
33
+ ) # max point between cell
34
+ c = np.logical_and(
35
+ minx[None, :] < x_boundary[:, None, 0],
36
+ maxx[None, :] > x_boundary[:, None, 0],
37
+ ) # min point < than cell & max point > cell
38
+
39
+ x_logic = np.logical_or(np.logical_or(a, b), c)
40
+
41
+ a = np.logical_and(
42
+ miny[None, :] > y_boundary[:, None, 0],
43
+ miny[None, :] < y_boundary[:, None, 1],
44
+ ) # min point between cell
45
+ b = np.logical_and(
46
+ maxy[None, :] < y_boundary[:, None, 1],
47
+ maxy[None, :] > y_boundary[:, None, 0],
48
+ ) # max point between cell
49
+ c = np.logical_and(
50
+ miny[None, :] < y_boundary[:, None, 0],
51
+ maxy[None, :] > y_boundary[:, None, 0],
52
+ ) # min point < than cell & max point > cell
53
+
54
+ y_logic = np.logical_or(np.logical_or(a, b), c)
55
+ logic = np.logical_and(x_logic, y_logic)
56
+
57
+ if grid.dimension == 3:
58
+ z_boundary = positions[:, [0, 6], 2]
59
+ minz = np.min(grid.nodes[grid.elements[:, :4], 2], axis=1)
60
+ maxz = np.max(grid.nodes[grid.elements[:, :4], 2], axis=1)
61
+ a = np.logical_and(
62
+ minz[None, :] > z_boundary[:, None, 0],
63
+ minz[None, :] < z_boundary[:, None, 1],
64
+ ) # min point between cell
65
+ b = np.logical_and(
66
+ maxz[None, :] < z_boundary[:, None, 1],
67
+ maxz[None, :] > z_boundary[:, None, 0],
68
+ ) # max point between cell
69
+ c = np.logical_and(
70
+ minz[None, :] < z_boundary[:, None, 0],
71
+ maxz[None, :] > z_boundary[:, None, 0],
72
+ ) # min point < than cell & max point > cell
73
+
74
+ z_logic = np.logical_or(np.logical_or(a, b), c)
75
+ logic = np.logical_and(logic, z_logic)
76
+
77
+ grid._aabb_table = sparse.csr_matrix(logic)
@@ -0,0 +1,114 @@
1
+ from abc import ABCMeta, abstractmethod
2
+ import numpy as np
3
+ from typing import Tuple
4
+
5
+
6
+ class BaseSupport(metaclass=ABCMeta):
7
+ """
8
+ Base support class
9
+ """
10
+
11
+ @abstractmethod
12
+ def __init__(self):
13
+ """
14
+ This class is the base
15
+ """
16
+
17
+ @abstractmethod
18
+ def evaluate_value(self, evaluation_points: np.ndarray, property_array: np.ndarray):
19
+ """
20
+ Evaluate the value of the support at the evaluation points
21
+ """
22
+ pass
23
+
24
+ @abstractmethod
25
+ def evaluate_gradient(self, evaluation_points: np.ndarray, property_array: np.ndarray):
26
+ """
27
+ Evaluate the gradient of the support at the evaluation points
28
+ """
29
+ pass
30
+
31
+ @abstractmethod
32
+ def inside(self, pos):
33
+ """
34
+ Check if a position is inside the support
35
+ """
36
+ pass
37
+
38
+ @abstractmethod
39
+ def onGeometryChange(self):
40
+ """
41
+ Called when the geometry changes
42
+ """
43
+ pass
44
+
45
+ @abstractmethod
46
+ def get_element_for_location(
47
+ self, pos: np.ndarray
48
+ ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
49
+ """
50
+ Get the element for a location
51
+ """
52
+ pass
53
+
54
+ @abstractmethod
55
+ def get_element_gradient_for_location(
56
+ self, pos: np.ndarray
57
+ ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
58
+ pass
59
+
60
+ @property
61
+ @abstractmethod
62
+ def elements(self):
63
+ """
64
+ Return the elements
65
+ """
66
+ pass
67
+
68
+ @property
69
+ @abstractmethod
70
+ def n_elements(self):
71
+ """
72
+ Return the number of elements
73
+ """
74
+ pass
75
+
76
+ @property
77
+ @abstractmethod
78
+ def n_nodes(self):
79
+ """
80
+ Return the number of points
81
+ """
82
+ pass
83
+
84
+ @property
85
+ @abstractmethod
86
+ def nodes(self):
87
+ """
88
+ Return the nodes
89
+ """
90
+ pass
91
+
92
+ @property
93
+ @abstractmethod
94
+ def barycentre(self):
95
+ """
96
+ Return the number of dimensions
97
+ """
98
+ pass
99
+
100
+ @property
101
+ @abstractmethod
102
+ def dimension(self):
103
+ """
104
+ Return the number of dimensions
105
+ """
106
+ pass
107
+
108
+ @property
109
+ @abstractmethod
110
+ def element_size(self):
111
+ """
112
+ Return the element size
113
+ """
114
+ pass
@@ -0,0 +1,70 @@
1
+ import numpy as np
2
+ from scipy import sparse
3
+
4
+
5
+ def _init_face_table(grid):
6
+ """
7
+ Fill table containing elements that share a face, and another
8
+ table that contains the nodes for a face.
9
+ """
10
+ # need to identify the shared nodes for pairs of elements
11
+ # we do this by creating a sparse matrix that has N rows (number of elements)
12
+ # and M columns (number of nodes).
13
+ # We then fill the location where a node is in an element with true
14
+ # Then we create a table for the pairs of elements in the mesh
15
+ # we have the neighbour relationships, which are the 4 neighbours for each element
16
+ # create a new table that shows the element index repeated four times
17
+ # flatten both of these arrays so we effectively have a table with pairs of neighbours
18
+ # disgard the negative neighbours because these are border neighbours
19
+ rows = np.tile(np.arange(grid.n_elements)[:, None], (1, grid.dimension + 1))
20
+ elements = grid.elements
21
+ neighbours = grid.neighbours
22
+ # add array of bool to the location where there are elements for each node
23
+
24
+ # use this to determine shared faces
25
+
26
+ element_nodes = sparse.coo_matrix(
27
+ (
28
+ np.ones(elements.shape[0] * (grid.dimension + 1)),
29
+ (rows.ravel(), elements[:, : grid.dimension + 1].ravel()),
30
+ ),
31
+ shape=(grid.n_elements, grid.n_nodes),
32
+ dtype=bool,
33
+ ).tocsr()
34
+ n1 = np.tile(np.arange(neighbours.shape[0], dtype=int)[:, None], (1, grid.dimension + 1))
35
+ n1 = n1.flatten()
36
+ n2 = neighbours.flatten()
37
+ n1 = n1[n2 >= 0]
38
+ n2 = n2[n2 >= 0]
39
+ el_rel = np.zeros((grid.neighbours.flatten().shape[0], 2), dtype=int)
40
+ el_rel[:] = -1
41
+ el_rel[np.arange(n1.shape[0]), 0] = n1
42
+ el_rel[np.arange(n1.shape[0]), 1] = n2
43
+ el_rel = el_rel[el_rel[:, 0] >= 0, :]
44
+
45
+ # el_rel2 = np.zeros((grid.neighbours.flatten().shape[0], 2), dtype=int)
46
+ grid._shared_element_relationships[:] = -1
47
+ el_pairs = sparse.coo_matrix((np.ones(el_rel.shape[0]), (el_rel[:, 0], el_rel[:, 1]))).tocsr()
48
+ i, j = sparse.tril(el_pairs).nonzero()
49
+ grid._shared_element_relationships[: len(i), 0] = i
50
+ grid._shared_element_relationships[: len(i), 1] = j
51
+
52
+ grid._shared_element_relationships = grid.shared_element_relationships[
53
+ grid.shared_element_relationships[:, 0] >= 0, :
54
+ ]
55
+
56
+ faces = element_nodes[grid.shared_element_relationships[:, 0], :].multiply(
57
+ element_nodes[grid.shared_element_relationships[:, 1], :]
58
+ )
59
+ shared_faces = faces[np.array(np.sum(faces, axis=1) == grid.dimension).flatten(), :]
60
+ row, col = shared_faces.nonzero()
61
+ row = row[row.argsort()]
62
+ col = col[row.argsort()]
63
+ shared_face_index = np.zeros((shared_faces.shape[0], grid.dimension), dtype=int)
64
+ shared_face_index[:] = -1
65
+ shared_face_index[row.reshape(-1, grid.dimension)[:, 0], :] = col.reshape(-1, grid.dimension)
66
+ grid._shared_elements[np.arange(grid.shared_element_relationships.shape[0]), :] = (
67
+ shared_face_index
68
+ )
69
+ # resize
70
+ grid._shared_elements = grid.shared_elements[: len(grid.shared_element_relationships), :]
@@ -0,0 +1,32 @@
1
+ from LoopStructural.interpolators.supports import support_map, SupportType
2
+
3
+
4
+ class SupportFactory:
5
+ @staticmethod
6
+ def create_support(support_type, **kwargs):
7
+ if support_type is None:
8
+ raise ValueError("No support type specified")
9
+ if isinstance(support_type, str):
10
+ support_type = SupportType._member_map_[support_type].numerator
11
+ return support_map[support_type](**kwargs)
12
+
13
+ @staticmethod
14
+ def from_dict(d):
15
+ d = d.copy()
16
+ support_type = d.pop("type", None)
17
+ if support_type is None:
18
+ raise ValueError("No support type specified")
19
+ return SupportFactory.create_support(support_type, **d)
20
+
21
+ @staticmethod
22
+ def create_support_from_bbox(
23
+ support_type, bounding_box, nelements, element_volume=None, buffer: float = 0.2
24
+ ):
25
+ if isinstance(support_type, str):
26
+ support_type = SupportType._member_map_[support_type].numerator
27
+ bbox = bounding_box.with_buffer(buffer=buffer)
28
+ bbox.nelements = nelements
29
+
30
+ return support_map[support_type](
31
+ origin=bbox.origin, step_vector=bbox.step_vector, nsteps=bbox.nsteps
32
+ )
@@ -0,0 +1,29 @@
1
+ """
2
+ Geological modelling classes and functions
3
+
4
+ """
5
+
6
+ __all__ = [
7
+ "GeologicalModel",
8
+ "ProcessInputData",
9
+ "Loop3DView",
10
+ "Map2LoopProcessor",
11
+ "LoopProjectfileProcessor",
12
+ ]
13
+ from ..utils import getLogger
14
+ from ..utils import LoopImportError
15
+
16
+ logger = getLogger(__name__)
17
+ from ..modelling.input import (
18
+ ProcessInputData,
19
+ Map2LoopProcessor,
20
+ )
21
+
22
+ try:
23
+ from ..modelling.input.project_file import LoopProjectfileProcessor
24
+ except (LoopImportError, ImportError):
25
+ logger.warning(
26
+ "Cannot use LoopProjectfileProcessor: Loop project file cannot be imported, try installing LoopProjectFile"
27
+ )
28
+ # from LoopStructural.modelling.features import StructuralFrame
29
+ # from LoopStructural.modelling.features.fault import FaultSegment
File without changes