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,126 @@
1
+ import numpy as np
2
+
3
+
4
+ def _write_feat_surfs_gocad(surf, file_name):
5
+ """
6
+ Writes out a GOCAD TSURF file for each surface in list
7
+
8
+ Parameters
9
+ ----------
10
+ surf_list: [ SimpleNamespace() ... ]
11
+ Details of the surfaces, as a list of SimpleNamespace() objects. Fields are:
12
+ verts: vertices, numpy ndarray with dtype = float64 & shape = (N,3)
13
+ faces: faces, numpy ndarray with dtype = int32 & shape = (M,3)
14
+ values: values, numpy ndarray with dtype = float32 & shape = (N,)
15
+ normals: normals, numpy ndarray with dtype = float32 & shape = (N,3)
16
+ name: name of feature e.g. fault or supergroup, string
17
+
18
+ file_name: string
19
+ Desired filename
20
+
21
+ Returns
22
+ -------
23
+ True if successful
24
+
25
+ """
26
+ from pathlib import Path
27
+
28
+ properties_header = None
29
+ if surf.properties:
30
+
31
+ properties_header = f"""PROPERTIES {' '.join(list(surf.properties.keys()))}
32
+ NO_DATA_VALUES -99999
33
+ PROPERTY_CLASSES {' '.join(list(surf.properties.keys()))}
34
+ """
35
+
36
+ file_name = Path(file_name).with_suffix(".ts")
37
+ with open(f"{file_name}", "w") as fd:
38
+ fd.write(
39
+ f"""GOCAD TSurf 1
40
+ HEADER {{
41
+ *solid*color: #ffa500
42
+ ivolmap: false
43
+ imap: false
44
+ name: {surf.name}
45
+ }}
46
+ GOCAD_ORIGINAL_COORDINATE_SYSTEM
47
+ NAME Default
48
+ PROJECTION Unknown
49
+ DATUM Unknown
50
+ AXIS_NAME X Y Z
51
+ AXIS_UNIT m m m
52
+ ZPOSITIVE Elevation
53
+ END_ORIGINAL_COORDINATE_SYSTEM
54
+ GEOLOGICAL_FEATURE {surf.name}
55
+ GEOLOGICAL_TYPE fault
56
+ {properties_header if properties_header else ""}
57
+ PROPERTY_CLASS_HEADER X {{
58
+ kind: X
59
+ unit: m
60
+ }}
61
+ PROPERTY_CLASS_HEADER Y {{
62
+ kind: Y
63
+ unit: m
64
+ }}
65
+ PROPERTY_CLASS_HEADER Z {{
66
+ kind: Z
67
+ unit: m
68
+ is_z: on
69
+ }}
70
+ PROPERTY_CLASS_HEADER vector3d {{
71
+ kind: Length
72
+ unit: m
73
+ }}
74
+ TFACE
75
+ """
76
+ )
77
+ v_idx = 1
78
+ v_map = {}
79
+ for idx, vert in enumerate(surf.vertices):
80
+ if not np.isnan(vert[0]) and not np.isnan(vert[1]) and not np.isnan(vert[2]):
81
+ fd.write(f"VRTX {v_idx:} {vert[0]} {vert[1]} {vert[2]}")
82
+ if surf.properties:
83
+ for value in surf.properties.values():
84
+ fd.write(f" {value[idx]}")
85
+ fd.write("\n")
86
+ v_map[idx] = v_idx
87
+ v_idx += 1
88
+ for face in surf.triangles:
89
+ if face[0] in v_map and face[1] in v_map and face[2] in v_map:
90
+ fd.write(f"TRGL {v_map[face[0]]} {v_map[face[1]]} {v_map[face[2]]} \n")
91
+ fd.write("END\n")
92
+ return True
93
+
94
+
95
+ # def _write_pointset(points, file_name):
96
+ # """
97
+ # Write out a GOCAD VS file for a pointset
98
+
99
+ # Parameters
100
+ # ----------
101
+ # points: SimpleNamespace()
102
+ # Details of the points, as a SimpleNamespace() object. Fields are:
103
+ # locations: locations, numpy ndarray with dtype = float64 & shape = (N,3)
104
+ # vectors: vectors, numpy ndarray with dtype = float64 & shape = (N,3)
105
+ # name: name of feature e.g. fault or supergroup, string
106
+
107
+ # file_name: string
108
+ # Desired filename
109
+
110
+ # Returns
111
+ # -------
112
+ # True if successful
113
+
114
+ # """
115
+ # from pathlib import Path
116
+
117
+ # file_name = Path(file_name).with_suffix(".vs")
118
+ # with open(f"{file_name}", "w") as fd:
119
+ # fd.write(
120
+ # f"""GOCAD VSet 1
121
+ # HEADER {{
122
+ # name: {points.name}
123
+ # }}
124
+ # GOCAD_ORIGINAL_COORDINATE_SYSTEM
125
+ # NAME Default
126
+ # PROJECTION Unknown
@@ -0,0 +1,88 @@
1
+ try:
2
+ import omf
3
+ except ImportError:
4
+ raise ImportError(
5
+ "You need to install the omf package to use this feature. "
6
+ "You can install it with: pip install --pre omf"
7
+ )
8
+
9
+
10
+ def get_project(filename):
11
+ try:
12
+ project = omf.load(filename)
13
+ except FileNotFoundError:
14
+ project = omf.Project(name='LoopStructural Model')
15
+ return project
16
+
17
+
18
+ def get_cell_attributes(loopobject):
19
+ attributes = []
20
+ if loopobject.cell_properties:
21
+ attributes += [
22
+ omf.NumericAttribute(name=k, array=v, location="faces")
23
+ for k, v in loopobject.cell_properties.items()
24
+ ]
25
+ return attributes
26
+
27
+
28
+ def get_point_attributed(loopobject):
29
+ attributes = []
30
+ if loopobject.properties:
31
+ attributes += [
32
+ omf.NumericAttribute(name=k, array=v, location="vertices")
33
+ for k, v in loopobject.properties.items()
34
+ ]
35
+ return attributes
36
+
37
+
38
+ def add_surface_to_omf(surface, filename):
39
+
40
+ attributes = []
41
+ attributes += get_cell_attributes(surface)
42
+ attributes += get_point_attributed(surface)
43
+ surface = omf.Surface(
44
+ vertices=surface.vertices,
45
+ triangles=surface.triangles,
46
+ attributes=attributes,
47
+ name=surface.name,
48
+ )
49
+ project = get_project(filename)
50
+
51
+ project.elements += [surface]
52
+ omf.save(project, filename, mode='w')
53
+
54
+
55
+ def add_pointset_to_omf(points, filename):
56
+
57
+ attributes = []
58
+ attributes += get_point_attributed(points)
59
+
60
+ points = omf.PointSet(
61
+ vertices=points.locations,
62
+ attributes=attributes,
63
+ name=points.name,
64
+ )
65
+
66
+ project = get_project(filename)
67
+ project.elements += [points]
68
+ omf.save(project, filename, mode='w')
69
+
70
+
71
+ def add_structured_grid_to_omf(grid, filename):
72
+ print('Open Mining Format cannot store structured grids')
73
+ return
74
+ # attributes = []
75
+ # attributes += get_cell_attributes(grid)
76
+ # attributes += get_point_attributed(grid)
77
+
78
+ # vol = omf.TensorGridBlockModel(
79
+ # name=grid.name,
80
+ # tensor_u=np.ones(grid.nsteps[0]).astype(float),
81
+ # tensor_v=np.ones(grid.nsteps[0]).astype(float),
82
+ # tensor_w=np.ones(grid.nsteps[0]).astype(float),
83
+ # origin=grid.origin,
84
+ # attributes=attributes,
85
+ # )
86
+ # project = get_project(filename)
87
+ # project.elements += [vol]
88
+ # omf.save(project, filename, mode='w')
@@ -0,0 +1,105 @@
1
+ """
2
+ Interpolators and interpolation supports
3
+
4
+ """
5
+
6
+ __all__ = [
7
+ "InterpolatorType",
8
+ "GeologicalInterpolator",
9
+ "DiscreteInterpolator",
10
+ "FiniteDifferenceInterpolator",
11
+ "PiecewiseLinearInterpolator",
12
+ "DiscreteFoldInterpolator",
13
+ "SurfeRBFInterpolator",
14
+ "P1Interpolator",
15
+ "P2Interpolator",
16
+ "TetMesh",
17
+ "StructuredGrid",
18
+ "UnStructuredTetMesh",
19
+ "P1Unstructured2d",
20
+ "P2Unstructured2d",
21
+ "StructuredGrid2D",
22
+ "P2UnstructuredTetMesh",
23
+ ]
24
+ from enum import IntEnum
25
+
26
+ from ..utils import getLogger
27
+
28
+ logger = getLogger(__name__)
29
+
30
+
31
+ class InterpolatorType(IntEnum):
32
+ """
33
+ Enum for the different interpolator types
34
+
35
+ 1-9 should cover interpolators with supports
36
+ 9+ are data supported
37
+ """
38
+
39
+ BASE = 0
40
+ BASE_DISCRETE = 1
41
+ FINITE_DIFFERENCE = 2
42
+ DISCRETE_FOLD = 3
43
+ PIECEWISE_LINEAR = 4
44
+ PIECEWISE_QUADRATIC = 5
45
+ BASE_DATA_SUPPORTED = 10
46
+ SURFE = 11
47
+
48
+
49
+ interpolator_string_map = {
50
+ "FDI": InterpolatorType.FINITE_DIFFERENCE,
51
+ "PLI": InterpolatorType.PIECEWISE_LINEAR,
52
+ "P2": InterpolatorType.PIECEWISE_QUADRATIC,
53
+ "P1": InterpolatorType.PIECEWISE_LINEAR,
54
+ "DFI": InterpolatorType.DISCRETE_FOLD,
55
+ }
56
+ from ..interpolators._geological_interpolator import GeologicalInterpolator
57
+ from ..interpolators._discrete_interpolator import DiscreteInterpolator
58
+ from ..interpolators.supports import (
59
+ TetMesh,
60
+ StructuredGrid,
61
+ UnStructuredTetMesh,
62
+ P1Unstructured2d,
63
+ P2Unstructured2d,
64
+ StructuredGrid2D,
65
+ P2UnstructuredTetMesh,
66
+ SupportType,
67
+ )
68
+
69
+
70
+ from ..interpolators._finite_difference_interpolator import (
71
+ FiniteDifferenceInterpolator,
72
+ )
73
+ from ..interpolators._p1interpolator import (
74
+ P1Interpolator as PiecewiseLinearInterpolator,
75
+ )
76
+ from ..interpolators._discrete_fold_interpolator import (
77
+ DiscreteFoldInterpolator,
78
+ )
79
+ from ..interpolators._p2interpolator import P2Interpolator
80
+ from ..interpolators._p1interpolator import P1Interpolator
81
+
82
+ interpolator_map = {
83
+ InterpolatorType.BASE: GeologicalInterpolator,
84
+ InterpolatorType.BASE_DISCRETE: DiscreteInterpolator,
85
+ InterpolatorType.FINITE_DIFFERENCE: FiniteDifferenceInterpolator,
86
+ InterpolatorType.DISCRETE_FOLD: DiscreteFoldInterpolator,
87
+ InterpolatorType.PIECEWISE_LINEAR: P1Interpolator,
88
+ InterpolatorType.PIECEWISE_QUADRATIC: P2Interpolator,
89
+ InterpolatorType.BASE_DATA_SUPPORTED: GeologicalInterpolator,
90
+ }
91
+
92
+ support_interpolator_map = {
93
+ InterpolatorType.FINITE_DIFFERENCE: {
94
+ 2: SupportType.StructuredGrid2D,
95
+ 3: SupportType.StructuredGrid,
96
+ },
97
+ InterpolatorType.DISCRETE_FOLD: {3: SupportType.TetMesh, 2: SupportType.P1Unstructured2d},
98
+ InterpolatorType.PIECEWISE_LINEAR: {3: SupportType.TetMesh, 2: SupportType.P1Unstructured2d},
99
+ InterpolatorType.PIECEWISE_QUADRATIC: {
100
+ 3: SupportType.P2UnstructuredTetMesh,
101
+ 2: SupportType.P2Unstructured2d,
102
+ },
103
+ }
104
+
105
+ from ._interpolator_factory import InterpolatorFactory
@@ -0,0 +1,143 @@
1
+ import numpy as np
2
+
3
+ from typing import Optional
4
+ from LoopStructural.interpolators import (
5
+ GeologicalInterpolator,
6
+ InterpolatorFactory,
7
+ InterpolatorType,
8
+ )
9
+ from LoopStructural.datatypes import BoundingBox
10
+ from LoopStructural.utils import getLogger
11
+
12
+ logger = getLogger(__name__)
13
+
14
+
15
+ class LoopInterpolator:
16
+ def __init__(
17
+ self,
18
+ bounding_box: BoundingBox,
19
+ dimensions: int = 3,
20
+ type=InterpolatorType.FINITE_DIFFERENCE,
21
+ nelements: int = 1000,
22
+ ):
23
+ """Scikitlearn like interface for LoopStructural interpolators
24
+ useful for quickly building an interpolator to apply to a dataset
25
+ build a generic interpolation object speficying the bounding box
26
+ and then fit to constraints and evaluate the interpolator
27
+
28
+ Parameters
29
+ ----------
30
+ bounding_box : BoundingBox
31
+ Area where the interpolation will work
32
+ dimensions : int, optional
33
+ number of dimensions e.g. 3d or 2d, by default 3
34
+ type : str, optional
35
+ type of interpolation algorithm FDI- finite difference, PLI - linear finite elements,
36
+ by default "FDI"
37
+ nelements : int, optional
38
+ degrees of freedom for interpolator, by default 1000
39
+ """
40
+ self.dimensions = dimensions
41
+ self.type = "FDI"
42
+ self.bounding_box = bounding_box
43
+ self.interpolator: GeologicalInterpolator = InterpolatorFactory.create_interpolator(
44
+ type,
45
+ bounding_box,
46
+ nelements,
47
+ )
48
+
49
+ def fit(
50
+ self,
51
+ values: Optional[np.ndarray] = None,
52
+ tangent_vectors: Optional[np.ndarray] = None,
53
+ normal_vectors: Optional[np.ndarray] = None,
54
+ inequality_constraints: Optional[np.ndarray] = None,
55
+ ):
56
+ """_summary_
57
+
58
+ Parameters
59
+ ----------
60
+ values : Optional[np.ndarray], optional
61
+ Value constraints for implicit function, by default None
62
+ tangent_vectors : Optional[np.ndarray], optional
63
+ tangent constraints for implicit function, by default None
64
+ normal_vectors : Optional[np.ndarray], optional
65
+ gradient norm constraints for implicit function, by default None
66
+ inequality_constraints : Optional[np.ndarray], optional
67
+ _description_, by default None
68
+ """
69
+ if values is not None:
70
+ self.interpolator.set_value_constraints(values)
71
+ if tangent_vectors is not None:
72
+ self.interpolator.set_tangent_constraints(tangent_vectors)
73
+ if normal_vectors is not None:
74
+ self.interpolator.set_normal_constraints(normal_vectors)
75
+ if inequality_constraints:
76
+ pass
77
+
78
+ self.interpolator.setup()
79
+
80
+ def evaluate_scalar_value(self, locations: np.ndarray) -> np.ndarray:
81
+ """Evaluate the value of the interpolator at locations
82
+
83
+ Parameters
84
+ ----------
85
+ locations : np.ndarray
86
+ Nx3 array of locations to evaluate the interpolator at
87
+
88
+ Returns
89
+ -------
90
+ np.ndarray
91
+ value of implicit function at locations
92
+ """
93
+ self.interpolator.update()
94
+ return self.interpolator.evaluate_value(locations)
95
+
96
+ def evaluate_gradient(self, locations: np.ndarray) -> np.ndarray:
97
+ """Evaluate the gradient of the interpolator at locations
98
+
99
+ Parameters
100
+ ----------
101
+ locations : np.ndarray
102
+ Nx3 locations
103
+
104
+ Returns
105
+ -------
106
+ np.ndarray
107
+ Nx3 gradient of implicit function
108
+ """
109
+ self.interpolator.update()
110
+ return self.interpolator.evaluate_gradient(locations)
111
+
112
+ def fit_and_evaluate_value(
113
+ self,
114
+ values: Optional[np.ndarray] = None,
115
+ tangent_vectors: Optional[np.ndarray] = None,
116
+ normal_vectors: Optional[np.ndarray] = None,
117
+ inequality_constraints: Optional[np.ndarray] = None,
118
+ ):
119
+ # get locations
120
+ self.fit(
121
+ values=values,
122
+ tangent_vectors=tangent_vectors,
123
+ normal_vectors=normal_vectors,
124
+ inequality_constraints=inequality_constraints,
125
+ )
126
+ locations = self.interpolator.get_data_locations()
127
+ return self.evalute_scalar_value(locations)
128
+
129
+ def fit_and_evaluate_gradient(
130
+ self,
131
+ values: Optional[np.ndarray] = None,
132
+ tangent_vectors: Optional[np.ndarray] = None,
133
+ normal_vectors: Optional[np.ndarray] = None,
134
+ inequality_constraints: Optional[np.ndarray] = None,
135
+ ):
136
+ self.fit(
137
+ values=values,
138
+ tangent_vectors=tangent_vectors,
139
+ normal_vectors=normal_vectors,
140
+ inequality_constraints=inequality_constraints,
141
+ )
142
+ locations = self.interpolator.get_data_locations()
143
+ return self.evaluate_gradient(locations)
@@ -0,0 +1,149 @@
1
+ from LoopStructural.utils.exceptions import LoopException
2
+ import numpy as np
3
+ from typing import Optional
4
+ from LoopStructural.interpolators import (
5
+ P1Interpolator,
6
+ P2Interpolator,
7
+ FiniteDifferenceInterpolator,
8
+ GeologicalInterpolator,
9
+ DiscreteFoldInterpolator,
10
+ StructuredGrid,
11
+ TetMesh,
12
+ )
13
+ from LoopStructural.datatypes import BoundingBox
14
+ from LoopStructural.utils.logging import getLogger
15
+
16
+ logger = getLogger(__name__)
17
+
18
+
19
+ def get_interpolator(
20
+ bounding_box: BoundingBox,
21
+ interpolatortype: str,
22
+ nelements: int,
23
+ element_volume: Optional[float] = None,
24
+ buffer: float = 0.2,
25
+ dimensions: int = 3,
26
+ support=None,
27
+ ) -> GeologicalInterpolator:
28
+ # add a buffer to the interpolation domain, this is necessary for
29
+ # faults but also generally a good
30
+ # idea to avoid boundary problems
31
+ # buffer = bb[1, :]
32
+ origin = bounding_box.with_buffer(buffer).origin
33
+ maximum = bounding_box.with_buffer(buffer).maximum
34
+ box_vol = np.prod(maximum - origin)
35
+ if interpolatortype == "PLI":
36
+ if support is None:
37
+ if element_volume is None:
38
+ # nelements /= 5
39
+ element_volume = box_vol / nelements
40
+ # calculate the step vector of a regular cube
41
+ step_vector = np.zeros(3)
42
+ step_vector[:] = element_volume ** (1.0 / 3.0)
43
+ # step_vector /= np.array([1,1,2])
44
+ # number of steps is the length of the box / step vector
45
+ nsteps = np.ceil((maximum - origin) / step_vector).astype(int)
46
+ if np.any(np.less(nsteps, 3)):
47
+ axis_labels = ["x", "y", "z"]
48
+ for i in range(3):
49
+ if nsteps[i] < 3:
50
+ nsteps[i] = 3
51
+ logger.error(
52
+ f"Number of steps in direction {axis_labels[i]} is too small, try increasing nelements"
53
+ )
54
+ logger.error("Cannot create interpolator: number of steps is too small")
55
+ raise ValueError("Number of steps too small cannot create interpolator")
56
+
57
+ support = TetMesh(origin=origin, nsteps=nsteps, step_vector=step_vector)
58
+ logger.info(
59
+ "Creating regular tetrahedron mesh with %i elements \n"
60
+ "for modelling using PLI" % (support.ntetra)
61
+ )
62
+
63
+ return P1Interpolator(support)
64
+ if interpolatortype == "P2":
65
+ if support is not None:
66
+ logger.info(
67
+ "Creating regular tetrahedron mesh with %i elements \n"
68
+ "for modelling using P2" % (support.ntetra)
69
+ )
70
+ return P2Interpolator(support)
71
+ else:
72
+ raise ValueError("Cannot create P2 interpolator without support, try using PLI")
73
+
74
+ if interpolatortype == "FDI":
75
+ # find the volume of one element
76
+ if element_volume is None:
77
+ element_volume = box_vol / nelements
78
+ # calculate the step vector of a regular cube
79
+ step_vector = np.zeros(3)
80
+ step_vector[:] = element_volume ** (1.0 / 3.0)
81
+ # number of steps is the length of the box / step vector
82
+ nsteps = np.ceil((maximum - origin) / step_vector).astype(int)
83
+ if np.any(np.less(nsteps, 3)):
84
+ logger.error("Cannot create interpolator: number of steps is too small")
85
+ axis_labels = ["x", "y", "z"]
86
+ for i in range(3):
87
+ if nsteps[i] < 3:
88
+ nsteps[i] = 3
89
+ # logger.error(
90
+ # f"Number of steps in direction {axis_labels[i]} is too small, try increasing nelements"
91
+ # )
92
+ # raise ValueError("Number of steps too small cannot create interpolator")
93
+ # create a structured grid using the origin and number of steps
94
+
95
+ grid = StructuredGrid(origin=origin, nsteps=nsteps, step_vector=step_vector)
96
+ logger.info(
97
+ f"Creating regular grid with {grid.n_elements} elements \n" "for modelling using FDI"
98
+ )
99
+ return FiniteDifferenceInterpolator(grid)
100
+ if interpolatortype == "DFI":
101
+ if element_volume is None:
102
+ nelements /= 5
103
+ element_volume = box_vol / nelements
104
+ # calculate the step vector of a regular cube
105
+ step_vector = np.zeros(3)
106
+ step_vector[:] = element_volume ** (1.0 / 3.0)
107
+ # number of steps is the length of the box / step vector
108
+ nsteps = np.ceil((maximum - origin) / step_vector).astype(int)
109
+ # create a structured grid using the origin and number of steps
110
+
111
+ mesh = TetMesh(origin=origin, nsteps=nsteps, step_vector=step_vector)
112
+ logger.info(
113
+ f"Creating regular tetrahedron mesh with {mesh.ntetra} elements \n"
114
+ "for modelling using DFI"
115
+ )
116
+ return DiscreteFoldInterpolator(mesh, None)
117
+ raise LoopException("No interpolator")
118
+ # fi interpolatortype == "DFI" and dfi is True:
119
+ # if element_volume is None:
120
+ # nelements /= 5
121
+ # element_volume = box_vol / nelements
122
+ # # calculate the step vector of a regular cube
123
+ # step_vector = np.zeros(3)
124
+ # step_vector[:] = element_volume ** (1.0 / 3.0)
125
+ # # number of steps is the length of the box / step vector
126
+ # nsteps = np.ceil((bb[1, :] - bb[0, :]) / step_vector).astype(int)
127
+ # # create a structured grid using the origin and number of steps
128
+ # if "meshbuilder" in kwargs:
129
+ # mesh = kwargs["meshbuilder"].build(bb, nelements)
130
+ # else:
131
+ # mesh = kwargs.get(
132
+ # "mesh",
133
+ # TetMesh(origin=bb[0, :], nsteps=nsteps, step_vector=step_vector),
134
+ # )
135
+ # logger.info(
136
+ # f"Creating regular tetrahedron mesh with {mesh.ntetra} elements \n"
137
+ # "for modelling using DFI"
138
+ # )
139
+ # return DFI(mesh, kwargs["fold"])
140
+ # if interpolatortype == "Surfe" or interpolatortype == "surfe":
141
+ # # move import of surfe to where we actually try and use it
142
+ # if not surfe:
143
+ # logger.warning("Cannot import Surfe, try another interpolator")
144
+ # raise ImportError("Cannot import surfepy, try pip install surfe")
145
+ # method = kwargs.get("method", "single_surface")
146
+ # logger.info("Using surfe interpolator")
147
+ # return SurfeRBFInterpolator(method)
148
+ # logger.warning("No interpolator")
149
+ # raise InterpolatorError("Could not create interpolator")
File without changes