LoopStructural 1.6.14__tar.gz → 1.6.16__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/__init__.py +71 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datatypes/_bounding_box.py +22 -13
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datatypes/_point.py +0 -1
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/export/exporters.py +2 -2
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/__init__.py +33 -30
- loopstructural-1.6.16/LoopStructural/interpolators/_constant_norm.py +205 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/_discrete_interpolator.py +15 -14
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/_finite_difference_interpolator.py +10 -10
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/_geological_interpolator.py +9 -3
- loopstructural-1.6.16/LoopStructural/interpolators/_interpolatortype.py +22 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/_p1interpolator.py +6 -2
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/_surfe_wrapper.py +4 -1
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/_2d_base_unstructured.py +1 -1
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/_2d_structured_grid.py +16 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/_3d_base_structured.py +16 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/_3d_structured_tetra.py +7 -3
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/core/geological_model.py +250 -312
- loopstructural-1.6.16/LoopStructural/modelling/core/stratigraphic_column.py +473 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/_base_geological_feature.py +38 -2
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/builders/_fault_builder.py +1 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/builders/_geological_feature_builder.py +1 -1
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/fault/_fault_segment.py +1 -1
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/intrusions/intrusion_builder.py +1 -1
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/intrusions/intrusion_frame_builder.py +1 -1
- loopstructural-1.6.16/LoopStructural/version.py +1 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural.egg-info/PKG-INFO +2 -2
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural.egg-info/SOURCES.txt +3 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural.egg-info/requires.txt +1 -1
- {loopstructural-1.6.14 → loopstructural-1.6.16}/PKG-INFO +2 -2
- {loopstructural-1.6.14 → loopstructural-1.6.16}/pyproject.toml +1 -1
- loopstructural-1.6.14/LoopStructural/__init__.py +0 -53
- loopstructural-1.6.14/LoopStructural/version.py +0 -1
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LICENSE +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/_base.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/_example_models.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/claudius.csv +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/claudiusbb.txt +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/duplex.csv +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/duplexbb.txt +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/fault_trace/fault_trace.cpg +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/fault_trace/fault_trace.dbf +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/fault_trace/fault_trace.prj +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/fault_trace/fault_trace.shp +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/fault_trace/fault_trace.shx +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/geological_map_data/bbox.csv +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/geological_map_data/contacts.csv +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/geological_map_data/fault_displacement.csv +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/geological_map_data/fault_edges.txt +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/geological_map_data/fault_locations.csv +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/geological_map_data/fault_orientations.csv +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/geological_map_data/stratigraphic_order.csv +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/geological_map_data/stratigraphic_orientations.csv +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/geological_map_data/stratigraphic_thickness.csv +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/intrusion.csv +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/intrusionbb.txt +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/onefoldbb.txt +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/onefolddata.csv +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/refolded_bb.txt +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/refolded_fold.csv +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datasets/data/tabular_intrusion.csv +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datatypes/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datatypes/_structured_grid.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/datatypes/_surface.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/export/file_formats.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/export/geoh5.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/export/gocad.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/export/omf_wrapper.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/_api.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/_builders.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/_cython/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/_discrete_fold_interpolator.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/_interpolator_builder.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/_interpolator_factory.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/_operator.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/_p2interpolator.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/_2d_p1_unstructured.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/_2d_p2_unstructured.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/_2d_structured_tetra.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/_3d_p2_tetra.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/_3d_structured_grid.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/_3d_unstructured_tetra.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/_aabb.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/_base_support.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/_face_table.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/interpolators/supports/_support_factory.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/core/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/_analytical_feature.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/_cross_product_geological_feature.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/_geological_feature.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/_lambda_geological_feature.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/_projected_vector_feature.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/_region.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/_structural_frame.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/_unconformity_feature.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/builders/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/builders/_base_builder.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/builders/_folded_feature_builder.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/builders/_structural_frame_builder.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/fault/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/fault/_fault_function.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/fault/_fault_function_feature.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/fold/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/fold/_fold.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/fold/_fold_rotation_angle_feature.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/fold/_foldframe.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/fold/_svariogram.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/fold/fold_function/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/fold/fold_function/_base_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/fold/fold_function/_fourier_series_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/fold/fold_function/_lambda_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/features/fold/fold_function/_trigo_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/input/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/input/fault_network.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/input/map2loop_processor.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/input/process_data.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/input/project_file.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/intrusions/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/intrusions/geom_conceptual_models.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/intrusions/geometric_scaling_functions.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/intrusions/intrusion_feature.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/modelling/intrusions/intrusion_support_functions.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/_surface.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/_transformation.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/colours.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/config.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/dtm_creator.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/exceptions.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/features.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/helper.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/json_encoder.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/linalg.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/logging.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/maths.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/regions.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/typing.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/utils/utils.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural/visualisation/__init__.py +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural.egg-info/dependency_links.txt +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/LoopStructural.egg-info/top_level.txt +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/README.md +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/setup.cfg +0 -0
- {loopstructural-1.6.14 → loopstructural-1.6.16}/setup.py +0 -0
|
@@ -0,0 +1,71 @@
|
|
|
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 .interpolators._api import LoopInterpolator
|
|
24
|
+
from .interpolators import InterpolatorBuilder
|
|
25
|
+
from .datatypes import BoundingBox
|
|
26
|
+
from .utils import log_to_console, log_to_file, getLogger, rng, get_levels
|
|
27
|
+
|
|
28
|
+
logger = getLogger(__name__)
|
|
29
|
+
logger.info("Imported LoopStructural")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def setLogging(level="info", handler=None):
|
|
33
|
+
"""
|
|
34
|
+
Set the logging parameters for log file or custom handler
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
level : str
|
|
39
|
+
'info', 'warning', 'error', 'debug'
|
|
40
|
+
handler : logging.Handler, optional
|
|
41
|
+
A logging handler to use instead of the default StreamHandler
|
|
42
|
+
"""
|
|
43
|
+
import LoopStructural
|
|
44
|
+
|
|
45
|
+
levels = get_levels()
|
|
46
|
+
level_value = levels.get(level, logging.WARNING)
|
|
47
|
+
|
|
48
|
+
# Create default handler if none provided
|
|
49
|
+
if handler is None:
|
|
50
|
+
handler = logging.StreamHandler()
|
|
51
|
+
|
|
52
|
+
formatter = logging.Formatter(
|
|
53
|
+
"%(levelname)s: %(asctime)s: %(filename)s:%(lineno)d -- %(message)s"
|
|
54
|
+
)
|
|
55
|
+
handler.setFormatter(formatter)
|
|
56
|
+
handler.setLevel(level_value)
|
|
57
|
+
|
|
58
|
+
# Replace handlers in all known loggers
|
|
59
|
+
for name in LoopStructural.loggers:
|
|
60
|
+
logger = logging.getLogger(name)
|
|
61
|
+
logger.handlers = []
|
|
62
|
+
logger.addHandler(handler)
|
|
63
|
+
logger.setLevel(level_value)
|
|
64
|
+
|
|
65
|
+
# Also apply to main module logger
|
|
66
|
+
main_logger = logging.getLogger(__name__)
|
|
67
|
+
main_logger.handlers = []
|
|
68
|
+
main_logger.addHandler(handler)
|
|
69
|
+
main_logger.setLevel(level_value)
|
|
70
|
+
|
|
71
|
+
main_logger.info(f"Set logging to {level}")
|
|
@@ -17,6 +17,7 @@ class BoundingBox:
|
|
|
17
17
|
origin: Optional[np.ndarray] = None,
|
|
18
18
|
maximum: Optional[np.ndarray] = None,
|
|
19
19
|
global_origin: Optional[np.ndarray] = None,
|
|
20
|
+
global_maximum: Optional[np.ndarray] = None,
|
|
20
21
|
nsteps: Optional[np.ndarray] = None,
|
|
21
22
|
step_vector: Optional[np.ndarray] = None,
|
|
22
23
|
dimensions: Optional[int] = 3,
|
|
@@ -39,9 +40,12 @@ class BoundingBox:
|
|
|
39
40
|
# we want the local coordinates to start at 0
|
|
40
41
|
# otherwise uses provided origin. This is useful for having multiple bounding boxes rela
|
|
41
42
|
if global_origin is not None and origin is None:
|
|
42
|
-
origin = np.zeros(global_origin.shape)
|
|
43
|
+
origin = np.zeros(np.array(global_origin).shape)
|
|
44
|
+
if global_maximum is not None and global_origin is not None:
|
|
45
|
+
maximum = np.array(global_maximum) - np.array(global_origin)
|
|
46
|
+
|
|
43
47
|
if maximum is None and nsteps is not None and step_vector is not None:
|
|
44
|
-
maximum = origin + nsteps * step_vector
|
|
48
|
+
maximum = np.array(origin) + np.array(nsteps) * np.array(step_vector)
|
|
45
49
|
if origin is not None and global_origin is None:
|
|
46
50
|
global_origin = np.zeros(3)
|
|
47
51
|
self._origin = np.array(origin)
|
|
@@ -500,48 +504,53 @@ class BoundingBox:
|
|
|
500
504
|
name=name,
|
|
501
505
|
)
|
|
502
506
|
|
|
503
|
-
def project(self, xyz):
|
|
507
|
+
def project(self, xyz, inplace=False):
|
|
504
508
|
"""Project a point into the bounding box
|
|
505
509
|
|
|
506
510
|
Parameters
|
|
507
511
|
----------
|
|
508
512
|
xyz : np.ndarray
|
|
509
513
|
point to project
|
|
514
|
+
inplace : bool, optional
|
|
515
|
+
Whether to modify the input array in place, by default False
|
|
510
516
|
|
|
511
517
|
Returns
|
|
512
518
|
-------
|
|
513
519
|
np.ndarray
|
|
514
520
|
projected point
|
|
515
521
|
"""
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
) # np.clip(xyz, self.origin, self.maximum)
|
|
522
|
+
if inplace:
|
|
523
|
+
xyz -= self.global_origin
|
|
524
|
+
return xyz
|
|
525
|
+
return (xyz - self.global_origin) # np.clip(xyz, self.origin, self.maximum)
|
|
520
526
|
|
|
521
527
|
def scale_by_projection_factor(self, value):
|
|
522
528
|
return value / np.max((self.global_maximum - self.global_origin))
|
|
523
529
|
|
|
524
|
-
def reproject(self, xyz):
|
|
530
|
+
def reproject(self, xyz, inplace=False):
|
|
525
531
|
"""Reproject a point from the bounding box to the global space
|
|
526
532
|
|
|
527
533
|
Parameters
|
|
528
534
|
----------
|
|
529
535
|
xyz : np.ndarray
|
|
530
536
|
point to reproject
|
|
531
|
-
|
|
537
|
+
inplace : bool, optional
|
|
538
|
+
Whether to modify the input array in place, by default False
|
|
532
539
|
Returns
|
|
533
540
|
-------
|
|
534
541
|
np.ndarray
|
|
535
542
|
reprojected point
|
|
536
543
|
"""
|
|
537
|
-
|
|
538
|
-
|
|
544
|
+
if inplace:
|
|
545
|
+
xyz += self.global_origin
|
|
546
|
+
return xyz
|
|
547
|
+
return xyz + self.global_origin
|
|
539
548
|
|
|
540
549
|
def __repr__(self):
|
|
541
|
-
return f"BoundingBox({self.origin}, {self.maximum}, {self.nsteps})"
|
|
550
|
+
return f"BoundingBox(origin:{self.origin}, maximum:{self.maximum}, nsteps:{self.nsteps})"
|
|
542
551
|
|
|
543
552
|
def __str__(self):
|
|
544
|
-
return f"BoundingBox({self.origin}, {self.maximum}, {self.nsteps})"
|
|
553
|
+
return f"BoundingBox(origin:{self.origin}, maximum:{self.maximum}, nsteps:{self.nsteps})"
|
|
545
554
|
|
|
546
555
|
def __eq__(self, other):
|
|
547
556
|
if not isinstance(other, BoundingBox):
|
|
@@ -157,7 +157,6 @@ class VectorPoints:
|
|
|
157
157
|
try:
|
|
158
158
|
locations = bb.project(locations)
|
|
159
159
|
_projected = True
|
|
160
|
-
scale = bb.scale_by_projection_factor(scale)
|
|
161
160
|
except Exception as e:
|
|
162
161
|
logger.error(f'Failed to project points to bounding box: {e}')
|
|
163
162
|
logger.error('Using unprojected points, this may cause issues with the glyphing')
|
|
@@ -423,7 +423,7 @@ def _write_vol_evtk(model, file_name, data_label, nsteps, real_coords=True):
|
|
|
423
423
|
|
|
424
424
|
"""
|
|
425
425
|
# Define grid spacing
|
|
426
|
-
xyz = model.bounding_box.regular_grid(nsteps)
|
|
426
|
+
xyz = model.bounding_box.regular_grid(nsteps=nsteps)
|
|
427
427
|
vals = model.evaluate_model(xyz, scale=False)
|
|
428
428
|
if real_coords:
|
|
429
429
|
model.rescale(xyz)
|
|
@@ -465,7 +465,7 @@ def _write_vol_gocad(model, file_name, data_label, nsteps, real_coords=True):
|
|
|
465
465
|
|
|
466
466
|
"""
|
|
467
467
|
# Define grid spacing in model scale coords
|
|
468
|
-
xyz = model.bounding_box.regular_grid(nsteps)
|
|
468
|
+
xyz = model.bounding_box.regular_grid(nsteps=nsteps)
|
|
469
469
|
|
|
470
470
|
vals = model.evaluate_model(xyz, scale=False)
|
|
471
471
|
# Use FORTRAN style indexing for GOCAD VOXET
|
|
@@ -3,6 +3,7 @@ Interpolators and interpolation supports
|
|
|
3
3
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
|
|
6
7
|
__all__ = [
|
|
7
8
|
"InterpolatorType",
|
|
8
9
|
"GeologicalInterpolator",
|
|
@@ -21,39 +22,12 @@ __all__ = [
|
|
|
21
22
|
"StructuredGrid2D",
|
|
22
23
|
"P2UnstructuredTetMesh",
|
|
23
24
|
]
|
|
24
|
-
from
|
|
25
|
+
from ._interpolatortype import InterpolatorType
|
|
25
26
|
|
|
26
27
|
from ..utils import getLogger
|
|
27
28
|
|
|
28
29
|
logger = getLogger(__name__)
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
class InterpolatorType(IntEnum):
|
|
32
|
-
"""
|
|
33
|
-
Enum for the different interpolator types
|
|
34
|
-
|
|
35
|
-
1-9 should cover interpolators with supports
|
|
36
|
-
9+ are data supported
|
|
37
|
-
"""
|
|
38
|
-
|
|
39
|
-
BASE = 0
|
|
40
|
-
BASE_DISCRETE = 1
|
|
41
|
-
FINITE_DIFFERENCE = 2
|
|
42
|
-
DISCRETE_FOLD = 3
|
|
43
|
-
PIECEWISE_LINEAR = 4
|
|
44
|
-
PIECEWISE_QUADRATIC = 5
|
|
45
|
-
BASE_DATA_SUPPORTED = 10
|
|
46
|
-
SURFE = 11
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
interpolator_string_map = {
|
|
50
|
-
"FDI": InterpolatorType.FINITE_DIFFERENCE,
|
|
51
|
-
"PLI": InterpolatorType.PIECEWISE_LINEAR,
|
|
52
|
-
"P2": InterpolatorType.PIECEWISE_QUADRATIC,
|
|
53
|
-
"P1": InterpolatorType.PIECEWISE_LINEAR,
|
|
54
|
-
"DFI": InterpolatorType.DISCRETE_FOLD,
|
|
55
|
-
'surfe': InterpolatorType.SURFE,
|
|
56
|
-
}
|
|
57
31
|
from ..interpolators._geological_interpolator import GeologicalInterpolator
|
|
58
32
|
from ..interpolators._discrete_interpolator import DiscreteInterpolator
|
|
59
33
|
from ..interpolators.supports import (
|
|
@@ -79,7 +53,7 @@ from ..interpolators._discrete_fold_interpolator import (
|
|
|
79
53
|
)
|
|
80
54
|
from ..interpolators._p2interpolator import P2Interpolator
|
|
81
55
|
from ..interpolators._p1interpolator import P1Interpolator
|
|
82
|
-
|
|
56
|
+
from ..interpolators._constant_norm import ConstantNormP1Interpolator, ConstantNormFDIInterpolator
|
|
83
57
|
try:
|
|
84
58
|
from ..interpolators._surfe_wrapper import SurfeRBFInterpolator
|
|
85
59
|
except ImportError:
|
|
@@ -93,6 +67,24 @@ except ImportError:
|
|
|
93
67
|
raise ImportError(
|
|
94
68
|
"Surfe cannot be imported. Please install Surfe. pip install surfe/ conda install -c loop3d surfe"
|
|
95
69
|
)
|
|
70
|
+
|
|
71
|
+
# Ensure compatibility between the fallback and imported class
|
|
72
|
+
SurfeRBFInterpolator = SurfeRBFInterpolator
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
interpolator_string_map = {
|
|
76
|
+
"FDI": InterpolatorType.FINITE_DIFFERENCE,
|
|
77
|
+
"PLI": InterpolatorType.PIECEWISE_LINEAR,
|
|
78
|
+
"P2": InterpolatorType.PIECEWISE_QUADRATIC,
|
|
79
|
+
"P1": InterpolatorType.PIECEWISE_LINEAR,
|
|
80
|
+
"DFI": InterpolatorType.DISCRETE_FOLD,
|
|
81
|
+
'surfe': InterpolatorType.SURFE,
|
|
82
|
+
"FDI_CN": InterpolatorType.FINITE_DIFFERENCE_CONSTANT_NORM,
|
|
83
|
+
"P1_CN": InterpolatorType.PIECEWISE_LINEAR_CONSTANT_NORM,
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Define the mapping after all imports
|
|
96
88
|
interpolator_map = {
|
|
97
89
|
InterpolatorType.BASE: GeologicalInterpolator,
|
|
98
90
|
InterpolatorType.BASE_DISCRETE: DiscreteInterpolator,
|
|
@@ -102,6 +94,8 @@ interpolator_map = {
|
|
|
102
94
|
InterpolatorType.PIECEWISE_QUADRATIC: P2Interpolator,
|
|
103
95
|
InterpolatorType.BASE_DATA_SUPPORTED: GeologicalInterpolator,
|
|
104
96
|
InterpolatorType.SURFE: SurfeRBFInterpolator,
|
|
97
|
+
InterpolatorType.PIECEWISE_LINEAR_CONSTANT_NORM: ConstantNormP1Interpolator,
|
|
98
|
+
InterpolatorType.FINITE_DIFFERENCE_CONSTANT_NORM: ConstantNormFDIInterpolator,
|
|
105
99
|
}
|
|
106
100
|
|
|
107
101
|
support_interpolator_map = {
|
|
@@ -119,9 +113,18 @@ support_interpolator_map = {
|
|
|
119
113
|
3: SupportType.DataSupported,
|
|
120
114
|
2: SupportType.DataSupported,
|
|
121
115
|
},
|
|
116
|
+
InterpolatorType.PIECEWISE_LINEAR_CONSTANT_NORM:{
|
|
117
|
+
3: SupportType.TetMesh,
|
|
118
|
+
2: SupportType.P1Unstructured2d,
|
|
119
|
+
},
|
|
120
|
+
InterpolatorType.FINITE_DIFFERENCE_CONSTANT_NORM: {
|
|
121
|
+
3: SupportType.StructuredGrid,
|
|
122
|
+
2: SupportType.StructuredGrid2D,
|
|
123
|
+
}
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
from ._interpolator_factory import InterpolatorFactory
|
|
125
127
|
from ._interpolator_builder import InterpolatorBuilder
|
|
126
128
|
|
|
127
|
-
|
|
129
|
+
|
|
130
|
+
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from LoopStructural.interpolators._discrete_interpolator import DiscreteInterpolator
|
|
4
|
+
from LoopStructural.interpolators._finite_difference_interpolator import FiniteDifferenceInterpolator
|
|
5
|
+
from ._p1interpolator import P1Interpolator
|
|
6
|
+
from typing import Optional, Union, Callable
|
|
7
|
+
from scipy import sparse
|
|
8
|
+
from LoopStructural.utils import rng
|
|
9
|
+
|
|
10
|
+
class ConstantNormInterpolator:
|
|
11
|
+
"""Adds a non linear constraint to an interpolator to constrain
|
|
12
|
+
the norm of the gradient to be a set value.
|
|
13
|
+
|
|
14
|
+
Returns
|
|
15
|
+
-------
|
|
16
|
+
_type_
|
|
17
|
+
_description_
|
|
18
|
+
"""
|
|
19
|
+
def __init__(self, interpolator: DiscreteInterpolator,basetype):
|
|
20
|
+
"""Initialise the constant norm inteprolator
|
|
21
|
+
with a discrete interpolator.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
interpolator : DiscreteInterpolator
|
|
26
|
+
The discrete interpolator to add constant norm to.
|
|
27
|
+
"""
|
|
28
|
+
self.basetype = basetype
|
|
29
|
+
self.interpolator = interpolator
|
|
30
|
+
self.support = interpolator.support
|
|
31
|
+
self.random_subset = False
|
|
32
|
+
self.norm_length = 1.0
|
|
33
|
+
self.n_iterations = 20
|
|
34
|
+
self.store_solution_history = False
|
|
35
|
+
self.solution_history = []#np.zeros((self.n_iterations, self.support.n_nodes))
|
|
36
|
+
self.gradient_constraint_store = []
|
|
37
|
+
def add_constant_norm(self, w:float):
|
|
38
|
+
"""Add a constraint to the interpolator to constrain the norm of the gradient
|
|
39
|
+
to be a set value
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
w : float
|
|
44
|
+
weighting of the constraint
|
|
45
|
+
"""
|
|
46
|
+
if "constant norm" in self.interpolator.constraints:
|
|
47
|
+
_ = self.interpolator.constraints.pop("constant norm")
|
|
48
|
+
|
|
49
|
+
element_indices = np.arange(self.support.elements.shape[0])
|
|
50
|
+
if self.random_subset:
|
|
51
|
+
rng.shuffle(element_indices)
|
|
52
|
+
element_indices = element_indices[: int(0.1 * self.support.elements.shape[0])]
|
|
53
|
+
vertices, gradient, elements, inside = self.support.get_element_gradient_for_location(
|
|
54
|
+
self.support.barycentre[element_indices]
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
t_g = gradient[:, :, :]
|
|
58
|
+
# t_n = gradient[self.support.shared_element_relationships[:, 1], :, :]
|
|
59
|
+
v_t = np.einsum(
|
|
60
|
+
"ijk,ik->ij",
|
|
61
|
+
t_g,
|
|
62
|
+
self.interpolator.c[self.support.elements[elements]],
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
v_t = v_t / np.linalg.norm(v_t, axis=1)[:, np.newaxis]
|
|
66
|
+
self.gradient_constraint_store.append(np.hstack([self.support.barycentre[element_indices],v_t]))
|
|
67
|
+
A1 = np.einsum("ij,ijk->ik", v_t, t_g)
|
|
68
|
+
volume = self.support.element_size[element_indices]
|
|
69
|
+
A1 = A1 / volume[:, np.newaxis] # normalise by element size
|
|
70
|
+
|
|
71
|
+
b = np.zeros(A1.shape[0]) + self.norm_length
|
|
72
|
+
b = b / volume # normalise by element size
|
|
73
|
+
idc = np.hstack(
|
|
74
|
+
[
|
|
75
|
+
self.support.elements[elements],
|
|
76
|
+
]
|
|
77
|
+
)
|
|
78
|
+
self.interpolator.add_constraints_to_least_squares(A1, b, idc, w=w, name="constant norm")
|
|
79
|
+
|
|
80
|
+
def solve_system(
|
|
81
|
+
self,
|
|
82
|
+
solver: Optional[Union[Callable[[sparse.csr_matrix, np.ndarray], np.ndarray], str]] = None,
|
|
83
|
+
tol: Optional[float] = None,
|
|
84
|
+
solver_kwargs: dict = {},
|
|
85
|
+
) -> bool:
|
|
86
|
+
"""Solve the system of equations iteratively for the constant norm interpolator.
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
solver : Optional[Union[Callable[[sparse.csr_matrix, np.ndarray], np.ndarray], str]], optional
|
|
91
|
+
Solver function or name, by default None
|
|
92
|
+
tol : Optional[float], optional
|
|
93
|
+
Tolerance for the solver, by default None
|
|
94
|
+
solver_kwargs : dict, optional
|
|
95
|
+
Additional arguments for the solver, by default {}
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
bool
|
|
100
|
+
Success status of the solver
|
|
101
|
+
"""
|
|
102
|
+
success = True
|
|
103
|
+
for i in range(self.n_iterations):
|
|
104
|
+
if i > 0:
|
|
105
|
+
self.add_constant_norm(w=(0.1 * i) ** 2 + 0.01)
|
|
106
|
+
# Ensure the interpolator is cast to P1Interpolator before calling solve_system
|
|
107
|
+
if isinstance(self.interpolator, self.basetype):
|
|
108
|
+
success = self.basetype.solve_system(self.interpolator, solver=solver, tol=tol, solver_kwargs=solver_kwargs)
|
|
109
|
+
if self.store_solution_history:
|
|
110
|
+
|
|
111
|
+
self.solution_history.append(self.interpolator.c)
|
|
112
|
+
else:
|
|
113
|
+
raise TypeError("self.interpolator is not an instance of P1Interpolator")
|
|
114
|
+
if not success:
|
|
115
|
+
break
|
|
116
|
+
return success
|
|
117
|
+
|
|
118
|
+
class ConstantNormP1Interpolator(P1Interpolator, ConstantNormInterpolator):
|
|
119
|
+
"""Constant norm interpolator using P1 base interpolator
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
P1Interpolator : class
|
|
124
|
+
The P1Interpolator class.
|
|
125
|
+
ConstantNormInterpolator : class
|
|
126
|
+
The ConstantNormInterpolator class.
|
|
127
|
+
"""
|
|
128
|
+
def __init__(self, support):
|
|
129
|
+
"""Initialise the constant norm P1 interpolator.
|
|
130
|
+
|
|
131
|
+
Parameters
|
|
132
|
+
----------
|
|
133
|
+
support : _type_
|
|
134
|
+
_description_
|
|
135
|
+
"""
|
|
136
|
+
P1Interpolator.__init__(self, support)
|
|
137
|
+
ConstantNormInterpolator.__init__(self, self, P1Interpolator)
|
|
138
|
+
|
|
139
|
+
def solve_system(
|
|
140
|
+
self,
|
|
141
|
+
solver: Optional[Union[Callable[[sparse.csr_matrix, np.ndarray], np.ndarray], str]] = None,
|
|
142
|
+
tol: Optional[float] = None,
|
|
143
|
+
solver_kwargs: dict = {},
|
|
144
|
+
) -> bool:
|
|
145
|
+
"""Solve the system of equations for the constant norm P1 interpolator.
|
|
146
|
+
|
|
147
|
+
Parameters
|
|
148
|
+
----------
|
|
149
|
+
solver : Optional[Union[Callable[[sparse.csr_matrix, np.ndarray], np.ndarray], str]], optional
|
|
150
|
+
Solver function or name, by default None
|
|
151
|
+
tol : Optional[float], optional
|
|
152
|
+
Tolerance for the solver, by default None
|
|
153
|
+
solver_kwargs : dict, optional
|
|
154
|
+
Additional arguments for the solver, by default {}
|
|
155
|
+
|
|
156
|
+
Returns
|
|
157
|
+
-------
|
|
158
|
+
bool
|
|
159
|
+
Success status of the solver
|
|
160
|
+
"""
|
|
161
|
+
return ConstantNormInterpolator.solve_system(self, solver=solver, tol=tol, solver_kwargs=solver_kwargs)
|
|
162
|
+
|
|
163
|
+
class ConstantNormFDIInterpolator(FiniteDifferenceInterpolator, ConstantNormInterpolator):
|
|
164
|
+
"""Constant norm interpolator using finite difference base interpolator
|
|
165
|
+
|
|
166
|
+
Parameters
|
|
167
|
+
----------
|
|
168
|
+
FiniteDifferenceInterpolator : class
|
|
169
|
+
The FiniteDifferenceInterpolator class.
|
|
170
|
+
ConstantNormInterpolator : class
|
|
171
|
+
The ConstantNormInterpolator class.
|
|
172
|
+
"""
|
|
173
|
+
def __init__(self, support):
|
|
174
|
+
"""Initialise the constant norm finite difference interpolator.
|
|
175
|
+
|
|
176
|
+
Parameters
|
|
177
|
+
----------
|
|
178
|
+
support : _type_
|
|
179
|
+
_description_
|
|
180
|
+
"""
|
|
181
|
+
FiniteDifferenceInterpolator.__init__(self, support)
|
|
182
|
+
ConstantNormInterpolator.__init__(self, self, FiniteDifferenceInterpolator)
|
|
183
|
+
def solve_system(
|
|
184
|
+
self,
|
|
185
|
+
solver: Optional[Union[Callable[[sparse.csr_matrix, np.ndarray], np.ndarray], str]] = None,
|
|
186
|
+
tol: Optional[float] = None,
|
|
187
|
+
solver_kwargs: dict = {},
|
|
188
|
+
) -> bool:
|
|
189
|
+
"""Solve the system of equations for the constant norm finite difference interpolator.
|
|
190
|
+
|
|
191
|
+
Parameters
|
|
192
|
+
----------
|
|
193
|
+
solver : Optional[Union[Callable[[sparse.csr_matrix, np.ndarray], np.ndarray], str]], optional
|
|
194
|
+
Solver function or name, by default None
|
|
195
|
+
tol : Optional[float], optional
|
|
196
|
+
Tolerance for the solver, by default None
|
|
197
|
+
solver_kwargs : dict, optional
|
|
198
|
+
Additional arguments for the solver, by default {}
|
|
199
|
+
|
|
200
|
+
Returns
|
|
201
|
+
-------
|
|
202
|
+
bool
|
|
203
|
+
Success status of the solver
|
|
204
|
+
"""
|
|
205
|
+
return ConstantNormInterpolator.solve_system(self, solver=solver, tol=tol, solver_kwargs=solver_kwargs)
|
|
@@ -42,7 +42,7 @@ class DiscreteInterpolator(GeologicalInterpolator):
|
|
|
42
42
|
|
|
43
43
|
self.shape = "rectangular"
|
|
44
44
|
if self.shape == "square":
|
|
45
|
-
self.B = np.zeros(self.
|
|
45
|
+
self.B = np.zeros(self.dof)
|
|
46
46
|
self.c_ = 0
|
|
47
47
|
|
|
48
48
|
self.solver = "cg"
|
|
@@ -60,7 +60,7 @@ class DiscreteInterpolator(GeologicalInterpolator):
|
|
|
60
60
|
self.non_linear_constraints = []
|
|
61
61
|
self.constraints = {}
|
|
62
62
|
self.interpolation_weights = {}
|
|
63
|
-
logger.info("Creating discrete interpolator with {} degrees of freedom".format(self.
|
|
63
|
+
logger.info("Creating discrete interpolator with {} degrees of freedom".format(self.dof))
|
|
64
64
|
self.type = InterpolatorType.BASE_DISCRETE
|
|
65
65
|
|
|
66
66
|
def set_nelements(self, nelements: int) -> int:
|
|
@@ -78,7 +78,7 @@ class DiscreteInterpolator(GeologicalInterpolator):
|
|
|
78
78
|
return self.support.n_elements
|
|
79
79
|
|
|
80
80
|
@property
|
|
81
|
-
def
|
|
81
|
+
def dof(self) -> int:
|
|
82
82
|
"""Number of degrees of freedom for the interpolator
|
|
83
83
|
|
|
84
84
|
Returns
|
|
@@ -125,7 +125,7 @@ class DiscreteInterpolator(GeologicalInterpolator):
|
|
|
125
125
|
# self.region_function = region
|
|
126
126
|
logger.info(
|
|
127
127
|
"Cannot use region at the moment. Interpolation now uses region and has {} degrees of freedom".format(
|
|
128
|
-
self.
|
|
128
|
+
self.dof
|
|
129
129
|
)
|
|
130
130
|
)
|
|
131
131
|
|
|
@@ -175,7 +175,7 @@ class DiscreteInterpolator(GeologicalInterpolator):
|
|
|
175
175
|
"""
|
|
176
176
|
self.constraints = {}
|
|
177
177
|
self.c_ = 0
|
|
178
|
-
self.regularisation_scale = np.ones(self.
|
|
178
|
+
self.regularisation_scale = np.ones(self.dof)
|
|
179
179
|
logger.info("Resetting interpolation constraints")
|
|
180
180
|
|
|
181
181
|
def add_constraints_to_least_squares(self, A, B, idc, w=1.0, name="undefined"):
|
|
@@ -219,6 +219,7 @@ class DiscreteInterpolator(GeologicalInterpolator):
|
|
|
219
219
|
# normalise by rows of A
|
|
220
220
|
# Should this be done? It should make the solution more stable
|
|
221
221
|
length = np.linalg.norm(A, axis=1)
|
|
222
|
+
# length[length>0] = 1.
|
|
222
223
|
B[length > 0] /= length[length > 0]
|
|
223
224
|
# going to assume if any are nan they are all nan
|
|
224
225
|
mask = np.any(np.isnan(A), axis=1)
|
|
@@ -245,7 +246,7 @@ class DiscreteInterpolator(GeologicalInterpolator):
|
|
|
245
246
|
rows = np.tile(rows, (A.shape[-1], 1)).T
|
|
246
247
|
self.constraints[name] = {
|
|
247
248
|
'matrix': sparse.coo_matrix(
|
|
248
|
-
(A.flatten(), (rows.flatten(), idc.flatten())), shape=(n_rows, self.
|
|
249
|
+
(A.flatten(), (rows.flatten(), idc.flatten())), shape=(n_rows, self.dof)
|
|
249
250
|
).tocsc(),
|
|
250
251
|
'b': B.flatten(),
|
|
251
252
|
'w': w,
|
|
@@ -286,7 +287,7 @@ class DiscreteInterpolator(GeologicalInterpolator):
|
|
|
286
287
|
A : numpy array
|
|
287
288
|
matrix of coefficients
|
|
288
289
|
bounds : numpy array
|
|
289
|
-
|
|
290
|
+
n*3 lower, upper, 1
|
|
290
291
|
idc : numpy array
|
|
291
292
|
index of constraints in the matrix
|
|
292
293
|
Returns
|
|
@@ -296,14 +297,14 @@ class DiscreteInterpolator(GeologicalInterpolator):
|
|
|
296
297
|
# map from mesh node index to region node index
|
|
297
298
|
gi = np.zeros(self.support.n_nodes, dtype=int)
|
|
298
299
|
gi[:] = -1
|
|
299
|
-
gi[self.region] = np.arange(0, self.
|
|
300
|
+
gi[self.region] = np.arange(0, self.dof, dtype=int)
|
|
300
301
|
idc = gi[idc]
|
|
301
302
|
rows = np.arange(0, idc.shape[0])
|
|
302
303
|
rows = np.tile(rows, (A.shape[-1], 1)).T
|
|
303
304
|
|
|
304
305
|
self.ineq_constraints[name] = {
|
|
305
306
|
'matrix': sparse.coo_matrix(
|
|
306
|
-
(A.flatten(), (rows.flatten(), idc.flatten())), shape=(rows.shape[0], self.
|
|
307
|
+
(A.flatten(), (rows.flatten(), idc.flatten())), shape=(rows.shape[0], self.dof)
|
|
307
308
|
).tocsc(),
|
|
308
309
|
"bounds": bounds,
|
|
309
310
|
}
|
|
@@ -431,7 +432,7 @@ class DiscreteInterpolator(GeologicalInterpolator):
|
|
|
431
432
|
np.ones((value.shape[0], 1)),
|
|
432
433
|
l,
|
|
433
434
|
u,
|
|
434
|
-
np.arange(0, self.
|
|
435
|
+
np.arange(0, self.dof, dtype=int),
|
|
435
436
|
)
|
|
436
437
|
|
|
437
438
|
def add_equality_constraints(self, node_idx, values, name="undefined"):
|
|
@@ -454,7 +455,7 @@ class DiscreteInterpolator(GeologicalInterpolator):
|
|
|
454
455
|
# map from mesh node index to region node index
|
|
455
456
|
gi = np.zeros(self.support.n_nodes)
|
|
456
457
|
gi[:] = -1
|
|
457
|
-
gi[self.region] = np.arange(0, self.
|
|
458
|
+
gi[self.region] = np.arange(0, self.dof)
|
|
458
459
|
idc = gi[node_idx]
|
|
459
460
|
outside = ~(idc == -1)
|
|
460
461
|
|
|
@@ -515,7 +516,7 @@ class DiscreteInterpolator(GeologicalInterpolator):
|
|
|
515
516
|
if len(self.equal_constraints) > 0:
|
|
516
517
|
ATA = A.T.dot(A)
|
|
517
518
|
ATB = A.T.dot(B)
|
|
518
|
-
logger.info(f"Equality block is {self.eq_const_c} x {self.
|
|
519
|
+
logger.info(f"Equality block is {self.eq_const_c} x {self.dof}")
|
|
519
520
|
# solving constrained least squares using
|
|
520
521
|
# | ATA CT | |c| = b
|
|
521
522
|
# | C 0 | |y| d
|
|
@@ -540,7 +541,7 @@ class DiscreteInterpolator(GeologicalInterpolator):
|
|
|
540
541
|
|
|
541
542
|
C = sparse.coo_matrix(
|
|
542
543
|
(np.array(a), (np.array(rows), cols)),
|
|
543
|
-
shape=(self.eq_const_c, self.
|
|
544
|
+
shape=(self.eq_const_c, self.dof),
|
|
544
545
|
dtype=float,
|
|
545
546
|
).tocsr()
|
|
546
547
|
|
|
@@ -557,7 +558,7 @@ class DiscreteInterpolator(GeologicalInterpolator):
|
|
|
557
558
|
mats.append(c['matrix'])
|
|
558
559
|
bounds.append(c['bounds'])
|
|
559
560
|
if len(mats) == 0:
|
|
560
|
-
return sparse.csr_matrix((0, self.
|
|
561
|
+
return sparse.csr_matrix((0, self.dof), dtype=float), np.zeros((0, 3))
|
|
561
562
|
Q = sparse.vstack(mats)
|
|
562
563
|
bounds = np.vstack(bounds)
|
|
563
564
|
return Q, bounds
|