LoopStructural 1.8.0__tar.gz → 1.8.4__tar.gz
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.
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/_model_exporter.py +21 -11
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/_model_feature_factory.py +22 -4
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/_model_relationships.py +31 -8
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/geological_model.py +2 -1
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/stratigraphic_column.py +90 -45
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/_base_geological_feature.py +10 -1
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/builders/_folded_feature_builder.py +7 -1
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fold/_fold.py +3 -14
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural.egg-info/PKG-INFO +1 -1
- {loopstructural-1.8.0 → loopstructural-1.8.4}/PKG-INFO +1 -1
- {loopstructural-1.8.0 → loopstructural-1.8.4}/pyproject.toml +2 -1
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LICENSE +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/_base.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/_example_models.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/claudius.csv +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/claudiusbb.txt +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/duplex.csv +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/duplexbb.txt +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/fault_trace/fault_trace.cpg +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/fault_trace/fault_trace.dbf +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/fault_trace/fault_trace.prj +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/fault_trace/fault_trace.shp +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/fault_trace/fault_trace.shx +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/geological_map_data/bbox.csv +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/geological_map_data/contacts.csv +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/geological_map_data/fault_displacement.csv +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/geological_map_data/fault_edges.txt +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/geological_map_data/fault_locations.csv +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/geological_map_data/fault_orientations.csv +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/geological_map_data/stratigraphic_order.csv +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/geological_map_data/stratigraphic_orientations.csv +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/geological_map_data/stratigraphic_thickness.csv +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/intrusion.csv +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/intrusionbb.txt +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/onefoldbb.txt +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/onefolddata.csv +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/refolded_bb.txt +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/refolded_fold.csv +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/tabular_intrusion.csv +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datatypes/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/export/exporters.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/export/file_formats.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/export/geoh5.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/export/gocad.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/export/omf_wrapper.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/geometry/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/geometry/_structured_grid.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/interpolators/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/interpolators/_api.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/interpolators/_builders.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/interpolators/_constant_norm.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/interpolators/_cython/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/interpolators/_discrete_fold_interpolator.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/interpolators/_interpolatortype.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/_feature_registry.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/_model_serializer.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/fault_topology.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/_analytical_feature.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/_cross_product_geological_feature.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/_feature_converters.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/_geological_feature.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/_lambda_geological_feature.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/_projected_vector_feature.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/_region.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/_structural_frame.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/_unconformity_feature.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/builders/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/builders/_analytical_fold_builder.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/builders/_base_builder.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/builders/_fault_builder.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/builders/_geological_feature_builder.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/builders/_structural_frame_builder.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fault/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fault/_fault_function.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fault/_fault_function_feature.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fault/_fault_segment.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fold/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fold/_fold_rotation_angle_feature.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fold/_foldframe.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fold/_svariogram.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fold/fold_function/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fold/fold_function/_base_fold_rotation_angle.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fold/fold_function/_fourier_series_fold_rotation_angle.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fold/fold_function/_lambda_fold_rotation_angle.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fold/fold_function/_trigo_fold_rotation_angle.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/input/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/input/fault_network.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/input/map2loop_processor.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/input/process_data.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/input/project_file.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/intrusions/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/intrusions/geom_conceptual_models.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/intrusions/geometric_scaling_functions.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/intrusions/intrusion_builder.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/intrusions/intrusion_feature.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/intrusions/intrusion_frame.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/intrusions/intrusion_frame_builder.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/_api_registry.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/_surface.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/_transformation.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/colours.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/config.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/dtm_creator.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/exceptions.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/features.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/helper.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/json_encoder.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/linalg.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/logging.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/maths.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/observer.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/regions.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/typing.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/utils/utils.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/visualisation/__init__.py +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural.egg-info/SOURCES.txt +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural.egg-info/dependency_links.txt +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural.egg-info/requires.txt +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural.egg-info/top_level.txt +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/README.md +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/setup.cfg +0 -0
- {loopstructural-1.8.0 → loopstructural-1.8.4}/setup.py +0 -0
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/_model_exporter.py
RENAMED
|
@@ -8,17 +8,23 @@ of the CI-checked stable API surface -- and delegate to the staticmethods
|
|
|
8
8
|
here.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
11
13
|
import pathlib
|
|
14
|
+
from typing import TYPE_CHECKING
|
|
12
15
|
|
|
13
16
|
from ...geometry import StructuredGrid
|
|
14
|
-
from ...utils import getLogger
|
|
17
|
+
from ...utils import getLogger, surface_list
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from .geological_model import GeologicalModel
|
|
15
21
|
|
|
16
22
|
logger = getLogger(__name__)
|
|
17
23
|
|
|
18
24
|
|
|
19
25
|
class ModelExporter:
|
|
20
26
|
@staticmethod
|
|
21
|
-
def get_fault_surfaces(model, faults=None):
|
|
27
|
+
def get_fault_surfaces(model: GeologicalModel, faults: list[str] | None = None) -> surface_list:
|
|
22
28
|
if faults is None:
|
|
23
29
|
faults = []
|
|
24
30
|
surfaces = []
|
|
@@ -30,7 +36,9 @@ class ModelExporter:
|
|
|
30
36
|
return surfaces
|
|
31
37
|
|
|
32
38
|
@staticmethod
|
|
33
|
-
def get_stratigraphic_surfaces(
|
|
39
|
+
def get_stratigraphic_surfaces(
|
|
40
|
+
model: GeologicalModel, units: list[str] | None = None, bottoms: bool = True
|
|
41
|
+
) -> surface_list:
|
|
34
42
|
if units is None:
|
|
35
43
|
units = []
|
|
36
44
|
## TODO change the stratigraphic column to its own class and have methods to get the relevant surfaces
|
|
@@ -38,7 +46,7 @@ class ModelExporter:
|
|
|
38
46
|
units = []
|
|
39
47
|
if model.stratigraphic_column is None:
|
|
40
48
|
return []
|
|
41
|
-
units = model.stratigraphic_column.get_isovalues()
|
|
49
|
+
units = model.stratigraphic_column.get_isovalues(where='bottom' if bottoms else 'top')
|
|
42
50
|
units_for_group = {}
|
|
43
51
|
for name, u in units.items():
|
|
44
52
|
if u['group'] not in model:
|
|
@@ -60,7 +68,9 @@ class ModelExporter:
|
|
|
60
68
|
return surfaces
|
|
61
69
|
|
|
62
70
|
@staticmethod
|
|
63
|
-
def get_block_model(
|
|
71
|
+
def get_block_model(
|
|
72
|
+
model: GeologicalModel, name: str = 'block model'
|
|
73
|
+
) -> tuple[StructuredGrid, list]:
|
|
64
74
|
# NOTE: bounding_box.structured_grid() returns loop_common's
|
|
65
75
|
# interpolation-support StructuredGrid (no properties dict); use
|
|
66
76
|
# LoopStructural's own geometry StructuredGrid for storing values.
|
|
@@ -78,14 +88,14 @@ class ModelExporter:
|
|
|
78
88
|
|
|
79
89
|
@staticmethod
|
|
80
90
|
def save(
|
|
81
|
-
model,
|
|
91
|
+
model: GeologicalModel,
|
|
82
92
|
filename: str,
|
|
83
93
|
block_model: bool = True,
|
|
84
|
-
stratigraphic_surfaces=True,
|
|
85
|
-
fault_surfaces=True,
|
|
86
|
-
stratigraphic_data=True,
|
|
87
|
-
fault_data=True,
|
|
88
|
-
):
|
|
94
|
+
stratigraphic_surfaces: bool = True,
|
|
95
|
+
fault_surfaces: bool = True,
|
|
96
|
+
stratigraphic_data: bool = True,
|
|
97
|
+
fault_data: bool = True,
|
|
98
|
+
) -> None:
|
|
89
99
|
path = pathlib.Path(filename)
|
|
90
100
|
extension = path.suffix
|
|
91
101
|
parent = path.parent
|
|
@@ -31,6 +31,9 @@ from ...utils import getLogger
|
|
|
31
31
|
|
|
32
32
|
logger = getLogger(__name__)
|
|
33
33
|
|
|
34
|
+
# interpolator types that implement fold constraints
|
|
35
|
+
FOLD_INTERPOLATOR_TYPES = ("DFI", "P2Fold")
|
|
36
|
+
|
|
34
37
|
|
|
35
38
|
class ModelFeatureFactory:
|
|
36
39
|
@staticmethod
|
|
@@ -216,6 +219,13 @@ class ModelFeatureFactory:
|
|
|
216
219
|
fold_frame : FoldFrame
|
|
217
220
|
svario : Boolean
|
|
218
221
|
whether to calculate svariograms, saves time if avoided
|
|
222
|
+
interpolatortype : str
|
|
223
|
+
``"DFI"`` (default, piecewise linear) or ``"P2Fold"`` (piecewise quadratic).
|
|
224
|
+
Other values are replaced by ``"DFI"`` with a warning.
|
|
225
|
+
nelements : int
|
|
226
|
+
requested structured-grid cell budget. Each cell splits into five
|
|
227
|
+
tetrahedra. For ``"P2Fold"``, a request of 1e4 gave about 56k tets
|
|
228
|
+
and 86k unknowns in the Bermagui validation; inspect the actual counts
|
|
219
229
|
kwargs
|
|
220
230
|
additional kwargs to be passed through to other functions
|
|
221
231
|
|
|
@@ -227,6 +237,7 @@ class ModelFeatureFactory:
|
|
|
227
237
|
Notes
|
|
228
238
|
-----
|
|
229
239
|
|
|
240
|
+
- The P2 mesh is larger than the model box because of ``buffer``.
|
|
230
241
|
- Building a folded foliation uses the fold interpolation code from Laurent et al., 2016
|
|
231
242
|
and fold profile fitting from Grose et al., 2017. For more information about the fold modelling
|
|
232
243
|
see :class:`LoopStructural.modelling.features.fold.FoldEvent`,
|
|
@@ -245,8 +256,11 @@ class ModelFeatureFactory:
|
|
|
245
256
|
|
|
246
257
|
fold = FoldEvent(fold_frame, name=f"Fold_{foliation_name}", invert_norm=invert_fold_norm)
|
|
247
258
|
|
|
248
|
-
if interpolatortype
|
|
249
|
-
logger.warning(
|
|
259
|
+
if interpolatortype not in FOLD_INTERPOLATOR_TYPES:
|
|
260
|
+
logger.warning(
|
|
261
|
+
f"Folded foliation only supports {FOLD_INTERPOLATOR_TYPES} interpolators, "
|
|
262
|
+
f"changing {interpolatortype} to DFI"
|
|
263
|
+
)
|
|
250
264
|
interpolatortype = "DFI"
|
|
251
265
|
series_builder = FoldedFeatureBuilder(
|
|
252
266
|
interpolatortype=interpolatortype,
|
|
@@ -300,7 +314,10 @@ class ModelFeatureFactory:
|
|
|
300
314
|
fold_frame_data : pandas data frame, optional
|
|
301
315
|
data frame containing the fold frame data, if not specified uses the model data
|
|
302
316
|
interpolatortype : str
|
|
303
|
-
|
|
317
|
+
``"DFI"`` or ``"P2Fold"`` sets the interpolator of the first (fold) coordinate.
|
|
318
|
+
Any other value gives ``"DFI"``. The other two coordinates always use FDI.
|
|
319
|
+
``nelements`` is a structured-grid cell budget, not a literal
|
|
320
|
+
tetrahedron count. P2 adds edge nodes; inspect the actual dof.
|
|
304
321
|
fold_frame : StructuralFrame, optional
|
|
305
322
|
the fold frame for the fold if not specified uses last feature added
|
|
306
323
|
nelements : int
|
|
@@ -342,8 +359,9 @@ class ModelFeatureFactory:
|
|
|
342
359
|
raise TypeError("Please specify a FoldFrame")
|
|
343
360
|
fold = FoldEvent(fold_frame, name=f"Fold_{fold_frame_name}")
|
|
344
361
|
|
|
362
|
+
# the first coordinate carries the fold constraints, the others are plain FDI
|
|
345
363
|
interpolatortypes = [
|
|
346
|
-
"DFI",
|
|
364
|
+
interpolatortype if interpolatortype in FOLD_INTERPOLATOR_TYPES else "DFI",
|
|
347
365
|
"FDI",
|
|
348
366
|
"FDI",
|
|
349
367
|
]
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/_model_relationships.py
RENAMED
|
@@ -52,15 +52,22 @@ class FeatureRelationshipManager:
|
|
|
52
52
|
for f in reversed(model.features):
|
|
53
53
|
if f.name == feature.name:
|
|
54
54
|
continue
|
|
55
|
-
if f.type ==
|
|
56
|
-
|
|
55
|
+
if f.type == FeatureType.DOMAINFAULT:
|
|
56
|
+
# A proper Feature-like region (name/parent), not a bare
|
|
57
|
+
# lambda -- code that walks `self.regions` expecting
|
|
58
|
+
# Feature-like objects (e.g. BaseFeature.surfaces) would
|
|
59
|
+
# otherwise raise AttributeError on this region and
|
|
60
|
+
# silently produce no surfaces for anything a domain fault
|
|
61
|
+
# crops.
|
|
62
|
+
feature.add_region(UnconformityFeature(f, 0, sign=True))
|
|
57
63
|
break
|
|
58
64
|
|
|
59
65
|
@staticmethod
|
|
60
66
|
def add_domain_fault_below(model, domain_fault):
|
|
61
67
|
"""
|
|
62
68
|
Looks through the feature list and adds any the domain_fault to the features
|
|
63
|
-
that already exist in the stack until an unconformity
|
|
69
|
+
that already exist in the stack until an unconformity or another domain
|
|
70
|
+
fault is reached (that boundary is not cropped). domain faults
|
|
64
71
|
to the feature. The domain fault masks everything where the fault scalar field
|
|
65
72
|
is < 0 as being active when added to feature.
|
|
66
73
|
|
|
@@ -70,12 +77,19 @@ class FeatureRelationshipManager:
|
|
|
70
77
|
domain_fault : GeologicalFeatureBuilder
|
|
71
78
|
the feature being added to the model where domain faults should be added
|
|
72
79
|
"""
|
|
80
|
+
region = UnconformityFeature(domain_fault, 0, sign=False)
|
|
73
81
|
for f in reversed(model.features):
|
|
74
82
|
if f.name == domain_fault.name:
|
|
75
83
|
continue
|
|
76
|
-
f.
|
|
77
|
-
|
|
84
|
+
if f.type == FeatureType.UNCONFORMITY or f.type == FeatureType.DOMAINFAULT:
|
|
85
|
+
# An unconformity or domain fault added before this one is
|
|
86
|
+
# the boundary above the features this domain fault crops.
|
|
87
|
+
# It is a stopping point and is not itself cropped, else the
|
|
88
|
+
# boundary surface is removed on one side of this fault.
|
|
89
|
+
# This matches add_unconformity, which also stops before it
|
|
90
|
+
# crops.
|
|
78
91
|
break
|
|
92
|
+
f.add_region(region)
|
|
79
93
|
|
|
80
94
|
@staticmethod
|
|
81
95
|
def add_unconformity_above(model, feature):
|
|
@@ -129,8 +143,13 @@ class FeatureRelationshipManager:
|
|
|
129
143
|
uc_feature = UnconformityFeature(feature, value)
|
|
130
144
|
feature.add_region(uc_feature.inverse())
|
|
131
145
|
for f in reversed(model.features):
|
|
132
|
-
if f.type == FeatureType.UNCONFORMITY:
|
|
133
|
-
|
|
146
|
+
if f.type == FeatureType.UNCONFORMITY or f.type == FeatureType.DOMAINFAULT:
|
|
147
|
+
# A domain fault is itself a boundary that already separates
|
|
148
|
+
# everything below it from what's built afterwards (see
|
|
149
|
+
# add_domain_fault_below/above) -- so it's a stopping point
|
|
150
|
+
# here too, the same as an unconformity, rather than
|
|
151
|
+
# something this unrelated unconformity should crop.
|
|
152
|
+
logger.debug(f"Reached unconformity/domain fault {f.name}")
|
|
134
153
|
break
|
|
135
154
|
logger.debug(f"Adding {uc_feature.name} as unconformity to {f.name}")
|
|
136
155
|
if f.type == FeatureType.FAULT or f.type == FeatureType.INACTIVEFAULT:
|
|
@@ -165,7 +184,11 @@ class FeatureRelationshipManager:
|
|
|
165
184
|
uc_feature = UnconformityFeature(feature, value, False, onlap=True)
|
|
166
185
|
feature.add_region(uc_feature.inverse())
|
|
167
186
|
for f in reversed(model.features):
|
|
168
|
-
if f.type in (
|
|
187
|
+
if f.type in (
|
|
188
|
+
FeatureType.UNCONFORMITY,
|
|
189
|
+
FeatureType.ONLAPUNCONFORMITY,
|
|
190
|
+
FeatureType.DOMAINFAULT,
|
|
191
|
+
):
|
|
169
192
|
logger.debug(f"Reached unconformity {f.name}")
|
|
170
193
|
break
|
|
171
194
|
if f.type == FeatureType.FAULT or f.type == FeatureType.INACTIVEFAULT:
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/geological_model.py
RENAMED
|
@@ -793,7 +793,8 @@ class GeologicalModel:
|
|
|
793
793
|
"""Create a folded foliation and add it to the model.
|
|
794
794
|
|
|
795
795
|
See :meth:`~._model_feature_factory.ModelFeatureFactory.build_folded_foliation`
|
|
796
|
-
for parameter documentation.
|
|
796
|
+
for parameter documentation. ``interpolatortype`` is ``"DFI"`` (default)
|
|
797
|
+
or ``"P2Fold"``.
|
|
797
798
|
Thin wrapper around :meth:`create_and_add_feature` (see
|
|
798
799
|
``API.md``); kept as a stable, unchanged entry point.
|
|
799
800
|
"""
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/stratigraphic_column.py
RENAMED
|
@@ -9,9 +9,11 @@ from LoopStructural.utils._api_registry import public_api
|
|
|
9
9
|
|
|
10
10
|
logger = getLogger(__name__)
|
|
11
11
|
logger.info("Imported LoopStructural Stratigraphic Column module")
|
|
12
|
+
|
|
13
|
+
|
|
12
14
|
class UnconformityType(enum.Enum):
|
|
13
15
|
"""Enumeration for different types of unconformities in a stratigraphic column.
|
|
14
|
-
|
|
16
|
+
|
|
15
17
|
Attributes
|
|
16
18
|
----------
|
|
17
19
|
ERODE : str
|
|
@@ -26,7 +28,7 @@ class UnconformityType(enum.Enum):
|
|
|
26
28
|
|
|
27
29
|
class StratigraphicColumnElementType(enum.Enum):
|
|
28
30
|
"""Enumeration for different types of elements in a stratigraphic column.
|
|
29
|
-
|
|
31
|
+
|
|
30
32
|
Attributes
|
|
31
33
|
----------
|
|
32
34
|
UNIT : str
|
|
@@ -41,8 +43,8 @@ class StratigraphicColumnElementType(enum.Enum):
|
|
|
41
43
|
|
|
42
44
|
class StratigraphicColumnElement:
|
|
43
45
|
"""Base class for elements in a stratigraphic column.
|
|
44
|
-
|
|
45
|
-
This class represents a generic element that can be either a stratigraphic unit
|
|
46
|
+
|
|
47
|
+
This class represents a generic element that can be either a stratigraphic unit
|
|
46
48
|
or a topological object such as an unconformity.
|
|
47
49
|
|
|
48
50
|
Parameters
|
|
@@ -132,6 +134,7 @@ class StratigraphicUnit(StratigraphicColumnElement, Observable['StratigraphicUni
|
|
|
132
134
|
self.id = id
|
|
133
135
|
self.min_value = None # Minimum scalar field value for the unit
|
|
134
136
|
self.max_value = None # Maximum scalar field value for the unit
|
|
137
|
+
|
|
135
138
|
@property
|
|
136
139
|
def id(self):
|
|
137
140
|
"""Get the numeric identifier of the unit.
|
|
@@ -142,7 +145,7 @@ class StratigraphicUnit(StratigraphicColumnElement, Observable['StratigraphicUni
|
|
|
142
145
|
The numeric identifier
|
|
143
146
|
"""
|
|
144
147
|
return self._id
|
|
145
|
-
|
|
148
|
+
|
|
146
149
|
@property
|
|
147
150
|
def thickness(self):
|
|
148
151
|
"""Get the thickness of the unit.
|
|
@@ -153,7 +156,7 @@ class StratigraphicUnit(StratigraphicColumnElement, Observable['StratigraphicUni
|
|
|
153
156
|
The thickness value
|
|
154
157
|
"""
|
|
155
158
|
return self._thickness
|
|
156
|
-
|
|
159
|
+
|
|
157
160
|
@thickness.setter
|
|
158
161
|
def thickness(self, value):
|
|
159
162
|
"""Set the thickness of the unit and notify observers.
|
|
@@ -165,7 +168,7 @@ class StratigraphicUnit(StratigraphicColumnElement, Observable['StratigraphicUni
|
|
|
165
168
|
"""
|
|
166
169
|
self._thickness = value
|
|
167
170
|
self.notify('unit/thickness_updated', unit=self)
|
|
168
|
-
|
|
171
|
+
|
|
169
172
|
@id.setter
|
|
170
173
|
def id(self, value):
|
|
171
174
|
"""Set the ID of the unit and notify observers.
|
|
@@ -179,6 +182,7 @@ class StratigraphicUnit(StratigraphicColumnElement, Observable['StratigraphicUni
|
|
|
179
182
|
raise TypeError("ID must be an integer")
|
|
180
183
|
self._id = value
|
|
181
184
|
self.notify('unit/id_updated', unit=self)
|
|
185
|
+
|
|
182
186
|
def min(self):
|
|
183
187
|
"""Return the minimum scalar field value of the unit.
|
|
184
188
|
|
|
@@ -188,7 +192,7 @@ class StratigraphicUnit(StratigraphicColumnElement, Observable['StratigraphicUni
|
|
|
188
192
|
Minimum value, or 0 if not set
|
|
189
193
|
"""
|
|
190
194
|
return self.min_value if self.min_value is not None else 0
|
|
191
|
-
|
|
195
|
+
|
|
192
196
|
def max(self):
|
|
193
197
|
"""Return the maximum scalar field value of the unit.
|
|
194
198
|
|
|
@@ -198,7 +202,7 @@ class StratigraphicUnit(StratigraphicColumnElement, Observable['StratigraphicUni
|
|
|
198
202
|
Maximum value, or infinity if not set
|
|
199
203
|
"""
|
|
200
204
|
return self.max_value if self.max_value is not None else np.inf
|
|
201
|
-
|
|
205
|
+
|
|
202
206
|
def to_dict(self):
|
|
203
207
|
"""Convert the stratigraphic unit to a dictionary representation.
|
|
204
208
|
|
|
@@ -210,7 +214,13 @@ class StratigraphicUnit(StratigraphicColumnElement, Observable['StratigraphicUni
|
|
|
210
214
|
colour = self.colour
|
|
211
215
|
if isinstance(colour, np.ndarray):
|
|
212
216
|
colour = colour.astype(float).tolist()
|
|
213
|
-
return {
|
|
217
|
+
return {
|
|
218
|
+
"name": self.name,
|
|
219
|
+
"colour": colour,
|
|
220
|
+
"thickness": self.thickness,
|
|
221
|
+
'uuid': self.uuid,
|
|
222
|
+
'id': self.id,
|
|
223
|
+
}
|
|
214
224
|
|
|
215
225
|
@classmethod
|
|
216
226
|
def from_dict(cls, data):
|
|
@@ -237,7 +247,9 @@ class StratigraphicUnit(StratigraphicColumnElement, Observable['StratigraphicUni
|
|
|
237
247
|
colour = data.get("colour")
|
|
238
248
|
thickness = data.get("thickness", None)
|
|
239
249
|
uuid = data.get("uuid", None)
|
|
240
|
-
return cls(
|
|
250
|
+
return cls(
|
|
251
|
+
uuid=uuid, name=name, colour=colour, thickness=thickness, id=data.get("id", None)
|
|
252
|
+
)
|
|
241
253
|
|
|
242
254
|
def __str__(self):
|
|
243
255
|
"""Return a string representation of the stratigraphic unit.
|
|
@@ -303,9 +315,11 @@ class StratigraphicUnconformity(StratigraphicColumnElement):
|
|
|
303
315
|
)
|
|
304
316
|
uuid = data.get("uuid", None)
|
|
305
317
|
return cls(uuid=uuid, name=name, unconformity_type=unconformity_type)
|
|
318
|
+
|
|
319
|
+
|
|
306
320
|
class StratigraphicGroup:
|
|
307
321
|
"""A class representing a group of stratigraphic units.
|
|
308
|
-
|
|
322
|
+
|
|
309
323
|
This class serves as a container for related stratigraphic units and provides
|
|
310
324
|
a placeholder for future group-level functionality.
|
|
311
325
|
|
|
@@ -340,9 +354,9 @@ class StratigraphicGroup:
|
|
|
340
354
|
|
|
341
355
|
class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
342
356
|
"""A class representing a stratigraphic column.
|
|
343
|
-
|
|
344
|
-
The stratigraphic column represents a vertical section of the Earth's crust
|
|
345
|
-
showing the sequence of rock layers and their relationships, including
|
|
357
|
+
|
|
358
|
+
The stratigraphic column represents a vertical section of the Earth's crust
|
|
359
|
+
showing the sequence of rock layers and their relationships, including
|
|
346
360
|
unconformities and basement rock.
|
|
347
361
|
|
|
348
362
|
Attributes
|
|
@@ -372,18 +386,16 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
372
386
|
if not self.order:
|
|
373
387
|
return 0
|
|
374
388
|
return max([u.id for u in self.order if isinstance(u, StratigraphicUnit)], default=0) + 1
|
|
375
|
-
|
|
389
|
+
|
|
376
390
|
def add_basement(self):
|
|
377
391
|
"""Add basement unit and base unconformity to the stratigraphic column.
|
|
378
|
-
|
|
392
|
+
|
|
379
393
|
This method adds the fundamental basement unit with infinite thickness
|
|
380
394
|
and an erosional unconformity at the base of the column.
|
|
381
395
|
"""
|
|
382
396
|
self.add_unit(name='Basement', colour='grey', thickness=np.inf)
|
|
383
|
-
self.add_unconformity(
|
|
384
|
-
|
|
385
|
-
)
|
|
386
|
-
|
|
397
|
+
self.add_unconformity(name='Base Unconformity', unconformity_type=UnconformityType.ERODE)
|
|
398
|
+
|
|
387
399
|
def clear(self, basement=True):
|
|
388
400
|
"""Clear the stratigraphic column, removing all elements.
|
|
389
401
|
|
|
@@ -397,7 +409,8 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
397
409
|
if basement:
|
|
398
410
|
self.add_basement()
|
|
399
411
|
self.notify('column_cleared')
|
|
400
|
-
|
|
412
|
+
|
|
413
|
+
def add_unit(self, name, *, colour=None, thickness=None, where='top', id=None):
|
|
401
414
|
if id is None:
|
|
402
415
|
id = self.get_new_id()
|
|
403
416
|
unit = StratigraphicUnit(name=name, colour=colour, thickness=thickness, id=id)
|
|
@@ -425,7 +438,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
425
438
|
|
|
426
439
|
return False
|
|
427
440
|
|
|
428
|
-
def add_unconformity(self, name, *, unconformity_type=UnconformityType.ERODE, where='top'
|
|
441
|
+
def add_unconformity(self, name, *, unconformity_type=UnconformityType.ERODE, where='top'):
|
|
429
442
|
unconformity = StratigraphicUnconformity(
|
|
430
443
|
uuid=None, name=name, unconformity_type=unconformity_type
|
|
431
444
|
)
|
|
@@ -466,6 +479,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
466
479
|
return unconformity
|
|
467
480
|
|
|
468
481
|
return None
|
|
482
|
+
|
|
469
483
|
def get_element_by_uuid(self, uuid):
|
|
470
484
|
"""
|
|
471
485
|
Retrieves an element by its uuid from the stratigraphic column.
|
|
@@ -475,7 +489,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
475
489
|
return element
|
|
476
490
|
raise KeyError(f"No element found with uuid: {uuid}")
|
|
477
491
|
|
|
478
|
-
def get_group_for_unit_name(self, unit_name:str) -> StratigraphicGroup | None:
|
|
492
|
+
def get_group_for_unit_name(self, unit_name: str) -> StratigraphicGroup | None:
|
|
479
493
|
"""
|
|
480
494
|
Retrieves the group for a given unit name.
|
|
481
495
|
"""
|
|
@@ -483,6 +497,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
483
497
|
if any(unit.name == unit_name for unit in group.units):
|
|
484
498
|
return group
|
|
485
499
|
return None
|
|
500
|
+
|
|
486
501
|
def add_element(self, element):
|
|
487
502
|
"""
|
|
488
503
|
Adds a StratigraphicColumnElement to the stratigraphic column.
|
|
@@ -500,27 +515,22 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
500
515
|
|
|
501
516
|
def get_groups(self):
|
|
502
517
|
groups = []
|
|
503
|
-
i=0
|
|
504
|
-
group = StratigraphicGroup(
|
|
505
|
-
name=(
|
|
506
|
-
self.group_mapping.get(f'Group_{i}', f'Group_{i}')
|
|
507
|
-
)
|
|
508
|
-
)
|
|
518
|
+
i = 0
|
|
519
|
+
group = StratigraphicGroup(name=(self.group_mapping.get(f'Group_{i}', f'Group_{i}')))
|
|
509
520
|
for e in reversed(self.order):
|
|
510
521
|
if isinstance(e, StratigraphicUnit):
|
|
511
522
|
group.units.append(e)
|
|
512
523
|
else:
|
|
513
524
|
if group.units:
|
|
514
525
|
groups.append(group)
|
|
515
|
-
i+=1
|
|
526
|
+
i += 1
|
|
516
527
|
group = StratigraphicGroup(
|
|
517
|
-
name=(
|
|
518
|
-
self.group_mapping.get(f'Group_{i}', f'Group_{i}')
|
|
519
|
-
)
|
|
528
|
+
name=(self.group_mapping.get(f'Group_{i}', f'Group_{i}'))
|
|
520
529
|
)
|
|
521
530
|
if group:
|
|
522
531
|
groups.append(group)
|
|
523
532
|
return groups
|
|
533
|
+
|
|
524
534
|
def get_stratigraphic_ids(self) -> list[list[str]]:
|
|
525
535
|
ids = []
|
|
526
536
|
for group in self.get_groups():
|
|
@@ -530,6 +540,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
530
540
|
for unit in group.units:
|
|
531
541
|
ids.append([unit.id, group, unit.name, unit.min(), unit.max()])
|
|
532
542
|
return ids
|
|
543
|
+
|
|
533
544
|
def get_unitname_groups(self):
|
|
534
545
|
groups = self.get_groups()
|
|
535
546
|
groups_list = []
|
|
@@ -539,7 +550,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
539
550
|
groups_list.append(group)
|
|
540
551
|
return groups_list
|
|
541
552
|
|
|
542
|
-
def get_group_unit_pairs(self) -> list[tuple[str,str]]:
|
|
553
|
+
def get_group_unit_pairs(self) -> list[tuple[str, str]]:
|
|
543
554
|
"""
|
|
544
555
|
Returns a list of tuples containing group names and unit names.
|
|
545
556
|
"""
|
|
@@ -571,7 +582,10 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
571
582
|
]
|
|
572
583
|
self.notify('order_updated', new_order=self.order)
|
|
573
584
|
self.update_unit_values() # Update min and max values after updating the order
|
|
574
|
-
|
|
585
|
+
|
|
586
|
+
def update_unit_values(
|
|
587
|
+
self, observable: Observable | None = None, event: str | None = None, **kwargs
|
|
588
|
+
):
|
|
575
589
|
"""
|
|
576
590
|
Updates the min and max values for each unit based on their position in the column.
|
|
577
591
|
|
|
@@ -628,6 +642,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
628
642
|
return {
|
|
629
643
|
"elements": [element.to_dict() for element in self.order],
|
|
630
644
|
}
|
|
645
|
+
|
|
631
646
|
def update_from_dict(self, data):
|
|
632
647
|
"""
|
|
633
648
|
Updates the stratigraphic column from a dictionary representation.
|
|
@@ -643,6 +658,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
643
658
|
else:
|
|
644
659
|
element = StratigraphicUnit.from_dict(element_data)
|
|
645
660
|
self.add_element(element)
|
|
661
|
+
|
|
646
662
|
@classmethod
|
|
647
663
|
def from_dict(cls, data):
|
|
648
664
|
"""
|
|
@@ -661,23 +677,37 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
661
677
|
column.add_element(element)
|
|
662
678
|
return column
|
|
663
679
|
|
|
664
|
-
def get_isovalues(self) -> dict[str, float]:
|
|
680
|
+
def get_isovalues(self, where: str = 'bottom') -> dict[str, float]:
|
|
665
681
|
"""
|
|
666
682
|
Returns a dictionary of isovalues for the stratigraphic units in the column.
|
|
683
|
+
|
|
684
|
+
Parameters
|
|
685
|
+
----------
|
|
686
|
+
where : str, optional
|
|
687
|
+
'bottom' (default) returns the value at the base of each unit.
|
|
688
|
+
'top' returns the value at the top of each unit.
|
|
667
689
|
"""
|
|
690
|
+
if where not in ('top', 'bottom'):
|
|
691
|
+
raise ValueError("Invalid 'where' argument. Use 'top' or 'bottom'.")
|
|
668
692
|
surface_values = {}
|
|
669
693
|
for g in reversed(self.get_groups()):
|
|
670
694
|
v = 0
|
|
671
|
-
for u in g.units:
|
|
672
|
-
|
|
695
|
+
for u in reversed(g.units):
|
|
696
|
+
base = v
|
|
673
697
|
v += u.thickness
|
|
698
|
+
surface_values[u.name] = {
|
|
699
|
+
'value': v if where == 'top' else base,
|
|
700
|
+
'group': g.name,
|
|
701
|
+
'colour': u.colour,
|
|
702
|
+
}
|
|
674
703
|
return surface_values
|
|
675
704
|
|
|
676
|
-
def plot(self
|
|
705
|
+
def plot(self, *, ax=None, **kwargs):
|
|
677
706
|
import matplotlib.pyplot as plt
|
|
678
707
|
from matplotlib import cm
|
|
679
708
|
from matplotlib.collections import PatchCollection
|
|
680
709
|
from matplotlib.patches import Polygon
|
|
710
|
+
|
|
681
711
|
n_units = 0 # count how many discrete colours (number of stratigraphic units)
|
|
682
712
|
xmin = 0
|
|
683
713
|
ymin = 0
|
|
@@ -712,7 +742,17 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
712
742
|
n_units += 1
|
|
713
743
|
|
|
714
744
|
ymax = total_height
|
|
715
|
-
ymin = ymax - (
|
|
745
|
+
ymin = ymax - (
|
|
746
|
+
getattr(u, 'thickness', np.nan)
|
|
747
|
+
if not np.isinf(getattr(u, 'thickness', np.nan))
|
|
748
|
+
else np.nanmean(
|
|
749
|
+
[
|
|
750
|
+
getattr(e, 'thickness', np.nan)
|
|
751
|
+
for e in self.order
|
|
752
|
+
if not np.isinf(getattr(e, 'thickness', np.nan))
|
|
753
|
+
]
|
|
754
|
+
)
|
|
755
|
+
)
|
|
716
756
|
|
|
717
757
|
if not np.isfinite(ymin):
|
|
718
758
|
ymin = prev_coords[1] - (prev_coords[1] - prev_coords[0]) * (1 + rng.random())
|
|
@@ -723,7 +763,12 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
723
763
|
|
|
724
764
|
polygon_points = np.array([[xmin, ymin], [xmax, ymin], [xmax, ymax], [xmin, ymax]])
|
|
725
765
|
patches.append(Polygon(polygon_points))
|
|
726
|
-
ax.annotate(
|
|
766
|
+
ax.annotate(
|
|
767
|
+
getattr(u, 'name', 'Unknown'),
|
|
768
|
+
xy=(xmin + (xmax - xmin) / 2, (ymax - ymin) / 2 + ymin),
|
|
769
|
+
fontsize=8,
|
|
770
|
+
ha='left',
|
|
771
|
+
)
|
|
727
772
|
|
|
728
773
|
if 'cmap' not in kwargs:
|
|
729
774
|
from matplotlib import colors
|
|
@@ -752,7 +797,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
752
797
|
ax.axis("off")
|
|
753
798
|
|
|
754
799
|
return fig
|
|
755
|
-
|
|
800
|
+
|
|
756
801
|
def cmap(self):
|
|
757
802
|
try:
|
|
758
803
|
from matplotlib import colors
|
|
@@ -772,9 +817,9 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
|
772
817
|
data.append((u.id, u.colour))
|
|
773
818
|
colours.append(u.colour)
|
|
774
819
|
boundaries.append(u.id)
|
|
775
|
-
|
|
820
|
+
# print(u,v)
|
|
776
821
|
cmap = colors.ListedColormap(colours)
|
|
777
822
|
except ImportError:
|
|
778
823
|
logger.warning("Cannot use predefined colours as I can't import matplotlib")
|
|
779
824
|
cmap = "tab20"
|
|
780
|
-
return cmap
|
|
825
|
+
return cmap
|
|
@@ -340,8 +340,17 @@ class BaseFeature(metaclass=ABCMeta):
|
|
|
340
340
|
regions = self.regions
|
|
341
341
|
|
|
342
342
|
try:
|
|
343
|
+
# A region can also be a plain callable (e.g. the lambdas
|
|
344
|
+
# add_domain_fault_below/above attach for a domain-fault crop),
|
|
345
|
+
# not just another BaseFeature -- those have no .name/.parent,
|
|
346
|
+
# so getattr(..., None) rather than direct attribute access,
|
|
347
|
+
# or this raises AttributeError and silently drops every
|
|
348
|
+
# surface for any feature cropped by a domain fault.
|
|
343
349
|
self.regions = [
|
|
344
|
-
r
|
|
350
|
+
r
|
|
351
|
+
for r in self.regions
|
|
352
|
+
if getattr(r, 'name', None) != self.name
|
|
353
|
+
and getattr(getattr(r, 'parent', None), 'name', None) != self.name
|
|
345
354
|
]
|
|
346
355
|
|
|
347
356
|
callable = lambda xyz: self.evaluate_value(xyz)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
|
|
3
3
|
from ....geometry import BoundingBox
|
|
4
|
+
from ....interpolators import InterpolatorType
|
|
4
5
|
from ....modelling.features import FeatureType
|
|
5
6
|
from ._geological_feature_builder import GeologicalFeatureBuilder
|
|
6
7
|
from ....modelling.features.fold.fold_function import FoldRotationType, get_fold_rotation_profile
|
|
@@ -71,8 +72,13 @@ class FoldedFeatureBuilder(GeologicalFeatureBuilder):
|
|
|
71
72
|
if not isinstance(feature_builder, GeologicalFeatureBuilder):
|
|
72
73
|
logger.error(f'Feature builder is {type(feature_builder)} not GeologicalFeatureBuilder')
|
|
73
74
|
raise TypeError("feature_builder must be an instance of GeologicalFeatureBuilder")
|
|
75
|
+
# keep the fold type of the source builder, DFI otherwise
|
|
76
|
+
source_type = getattr(feature_builder.interpolator, "type", None)
|
|
77
|
+
interpolatortype = (
|
|
78
|
+
'P2Fold' if source_type == InterpolatorType.PIECEWISE_QUADRATIC_FOLD else 'DFI'
|
|
79
|
+
)
|
|
74
80
|
builder = cls(
|
|
75
|
-
interpolatortype=
|
|
81
|
+
interpolatortype=interpolatortype,
|
|
76
82
|
bounding_box=feature_builder.model.bounding_box,
|
|
77
83
|
fold=fold,
|
|
78
84
|
nelements=feature_builder.interpolator.n_elements,
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fold/_fold.py
RENAMED
|
@@ -104,22 +104,11 @@ class FoldEvent:
|
|
|
104
104
|
dgz[mask, :] /= np.linalg.norm(dgz[mask, :], axis=1)[:, None]
|
|
105
105
|
R2 = self.rot_mat(fold_axis, self.fold_limb_rotation(gx))
|
|
106
106
|
fold_direction = np.einsum("ijk,ki->kj", R2, dgx)
|
|
107
|
-
fold_direction /= np.
|
|
108
|
-
# calculate dot product between fold_direction and axis
|
|
109
|
-
# if its less than 0 then inverse dgz
|
|
110
|
-
d = np.einsum("ij,ik->i", fold_direction, fold_axis)
|
|
107
|
+
fold_direction /= np.linalg.norm(fold_direction, axis=1)[:, None]
|
|
111
108
|
|
|
112
109
|
if self.invert_norm:
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
elif not self.invert_norm:
|
|
117
|
-
return fold_direction, fold_axis, dgz
|
|
118
|
-
else:
|
|
119
|
-
logger.warning("invert fold frame param not valid. Defaulting to false.")
|
|
120
|
-
return fold_direction, fold_axis, dgz
|
|
121
|
-
|
|
122
|
-
# return fold_direction, fold_axis, dgz
|
|
110
|
+
dgz = -dgz
|
|
111
|
+
return fold_direction, fold_axis, dgz
|
|
123
112
|
|
|
124
113
|
# def get_regularisation_direction(self, points):
|
|
125
114
|
# self.foldframe.features[2].evaluate_gradient(points)
|
|
@@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta'
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = 'LoopStructural'
|
|
7
|
-
version = "1.8.
|
|
7
|
+
version = "1.8.4"
|
|
8
8
|
description = '3D geological modelling'
|
|
9
9
|
authors = [{ name = 'Lachlan Grose', email = 'lachlan.grose@monash.edu' }]
|
|
10
10
|
readme = 'README.md'
|
|
@@ -97,6 +97,7 @@ LoopStructural = { workspace = true }
|
|
|
97
97
|
[tool.pytest.ini_options]
|
|
98
98
|
addopts = "--import-mode=importlib"
|
|
99
99
|
testpaths = ["tests"]
|
|
100
|
+
pythonpath = ["."]
|
|
100
101
|
|
|
101
102
|
[tool.isort]
|
|
102
103
|
profile = 'black'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/refolded_fold.csv
RENAMED
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/datasets/data/tabular_intrusion.csv
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/interpolators/_constant_norm.py
RENAMED
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/interpolators/_cython/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/interpolators/_interpolatortype.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/_feature_registry.py
RENAMED
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/_model_serializer.py
RENAMED
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/core/fault_topology.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/_structural_frame.py
RENAMED
|
File without changes
|
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/builders/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fault/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fold/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fold/_foldframe.py
RENAMED
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/features/fold/_svariogram.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/input/fault_network.py
RENAMED
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/input/map2loop_processor.py
RENAMED
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/input/process_data.py
RENAMED
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/input/project_file.py
RENAMED
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/intrusions/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{loopstructural-1.8.0 → loopstructural-1.8.4}/LoopStructural/modelling/intrusions/intrusion_frame.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|