LoopStructural 1.6.16__tar.gz → 1.6.18__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.
Potentially problematic release.
This version of LoopStructural might be problematic. Click here for more details.
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/__init__.py +1 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_geological_interpolator.py +1 -2
- loopstructural-1.6.18/LoopStructural/modelling/core/fault_topology.py +234 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/core/geological_model.py +43 -34
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/core/stratigraphic_column.py +129 -25
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/fold/_svariogram.py +3 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/__init__.py +1 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/_surface.py +6 -1
- loopstructural-1.6.18/LoopStructural/utils/observer.py +150 -0
- loopstructural-1.6.18/LoopStructural/version.py +1 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural.egg-info/PKG-INFO +1 -1
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural.egg-info/SOURCES.txt +2 -1
- {loopstructural-1.6.16 → loopstructural-1.6.18}/PKG-INFO +1 -1
- {loopstructural-1.6.16 → loopstructural-1.6.18}/setup.cfg +0 -2
- loopstructural-1.6.16/LoopStructural/version.py +0 -1
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LICENSE +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/_base.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/_example_models.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/claudius.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/claudiusbb.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/duplex.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/duplexbb.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/fault_trace/fault_trace.cpg +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/fault_trace/fault_trace.dbf +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/fault_trace/fault_trace.prj +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/fault_trace/fault_trace.shp +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/fault_trace/fault_trace.shx +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/geological_map_data/bbox.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/geological_map_data/contacts.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/geological_map_data/fault_displacement.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/geological_map_data/fault_edges.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/geological_map_data/fault_locations.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/geological_map_data/fault_orientations.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/geological_map_data/stratigraphic_order.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/geological_map_data/stratigraphic_orientations.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/geological_map_data/stratigraphic_thickness.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/intrusion.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/intrusionbb.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/onefoldbb.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/onefolddata.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/refolded_bb.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/refolded_fold.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datasets/data/tabular_intrusion.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datatypes/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datatypes/_bounding_box.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datatypes/_point.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datatypes/_structured_grid.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/datatypes/_surface.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/export/exporters.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/export/file_formats.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/export/geoh5.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/export/gocad.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/export/omf_wrapper.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_api.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_builders.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_constant_norm.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_cython/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_discrete_fold_interpolator.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_discrete_interpolator.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_finite_difference_interpolator.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_interpolator_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_interpolator_factory.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_interpolatortype.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_operator.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_p1interpolator.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_p2interpolator.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/_surfe_wrapper.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/_2d_base_unstructured.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/_2d_p1_unstructured.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/_2d_p2_unstructured.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/_2d_structured_grid.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/_2d_structured_tetra.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/_3d_base_structured.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/_3d_p2_tetra.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/_3d_structured_grid.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/_3d_structured_tetra.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/_3d_unstructured_tetra.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/_aabb.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/_base_support.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/_face_table.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/interpolators/supports/_support_factory.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/core/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/_analytical_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/_base_geological_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/_cross_product_geological_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/_geological_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/_lambda_geological_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/_projected_vector_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/_region.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/_structural_frame.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/_unconformity_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/builders/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/builders/_base_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/builders/_fault_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/builders/_folded_feature_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/builders/_geological_feature_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/builders/_structural_frame_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/fault/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/fault/_fault_function.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/fault/_fault_function_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/fault/_fault_segment.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/fold/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/fold/_fold.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/fold/_fold_rotation_angle_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/fold/_foldframe.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/fold/fold_function/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/fold/fold_function/_base_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/fold/fold_function/_fourier_series_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/fold/fold_function/_lambda_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/features/fold/fold_function/_trigo_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/input/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/input/fault_network.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/input/map2loop_processor.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/input/process_data.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/input/project_file.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/intrusions/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/intrusions/geom_conceptual_models.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/intrusions/geometric_scaling_functions.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/intrusions/intrusion_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/intrusions/intrusion_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/intrusions/intrusion_frame_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/intrusions/intrusion_support_functions.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/_transformation.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/colours.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/config.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/dtm_creator.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/exceptions.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/features.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/helper.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/json_encoder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/linalg.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/logging.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/maths.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/regions.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/typing.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/utils/utils.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/visualisation/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural.egg-info/dependency_links.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural.egg-info/requires.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural.egg-info/top_level.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/README.md +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/pyproject.toml +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.18}/setup.py +0 -0
|
@@ -20,6 +20,7 @@ ch.setLevel(logging.WARNING)
|
|
|
20
20
|
loggers = {}
|
|
21
21
|
from .modelling.core.geological_model import GeologicalModel
|
|
22
22
|
from .modelling.core.stratigraphic_column import StratigraphicColumn
|
|
23
|
+
from .modelling.core.fault_topology import FaultTopology
|
|
23
24
|
from .interpolators._api import LoopInterpolator
|
|
24
25
|
from .interpolators import InterpolatorBuilder
|
|
25
26
|
from .datatypes import BoundingBox
|
|
@@ -166,8 +166,7 @@ class GeologicalInterpolator(metaclass=ABCMeta):
|
|
|
166
166
|
"""
|
|
167
167
|
if points.shape[1] == self.dimensions * 2:
|
|
168
168
|
points = np.hstack([points, np.ones((points.shape[0], 1))])
|
|
169
|
-
logger.
|
|
170
|
-
raise Warning
|
|
169
|
+
logger.info("No weight provided for normal constraints, all weights are set to 1")
|
|
171
170
|
if points.shape[1] < self.dimensions * 2 + 1:
|
|
172
171
|
raise ValueError("Normal constraints must at least have X,Y,Z,nx,ny,nz")
|
|
173
172
|
self.n_n = points.shape[0]
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
from ..features.fault import FaultSegment
|
|
2
|
+
from ...utils import Observable
|
|
3
|
+
from .stratigraphic_column import StratigraphicColumn
|
|
4
|
+
import enum
|
|
5
|
+
import numpy as np
|
|
6
|
+
class FaultRelationshipType(enum.Enum):
|
|
7
|
+
ABUTTING = "abutting"
|
|
8
|
+
FAULTED = "faulted"
|
|
9
|
+
NONE = "none"
|
|
10
|
+
|
|
11
|
+
class FaultTopology(Observable['FaultTopology']):
|
|
12
|
+
"""A graph representation of the relationships between faults and the
|
|
13
|
+
relationship with stratigraphic units.
|
|
14
|
+
"""
|
|
15
|
+
def __init__(self, stratigraphic_column: 'StratigraphicColumn'):
|
|
16
|
+
super().__init__()
|
|
17
|
+
self.faults = []
|
|
18
|
+
self.stratigraphic_column = stratigraphic_column
|
|
19
|
+
self.adjacency = {}
|
|
20
|
+
self.stratigraphy_fault_relationships = {}
|
|
21
|
+
def add_fault(self, fault: FaultSegment):
|
|
22
|
+
"""
|
|
23
|
+
Adds a fault to the fault topology.
|
|
24
|
+
"""
|
|
25
|
+
if not isinstance(fault, str):
|
|
26
|
+
raise TypeError("Expected a fault name.")
|
|
27
|
+
|
|
28
|
+
self.faults.append(fault)
|
|
29
|
+
self.notify('fault_added', fault=fault)
|
|
30
|
+
|
|
31
|
+
def remove_fault(self, fault: str):
|
|
32
|
+
"""
|
|
33
|
+
Removes a fault from the fault topology.
|
|
34
|
+
"""
|
|
35
|
+
if fault not in self.faults:
|
|
36
|
+
raise ValueError(f"Fault {fault} not found in the topology.")
|
|
37
|
+
|
|
38
|
+
self.faults.remove(fault)
|
|
39
|
+
# Remove any relationships involving this fault
|
|
40
|
+
self.adjacency = {k: v for k, v in self.adjacency.items() if fault not in k}
|
|
41
|
+
self.stratigraphy_fault_relationships = {
|
|
42
|
+
k: v for k, v in self.stratigraphy_fault_relationships.items() if k[1] != fault
|
|
43
|
+
}
|
|
44
|
+
self.notify('fault_removed', fault=fault)
|
|
45
|
+
|
|
46
|
+
def add_abutting_relationship(self, fault_name: str, abutting_fault: str):
|
|
47
|
+
"""
|
|
48
|
+
Adds an abutting relationship between two faults.
|
|
49
|
+
"""
|
|
50
|
+
if fault_name not in self.faults or abutting_fault not in self.faults:
|
|
51
|
+
raise ValueError("Both faults must be part of the fault topology.")
|
|
52
|
+
|
|
53
|
+
if fault_name not in self.adjacency:
|
|
54
|
+
self.adjacency[fault_name] = []
|
|
55
|
+
|
|
56
|
+
self.adjacency[(fault_name, abutting_fault)] = FaultRelationshipType.ABUTTING
|
|
57
|
+
self.notify('abutting_relationship_added', {'fault': fault_name, 'abutting_fault': abutting_fault})
|
|
58
|
+
def add_stratigraphy_fault_relationship(self, unit_name:str, fault_name: str):
|
|
59
|
+
"""
|
|
60
|
+
Adds a relationship between a stratigraphic unit and a fault.
|
|
61
|
+
"""
|
|
62
|
+
if fault_name not in self.faults:
|
|
63
|
+
raise ValueError("Fault must be part of the fault topology.")
|
|
64
|
+
|
|
65
|
+
if unit_name is None:
|
|
66
|
+
raise ValueError(f"No stratigraphic group found for unit name: {unit_name}")
|
|
67
|
+
self.stratigraphy_fault_relationships[(unit_name,fault_name)] = True
|
|
68
|
+
|
|
69
|
+
self.notify('stratigraphy_fault_relationship_added', {'unit': unit_name, 'fault': fault_name})
|
|
70
|
+
def add_faulted_relationship(self, fault_name: str, faulted_fault_name: str):
|
|
71
|
+
"""
|
|
72
|
+
Adds a faulted relationship between two faults.
|
|
73
|
+
"""
|
|
74
|
+
if fault_name not in self.faults or faulted_fault_name not in self.faults:
|
|
75
|
+
raise ValueError("Both faults must be part of the fault topology.")
|
|
76
|
+
|
|
77
|
+
if fault_name not in self.adjacency:
|
|
78
|
+
self.adjacency[fault_name] = []
|
|
79
|
+
|
|
80
|
+
self.adjacency[(fault_name, faulted_fault_name)] = FaultRelationshipType.FAULTED
|
|
81
|
+
self.notify('faulted_relationship_added', {'fault': fault_name, 'faulted_fault': faulted_fault_name})
|
|
82
|
+
def remove_fault_relationship(self, fault_name: str, related_fault_name: str):
|
|
83
|
+
"""
|
|
84
|
+
Removes a relationship between two faults.
|
|
85
|
+
"""
|
|
86
|
+
if (fault_name, related_fault_name) in self.adjacency:
|
|
87
|
+
del self.adjacency[(fault_name, related_fault_name)]
|
|
88
|
+
elif (related_fault_name, fault_name) in self.adjacency:
|
|
89
|
+
del self.adjacency[(related_fault_name, fault_name)]
|
|
90
|
+
else:
|
|
91
|
+
raise ValueError(f"No relationship found between {fault_name} and {related_fault_name}.")
|
|
92
|
+
self.notify('fault_relationship_removed', {'fault': fault_name, 'related_fault': related_fault_name})
|
|
93
|
+
def update_fault_relationship(self, fault_name: str, related_fault_name: str, new_relationship_type: FaultRelationshipType):
|
|
94
|
+
if new_relationship_type == FaultRelationshipType.NONE:
|
|
95
|
+
self.adjacency.pop((fault_name, related_fault_name), None)
|
|
96
|
+
else:
|
|
97
|
+
self.adjacency[(fault_name, related_fault_name)] = new_relationship_type
|
|
98
|
+
self.notify('fault_relationship_updated', {'fault': fault_name, 'related_fault': related_fault_name, 'new_relationship_type': new_relationship_type})
|
|
99
|
+
def change_relationship_type(self, fault_name: str, related_fault_name: str, new_relationship_type: FaultRelationshipType):
|
|
100
|
+
"""
|
|
101
|
+
Changes the relationship type between two faults.
|
|
102
|
+
"""
|
|
103
|
+
if (fault_name, related_fault_name) in self.adjacency:
|
|
104
|
+
self.adjacency[(fault_name, related_fault_name)] = new_relationship_type
|
|
105
|
+
|
|
106
|
+
else:
|
|
107
|
+
raise ValueError(f"No relationship found between {fault_name} and {related_fault_name}.")
|
|
108
|
+
self.notify('relationship_type_changed', {'fault': fault_name, 'related_fault': related_fault_name, 'new_relationship_type': new_relationship_type})
|
|
109
|
+
def get_fault_relationships(self, fault_name: str):
|
|
110
|
+
"""
|
|
111
|
+
Returns a list of relationships for a given fault.
|
|
112
|
+
"""
|
|
113
|
+
relationships = []
|
|
114
|
+
for (f1, f2), relationship_type in self.adjacency.items():
|
|
115
|
+
if f1 == fault_name or f2 == fault_name:
|
|
116
|
+
relationships.append((f1, f2, relationship_type))
|
|
117
|
+
return relationships
|
|
118
|
+
def get_fault_relationship(self, fault_name: str, related_fault_name: str):
|
|
119
|
+
"""
|
|
120
|
+
Returns the relationship type between two faults.
|
|
121
|
+
"""
|
|
122
|
+
return self.adjacency.get((fault_name, related_fault_name), FaultRelationshipType.NONE)
|
|
123
|
+
def get_faults(self):
|
|
124
|
+
"""
|
|
125
|
+
Returns a list of all faults in the topology.
|
|
126
|
+
"""
|
|
127
|
+
return self.faults
|
|
128
|
+
|
|
129
|
+
def get_stratigraphy_fault_relationships(self):
|
|
130
|
+
"""
|
|
131
|
+
Returns a dictionary of stratigraphic unit to fault relationships.
|
|
132
|
+
"""
|
|
133
|
+
return self.stratigraphy_fault_relationships
|
|
134
|
+
def get_fault_stratigraphic_unit_relationships(self):
|
|
135
|
+
units_group_pairs = self.stratigraphic_column.get_group_unit_pairs()
|
|
136
|
+
matrix = np.zeros((len(self.faults), len(units_group_pairs)), dtype=int)
|
|
137
|
+
for i, fault in enumerate(self.faults):
|
|
138
|
+
for j, (unit_name, _group) in enumerate(units_group_pairs):
|
|
139
|
+
if (unit_name, fault) in self.stratigraphy_fault_relationships:
|
|
140
|
+
matrix[i, j] = 1
|
|
141
|
+
|
|
142
|
+
return matrix
|
|
143
|
+
def get_fault_stratigraphic_relationship(self, unit_name: str, fault:str) -> bool:
|
|
144
|
+
"""
|
|
145
|
+
Returns a dictionary of fault to stratigraphic unit relationships.
|
|
146
|
+
"""
|
|
147
|
+
if unit_name is None:
|
|
148
|
+
raise ValueError(f"No stratigraphic group found for unit name: {unit_name}")
|
|
149
|
+
if (unit_name, fault) not in self.stratigraphy_fault_relationships:
|
|
150
|
+
return False
|
|
151
|
+
return self.stratigraphy_fault_relationships[(unit_name, fault)]
|
|
152
|
+
|
|
153
|
+
def update_fault_stratigraphy_relationship(self, unit_name: str, fault_name: str, flag: bool = True):
|
|
154
|
+
"""
|
|
155
|
+
Updates the relationship between a stratigraphic unit and a fault.
|
|
156
|
+
"""
|
|
157
|
+
if not flag:
|
|
158
|
+
if (unit_name, fault_name) in self.stratigraphy_fault_relationships:
|
|
159
|
+
del self.stratigraphy_fault_relationships[(unit_name, fault_name)]
|
|
160
|
+
else:
|
|
161
|
+
self.stratigraphy_fault_relationships[(unit_name, fault_name)] = flag
|
|
162
|
+
|
|
163
|
+
self.notify('stratigraphy_fault_relationship_updated', {'unit': unit_name, 'fault': fault_name})
|
|
164
|
+
|
|
165
|
+
def remove_fault_stratigraphy_relationship(self, unit_name: str, fault_name: str):
|
|
166
|
+
"""
|
|
167
|
+
Removes a relationship between a stratigraphic unit and a fault.
|
|
168
|
+
"""
|
|
169
|
+
if (unit_name, fault_name) not in self.stratigraphy_fault_relationships:
|
|
170
|
+
raise ValueError(f"No relationship found between unit {unit_name} and fault {fault_name}.")
|
|
171
|
+
else:
|
|
172
|
+
self.stratigraphy_fault_relationships.pop((unit_name, fault_name), None)
|
|
173
|
+
|
|
174
|
+
self.notify('stratigraphy_fault_relationship_removed', {'unit': unit_name, 'fault': fault_name})
|
|
175
|
+
def get_matrix(self):
|
|
176
|
+
"""
|
|
177
|
+
Returns a matrix representation of the fault relationships.
|
|
178
|
+
"""
|
|
179
|
+
matrix = np.zeros((len(self.faults), len(self.faults)), dtype=int)
|
|
180
|
+
for (fault_name, related_fault_name), relationship_type in self.adjacency.items():
|
|
181
|
+
fault_index = self.faults.index(next(f for f in self.faults if f == fault_name))
|
|
182
|
+
related_fault_index = self.faults.index(next(f for f in self.faults if f == related_fault_name))
|
|
183
|
+
if relationship_type == FaultRelationshipType.ABUTTING:
|
|
184
|
+
matrix[fault_index, related_fault_index] = 1
|
|
185
|
+
elif relationship_type == FaultRelationshipType.FAULTED:
|
|
186
|
+
matrix[fault_index, related_fault_index] = 2
|
|
187
|
+
return matrix
|
|
188
|
+
|
|
189
|
+
def to_dict(self):
|
|
190
|
+
"""
|
|
191
|
+
Returns a dictionary representation of the fault topology.
|
|
192
|
+
"""
|
|
193
|
+
return {
|
|
194
|
+
"faults": self.faults,
|
|
195
|
+
"adjacency": self.adjacency,
|
|
196
|
+
"stratigraphy_fault_relationships": self.stratigraphy_fault_relationships,
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
def update_from_dict(self, data):
|
|
200
|
+
"""
|
|
201
|
+
Updates the fault topology from a dictionary representation.
|
|
202
|
+
"""
|
|
203
|
+
with self.freeze_notifications():
|
|
204
|
+
self.faults.extend(data.get("faults", []))
|
|
205
|
+
adjacency = data.get("adjacency", {})
|
|
206
|
+
stratigraphy_fault_relationships = data.get("stratigraphy_fault_relationships", {})
|
|
207
|
+
for (fault,abutting_fault) in adjacency.values():
|
|
208
|
+
if fault not in self.faults:
|
|
209
|
+
self.add_fault(fault)
|
|
210
|
+
if abutting_fault not in self.faults:
|
|
211
|
+
self.add_fault(abutting_fault)
|
|
212
|
+
self.add_abutting_relationship(fault, abutting_fault)
|
|
213
|
+
for unit_name, fault_names in stratigraphy_fault_relationships.items():
|
|
214
|
+
for fault_name in fault_names:
|
|
215
|
+
if fault_name not in self.faults:
|
|
216
|
+
self.add_fault(fault_name)
|
|
217
|
+
self.add_stratigraphy_fault_relationship(unit_name, fault_name)
|
|
218
|
+
|
|
219
|
+
@classmethod
|
|
220
|
+
def from_dict(cls, data):
|
|
221
|
+
"""
|
|
222
|
+
Creates a FaultTopology instance from a dictionary representation.
|
|
223
|
+
"""
|
|
224
|
+
from .stratigraphic_column import StratigraphicColumn
|
|
225
|
+
stratigraphic_column = data.get("stratigraphic_column",None)
|
|
226
|
+
if not isinstance(stratigraphic_column, StratigraphicColumn):
|
|
227
|
+
if isinstance(stratigraphic_column, dict):
|
|
228
|
+
stratigraphic_column = StratigraphicColumn.from_dict(stratigraphic_column)
|
|
229
|
+
elif not isinstance(stratigraphic_column, StratigraphicColumn):
|
|
230
|
+
raise TypeError("Expected 'stratigraphic_column' to be a StratigraphicColumn instance or dict.")
|
|
231
|
+
|
|
232
|
+
topology = cls(stratigraphic_column)
|
|
233
|
+
topology.update_from_dict(data)
|
|
234
|
+
return topology
|
{loopstructural-1.6.16 → loopstructural-1.6.18}/LoopStructural/modelling/core/geological_model.py
RENAMED
|
@@ -6,7 +6,7 @@ from ...utils import getLogger
|
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
import pandas as pd
|
|
9
|
-
from typing import List, Optional
|
|
9
|
+
from typing import List, Optional, Union, Dict
|
|
10
10
|
import pathlib
|
|
11
11
|
from ...modelling.features.fault import FaultSegment
|
|
12
12
|
|
|
@@ -123,8 +123,7 @@ class GeologicalModel:
|
|
|
123
123
|
self.feature_name_index = {}
|
|
124
124
|
self._data = pd.DataFrame() # None
|
|
125
125
|
|
|
126
|
-
self.
|
|
127
|
-
|
|
126
|
+
self._stratigraphic_column = StratigraphicColumn()
|
|
128
127
|
|
|
129
128
|
self.tol = 1e-10 * np.max(self.bounding_box.maximum - self.bounding_box.origin)
|
|
130
129
|
self._dtm = None
|
|
@@ -187,7 +186,6 @@ class GeologicalModel:
|
|
|
187
186
|
].astype(float)
|
|
188
187
|
return data
|
|
189
188
|
|
|
190
|
-
|
|
191
189
|
if "type" in data:
|
|
192
190
|
logger.warning("'type' is deprecated replace with 'feature_name' \n")
|
|
193
191
|
data.rename(columns={"type": "feature_name"}, inplace=True)
|
|
@@ -409,7 +407,6 @@ class GeologicalModel:
|
|
|
409
407
|
"""
|
|
410
408
|
return [f.name for f in self.faults]
|
|
411
409
|
|
|
412
|
-
|
|
413
410
|
def to_file(self, file):
|
|
414
411
|
"""Save a model to a pickle file requires dill
|
|
415
412
|
|
|
@@ -506,10 +503,34 @@ class GeologicalModel:
|
|
|
506
503
|
self._data = data.copy()
|
|
507
504
|
# self._data[['X','Y','Z']] = self.bounding_box.project(self._data[['X','Y','Z']].to_numpy())
|
|
508
505
|
|
|
509
|
-
|
|
510
506
|
def set_model_data(self, data):
|
|
511
507
|
logger.warning("deprecated method. Model data can now be set using the data attribute")
|
|
512
508
|
self.data = data.copy()
|
|
509
|
+
@property
|
|
510
|
+
def stratigraphic_column(self):
|
|
511
|
+
"""Get the stratigraphic column of the model
|
|
512
|
+
|
|
513
|
+
Returns
|
|
514
|
+
-------
|
|
515
|
+
StratigraphicColumn
|
|
516
|
+
the stratigraphic column of the model
|
|
517
|
+
"""
|
|
518
|
+
return self._stratigraphic_column
|
|
519
|
+
@stratigraphic_column.setter
|
|
520
|
+
def stratigraphic_column(self, stratigraphic_column: Union[StratigraphicColumn,Dict]):
|
|
521
|
+
"""Set the stratigraphic column of the model
|
|
522
|
+
|
|
523
|
+
Parameters
|
|
524
|
+
----------
|
|
525
|
+
stratigraphic_column : StratigraphicColumn
|
|
526
|
+
the stratigraphic column to set
|
|
527
|
+
"""
|
|
528
|
+
if isinstance(stratigraphic_column, dict):
|
|
529
|
+
self.set_stratigraphic_column(stratigraphic_column)
|
|
530
|
+
return
|
|
531
|
+
elif not isinstance(stratigraphic_column, StratigraphicColumn):
|
|
532
|
+
raise ValueError("stratigraphic_column must be a StratigraphicColumn object")
|
|
533
|
+
self._stratigraphic_column = stratigraphic_column
|
|
513
534
|
|
|
514
535
|
def set_stratigraphic_column(self, stratigraphic_column, cmap="tab20"):
|
|
515
536
|
"""
|
|
@@ -539,14 +560,14 @@ class GeologicalModel:
|
|
|
539
560
|
DeprecationWarning(
|
|
540
561
|
"set_stratigraphic_column is deprecated, use model.stratigraphic_column.add_units instead"
|
|
541
562
|
)
|
|
542
|
-
for g in stratigraphic_column.keys():
|
|
563
|
+
for i, g in enumerate(stratigraphic_column.keys()):
|
|
543
564
|
for u in stratigraphic_column[g].keys():
|
|
544
565
|
thickness = 0
|
|
545
566
|
if "min" in stratigraphic_column[g][u] and "max" in stratigraphic_column[g][u]:
|
|
546
567
|
min_val = stratigraphic_column[g][u]["min"]
|
|
547
568
|
max_val = stratigraphic_column[g][u].get("max", None)
|
|
548
569
|
thickness = max_val - min_val if max_val is not None else None
|
|
549
|
-
logger.
|
|
570
|
+
logger.info(
|
|
550
571
|
f"""
|
|
551
572
|
model.stratigraphic_column.add_unit({u},
|
|
552
573
|
colour={stratigraphic_column[g][u].get("colour", None)},
|
|
@@ -557,9 +578,11 @@ class GeologicalModel:
|
|
|
557
578
|
colour=stratigraphic_column[g][u].get("colour", None),
|
|
558
579
|
thickness=thickness,
|
|
559
580
|
)
|
|
581
|
+
|
|
560
582
|
self.stratigraphic_column.add_unconformity(
|
|
561
583
|
name=''.join([g, 'unconformity']),
|
|
562
584
|
)
|
|
585
|
+
self.stratigraphic_column.group_mapping[f'Group_{i+1}'] = g
|
|
563
586
|
|
|
564
587
|
def create_and_add_foliation(
|
|
565
588
|
self,
|
|
@@ -1400,7 +1423,6 @@ class GeologicalModel:
|
|
|
1400
1423
|
|
|
1401
1424
|
return self.bounding_box.reproject(points, inplace=inplace)
|
|
1402
1425
|
|
|
1403
|
-
|
|
1404
1426
|
# TODO move scale to bounding box/transformer
|
|
1405
1427
|
def scale(self, points: np.ndarray, *, inplace: bool = False) -> np.ndarray:
|
|
1406
1428
|
"""Take points in UTM coordinates and reproject
|
|
@@ -1419,7 +1441,6 @@ class GeologicalModel:
|
|
|
1419
1441
|
"""
|
|
1420
1442
|
return self.bounding_box.project(np.array(points).astype(float), inplace=inplace)
|
|
1421
1443
|
|
|
1422
|
-
|
|
1423
1444
|
def regular_grid(self, *, nsteps=None, shuffle=True, rescale=False, order="C"):
|
|
1424
1445
|
"""
|
|
1425
1446
|
Return a regular grid within the model bounding box
|
|
@@ -1494,22 +1515,18 @@ class GeologicalModel:
|
|
|
1494
1515
|
if self.stratigraphic_column is None:
|
|
1495
1516
|
logger.warning("No stratigraphic column defined")
|
|
1496
1517
|
return strat_id
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
feature_id = self.feature_name_index.get(
|
|
1518
|
+
|
|
1519
|
+
s_id = 0
|
|
1520
|
+
for g in reversed(self.stratigraphic_column.get_groups()):
|
|
1521
|
+
feature_id = self.feature_name_index.get(g.name, -1)
|
|
1501
1522
|
if feature_id >= 0:
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
np.logical_and(
|
|
1507
|
-
vals < series.get("max", feature.max()),
|
|
1508
|
-
vals > series.get("min", feature.min()),
|
|
1509
|
-
)
|
|
1510
|
-
] = series["id"]
|
|
1523
|
+
vals = self.features[feature_id].evaluate_value(xyz)
|
|
1524
|
+
for u in g.units:
|
|
1525
|
+
strat_id[np.logical_and(vals < u.max(), vals > u.min())] = s_id
|
|
1526
|
+
s_id += 1
|
|
1511
1527
|
if feature_id == -1:
|
|
1512
|
-
logger.error(f"Model does not contain {
|
|
1528
|
+
logger.error(f"Model does not contain {g.name}")
|
|
1529
|
+
|
|
1513
1530
|
return strat_id
|
|
1514
1531
|
|
|
1515
1532
|
def evaluate_model_gradient(self, points: np.ndarray, *, scale: bool = True) -> np.ndarray:
|
|
@@ -1710,16 +1727,8 @@ class GeologicalModel:
|
|
|
1710
1727
|
ids : list
|
|
1711
1728
|
list of unique stratigraphic ids, featurename, unit name and min and max scalar values
|
|
1712
1729
|
"""
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
logger.warning('No stratigraphic column defined')
|
|
1716
|
-
return ids
|
|
1717
|
-
for group in self.stratigraphic_column.keys():
|
|
1718
|
-
if group == "faults":
|
|
1719
|
-
continue
|
|
1720
|
-
for name, series in self.stratigraphic_column[group].items():
|
|
1721
|
-
ids.append([series["id"], group, name, series['min'], series['max']])
|
|
1722
|
-
return ids
|
|
1730
|
+
return self.stratigraphic_column.get_stratigraphic_ids()
|
|
1731
|
+
|
|
1723
1732
|
|
|
1724
1733
|
def get_fault_surfaces(self, faults: List[str] = []):
|
|
1725
1734
|
surfaces = []
|