LoopStructural 1.6.15__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.17/LoopStructural/__init__.py +72 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_geological_interpolator.py +7 -2
- loopstructural-1.6.17/LoopStructural/modelling/core/fault_topology.py +234 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/core/geological_model.py +119 -119
- loopstructural-1.6.17/LoopStructural/modelling/core/stratigraphic_column.py +500 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/builders/_fault_builder.py +1 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/fault/_fault_segment.py +1 -1
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/__init__.py +1 -0
- {loopstructural-1.6.15 → 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.15 → loopstructural-1.6.17}/LoopStructural.egg-info/PKG-INFO +1 -1
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural.egg-info/SOURCES.txt +3 -1
- {loopstructural-1.6.15 → loopstructural-1.6.17}/PKG-INFO +1 -1
- {loopstructural-1.6.15 → loopstructural-1.6.17}/setup.cfg +0 -2
- loopstructural-1.6.15/LoopStructural/__init__.py +0 -53
- loopstructural-1.6.15/LoopStructural/version.py +0 -1
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LICENSE +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/_base.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/_example_models.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/claudius.csv +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/claudiusbb.txt +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/duplex.csv +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/duplexbb.txt +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/fault_trace/fault_trace.cpg +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/fault_trace/fault_trace.dbf +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/fault_trace/fault_trace.prj +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/fault_trace/fault_trace.shp +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/fault_trace/fault_trace.shx +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/bbox.csv +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/contacts.csv +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/fault_displacement.csv +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/fault_edges.txt +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/fault_locations.csv +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/fault_orientations.csv +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/stratigraphic_order.csv +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/stratigraphic_orientations.csv +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/geological_map_data/stratigraphic_thickness.csv +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/intrusion.csv +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/intrusionbb.txt +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/onefoldbb.txt +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/onefolddata.csv +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/refolded_bb.txt +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/refolded_fold.csv +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datasets/data/tabular_intrusion.csv +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datatypes/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datatypes/_bounding_box.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datatypes/_point.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datatypes/_structured_grid.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/datatypes/_surface.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/export/exporters.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/export/file_formats.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/export/geoh5.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/export/gocad.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/export/omf_wrapper.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_api.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_builders.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_constant_norm.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_cython/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_discrete_fold_interpolator.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_discrete_interpolator.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_finite_difference_interpolator.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_interpolator_builder.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_interpolator_factory.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_interpolatortype.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_operator.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_p1interpolator.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_p2interpolator.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/_surfe_wrapper.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_2d_base_unstructured.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_2d_p1_unstructured.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_2d_p2_unstructured.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_2d_structured_grid.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_2d_structured_tetra.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_3d_base_structured.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_3d_p2_tetra.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_3d_structured_grid.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_3d_structured_tetra.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_3d_unstructured_tetra.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_aabb.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_base_support.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_face_table.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/interpolators/supports/_support_factory.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/core/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/_analytical_feature.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/_base_geological_feature.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/_cross_product_geological_feature.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/_geological_feature.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/_lambda_geological_feature.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/_projected_vector_feature.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/_region.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/_structural_frame.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/_unconformity_feature.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/builders/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/builders/_base_builder.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/builders/_folded_feature_builder.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/builders/_geological_feature_builder.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/builders/_structural_frame_builder.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/fault/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/fault/_fault_function.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/fault/_fault_function_feature.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/_fold.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/_fold_rotation_angle_feature.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/_foldframe.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/_svariogram.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/fold_function/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/fold_function/_base_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/fold_function/_fourier_series_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/fold_function/_lambda_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/features/fold/fold_function/_trigo_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/input/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/input/fault_network.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/input/map2loop_processor.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/input/process_data.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/input/project_file.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/intrusions/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/intrusions/geom_conceptual_models.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/intrusions/geometric_scaling_functions.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/intrusions/intrusion_builder.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/intrusions/intrusion_feature.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/intrusions/intrusion_frame_builder.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/modelling/intrusions/intrusion_support_functions.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/_transformation.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/colours.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/config.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/dtm_creator.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/exceptions.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/features.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/helper.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/json_encoder.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/linalg.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/logging.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/maths.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/regions.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/typing.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/utils/utils.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural/visualisation/__init__.py +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural.egg-info/dependency_links.txt +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural.egg-info/requires.txt +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/LoopStructural.egg-info/top_level.txt +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/README.md +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/pyproject.toml +0 -0
- {loopstructural-1.6.15 → loopstructural-1.6.17}/setup.py +0 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LoopStructural
|
|
3
|
+
==============
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from logging.config import dictConfig
|
|
9
|
+
|
|
10
|
+
__all__ = ["GeologicalModel"]
|
|
11
|
+
import tempfile
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from .version import __version__
|
|
14
|
+
|
|
15
|
+
experimental = False
|
|
16
|
+
ch = logging.StreamHandler()
|
|
17
|
+
formatter = logging.Formatter("%(levelname)s: %(asctime)s: %(filename)s:%(lineno)d -- %(message)s")
|
|
18
|
+
ch.setFormatter(formatter)
|
|
19
|
+
ch.setLevel(logging.WARNING)
|
|
20
|
+
loggers = {}
|
|
21
|
+
from .modelling.core.geological_model import GeologicalModel
|
|
22
|
+
from .modelling.core.stratigraphic_column import StratigraphicColumn
|
|
23
|
+
from .modelling.core.fault_topology import FaultTopology
|
|
24
|
+
from .interpolators._api import LoopInterpolator
|
|
25
|
+
from .interpolators import InterpolatorBuilder
|
|
26
|
+
from .datatypes import BoundingBox
|
|
27
|
+
from .utils import log_to_console, log_to_file, getLogger, rng, get_levels
|
|
28
|
+
|
|
29
|
+
logger = getLogger(__name__)
|
|
30
|
+
logger.info("Imported LoopStructural")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def setLogging(level="info", handler=None):
|
|
34
|
+
"""
|
|
35
|
+
Set the logging parameters for log file or custom handler
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
level : str
|
|
40
|
+
'info', 'warning', 'error', 'debug'
|
|
41
|
+
handler : logging.Handler, optional
|
|
42
|
+
A logging handler to use instead of the default StreamHandler
|
|
43
|
+
"""
|
|
44
|
+
import LoopStructural
|
|
45
|
+
|
|
46
|
+
levels = get_levels()
|
|
47
|
+
level_value = levels.get(level, logging.WARNING)
|
|
48
|
+
|
|
49
|
+
# Create default handler if none provided
|
|
50
|
+
if handler is None:
|
|
51
|
+
handler = logging.StreamHandler()
|
|
52
|
+
|
|
53
|
+
formatter = logging.Formatter(
|
|
54
|
+
"%(levelname)s: %(asctime)s: %(filename)s:%(lineno)d -- %(message)s"
|
|
55
|
+
)
|
|
56
|
+
handler.setFormatter(formatter)
|
|
57
|
+
handler.setLevel(level_value)
|
|
58
|
+
|
|
59
|
+
# Replace handlers in all known loggers
|
|
60
|
+
for name in LoopStructural.loggers:
|
|
61
|
+
logger = logging.getLogger(name)
|
|
62
|
+
logger.handlers = []
|
|
63
|
+
logger.addHandler(handler)
|
|
64
|
+
logger.setLevel(level_value)
|
|
65
|
+
|
|
66
|
+
# Also apply to main module logger
|
|
67
|
+
main_logger = logging.getLogger(__name__)
|
|
68
|
+
main_logger.handlers = []
|
|
69
|
+
main_logger.addHandler(handler)
|
|
70
|
+
main_logger.setLevel(level_value)
|
|
71
|
+
|
|
72
|
+
main_logger.info(f"Set logging to {level}")
|
|
@@ -154,16 +154,21 @@ class GeologicalInterpolator(metaclass=ABCMeta):
|
|
|
154
154
|
----------
|
|
155
155
|
points : np.ndarray
|
|
156
156
|
array containing the value constraints usually 7-8 columns.
|
|
157
|
-
X,Y,Z,nx,ny,nz,weight
|
|
157
|
+
X,Y,Z,nx,ny,nz,(weight, default : 1 for each row)
|
|
158
158
|
|
|
159
159
|
Returns
|
|
160
160
|
-------
|
|
161
161
|
|
|
162
|
+
Notes
|
|
163
|
+
-------
|
|
164
|
+
If no weights are provided, w = 1 is assigned to each normal constraint.
|
|
165
|
+
|
|
162
166
|
"""
|
|
163
167
|
if points.shape[1] == self.dimensions * 2:
|
|
164
168
|
points = np.hstack([points, np.ones((points.shape[0], 1))])
|
|
169
|
+
logger.info("No weight provided for normal constraints, all weights are set to 1")
|
|
165
170
|
if points.shape[1] < self.dimensions * 2 + 1:
|
|
166
|
-
raise ValueError("
|
|
171
|
+
raise ValueError("Normal constraints must at least have X,Y,Z,nx,ny,nz")
|
|
167
172
|
self.n_n = points.shape[0]
|
|
168
173
|
self.data["normal"] = points
|
|
169
174
|
self.up_to_date = False
|
|
@@ -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
|