LoopStructural 1.6.16__tar.gz → 1.6.17__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.17}/LoopStructural/__init__.py +1 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_geological_interpolator.py +1 -2
- loopstructural-1.6.17/LoopStructural/modelling/core/fault_topology.py +234 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/core/geological_model.py +37 -22
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/core/stratigraphic_column.py +42 -15
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/__init__.py +1 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/_surface.py +6 -1
- loopstructural-1.6.17/LoopStructural/utils/observer.py +150 -0
- loopstructural-1.6.17/LoopStructural/version.py +1 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural.egg-info/PKG-INFO +1 -1
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural.egg-info/SOURCES.txt +2 -1
- {loopstructural-1.6.16 → loopstructural-1.6.17}/PKG-INFO +1 -1
- {loopstructural-1.6.16 → loopstructural-1.6.17}/setup.cfg +0 -2
- loopstructural-1.6.16/LoopStructural/version.py +0 -1
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LICENSE +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/_base.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/_example_models.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/claudius.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/claudiusbb.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/duplex.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/duplexbb.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/fault_trace/fault_trace.cpg +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/fault_trace/fault_trace.dbf +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/fault_trace/fault_trace.prj +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/fault_trace/fault_trace.shp +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/fault_trace/fault_trace.shx +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/bbox.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/contacts.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/fault_displacement.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/fault_edges.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/fault_locations.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/fault_orientations.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/stratigraphic_order.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/stratigraphic_orientations.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/stratigraphic_thickness.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/intrusion.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/intrusionbb.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/onefoldbb.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/onefolddata.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/refolded_bb.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/refolded_fold.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datasets/data/tabular_intrusion.csv +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datatypes/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datatypes/_bounding_box.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datatypes/_point.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datatypes/_structured_grid.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/datatypes/_surface.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/export/exporters.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/export/file_formats.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/export/geoh5.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/export/gocad.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/export/omf_wrapper.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_api.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_builders.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_constant_norm.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_cython/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_discrete_fold_interpolator.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_discrete_interpolator.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_finite_difference_interpolator.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_interpolator_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_interpolator_factory.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_interpolatortype.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_operator.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_p1interpolator.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_p2interpolator.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/_surfe_wrapper.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_2d_base_unstructured.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_2d_p1_unstructured.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_2d_p2_unstructured.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_2d_structured_grid.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_2d_structured_tetra.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_3d_base_structured.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_3d_p2_tetra.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_3d_structured_grid.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_3d_structured_tetra.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_3d_unstructured_tetra.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_aabb.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_base_support.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_face_table.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_support_factory.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/core/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/_analytical_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/_base_geological_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/_cross_product_geological_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/_geological_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/_lambda_geological_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/_projected_vector_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/_region.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/_structural_frame.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/_unconformity_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/builders/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/builders/_base_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/builders/_fault_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/builders/_folded_feature_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/builders/_geological_feature_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/builders/_structural_frame_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/fault/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/fault/_fault_function.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/fault/_fault_function_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/fault/_fault_segment.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/_fold.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/_fold_rotation_angle_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/_foldframe.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/_svariogram.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/fold_function/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/fold_function/_base_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/fold_function/_fourier_series_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/fold_function/_lambda_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/fold_function/_trigo_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/input/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/input/fault_network.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/input/map2loop_processor.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/input/process_data.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/input/project_file.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/intrusions/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/intrusions/geom_conceptual_models.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/intrusions/geometric_scaling_functions.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/intrusions/intrusion_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/intrusions/intrusion_feature.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/intrusions/intrusion_frame_builder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/modelling/intrusions/intrusion_support_functions.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/_transformation.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/colours.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/config.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/dtm_creator.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/exceptions.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/features.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/helper.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/json_encoder.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/linalg.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/logging.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/maths.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/regions.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/typing.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/utils/utils.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural/visualisation/__init__.py +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural.egg-info/dependency_links.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural.egg-info/requires.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/LoopStructural.egg-info/top_level.txt +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/README.md +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/pyproject.toml +0 -0
- {loopstructural-1.6.16 → loopstructural-1.6.17}/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.17}/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
|
"""
|
|
@@ -1400,7 +1421,6 @@ class GeologicalModel:
|
|
|
1400
1421
|
|
|
1401
1422
|
return self.bounding_box.reproject(points, inplace=inplace)
|
|
1402
1423
|
|
|
1403
|
-
|
|
1404
1424
|
# TODO move scale to bounding box/transformer
|
|
1405
1425
|
def scale(self, points: np.ndarray, *, inplace: bool = False) -> np.ndarray:
|
|
1406
1426
|
"""Take points in UTM coordinates and reproject
|
|
@@ -1419,7 +1439,6 @@ class GeologicalModel:
|
|
|
1419
1439
|
"""
|
|
1420
1440
|
return self.bounding_box.project(np.array(points).astype(float), inplace=inplace)
|
|
1421
1441
|
|
|
1422
|
-
|
|
1423
1442
|
def regular_grid(self, *, nsteps=None, shuffle=True, rescale=False, order="C"):
|
|
1424
1443
|
"""
|
|
1425
1444
|
Return a regular grid within the model bounding box
|
|
@@ -1494,22 +1513,18 @@ class GeologicalModel:
|
|
|
1494
1513
|
if self.stratigraphic_column is None:
|
|
1495
1514
|
logger.warning("No stratigraphic column defined")
|
|
1496
1515
|
return strat_id
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
feature_id = self.feature_name_index.get(
|
|
1516
|
+
|
|
1517
|
+
s_id = 0
|
|
1518
|
+
for g in reversed(self.stratigraphic_column.get_groups()):
|
|
1519
|
+
feature_id = self.feature_name_index.get(g.name, -1)
|
|
1501
1520
|
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"]
|
|
1521
|
+
vals = self.features[feature_id].evaluate_value(xyz)
|
|
1522
|
+
for u in g.units:
|
|
1523
|
+
strat_id[np.logical_and(vals < u.max, vals > u.min)] = s_id
|
|
1524
|
+
s_id += 1
|
|
1511
1525
|
if feature_id == -1:
|
|
1512
|
-
logger.error(f"Model does not contain {
|
|
1526
|
+
logger.error(f"Model does not contain {g.name}")
|
|
1527
|
+
|
|
1513
1528
|
return strat_id
|
|
1514
1529
|
|
|
1515
1530
|
def evaluate_model_gradient(self, points: np.ndarray, *, scale: bool = True) -> np.ndarray:
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import enum
|
|
2
|
-
from typing import Dict
|
|
2
|
+
from typing import Dict, Optional, List, Tuple
|
|
3
3
|
import numpy as np
|
|
4
|
-
from LoopStructural.utils import rng, getLogger
|
|
5
|
-
|
|
4
|
+
from LoopStructural.utils import rng, getLogger, Observable
|
|
6
5
|
logger = getLogger(__name__)
|
|
7
6
|
logger.info("Imported LoopStructural Stratigraphic Column module")
|
|
8
7
|
class UnconformityType(enum.Enum):
|
|
@@ -154,7 +153,7 @@ class StratigraphicGroup:
|
|
|
154
153
|
self.units = units if units is not None else []
|
|
155
154
|
|
|
156
155
|
|
|
157
|
-
class StratigraphicColumn:
|
|
156
|
+
class StratigraphicColumn(Observable['StratigraphicColumn']):
|
|
158
157
|
"""
|
|
159
158
|
A class to represent a stratigraphic column, which is a vertical section of the Earth's crust
|
|
160
159
|
showing the sequence of rock layers and their relationships.
|
|
@@ -164,6 +163,7 @@ class StratigraphicColumn:
|
|
|
164
163
|
"""
|
|
165
164
|
Initializes the StratigraphicColumn with a name and a list of layers.
|
|
166
165
|
"""
|
|
166
|
+
super().__init__()
|
|
167
167
|
self.order = [StratigraphicUnit(name='Basement', colour='grey', thickness=np.inf),StratigraphicUnconformity(name='Base Unconformity', unconformity_type=UnconformityType.ERODE)]
|
|
168
168
|
self.group_mapping = {}
|
|
169
169
|
def clear(self,basement=True):
|
|
@@ -175,7 +175,7 @@ class StratigraphicColumn:
|
|
|
175
175
|
else:
|
|
176
176
|
self.order = []
|
|
177
177
|
self.group_mapping = {}
|
|
178
|
-
|
|
178
|
+
self.notify('column_cleared')
|
|
179
179
|
def add_unit(self, name,*, colour=None, thickness=None, where='top'):
|
|
180
180
|
unit = StratigraphicUnit(name=name, colour=colour, thickness=thickness)
|
|
181
181
|
|
|
@@ -185,7 +185,7 @@ class StratigraphicColumn:
|
|
|
185
185
|
self.order.insert(0, unit)
|
|
186
186
|
else:
|
|
187
187
|
raise ValueError("Invalid 'where' argument. Use 'top' or 'bottom'.")
|
|
188
|
-
|
|
188
|
+
self.notify('unit_added', unit=unit)
|
|
189
189
|
return unit
|
|
190
190
|
|
|
191
191
|
def remove_unit(self, uuid):
|
|
@@ -195,7 +195,9 @@ class StratigraphicColumn:
|
|
|
195
195
|
for i, element in enumerate(self.order):
|
|
196
196
|
if element.uuid == uuid:
|
|
197
197
|
del self.order[i]
|
|
198
|
+
self.notify('unit_removed', uuid=uuid)
|
|
198
199
|
return True
|
|
200
|
+
|
|
199
201
|
return False
|
|
200
202
|
|
|
201
203
|
def add_unconformity(self, name, *, unconformity_type=UnconformityType.ERODE, where='top' ):
|
|
@@ -209,6 +211,7 @@ class StratigraphicColumn:
|
|
|
209
211
|
self.order.insert(0, unconformity)
|
|
210
212
|
else:
|
|
211
213
|
raise ValueError("Invalid 'where' argument. Use 'top' or 'bottom'.")
|
|
214
|
+
self.notify('unconformity_added', unconformity=unconformity)
|
|
212
215
|
return unconformity
|
|
213
216
|
|
|
214
217
|
def get_element_by_index(self, index):
|
|
@@ -228,6 +231,7 @@ class StratigraphicColumn:
|
|
|
228
231
|
return unit
|
|
229
232
|
|
|
230
233
|
return None
|
|
234
|
+
|
|
231
235
|
def get_unconformity_by_name(self, name):
|
|
232
236
|
"""
|
|
233
237
|
Retrieves an unconformity by its name from the stratigraphic column.
|
|
@@ -245,6 +249,15 @@ class StratigraphicColumn:
|
|
|
245
249
|
if element.uuid == uuid:
|
|
246
250
|
return element
|
|
247
251
|
raise KeyError(f"No element found with uuid: {uuid}")
|
|
252
|
+
|
|
253
|
+
def get_group_for_unit_name(self, unit_name:str) -> Optional[StratigraphicGroup]:
|
|
254
|
+
"""
|
|
255
|
+
Retrieves the group for a given unit name.
|
|
256
|
+
"""
|
|
257
|
+
for group in self.get_groups():
|
|
258
|
+
if any(unit.name == unit_name for unit in group.units):
|
|
259
|
+
return group
|
|
260
|
+
return None
|
|
248
261
|
def add_element(self, element):
|
|
249
262
|
"""
|
|
250
263
|
Adds a StratigraphicColumnElement to the stratigraphic column.
|
|
@@ -296,7 +309,18 @@ class StratigraphicColumn:
|
|
|
296
309
|
group = [u.name for u in g.units if isinstance(u, StratigraphicUnit)]
|
|
297
310
|
groups_list.append(group)
|
|
298
311
|
return groups_list
|
|
299
|
-
|
|
312
|
+
|
|
313
|
+
def get_group_unit_pairs(self) -> List[Tuple[str,str]]:
|
|
314
|
+
"""
|
|
315
|
+
Returns a list of tuples containing group names and unit names.
|
|
316
|
+
"""
|
|
317
|
+
groups = self.get_groups()
|
|
318
|
+
group_unit_pairs = []
|
|
319
|
+
for g in groups:
|
|
320
|
+
for u in g.units:
|
|
321
|
+
if isinstance(u, StratigraphicUnit):
|
|
322
|
+
group_unit_pairs.append((g.name, u.name))
|
|
323
|
+
return group_unit_pairs
|
|
300
324
|
|
|
301
325
|
def __getitem__(self, uuid):
|
|
302
326
|
"""
|
|
@@ -316,6 +340,7 @@ class StratigraphicColumn:
|
|
|
316
340
|
self.order = [
|
|
317
341
|
self.__getitem__(uuid) for uuid in new_order if self.__getitem__(uuid) is not None
|
|
318
342
|
]
|
|
343
|
+
self.notify('order_updated', new_order=self.order)
|
|
319
344
|
|
|
320
345
|
def update_element(self, unit_data: Dict):
|
|
321
346
|
"""
|
|
@@ -334,6 +359,7 @@ class StratigraphicColumn:
|
|
|
334
359
|
element.unconformity_type = UnconformityType(
|
|
335
360
|
unit_data.get('unconformity_type', element.unconformity_type.value)
|
|
336
361
|
)
|
|
362
|
+
self.notify('element_updated', element=element)
|
|
337
363
|
|
|
338
364
|
def __str__(self):
|
|
339
365
|
"""
|
|
@@ -354,14 +380,15 @@ class StratigraphicColumn:
|
|
|
354
380
|
"""
|
|
355
381
|
if not isinstance(data, dict):
|
|
356
382
|
raise TypeError("Data must be a dictionary")
|
|
357
|
-
self.
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
383
|
+
with self.freeze_notifications():
|
|
384
|
+
self.clear(basement=False)
|
|
385
|
+
elements_data = data.get("elements", [])
|
|
386
|
+
for element_data in elements_data:
|
|
387
|
+
if "unconformity_type" in element_data:
|
|
388
|
+
element = StratigraphicUnconformity.from_dict(element_data)
|
|
389
|
+
else:
|
|
390
|
+
element = StratigraphicUnit.from_dict(element_data)
|
|
391
|
+
self.add_element(element)
|
|
365
392
|
@classmethod
|
|
366
393
|
def from_dict(cls, data):
|
|
367
394
|
"""
|
|
@@ -115,12 +115,17 @@ class LoopIsosurfacer:
|
|
|
115
115
|
values,
|
|
116
116
|
)
|
|
117
117
|
logger.info(f'Isosurfacing at values: {isovalues}')
|
|
118
|
+
individual_names = False
|
|
118
119
|
if name is None:
|
|
119
120
|
names = ["surface"] * len(isovalues)
|
|
120
121
|
if isinstance(name, str):
|
|
121
122
|
names = [name] * len(isovalues)
|
|
123
|
+
if len(isovalues) == 1:
|
|
124
|
+
individual_names = True
|
|
122
125
|
if isinstance(name, list):
|
|
123
126
|
names = name
|
|
127
|
+
if len(names) == len(isovalues):
|
|
128
|
+
individual_names = True
|
|
124
129
|
if colours is None:
|
|
125
130
|
colours = [None] * len(isovalues)
|
|
126
131
|
for name, isovalue, colour in zip(names, isovalues, colours):
|
|
@@ -151,7 +156,7 @@ class LoopIsosurfacer:
|
|
|
151
156
|
vertices=verts,
|
|
152
157
|
triangles=faces,
|
|
153
158
|
normals=normals,
|
|
154
|
-
name=f"{name}_{isovalue}",
|
|
159
|
+
name=name if individual_names else f"{name}_{isovalue}",
|
|
155
160
|
values=values,
|
|
156
161
|
colour=colour,
|
|
157
162
|
)
|