LoopStructural 1.6.27__tar.gz → 1.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/__init__.py +49 -9
- loopstructural-1.7.0/LoopStructural/datasets/__init__.py +26 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/_base.py +3 -6
- loopstructural-1.7.0/LoopStructural/datasets/_example_models.py +11 -0
- loopstructural-1.7.0/LoopStructural/datatypes/__init__.py +27 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/export/exporters.py +16 -13
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/export/geoh5.py +99 -6
- loopstructural-1.7.0/LoopStructural/export/gocad.py +269 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/export/omf_wrapper.py +4 -4
- loopstructural-1.7.0/LoopStructural/geometry/__init__.py +29 -0
- {loopstructural-1.6.27/LoopStructural/datatypes → loopstructural-1.7.0/LoopStructural/geometry}/_structured_grid.py +27 -25
- loopstructural-1.7.0/LoopStructural/interpolators/__init__.py +66 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/interpolators/_api.py +50 -32
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/interpolators/_builders.py +1 -1
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/interpolators/_constant_norm.py +68 -32
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/interpolators/_discrete_fold_interpolator.py +9 -7
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/interpolators/_interpolatortype.py +1 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/__init__.py +4 -5
- loopstructural-1.7.0/LoopStructural/modelling/core/_feature_registry.py +30 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/core/fault_topology.py +20 -17
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/core/geological_model.py +841 -146
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/core/stratigraphic_column.py +34 -24
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/__init__.py +3 -4
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/_analytical_feature.py +23 -9
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/_base_geological_feature.py +79 -39
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/_cross_product_geological_feature.py +4 -5
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/_feature_converters.py +5 -3
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/_geological_feature.py +38 -22
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/_lambda_geological_feature.py +48 -35
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/_projected_vector_feature.py +4 -5
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/_structural_frame.py +8 -5
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/_unconformity_feature.py +3 -4
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/builders/__init__.py +3 -3
- loopstructural-1.7.0/LoopStructural/modelling/features/builders/_analytical_fold_builder.py +41 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/builders/_base_builder.py +4 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/builders/_fault_builder.py +12 -8
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/builders/_folded_feature_builder.py +22 -17
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/builders/_geological_feature_builder.py +30 -23
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/builders/_structural_frame_builder.py +33 -17
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/fault/__init__.py +1 -1
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/fault/_fault_function.py +28 -26
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/fault/_fault_function_feature.py +10 -6
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/fault/_fault_segment.py +11 -10
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/fold/_fold_rotation_angle_feature.py +17 -6
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/fold/_foldframe.py +6 -6
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/fold/_svariogram.py +44 -50
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/fold/fold_function/__init__.py +9 -5
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/fold/fold_function/_base_fold_rotation_angle.py +46 -31
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/fold/fold_function/_fourier_series_fold_rotation_angle.py +29 -19
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/fold/fold_function/_lambda_fold_rotation_angle.py +11 -5
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/fold/fold_function/_trigo_fold_rotation_angle.py +20 -10
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/input/map2loop_processor.py +3 -4
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/input/process_data.py +6 -6
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/input/project_file.py +2 -1
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/intrusions/__init__.py +11 -9
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/intrusions/geom_conceptual_models.py +10 -3
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/intrusions/geometric_scaling_functions.py +2 -3
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/intrusions/intrusion_builder.py +31 -20
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/intrusions/intrusion_feature.py +10 -9
- loopstructural-1.7.0/LoopStructural/modelling/intrusions/intrusion_frame.py +10 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/intrusions/intrusion_frame_builder.py +30 -19
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/intrusions/intrusion_support_functions.py +110 -181
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/utils/__init__.py +35 -19
- loopstructural-1.7.0/LoopStructural/utils/_api_registry.py +59 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/utils/_surface.py +24 -18
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/utils/_transformation.py +9 -8
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/utils/dtm_creator.py +6 -2
- loopstructural-1.7.0/LoopStructural/utils/exceptions.py +17 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/utils/helper.py +4 -4
- loopstructural-1.7.0/LoopStructural/utils/logging.py +175 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/utils/maths.py +21 -20
- loopstructural-1.7.0/LoopStructural/utils/observer.py +9 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/utils/regions.py +4 -4
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/utils/typing.py +2 -2
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/utils/utils.py +3 -1
- loopstructural-1.7.0/LoopStructural/version.py +1 -0
- loopstructural-1.7.0/LoopStructural/visualisation/__init__.py +15 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0/LoopStructural.egg-info}/PKG-INFO +11 -4
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural.egg-info/SOURCES.txt +5 -28
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural.egg-info/requires.txt +10 -1
- {loopstructural-1.6.27/LoopStructural.egg-info → loopstructural-1.7.0}/PKG-INFO +11 -4
- {loopstructural-1.6.27 → loopstructural-1.7.0}/README.md +1 -1
- loopstructural-1.7.0/pyproject.toml +317 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/setup.py +4 -4
- loopstructural-1.6.27/LoopStructural/datasets/__init__.py +0 -24
- loopstructural-1.6.27/LoopStructural/datasets/_example_models.py +0 -10
- loopstructural-1.6.27/LoopStructural/datatypes/__init__.py +0 -4
- loopstructural-1.6.27/LoopStructural/datatypes/_bounding_box.py +0 -696
- loopstructural-1.6.27/LoopStructural/datatypes/_point.py +0 -232
- loopstructural-1.6.27/LoopStructural/datatypes/_surface.py +0 -248
- loopstructural-1.6.27/LoopStructural/export/gocad.py +0 -126
- loopstructural-1.6.27/LoopStructural/interpolators/__init__.py +0 -132
- loopstructural-1.6.27/LoopStructural/interpolators/_discrete_interpolator.py +0 -792
- loopstructural-1.6.27/LoopStructural/interpolators/_finite_difference_interpolator.py +0 -519
- loopstructural-1.6.27/LoopStructural/interpolators/_geological_interpolator.py +0 -549
- loopstructural-1.6.27/LoopStructural/interpolators/_interpolator_builder.py +0 -134
- loopstructural-1.6.27/LoopStructural/interpolators/_interpolator_factory.py +0 -77
- loopstructural-1.6.27/LoopStructural/interpolators/_operator.py +0 -38
- loopstructural-1.6.27/LoopStructural/interpolators/_p1interpolator.py +0 -233
- loopstructural-1.6.27/LoopStructural/interpolators/_p2interpolator.py +0 -278
- loopstructural-1.6.27/LoopStructural/interpolators/_surfe_wrapper.py +0 -210
- loopstructural-1.6.27/LoopStructural/interpolators/supports/_2d_base_unstructured.py +0 -359
- loopstructural-1.6.27/LoopStructural/interpolators/supports/_2d_p1_unstructured.py +0 -68
- loopstructural-1.6.27/LoopStructural/interpolators/supports/_2d_p2_unstructured.py +0 -288
- loopstructural-1.6.27/LoopStructural/interpolators/supports/_2d_structured_grid.py +0 -516
- loopstructural-1.6.27/LoopStructural/interpolators/supports/_2d_structured_tetra.py +0 -0
- loopstructural-1.6.27/LoopStructural/interpolators/supports/_3d_base_structured.py +0 -539
- loopstructural-1.6.27/LoopStructural/interpolators/supports/_3d_p2_tetra.py +0 -331
- loopstructural-1.6.27/LoopStructural/interpolators/supports/_3d_structured_grid.py +0 -499
- loopstructural-1.6.27/LoopStructural/interpolators/supports/_3d_structured_tetra.py +0 -754
- loopstructural-1.6.27/LoopStructural/interpolators/supports/_3d_unstructured_tetra.py +0 -651
- loopstructural-1.6.27/LoopStructural/interpolators/supports/__init__.py +0 -62
- loopstructural-1.6.27/LoopStructural/interpolators/supports/_aabb.py +0 -77
- loopstructural-1.6.27/LoopStructural/interpolators/supports/_base_support.py +0 -125
- loopstructural-1.6.27/LoopStructural/interpolators/supports/_face_table.py +0 -70
- loopstructural-1.6.27/LoopStructural/interpolators/supports/_support_factory.py +0 -40
- loopstructural-1.6.27/LoopStructural/modelling/features/builders/_analytical_fold_builder.py +0 -21
- loopstructural-1.6.27/LoopStructural/utils/exceptions.py +0 -31
- loopstructural-1.6.27/LoopStructural/utils/logging.py +0 -79
- loopstructural-1.6.27/LoopStructural/utils/observer.py +0 -240
- loopstructural-1.6.27/LoopStructural/version.py +0 -1
- loopstructural-1.6.27/LoopStructural/visualisation/__init__.py +0 -11
- loopstructural-1.6.27/pyproject.toml +0 -165
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LICENSE +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/claudius.csv +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/claudiusbb.txt +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/duplex.csv +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/duplexbb.txt +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/fault_trace/fault_trace.cpg +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/fault_trace/fault_trace.dbf +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/fault_trace/fault_trace.prj +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/fault_trace/fault_trace.shp +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/fault_trace/fault_trace.shx +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/geological_map_data/bbox.csv +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/geological_map_data/contacts.csv +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/geological_map_data/fault_displacement.csv +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/geological_map_data/fault_edges.txt +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/geological_map_data/fault_locations.csv +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/geological_map_data/fault_orientations.csv +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/geological_map_data/stratigraphic_order.csv +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/geological_map_data/stratigraphic_orientations.csv +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/geological_map_data/stratigraphic_thickness.csv +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/intrusion.csv +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/intrusionbb.txt +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/onefoldbb.txt +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/onefolddata.csv +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/refolded_bb.txt +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/refolded_fold.csv +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/datasets/data/tabular_intrusion.csv +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/export/file_formats.py +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/interpolators/_cython/__init__.py +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/core/__init__.py +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/_region.py +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/fold/__init__.py +2 -2
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/features/fold/_fold.py +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/input/__init__.py +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/modelling/input/fault_network.py +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/utils/colours.py +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/utils/config.py +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/utils/features.py +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/utils/json_encoder.py +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural/utils/linalg.py +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural.egg-info/dependency_links.txt +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/LoopStructural.egg-info/top_level.txt +0 -0
- {loopstructural-1.6.27 → loopstructural-1.7.0}/setup.cfg +0 -0
|
@@ -5,14 +5,35 @@ LoopStructural
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
|
-
from logging.config import dictConfig
|
|
9
|
-
|
|
10
8
|
from dataclasses import dataclass
|
|
9
|
+
from logging.config import dictConfig
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
__all__ = [
|
|
12
|
+
"BoundingBox",
|
|
13
|
+
"FaultTopology",
|
|
14
|
+
"FileSink",
|
|
15
|
+
"GeologicalModel",
|
|
16
|
+
"InterpolatorBuilder",
|
|
17
|
+
"LogSink",
|
|
18
|
+
"LoopInterpolator",
|
|
19
|
+
"LoopStructuralConfig",
|
|
20
|
+
"SqliteSink",
|
|
21
|
+
"StratigraphicColumn",
|
|
22
|
+
"StreamSink",
|
|
23
|
+
"add_sink",
|
|
24
|
+
"getLogger",
|
|
25
|
+
"get_levels",
|
|
26
|
+
"log_to_console",
|
|
27
|
+
"log_to_file",
|
|
28
|
+
"remove_sink",
|
|
29
|
+
"rng",
|
|
30
|
+
"setLogging",
|
|
31
|
+
"timed",
|
|
32
|
+
"timed_stage",
|
|
33
|
+
]
|
|
14
34
|
import tempfile
|
|
15
35
|
from pathlib import Path
|
|
36
|
+
|
|
16
37
|
from .version import __version__
|
|
17
38
|
|
|
18
39
|
experimental = False
|
|
@@ -21,6 +42,11 @@ formatter = logging.Formatter("%(levelname)s: %(asctime)s: %(filename)s:%(lineno
|
|
|
21
42
|
ch.setFormatter(formatter)
|
|
22
43
|
ch.setLevel(logging.WARNING)
|
|
23
44
|
loggers = {}
|
|
45
|
+
# Handlers attached via LoopStructural.utils.add_sink(); replayed onto every
|
|
46
|
+
# logger getLogger() creates from here on, in addition to the default `ch`.
|
|
47
|
+
_extra_sinks = []
|
|
48
|
+
|
|
49
|
+
|
|
24
50
|
@dataclass
|
|
25
51
|
class LoopStructuralConfig:
|
|
26
52
|
"""Configuration for LoopStructural package.
|
|
@@ -42,13 +68,27 @@ class LoopStructuralConfig:
|
|
|
42
68
|
|
|
43
69
|
nelements: int = 10_000
|
|
44
70
|
|
|
71
|
+
from .geometry import BoundingBox
|
|
72
|
+
from .interpolators import InterpolatorBuilder
|
|
73
|
+
from .interpolators._api import LoopInterpolator
|
|
74
|
+
from .modelling.core.fault_topology import FaultTopology
|
|
45
75
|
from .modelling.core.geological_model import GeologicalModel
|
|
46
76
|
from .modelling.core.stratigraphic_column import StratigraphicColumn
|
|
47
|
-
from .
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
77
|
+
from .utils import (
|
|
78
|
+
FileSink,
|
|
79
|
+
LogSink,
|
|
80
|
+
SqliteSink,
|
|
81
|
+
StreamSink,
|
|
82
|
+
add_sink,
|
|
83
|
+
get_levels,
|
|
84
|
+
getLogger,
|
|
85
|
+
log_to_console,
|
|
86
|
+
log_to_file,
|
|
87
|
+
remove_sink,
|
|
88
|
+
rng,
|
|
89
|
+
timed,
|
|
90
|
+
timed_stage,
|
|
91
|
+
)
|
|
52
92
|
|
|
53
93
|
logger = getLogger(__name__)
|
|
54
94
|
logger.info("Imported LoopStructural")
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Demo Datasets
|
|
3
|
+
=============
|
|
4
|
+
|
|
5
|
+
Various datasets used for documentation and tutorials.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from ._base import (
|
|
9
|
+
load_claudius,
|
|
10
|
+
load_duplex,
|
|
11
|
+
load_fault_trace,
|
|
12
|
+
load_geological_map_data,
|
|
13
|
+
load_grose2017,
|
|
14
|
+
load_grose2018,
|
|
15
|
+
load_grose2019,
|
|
16
|
+
load_horizontal,
|
|
17
|
+
load_horizontal_v,
|
|
18
|
+
load_intrusion,
|
|
19
|
+
load_laurent2016,
|
|
20
|
+
load_noddy_single_fold,
|
|
21
|
+
load_tabular_intrusion,
|
|
22
|
+
load_unconformity,
|
|
23
|
+
normal_vector_headers,
|
|
24
|
+
strike_dip_headers,
|
|
25
|
+
value_headers,
|
|
26
|
+
)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
from os.path import dirname, join
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import numpy as np
|
|
5
5
|
import pandas as pd
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
def load_horizontal() ->
|
|
8
|
+
def load_horizontal() -> tuple[pd.DataFrame, np.ndarray]:
|
|
9
9
|
"""Synthetic model for horizontal layers
|
|
10
10
|
|
|
11
11
|
Returns
|
|
@@ -41,7 +41,7 @@ def load_horizontal() -> Tuple[pd.DataFrame, np.ndarray]:
|
|
|
41
41
|
return data, bb
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
def load_horizontal_v(v=0.5) ->
|
|
44
|
+
def load_horizontal_v(v=0.5) -> tuple[pd.DataFrame, np.ndarray]:
|
|
45
45
|
"""Synthetic model for horizontal layers
|
|
46
46
|
|
|
47
47
|
Returns
|
|
@@ -152,7 +152,6 @@ def load_grose2017():
|
|
|
152
152
|
tuple
|
|
153
153
|
pandas data frame with loopstructural dataset and numpy array for bounding box
|
|
154
154
|
"""
|
|
155
|
-
pass
|
|
156
155
|
|
|
157
156
|
|
|
158
157
|
def load_grose2018():
|
|
@@ -164,7 +163,6 @@ def load_grose2018():
|
|
|
164
163
|
tuple
|
|
165
164
|
pandas data frame with loopstructural dataset and numpy array for bounding box
|
|
166
165
|
"""
|
|
167
|
-
pass
|
|
168
166
|
|
|
169
167
|
|
|
170
168
|
def load_grose2019():
|
|
@@ -176,7 +174,6 @@ def load_grose2019():
|
|
|
176
174
|
tuple
|
|
177
175
|
pandas data frame with loopstructural dataset and numpy array for bounding box
|
|
178
176
|
"""
|
|
179
|
-
pass
|
|
180
177
|
|
|
181
178
|
|
|
182
179
|
def load_intrusion():
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Deprecated import path.
|
|
2
|
+
|
|
3
|
+
``BoundingBox``, ``Surface``, ``ValuePoints`` and ``VectorPoints`` moved to
|
|
4
|
+
:mod:`LoopStructural.geometry` in v1.6.x. This shim re-exports them so
|
|
5
|
+
existing consumers (e.g. the LoopStructural QGIS plugin) keep working, and
|
|
6
|
+
will be removed after two minor releases per the versioning policy in
|
|
7
|
+
``ROADMAP.md``.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
from ..geometry import BoundingBox, Surface, ValuePoints, VectorPoints
|
|
13
|
+
|
|
14
|
+
warnings.warn(
|
|
15
|
+
"LoopStructural.datatypes is deprecated and will be removed in a future "
|
|
16
|
+
"release; import BoundingBox, Surface, ValuePoints and VectorPoints from "
|
|
17
|
+
"LoopStructural.geometry instead.",
|
|
18
|
+
DeprecationWarning,
|
|
19
|
+
stacklevel=2,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"BoundingBox",
|
|
24
|
+
"Surface",
|
|
25
|
+
"ValuePoints",
|
|
26
|
+
"VectorPoints",
|
|
27
|
+
]
|
|
@@ -3,14 +3,15 @@ Routines to export geological model data to file in a variety of formats
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
-
|
|
7
|
-
from pyevtk.vtk import VtkTriangle
|
|
6
|
+
|
|
8
7
|
import numpy as np
|
|
8
|
+
from pyevtk.hl import pointsToVTK, unstructuredGridToVTK
|
|
9
|
+
from pyevtk.vtk import VtkTriangle
|
|
9
10
|
from skimage.measure import marching_cubes
|
|
10
11
|
|
|
11
|
-
from LoopStructural.utils.helper import create_box
|
|
12
12
|
from LoopStructural.export.file_formats import FileFormat
|
|
13
|
-
from LoopStructural.
|
|
13
|
+
from LoopStructural.geometry import Surface
|
|
14
|
+
from LoopStructural.utils.helper import create_box
|
|
14
15
|
|
|
15
16
|
from ..utils import getLogger
|
|
16
17
|
|
|
@@ -193,7 +194,7 @@ def _write_feat_surfs_evtk(surf, file_name):
|
|
|
193
194
|
cell_types=cell_types,
|
|
194
195
|
pointData={"values": pointData},
|
|
195
196
|
)
|
|
196
|
-
except
|
|
197
|
+
except (OSError, ValueError) as e:
|
|
197
198
|
logger.warning(f"Cannot export fault surface to VTK file {file_name}: {e}")
|
|
198
199
|
return False
|
|
199
200
|
|
|
@@ -396,7 +397,7 @@ def _write_cubeface_evtk(model, file_name, data_label, nsteps, real_coords=True)
|
|
|
396
397
|
cellData=None,
|
|
397
398
|
pointData={data_label: val},
|
|
398
399
|
)
|
|
399
|
-
except
|
|
400
|
+
except (OSError, ValueError) as e:
|
|
400
401
|
logger.warning(f"Cannot export cuboid surface to VTK file {file_name}: {e}")
|
|
401
402
|
return False
|
|
402
403
|
return True
|
|
@@ -422,8 +423,9 @@ def _write_vol_evtk(model, file_name, data_label, nsteps, real_coords=True):
|
|
|
422
423
|
True if successful
|
|
423
424
|
|
|
424
425
|
"""
|
|
425
|
-
# Define grid spacing
|
|
426
|
-
|
|
426
|
+
# Define grid spacing (world coordinates -- evaluate_model/features now
|
|
427
|
+
# project world -> local internally)
|
|
428
|
+
xyz = model.bounding_box.regular_grid(nsteps=nsteps, local=False)
|
|
427
429
|
vals = model.evaluate_model(xyz, scale=False)
|
|
428
430
|
if real_coords:
|
|
429
431
|
model.rescale(xyz)
|
|
@@ -438,7 +440,7 @@ def _write_vol_evtk(model, file_name, data_label, nsteps, real_coords=True):
|
|
|
438
440
|
# Write to grid
|
|
439
441
|
try:
|
|
440
442
|
pointsToVTK(file_name, x, y, z, data={data_label: vals})
|
|
441
|
-
except
|
|
443
|
+
except (OSError, ValueError) as e:
|
|
442
444
|
logger.warning(f"Cannot export volume to VTK file {file_name}: {e}")
|
|
443
445
|
return False
|
|
444
446
|
return True
|
|
@@ -464,8 +466,9 @@ def _write_vol_gocad(model, file_name, data_label, nsteps, real_coords=True):
|
|
|
464
466
|
True if successful
|
|
465
467
|
|
|
466
468
|
"""
|
|
467
|
-
# Define grid spacing
|
|
468
|
-
|
|
469
|
+
# Define grid spacing (world coordinates -- evaluate_model/features now
|
|
470
|
+
# project world -> local internally)
|
|
471
|
+
xyz = model.bounding_box.regular_grid(nsteps=nsteps, local=False)
|
|
469
472
|
|
|
470
473
|
vals = model.evaluate_model(xyz, scale=False)
|
|
471
474
|
# Use FORTRAN style indexing for GOCAD VOXET
|
|
@@ -539,7 +542,7 @@ PROP_OFFSET 1 0
|
|
|
539
542
|
PROP_FILE 1 {data_filename}
|
|
540
543
|
END\n"""
|
|
541
544
|
)
|
|
542
|
-
except
|
|
545
|
+
except OSError as exc:
|
|
543
546
|
logger.warning(f"Cannot export volume to GOCAD VOXET file {vo_filename}: {exc}")
|
|
544
547
|
return False
|
|
545
548
|
|
|
@@ -548,7 +551,7 @@ END\n"""
|
|
|
548
551
|
try:
|
|
549
552
|
with open(data_filename, "wb") as fp:
|
|
550
553
|
export_vals.tofile(fp)
|
|
551
|
-
except
|
|
554
|
+
except OSError as exc:
|
|
552
555
|
logger.warning(f"Cannot export volume to GOCAD VOXET data file {data_filename}: {exc}")
|
|
553
556
|
return False
|
|
554
557
|
return True
|
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
import geoh5py
|
|
2
2
|
import geoh5py.workspace
|
|
3
3
|
import numpy as np
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
from LoopStructural.geometry import ValuePoints, VectorPoints
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def add_group_to_geoh5(filename, groupname="Loop", parent=None, overwrite=True):
|
|
9
|
+
with geoh5py.workspace.Workspace(filename) as workspace:
|
|
10
|
+
|
|
11
|
+
group = workspace.get_entity(groupname)[0]
|
|
12
|
+
if group and overwrite:
|
|
13
|
+
group.allow_delete = True
|
|
14
|
+
workspace.remove_entity(group)
|
|
15
|
+
if not group:
|
|
16
|
+
group = geoh5py.groups.ContainerGroup.create(
|
|
17
|
+
workspace, name=groupname, allow_delete=True
|
|
18
|
+
)
|
|
19
|
+
if parent is not None:
|
|
20
|
+
parent = workspace.get_entity(parent)[0]
|
|
21
|
+
if parent:
|
|
22
|
+
parent.add_children(group)
|
|
23
|
+
return group.uid
|
|
5
24
|
|
|
6
25
|
|
|
7
26
|
def add_surface_to_geoh5(filename, surface, overwrite=True, groupname="Loop"):
|
|
@@ -32,6 +51,7 @@ def add_surface_to_geoh5(filename, surface, overwrite=True, groupname="Loop"):
|
|
|
32
51
|
|
|
33
52
|
def add_points_to_geoh5(filename, point, overwrite=True, groupname="Loop"):
|
|
34
53
|
with geoh5py.workspace.Workspace(filename) as workspace:
|
|
54
|
+
|
|
35
55
|
group = workspace.get_entity(groupname)[0]
|
|
36
56
|
if not group:
|
|
37
57
|
group = geoh5py.groups.ContainerGroup.create(
|
|
@@ -45,14 +65,15 @@ def add_points_to_geoh5(filename, point, overwrite=True, groupname="Loop"):
|
|
|
45
65
|
data = {}
|
|
46
66
|
if point.properties is not None:
|
|
47
67
|
for k, v in point.properties.items():
|
|
48
|
-
data[k] = {'association': "VERTEX", "values": v}
|
|
68
|
+
data[k] = {'association': "VERTEX", "values": np.asarray(v)}
|
|
49
69
|
if isinstance(point, VectorPoints):
|
|
50
|
-
|
|
51
|
-
data['
|
|
52
|
-
data['
|
|
70
|
+
vectors = np.asarray(point.vectors)
|
|
71
|
+
data['vx'] = {'association': "VERTEX", "values": vectors[:, 0]}
|
|
72
|
+
data['vy'] = {'association': "VERTEX", "values": vectors[:, 1]}
|
|
73
|
+
data['vz'] = {'association': "VERTEX", "values": vectors[:, 2]}
|
|
53
74
|
|
|
54
75
|
if isinstance(point, ValuePoints):
|
|
55
|
-
data['
|
|
76
|
+
data['values'] = {'association': "VERTEX", "values": np.asarray(point.values)}
|
|
56
77
|
point = geoh5py.objects.Points.create(
|
|
57
78
|
workspace,
|
|
58
79
|
name=point.name,
|
|
@@ -62,6 +83,78 @@ def add_points_to_geoh5(filename, point, overwrite=True, groupname="Loop"):
|
|
|
62
83
|
point.add_data(data)
|
|
63
84
|
|
|
64
85
|
|
|
86
|
+
def overwrite_object(workspace, name, overwrite):
|
|
87
|
+
if name in workspace.list_entities_name.values():
|
|
88
|
+
existing_entity = workspace.get_entity(name)
|
|
89
|
+
existing_entity[0].allow_delete = True
|
|
90
|
+
if overwrite:
|
|
91
|
+
workspace.remove_entity(existing_entity[0])
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def add_points_from_df(
|
|
95
|
+
filename,
|
|
96
|
+
df,
|
|
97
|
+
name='pointset',
|
|
98
|
+
overwrite=True,
|
|
99
|
+
columns=None,
|
|
100
|
+
groupname="Loop",
|
|
101
|
+
x_col='X',
|
|
102
|
+
y_col='Y',
|
|
103
|
+
z_col='Z',
|
|
104
|
+
):
|
|
105
|
+
"""
|
|
106
|
+
Add points to a geoh5 file from a pandas DataFrame. The DataFrame must have columns 'name', 'X', 'Y', 'Z' for the point locations.
|
|
107
|
+
Additional columns can be added as data associated with the points.
|
|
108
|
+
Parameters
|
|
109
|
+
----------
|
|
110
|
+
filename: str
|
|
111
|
+
Path to the geoh5 file.
|
|
112
|
+
df: pandas.DataFrame
|
|
113
|
+
DataFrame containing point data. Must have columns 'name', 'X', 'Y', 'Z'. Additional columns will be added as data.
|
|
114
|
+
overwrite: bool, optional
|
|
115
|
+
Whether to overwrite existing points with the same name. Default is True.
|
|
116
|
+
columns: list of str, optional
|
|
117
|
+
List of columns in the DataFrame to add as data. If None, all columns except 'name', 'X', 'Y', 'Z' will be added. Default is None.
|
|
118
|
+
|
|
119
|
+
"""
|
|
120
|
+
if columns is None:
|
|
121
|
+
columns = df.columns.tolist()
|
|
122
|
+
if x_col not in columns or y_col not in columns or z_col not in columns:
|
|
123
|
+
raise ValueError(
|
|
124
|
+
"DataFrame must contain 'name', 'X', 'Y', 'Z' columns. "
|
|
125
|
+
"Specify the column names using x_col, y_col, z_col parameters if they are different."
|
|
126
|
+
)
|
|
127
|
+
with geoh5py.workspace.Workspace(filename) as workspace:
|
|
128
|
+
if groupname:
|
|
129
|
+
group = workspace.get_entity(groupname)
|
|
130
|
+
group = group[0] if group else None
|
|
131
|
+
if not group:
|
|
132
|
+
group = geoh5py.groups.ContainerGroup.create(
|
|
133
|
+
workspace,
|
|
134
|
+
name=groupname,
|
|
135
|
+
allow_delete=True,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
location = np.array(df[[x_col, y_col, z_col]].values) # shape (n,3)
|
|
139
|
+
|
|
140
|
+
overwrite_object(workspace, name, overwrite)
|
|
141
|
+
|
|
142
|
+
pts = geoh5py.objects.Points.create(
|
|
143
|
+
workspace,
|
|
144
|
+
name=name,
|
|
145
|
+
vertices=location,
|
|
146
|
+
parent=group,
|
|
147
|
+
)
|
|
148
|
+
data = {}
|
|
149
|
+
for col in columns:
|
|
150
|
+
if col in ['name', x_col, y_col, z_col]:
|
|
151
|
+
continue
|
|
152
|
+
data[col] = {"association": "VERTEX", "values": np.array(df[col]).flatten()}
|
|
153
|
+
|
|
154
|
+
if data:
|
|
155
|
+
pts.add_data(data)
|
|
156
|
+
|
|
157
|
+
|
|
65
158
|
def add_structured_grid_to_geoh5(filename, structured_grid, overwrite=True, groupname="Loop"):
|
|
66
159
|
with geoh5py.workspace.Workspace(filename) as workspace:
|
|
67
160
|
group = workspace.get_entity(groupname)[0]
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from LoopStructural.utils import getLogger
|
|
7
|
+
|
|
8
|
+
logger = getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _normalise_voxet_property(values, property_name, nsteps):
|
|
12
|
+
array = np.asarray(values)
|
|
13
|
+
expected_shape = tuple(int(step) for step in nsteps)
|
|
14
|
+
expected_size = int(np.prod(expected_shape))
|
|
15
|
+
|
|
16
|
+
if array.shape == expected_shape:
|
|
17
|
+
flat_values = array.reshape(-1, order="F")
|
|
18
|
+
else:
|
|
19
|
+
flat_values = np.squeeze(array)
|
|
20
|
+
if flat_values.shape == expected_shape:
|
|
21
|
+
flat_values = flat_values.reshape(-1, order="F")
|
|
22
|
+
elif flat_values.ndim == 1 and flat_values.size == expected_size:
|
|
23
|
+
flat_values = flat_values.copy()
|
|
24
|
+
else:
|
|
25
|
+
raise ValueError(
|
|
26
|
+
f"Property '{property_name}' must have shape {expected_shape} or size {expected_size}"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
if np.issubdtype(flat_values.dtype, np.integer):
|
|
30
|
+
if (
|
|
31
|
+
flat_values.size == 0
|
|
32
|
+
or flat_values.min() >= np.iinfo(np.int8).min
|
|
33
|
+
and flat_values.max() <= np.iinfo(np.int8).max
|
|
34
|
+
):
|
|
35
|
+
export_dtype = np.int8
|
|
36
|
+
storage_type = "Octet"
|
|
37
|
+
element_size = 1
|
|
38
|
+
else:
|
|
39
|
+
export_dtype = np.dtype(">i4")
|
|
40
|
+
storage_type = "Integer"
|
|
41
|
+
element_size = 4
|
|
42
|
+
no_data_value = None
|
|
43
|
+
elif np.issubdtype(flat_values.dtype, np.floating):
|
|
44
|
+
export_dtype = np.dtype(">f4")
|
|
45
|
+
storage_type = "Float"
|
|
46
|
+
element_size = 4
|
|
47
|
+
no_data_value = -999999.0
|
|
48
|
+
flat_values = np.nan_to_num(flat_values, nan=no_data_value)
|
|
49
|
+
else:
|
|
50
|
+
raise ValueError(f"Property '{property_name}' has unsupported dtype {flat_values.dtype}")
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
"values": np.asarray(flat_values, dtype=export_dtype),
|
|
54
|
+
"storage_type": storage_type,
|
|
55
|
+
"element_size": element_size,
|
|
56
|
+
"no_data_value": no_data_value,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _write_structured_grid_gocad(grid, file_name):
|
|
61
|
+
"""Write a StructuredGrid to GOCAD VOXET format."""
|
|
62
|
+
vo_path = Path(file_name).with_suffix(".vo")
|
|
63
|
+
axis_n = np.asarray(grid.nsteps, dtype=int)
|
|
64
|
+
property_source = grid.properties
|
|
65
|
+
axis_min = np.min(grid.nodes, axis=0)
|
|
66
|
+
axis_max = np.max(grid.nodes, axis=0)
|
|
67
|
+
|
|
68
|
+
if property_source:
|
|
69
|
+
if grid.cell_properties:
|
|
70
|
+
logger.warning(
|
|
71
|
+
"StructuredGrid GOCAD export uses point properties; cell_properties were not exported"
|
|
72
|
+
)
|
|
73
|
+
elif grid.cell_properties:
|
|
74
|
+
axis_n = np.asarray(grid.nsteps, dtype=int) - 1
|
|
75
|
+
if np.any(axis_n <= 0):
|
|
76
|
+
raise ValueError("StructuredGrid cell_properties require at least two grid nodes per axis")
|
|
77
|
+
property_source = grid.cell_properties
|
|
78
|
+
axis_min = np.min(grid.cell_centres, axis=0)
|
|
79
|
+
axis_max = np.max(grid.cell_centres, axis=0)
|
|
80
|
+
else:
|
|
81
|
+
raise ValueError("StructuredGrid has no properties to export to GOCAD")
|
|
82
|
+
|
|
83
|
+
export_properties = []
|
|
84
|
+
for index, (property_name, values) in enumerate(property_source.items(), start=1):
|
|
85
|
+
export_info = _normalise_voxet_property(values, property_name, axis_n)
|
|
86
|
+
safe_name = re.sub(r"[^0-9A-Za-z_-]+", "_", property_name).strip("_") or f"property_{index}"
|
|
87
|
+
data_path = vo_path.with_name(f"{vo_path.stem}_{safe_name}@@")
|
|
88
|
+
export_properties.append(
|
|
89
|
+
{
|
|
90
|
+
"index": index,
|
|
91
|
+
"name": safe_name,
|
|
92
|
+
"data_path": data_path,
|
|
93
|
+
**export_info,
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
with open(vo_path, "w") as fp:
|
|
98
|
+
fp.write(
|
|
99
|
+
f"""GOCAD Voxet 1
|
|
100
|
+
HEADER {{
|
|
101
|
+
name: {grid.name}
|
|
102
|
+
}}
|
|
103
|
+
GOCAD_ORIGINAL_COORDINATE_SYSTEM
|
|
104
|
+
NAME Default
|
|
105
|
+
AXIS_NAME \"X\" \"Y\" \"Z\"
|
|
106
|
+
AXIS_UNIT \"m\" \"m\" \"m\"
|
|
107
|
+
ZPOSITIVE Elevation
|
|
108
|
+
END_ORIGINAL_COORDINATE_SYSTEM
|
|
109
|
+
AXIS_O 0.000000 0.000000 0.000000
|
|
110
|
+
AXIS_U 1.000000 0.000000 0.000000
|
|
111
|
+
AXIS_V 0.000000 1.000000 0.000000
|
|
112
|
+
AXIS_W 0.000000 0.000000 1.000000
|
|
113
|
+
AXIS_MIN {axis_min[0]} {axis_min[1]} {axis_min[2]}
|
|
114
|
+
AXIS_MAX {axis_max[0]} {axis_max[1]} {axis_max[2]}
|
|
115
|
+
AXIS_N {axis_n[0]} {axis_n[1]} {axis_n[2]}
|
|
116
|
+
AXIS_NAME \"X\" \"Y\" \"Z\"
|
|
117
|
+
AXIS_UNIT \"m\" \"m\" \"m\"
|
|
118
|
+
AXIS_TYPE even even even
|
|
119
|
+
"""
|
|
120
|
+
)
|
|
121
|
+
for export_property in export_properties:
|
|
122
|
+
fp.write(
|
|
123
|
+
f"""PROPERTY {export_property['index']} {export_property['name']}
|
|
124
|
+
PROPERTY_CLASS {export_property['index']} {export_property['name']}
|
|
125
|
+
PROP_UNIT {export_property['index']} {export_property['name']}
|
|
126
|
+
PROPERTY_CLASS_HEADER {export_property['index']} {export_property['name']} {{
|
|
127
|
+
}}
|
|
128
|
+
PROPERTY_SUBCLASS {export_property['index']} QUANTITY {export_property['storage_type']}
|
|
129
|
+
"""
|
|
130
|
+
)
|
|
131
|
+
if export_property["no_data_value"] is not None:
|
|
132
|
+
fp.write(
|
|
133
|
+
f"PROP_NO_DATA_VALUE {export_property['index']} {export_property['no_data_value']}\n"
|
|
134
|
+
)
|
|
135
|
+
fp.write(
|
|
136
|
+
f"""PROP_ETYPE {export_property['index']} IEEE
|
|
137
|
+
PROP_FORMAT {export_property['index']} RAW
|
|
138
|
+
PROP_ESIZE {export_property['index']} {export_property['element_size']}
|
|
139
|
+
PROP_OFFSET {export_property['index']} 0
|
|
140
|
+
PROP_FILE {export_property['index']} {export_property['data_path'].name}
|
|
141
|
+
"""
|
|
142
|
+
)
|
|
143
|
+
fp.write("END\n")
|
|
144
|
+
|
|
145
|
+
for export_property in export_properties:
|
|
146
|
+
with open(export_property["data_path"], "wb") as fp:
|
|
147
|
+
export_property["values"].tofile(fp)
|
|
148
|
+
|
|
149
|
+
return True
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _write_feat_surfs_gocad(surf, file_name):
|
|
153
|
+
"""
|
|
154
|
+
Writes out a GOCAD TSURF file for each surface in list
|
|
155
|
+
|
|
156
|
+
Parameters
|
|
157
|
+
----------
|
|
158
|
+
surf_list: [ SimpleNamespace() ... ]
|
|
159
|
+
Details of the surfaces, as a list of SimpleNamespace() objects. Fields are:
|
|
160
|
+
verts: vertices, numpy ndarray with dtype = float64 & shape = (N,3)
|
|
161
|
+
faces: faces, numpy ndarray with dtype = int32 & shape = (M,3)
|
|
162
|
+
values: values, numpy ndarray with dtype = float32 & shape = (N,)
|
|
163
|
+
normals: normals, numpy ndarray with dtype = float32 & shape = (N,3)
|
|
164
|
+
name: name of feature e.g. fault or supergroup, string
|
|
165
|
+
|
|
166
|
+
file_name: string
|
|
167
|
+
Desired filename
|
|
168
|
+
|
|
169
|
+
Returns
|
|
170
|
+
-------
|
|
171
|
+
True if successful
|
|
172
|
+
|
|
173
|
+
"""
|
|
174
|
+
properties_header = None
|
|
175
|
+
if surf.properties:
|
|
176
|
+
|
|
177
|
+
properties_header = f"""PROPERTIES {' '.join(list(surf.properties.keys()))}
|
|
178
|
+
NO_DATA_VALUES -99999
|
|
179
|
+
PROPERTY_CLASSES {' '.join(list(surf.properties.keys()))}
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
file_name = Path(file_name).with_suffix(".ts")
|
|
183
|
+
with open(f"{file_name}", "w") as fd:
|
|
184
|
+
fd.write(
|
|
185
|
+
f"""GOCAD TSurf 1
|
|
186
|
+
HEADER {{
|
|
187
|
+
*solid*color: #ffa500
|
|
188
|
+
ivolmap: false
|
|
189
|
+
imap: false
|
|
190
|
+
name: {surf.name}
|
|
191
|
+
}}
|
|
192
|
+
GOCAD_ORIGINAL_COORDINATE_SYSTEM
|
|
193
|
+
NAME Default
|
|
194
|
+
PROJECTION Unknown
|
|
195
|
+
DATUM Unknown
|
|
196
|
+
AXIS_NAME X Y Z
|
|
197
|
+
AXIS_UNIT m m m
|
|
198
|
+
ZPOSITIVE Elevation
|
|
199
|
+
END_ORIGINAL_COORDINATE_SYSTEM
|
|
200
|
+
GEOLOGICAL_FEATURE {surf.name}
|
|
201
|
+
GEOLOGICAL_TYPE fault
|
|
202
|
+
{properties_header if properties_header else ""}
|
|
203
|
+
PROPERTY_CLASS_HEADER X {{
|
|
204
|
+
kind: X
|
|
205
|
+
unit: m
|
|
206
|
+
}}
|
|
207
|
+
PROPERTY_CLASS_HEADER Y {{
|
|
208
|
+
kind: Y
|
|
209
|
+
unit: m
|
|
210
|
+
}}
|
|
211
|
+
PROPERTY_CLASS_HEADER Z {{
|
|
212
|
+
kind: Z
|
|
213
|
+
unit: m
|
|
214
|
+
is_z: on
|
|
215
|
+
}}
|
|
216
|
+
PROPERTY_CLASS_HEADER vector3d {{
|
|
217
|
+
kind: Length
|
|
218
|
+
unit: m
|
|
219
|
+
}}
|
|
220
|
+
TFACE
|
|
221
|
+
"""
|
|
222
|
+
)
|
|
223
|
+
v_idx = 1
|
|
224
|
+
v_map = {}
|
|
225
|
+
for idx, vert in enumerate(surf.vertices):
|
|
226
|
+
if not np.isnan(vert[0]) and not np.isnan(vert[1]) and not np.isnan(vert[2]):
|
|
227
|
+
fd.write(f"VRTX {v_idx:} {vert[0]} {vert[1]} {vert[2]}")
|
|
228
|
+
if surf.properties:
|
|
229
|
+
fd.writelines(f" {value[idx]}" for value in surf.properties.values())
|
|
230
|
+
fd.write("\n")
|
|
231
|
+
v_map[idx] = v_idx
|
|
232
|
+
v_idx += 1
|
|
233
|
+
for face in surf.triangles:
|
|
234
|
+
if face[0] in v_map and face[1] in v_map and face[2] in v_map:
|
|
235
|
+
fd.write(f"TRGL {v_map[face[0]]} {v_map[face[1]]} {v_map[face[2]]} \n")
|
|
236
|
+
fd.write("END\n")
|
|
237
|
+
return True
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
# def _write_pointset(points, file_name):
|
|
241
|
+
# """
|
|
242
|
+
# Write out a GOCAD VS file for a pointset
|
|
243
|
+
|
|
244
|
+
# Parameters
|
|
245
|
+
# ----------
|
|
246
|
+
# points: SimpleNamespace()
|
|
247
|
+
# Details of the points, as a SimpleNamespace() object. Fields are:
|
|
248
|
+
# locations: locations, numpy ndarray with dtype = float64 & shape = (N,3)
|
|
249
|
+
# vectors: vectors, numpy ndarray with dtype = float64 & shape = (N,3)
|
|
250
|
+
# name: name of feature e.g. fault or supergroup, string
|
|
251
|
+
|
|
252
|
+
# file_name: string
|
|
253
|
+
# Desired filename
|
|
254
|
+
|
|
255
|
+
# Returns
|
|
256
|
+
# -------
|
|
257
|
+
# True if successful
|
|
258
|
+
|
|
259
|
+
# """
|
|
260
|
+
# file_name = Path(file_name).with_suffix(".vs")
|
|
261
|
+
# with open(f"{file_name}", "w") as fd:
|
|
262
|
+
# fd.write(
|
|
263
|
+
# f"""GOCAD VSet 1
|
|
264
|
+
# HEADER {{
|
|
265
|
+
# name: {points.name}
|
|
266
|
+
# }}
|
|
267
|
+
# GOCAD_ORIGINAL_COORDINATE_SYSTEM
|
|
268
|
+
# NAME Default
|
|
269
|
+
# PROJECTION Unknown
|