LoopStructural 1.6.5__tar.gz → 1.6.6__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.5 → loopstructural-1.6.6}/LoopStructural/datatypes/_bounding_box.py +58 -3
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datatypes/_point.py +32 -6
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/__init__.py +1 -1
- loopstructural-1.6.6/LoopStructural/interpolators/_builders.py +149 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/_finite_difference_interpolator.py +11 -11
- loopstructural-1.6.6/LoopStructural/interpolators/_interpolator_builder.py +55 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/_interpolator_factory.py +7 -18
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/_3d_base_structured.py +4 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/core/geological_model.py +9 -8
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/__init__.py +1 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/_analytical_feature.py +23 -2
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/_base_geological_feature.py +17 -1
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/_cross_product_geological_feature.py +7 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/_geological_feature.py +3 -1
- loopstructural-1.6.6/LoopStructural/modelling/features/_projected_vector_feature.py +112 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/_structural_frame.py +6 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/builders/_folded_feature_builder.py +2 -2
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/builders/_structural_frame_builder.py +2 -2
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/fault/_fault_function_feature.py +3 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/fault/_fault_segment.py +10 -2
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/intrusions/intrusion_feature.py +3 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/utils/__init__.py +1 -1
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/utils/_surface.py +6 -1
- loopstructural-1.6.6/LoopStructural/utils/_transformation.py +160 -0
- loopstructural-1.6.6/LoopStructural/utils/colours.py +50 -0
- loopstructural-1.6.6/LoopStructural/version.py +1 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural.egg-info/PKG-INFO +16 -2
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural.egg-info/SOURCES.txt +2 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural.egg-info/requires.txt +15 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/PKG-INFO +16 -2
- {loopstructural-1.6.5 → loopstructural-1.6.6}/pyproject.toml +1 -0
- loopstructural-1.6.5/LoopStructural/interpolators/_builders.py +0 -149
- loopstructural-1.6.5/LoopStructural/utils/_transformation.py +0 -76
- loopstructural-1.6.5/LoopStructural/utils/colours.py +0 -26
- loopstructural-1.6.5/LoopStructural/version.py +0 -1
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LICENSE +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/__init__.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/__init__.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/_base.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/_example_models.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/claudius.csv +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/claudiusbb.txt +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/duplex.csv +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/duplexbb.txt +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/fault_trace/fault_trace.cpg +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/fault_trace/fault_trace.dbf +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/fault_trace/fault_trace.prj +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/fault_trace/fault_trace.shp +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/fault_trace/fault_trace.shx +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/geological_map_data/bbox.csv +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/geological_map_data/contacts.csv +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/geological_map_data/fault_displacement.csv +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/geological_map_data/fault_edges.txt +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/geological_map_data/fault_locations.csv +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/geological_map_data/fault_orientations.csv +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/geological_map_data/stratigraphic_order.csv +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/geological_map_data/stratigraphic_orientations.csv +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/geological_map_data/stratigraphic_thickness.csv +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/intrusion.csv +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/intrusionbb.txt +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/onefoldbb.txt +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/onefolddata.csv +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/refolded_bb.txt +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/refolded_fold.csv +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datasets/data/tabular_intrusion.csv +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datatypes/__init__.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datatypes/_structured_grid.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/datatypes/_surface.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/export/exporters.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/export/file_formats.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/export/geoh5.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/export/gocad.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/export/omf_wrapper.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/_api.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/_cython/__init__.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/_discrete_fold_interpolator.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/_discrete_interpolator.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/_geological_interpolator.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/_operator.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/_p1interpolator.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/_p2interpolator.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/_surfe_wrapper.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/_2d_base_unstructured.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/_2d_p1_unstructured.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/_2d_p2_unstructured.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/_2d_structured_grid.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/_2d_structured_tetra.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/_3d_p2_tetra.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/_3d_structured_grid.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/_3d_structured_tetra.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/_3d_unstructured_tetra.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/__init__.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/_aabb.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/_base_support.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/_face_table.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/supports/_support_factory.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/__init__.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/core/__init__.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/_lambda_geological_feature.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/_region.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/_unconformity_feature.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/builders/__init__.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/builders/_base_builder.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/builders/_fault_builder.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/builders/_geological_feature_builder.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/fault/__init__.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/fault/_fault_function.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/fold/__init__.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/fold/_fold.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/fold/_fold_rotation_angle_feature.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/fold/_foldframe.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/fold/_svariogram.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/fold/fold_function/__init__.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/fold/fold_function/_base_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/fold/fold_function/_fourier_series_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/fold/fold_function/_lambda_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/features/fold/fold_function/_trigo_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/input/__init__.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/input/fault_network.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/input/map2loop_processor.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/input/process_data.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/input/project_file.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/intrusions/__init__.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/intrusions/geom_conceptual_models.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/intrusions/geometric_scaling_functions.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/intrusions/intrusion_builder.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/intrusions/intrusion_frame_builder.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/intrusions/intrusion_support_functions.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/utils/config.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/utils/dtm_creator.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/utils/exceptions.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/utils/features.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/utils/helper.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/utils/json_encoder.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/utils/linalg.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/utils/logging.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/utils/maths.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/utils/regions.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/utils/typing.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/utils/utils.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/visualisation/__init__.py +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural.egg-info/dependency_links.txt +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural.egg-info/top_level.txt +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/README.md +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/setup.cfg +0 -0
- {loopstructural-1.6.5 → loopstructural-1.6.6}/setup.py +0 -0
|
@@ -410,9 +410,15 @@ class BoundingBox:
|
|
|
410
410
|
import pyvista as pv
|
|
411
411
|
except ImportError:
|
|
412
412
|
raise ImportError("pyvista is required for vtk support")
|
|
413
|
-
x = np.linspace(
|
|
414
|
-
|
|
415
|
-
|
|
413
|
+
x = np.linspace(
|
|
414
|
+
self.global_origin[0] + self.origin[0], self.global_maximum[0], self.nsteps[0]
|
|
415
|
+
)
|
|
416
|
+
y = np.linspace(
|
|
417
|
+
self.global_origin[1] + self.origin[1], self.global_maximum[1], self.nsteps[1]
|
|
418
|
+
)
|
|
419
|
+
z = np.linspace(
|
|
420
|
+
self.global_origin[2] + self.origin[2], self.global_maximum[2], self.nsteps[2]
|
|
421
|
+
)
|
|
416
422
|
return pv.RectilinearGrid(
|
|
417
423
|
x,
|
|
418
424
|
y,
|
|
@@ -435,3 +441,52 @@ class BoundingBox:
|
|
|
435
441
|
properties=_vertex_data,
|
|
436
442
|
name=name,
|
|
437
443
|
)
|
|
444
|
+
|
|
445
|
+
def project(self, xyz):
|
|
446
|
+
"""Project a point into the bounding box
|
|
447
|
+
|
|
448
|
+
Parameters
|
|
449
|
+
----------
|
|
450
|
+
xyz : np.ndarray
|
|
451
|
+
point to project
|
|
452
|
+
|
|
453
|
+
Returns
|
|
454
|
+
-------
|
|
455
|
+
np.ndarray
|
|
456
|
+
projected point
|
|
457
|
+
"""
|
|
458
|
+
|
|
459
|
+
return (xyz - self.global_origin) / np.max(
|
|
460
|
+
(self.global_maximum - self.global_origin)
|
|
461
|
+
) # np.clip(xyz, self.origin, self.maximum)
|
|
462
|
+
|
|
463
|
+
def reproject(self, xyz):
|
|
464
|
+
"""Reproject a point from the bounding box to the global space
|
|
465
|
+
|
|
466
|
+
Parameters
|
|
467
|
+
----------
|
|
468
|
+
xyz : np.ndarray
|
|
469
|
+
point to reproject
|
|
470
|
+
|
|
471
|
+
Returns
|
|
472
|
+
-------
|
|
473
|
+
np.ndarray
|
|
474
|
+
reprojected point
|
|
475
|
+
"""
|
|
476
|
+
|
|
477
|
+
return xyz * np.max((self.global_maximum - self.global_origin)) + self.global_origin
|
|
478
|
+
|
|
479
|
+
def __repr__(self):
|
|
480
|
+
return f"BoundingBox({self.origin}, {self.maximum}, {self.nsteps})"
|
|
481
|
+
|
|
482
|
+
def __str__(self):
|
|
483
|
+
return f"BoundingBox({self.origin}, {self.maximum}, {self.nsteps})"
|
|
484
|
+
|
|
485
|
+
def __eq__(self, other):
|
|
486
|
+
if not isinstance(other, BoundingBox):
|
|
487
|
+
return False
|
|
488
|
+
return (
|
|
489
|
+
np.allclose(self.origin, other.origin)
|
|
490
|
+
and np.allclose(self.maximum, other.maximum)
|
|
491
|
+
and np.allclose(self.nsteps, other.nsteps)
|
|
492
|
+
)
|
|
@@ -25,11 +25,14 @@ class ValuePoints:
|
|
|
25
25
|
),
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
def vtk(self):
|
|
28
|
+
def vtk(self, scalars=None):
|
|
29
29
|
import pyvista as pv
|
|
30
30
|
|
|
31
31
|
points = pv.PolyData(self.locations)
|
|
32
|
-
|
|
32
|
+
if scalars is not None and len(scalars) == len(self.locations):
|
|
33
|
+
points.point_data['scalars'] = scalars
|
|
34
|
+
else:
|
|
35
|
+
points["values"] = self.values
|
|
33
36
|
return points
|
|
34
37
|
|
|
35
38
|
def plot(self, pyvista_kwargs={}):
|
|
@@ -123,9 +126,19 @@ class VectorPoints:
|
|
|
123
126
|
def from_dict(self, d):
|
|
124
127
|
return VectorPoints(d['locations'], d['vectors'], d['name'], d.get('properties', None))
|
|
125
128
|
|
|
126
|
-
def vtk(
|
|
129
|
+
def vtk(
|
|
130
|
+
self,
|
|
131
|
+
geom='arrow',
|
|
132
|
+
scale=0.10,
|
|
133
|
+
scale_function=None,
|
|
134
|
+
normalise=True,
|
|
135
|
+
tolerance=0.05,
|
|
136
|
+
bb=None,
|
|
137
|
+
scalars=None,
|
|
138
|
+
):
|
|
127
139
|
import pyvista as pv
|
|
128
140
|
|
|
141
|
+
_projected = False
|
|
129
142
|
vectors = np.copy(self.vectors)
|
|
130
143
|
if normalise:
|
|
131
144
|
norm = np.linalg.norm(vectors, axis=1)
|
|
@@ -133,15 +146,28 @@ class VectorPoints:
|
|
|
133
146
|
if scale_function is not None:
|
|
134
147
|
# vectors /= np.linalg.norm(vectors, axis=1)[:, None]
|
|
135
148
|
vectors *= scale_function(self.locations)[:, None]
|
|
136
|
-
|
|
149
|
+
locations = self.locations
|
|
150
|
+
if bb is not None:
|
|
151
|
+
try:
|
|
152
|
+
locations = bb.project(locations)
|
|
153
|
+
_projected = True
|
|
154
|
+
except Exception as e:
|
|
155
|
+
logger.error(f'Failed to project points to bounding box: {e}')
|
|
156
|
+
logger.error('Using unprojected points, this may cause issues with the glyphing')
|
|
157
|
+
points = pv.PolyData(locations)
|
|
158
|
+
if scalars is not None and len(scalars) == len(self.locations):
|
|
159
|
+
points['scalars'] = scalars
|
|
137
160
|
points.point_data.set_vectors(vectors, 'vectors')
|
|
138
161
|
if geom == 'arrow':
|
|
139
162
|
geom = pv.Arrow(scale=scale)
|
|
140
163
|
elif geom == 'disc':
|
|
141
|
-
geom = pv.Disc(inner=0, outer=scale)
|
|
164
|
+
geom = pv.Disc(inner=0, outer=scale).rotate_y(90)
|
|
142
165
|
|
|
143
166
|
# Perform the glyph
|
|
144
|
-
|
|
167
|
+
glyphed = points.glyph(orient="vectors", geom=geom, tolerance=tolerance, scale=False)
|
|
168
|
+
if _projected:
|
|
169
|
+
glyphed.points = bb.reproject(glyphed.points)
|
|
170
|
+
return glyphed
|
|
145
171
|
|
|
146
172
|
def plot(self, pyvista_kwargs={}):
|
|
147
173
|
"""Calls pyvista plot on the vtk object
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# from LoopStructural.utils.exceptions import LoopException
|
|
2
|
+
# import numpy as np
|
|
3
|
+
# from typing import Optional
|
|
4
|
+
# from LoopStructural.interpolators import (
|
|
5
|
+
# P1Interpolator,
|
|
6
|
+
# P2Interpolator,
|
|
7
|
+
# FiniteDifferenceInterpolator,
|
|
8
|
+
# GeologicalInterpolator,
|
|
9
|
+
# DiscreteFoldInterpolator,
|
|
10
|
+
# StructuredGrid,
|
|
11
|
+
# TetMesh,
|
|
12
|
+
# )
|
|
13
|
+
# from LoopStructural.datatypes import BoundingBox
|
|
14
|
+
# from LoopStructural.utils.logging import getLogger
|
|
15
|
+
|
|
16
|
+
# logger = getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# def get_interpolator(
|
|
20
|
+
# bounding_box: BoundingBox,
|
|
21
|
+
# interpolatortype: str,
|
|
22
|
+
# nelements: int,
|
|
23
|
+
# element_volume: Optional[float] = None,
|
|
24
|
+
# buffer: float = 0.2,
|
|
25
|
+
# dimensions: int = 3,
|
|
26
|
+
# support=None,
|
|
27
|
+
# ) -> GeologicalInterpolator:
|
|
28
|
+
# # add a buffer to the interpolation domain, this is necessary for
|
|
29
|
+
# # faults but also generally a good
|
|
30
|
+
# # idea to avoid boundary problems
|
|
31
|
+
# # buffer = bb[1, :]
|
|
32
|
+
# origin = bounding_box.with_buffer(buffer).origin
|
|
33
|
+
# maximum = bounding_box.with_buffer(buffer).maximum
|
|
34
|
+
# box_vol = np.prod(maximum - origin)
|
|
35
|
+
# if interpolatortype == "PLI":
|
|
36
|
+
# if support is None:
|
|
37
|
+
# if element_volume is None:
|
|
38
|
+
# # nelements /= 5
|
|
39
|
+
# element_volume = box_vol / nelements
|
|
40
|
+
# # calculate the step vector of a regular cube
|
|
41
|
+
# step_vector = np.zeros(3)
|
|
42
|
+
# step_vector[:] = element_volume ** (1.0 / 3.0)
|
|
43
|
+
# # step_vector /= np.array([1,1,2])
|
|
44
|
+
# # number of steps is the length of the box / step vector
|
|
45
|
+
# nsteps = np.ceil((maximum - origin) / step_vector).astype(int)
|
|
46
|
+
# if np.any(np.less(nsteps, 3)):
|
|
47
|
+
# axis_labels = ["x", "y", "z"]
|
|
48
|
+
# for i in range(3):
|
|
49
|
+
# if nsteps[i] < 3:
|
|
50
|
+
# nsteps[i] = 3
|
|
51
|
+
# logger.error(
|
|
52
|
+
# f"Number of steps in direction {axis_labels[i]} is too small, try increasing nelements"
|
|
53
|
+
# )
|
|
54
|
+
# logger.error("Cannot create interpolator: number of steps is too small")
|
|
55
|
+
# raise ValueError("Number of steps too small cannot create interpolator")
|
|
56
|
+
|
|
57
|
+
# support = TetMesh(origin=origin, nsteps=nsteps, step_vector=step_vector)
|
|
58
|
+
# logger.info(
|
|
59
|
+
# "Creating regular tetrahedron mesh with %i elements \n"
|
|
60
|
+
# "for modelling using PLI" % (support.ntetra)
|
|
61
|
+
# )
|
|
62
|
+
|
|
63
|
+
# return P1Interpolator(support)
|
|
64
|
+
# if interpolatortype == "P2":
|
|
65
|
+
# if support is not None:
|
|
66
|
+
# logger.info(
|
|
67
|
+
# "Creating regular tetrahedron mesh with %i elements \n"
|
|
68
|
+
# "for modelling using P2" % (support.ntetra)
|
|
69
|
+
# )
|
|
70
|
+
# return P2Interpolator(support)
|
|
71
|
+
# else:
|
|
72
|
+
# raise ValueError("Cannot create P2 interpolator without support, try using PLI")
|
|
73
|
+
|
|
74
|
+
# if interpolatortype == "FDI":
|
|
75
|
+
# # find the volume of one element
|
|
76
|
+
# if element_volume is None:
|
|
77
|
+
# element_volume = box_vol / nelements
|
|
78
|
+
# # calculate the step vector of a regular cube
|
|
79
|
+
# step_vector = np.zeros(3)
|
|
80
|
+
# step_vector[:] = element_volume ** (1.0 / 3.0)
|
|
81
|
+
# # number of steps is the length of the box / step vector
|
|
82
|
+
# nsteps = np.ceil((maximum - origin) / step_vector).astype(int)
|
|
83
|
+
# if np.any(np.less(nsteps, 3)):
|
|
84
|
+
# logger.error("Cannot create interpolator: number of steps is too small")
|
|
85
|
+
# axis_labels = ["x", "y", "z"]
|
|
86
|
+
# for i in range(3):
|
|
87
|
+
# if nsteps[i] < 3:
|
|
88
|
+
# nsteps[i] = 3
|
|
89
|
+
# # logger.error(
|
|
90
|
+
# # f"Number of steps in direction {axis_labels[i]} is too small, try increasing nelements"
|
|
91
|
+
# # )
|
|
92
|
+
# # raise ValueError("Number of steps too small cannot create interpolator")
|
|
93
|
+
# # create a structured grid using the origin and number of steps
|
|
94
|
+
|
|
95
|
+
# grid = StructuredGrid(origin=origin, nsteps=nsteps, step_vector=step_vector)
|
|
96
|
+
# logger.info(
|
|
97
|
+
# f"Creating regular grid with {grid.n_elements} elements \n" "for modelling using FDI"
|
|
98
|
+
# )
|
|
99
|
+
# return FiniteDifferenceInterpolator(grid)
|
|
100
|
+
# if interpolatortype == "DFI":
|
|
101
|
+
# if element_volume is None:
|
|
102
|
+
# nelements /= 5
|
|
103
|
+
# element_volume = box_vol / nelements
|
|
104
|
+
# # calculate the step vector of a regular cube
|
|
105
|
+
# step_vector = np.zeros(3)
|
|
106
|
+
# step_vector[:] = element_volume ** (1.0 / 3.0)
|
|
107
|
+
# # number of steps is the length of the box / step vector
|
|
108
|
+
# nsteps = np.ceil((maximum - origin) / step_vector).astype(int)
|
|
109
|
+
# # create a structured grid using the origin and number of steps
|
|
110
|
+
|
|
111
|
+
# mesh = TetMesh(origin=origin, nsteps=nsteps, step_vector=step_vector)
|
|
112
|
+
# logger.info(
|
|
113
|
+
# f"Creating regular tetrahedron mesh with {mesh.ntetra} elements \n"
|
|
114
|
+
# "for modelling using DFI"
|
|
115
|
+
# )
|
|
116
|
+
# return DiscreteFoldInterpolator(mesh, None)
|
|
117
|
+
# raise LoopException("No interpolator")
|
|
118
|
+
# # fi interpolatortype == "DFI" and dfi is True:
|
|
119
|
+
# # if element_volume is None:
|
|
120
|
+
# # nelements /= 5
|
|
121
|
+
# # element_volume = box_vol / nelements
|
|
122
|
+
# # # calculate the step vector of a regular cube
|
|
123
|
+
# # step_vector = np.zeros(3)
|
|
124
|
+
# # step_vector[:] = element_volume ** (1.0 / 3.0)
|
|
125
|
+
# # # number of steps is the length of the box / step vector
|
|
126
|
+
# # nsteps = np.ceil((bb[1, :] - bb[0, :]) / step_vector).astype(int)
|
|
127
|
+
# # # create a structured grid using the origin and number of steps
|
|
128
|
+
# # if "meshbuilder" in kwargs:
|
|
129
|
+
# # mesh = kwargs["meshbuilder"].build(bb, nelements)
|
|
130
|
+
# # else:
|
|
131
|
+
# # mesh = kwargs.get(
|
|
132
|
+
# # "mesh",
|
|
133
|
+
# # TetMesh(origin=bb[0, :], nsteps=nsteps, step_vector=step_vector),
|
|
134
|
+
# # )
|
|
135
|
+
# # logger.info(
|
|
136
|
+
# # f"Creating regular tetrahedron mesh with {mesh.ntetra} elements \n"
|
|
137
|
+
# # "for modelling using DFI"
|
|
138
|
+
# # )
|
|
139
|
+
# # return DFI(mesh, kwargs["fold"])
|
|
140
|
+
# # if interpolatortype == "Surfe" or interpolatortype == "surfe":
|
|
141
|
+
# # # move import of surfe to where we actually try and use it
|
|
142
|
+
# # if not surfe:
|
|
143
|
+
# # logger.warning("Cannot import Surfe, try another interpolator")
|
|
144
|
+
# # raise ImportError("Cannot import surfepy, try pip install surfe")
|
|
145
|
+
# # method = kwargs.get("method", "single_surface")
|
|
146
|
+
# # logger.info("Using surfe interpolator")
|
|
147
|
+
# # return SurfeRBFInterpolator(method)
|
|
148
|
+
# # logger.warning("No interpolator")
|
|
149
|
+
# # raise InterpolatorError("Could not create interpolator")
|
|
@@ -97,7 +97,7 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
|
|
|
97
97
|
self.add_interface_constraints(self.interpolation_weights["ipw"])
|
|
98
98
|
self.add_value_inequality_constraints()
|
|
99
99
|
self.add_inequality_pairs_constraints(
|
|
100
|
-
kwargs.get('inequality_pairs', None),
|
|
100
|
+
pairs=kwargs.get('inequality_pairs', None),
|
|
101
101
|
upper_bound=kwargs.get('inequality_pair_upper_bound', np.finfo(float).eps),
|
|
102
102
|
lower_bound=kwargs.get('inequality_pair_lower_bound', -np.inf),
|
|
103
103
|
)
|
|
@@ -172,16 +172,18 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
|
|
|
172
172
|
# get elements for points
|
|
173
173
|
points = self.get_interface_constraints()
|
|
174
174
|
if points.shape[0] > 1:
|
|
175
|
-
|
|
175
|
+
node_idx, inside = self.support.position_to_cell_corners(
|
|
176
176
|
points[:, : self.support.dimension]
|
|
177
177
|
)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
idc =
|
|
184
|
-
|
|
178
|
+
gi = np.zeros(self.support.n_nodes, dtype=int)
|
|
179
|
+
gi[:] = -1
|
|
180
|
+
gi[self.region] = np.arange(0, self.nx, dtype=int)
|
|
181
|
+
idc = np.zeros(node_idx.shape).astype(int)
|
|
182
|
+
idc[:] = -1
|
|
183
|
+
idc[inside, :] = gi[node_idx[inside, :]]
|
|
184
|
+
inside = np.logical_and(~np.any(idc == -1, axis=1), inside)
|
|
185
|
+
idc = idc[inside, :]
|
|
186
|
+
A = self.support.position_to_dof_coefs(points[inside, : self.support.dimension])
|
|
185
187
|
for unique_id in np.unique(
|
|
186
188
|
points[
|
|
187
189
|
np.logical_and(~np.isnan(points[:, self.support.dimension]), inside),
|
|
@@ -197,7 +199,6 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
|
|
|
197
199
|
).T.reshape(-1, 2)
|
|
198
200
|
interface_A = np.hstack([A[mask, :][ij[:, 0], :], -A[mask, :][ij[:, 1], :]])
|
|
199
201
|
interface_idc = np.hstack([idc[mask, :][ij[:, 0], :], idc[mask, :][ij[:, 1], :]])
|
|
200
|
-
|
|
201
202
|
# now map the index from global to region create array size of mesh
|
|
202
203
|
# initialise as np.nan, then map points inside region to 0->nx
|
|
203
204
|
gi = np.zeros(self.support.n_nodes).astype(int)
|
|
@@ -229,7 +230,6 @@ class FiniteDifferenceInterpolator(DiscreteInterpolator):
|
|
|
229
230
|
points = self.get_gradient_constraints()
|
|
230
231
|
if points.shape[0] > 0:
|
|
231
232
|
# calculate unit vector for orientation data
|
|
232
|
-
# points[:,3:]/=np.linalg.norm(points[:,3:],axis=1)[:,None]
|
|
233
233
|
|
|
234
234
|
node_idx, inside = self.support.position_to_cell_corners(
|
|
235
235
|
points[:, : self.support.dimension]
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from LoopStructural.interpolators import (
|
|
2
|
+
GeologicalInterpolator,
|
|
3
|
+
InterpolatorFactory,
|
|
4
|
+
InterpolatorType,
|
|
5
|
+
)
|
|
6
|
+
from LoopStructural.datatypes import BoundingBox
|
|
7
|
+
from typing import Optional, Union
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class InterpolatorBuilder:
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
interpolatortype: Union[str, InterpolatorType],
|
|
15
|
+
bounding_box: BoundingBox,
|
|
16
|
+
nelements: int = 1000,
|
|
17
|
+
buffer: float = 0.2,
|
|
18
|
+
**kwargs,
|
|
19
|
+
):
|
|
20
|
+
self.interpolatortype = interpolatortype
|
|
21
|
+
self.bounding_box = bounding_box
|
|
22
|
+
self.nelements = nelements
|
|
23
|
+
self.buffer = buffer
|
|
24
|
+
self.kwargs = kwargs
|
|
25
|
+
self.interpolator : Optional[GeologicalInterpolator]= None
|
|
26
|
+
|
|
27
|
+
def create_interpolator(self) -> 'InterpolatorBuilder':
|
|
28
|
+
self.interpolator = InterpolatorFactory.create_interpolator(
|
|
29
|
+
interpolatortype=self.interpolatortype,
|
|
30
|
+
boundingbox=self.bounding_box,
|
|
31
|
+
nelements=self.nelements,
|
|
32
|
+
buffer=self.buffer,
|
|
33
|
+
**self.kwargs,
|
|
34
|
+
)
|
|
35
|
+
return self
|
|
36
|
+
|
|
37
|
+
def set_value_constraints(self, value_constraints: np.ndarray) -> 'InterpolatorBuilder':
|
|
38
|
+
if self.interpolator:
|
|
39
|
+
self.interpolator.set_value_constraints(value_constraints)
|
|
40
|
+
return self
|
|
41
|
+
|
|
42
|
+
def set_gradient_constraints(self, gradient_constraints: np.ndarray) -> 'InterpolatorBuilder':
|
|
43
|
+
if self.interpolator:
|
|
44
|
+
self.interpolator.set_gradient_constraints(gradient_constraints)
|
|
45
|
+
return self
|
|
46
|
+
|
|
47
|
+
def set_normal_constraints(self, normal_constraints: np.ndarray) -> 'InterpolatorBuilder':
|
|
48
|
+
if self.interpolator:
|
|
49
|
+
self.interpolator.set_normal_constraints(normal_constraints)
|
|
50
|
+
return self
|
|
51
|
+
|
|
52
|
+
def setup_interpolator(self, **kwargs) -> Optional[GeologicalInterpolator]:
|
|
53
|
+
if self.interpolator:
|
|
54
|
+
self.interpolator.setup(**kwargs)
|
|
55
|
+
return self.interpolator
|
{loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/interpolators/_interpolator_factory.py
RENAMED
|
@@ -65,25 +65,14 @@ class InterpolatorFactory:
|
|
|
65
65
|
gradient_norm_constraints: Optional[np.ndarray] = None,
|
|
66
66
|
gradient_constraints: Optional[np.ndarray] = None,
|
|
67
67
|
):
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
raise ValueError("No bounding box specified")
|
|
72
|
-
if nelements is None:
|
|
73
|
-
raise ValueError("No number of elements specified")
|
|
74
|
-
if isinstance(interpolatortype, str):
|
|
75
|
-
interpolatortype = InterpolatorType._member_map_[interpolatortype].numerator
|
|
76
|
-
if support is None:
|
|
77
|
-
raise Exception("Support must be specified")
|
|
78
|
-
# supporttype = support_interpolator_map[interpolatortype]
|
|
79
|
-
# support = SupportFactory.create_support(
|
|
80
|
-
# supporttype, boundingbox, nelements, element_volume
|
|
81
|
-
# )
|
|
82
|
-
interpolator = interpolator_map[interpolatortype](support)
|
|
68
|
+
interpolator = InterpolatorFactory.create_interpolator(
|
|
69
|
+
interpolatortype, boundingbox, nelements, element_volume, support
|
|
70
|
+
)
|
|
83
71
|
if value_constraints is not None:
|
|
84
|
-
interpolator.
|
|
72
|
+
interpolator.set_value_constraints(value_constraints)
|
|
85
73
|
if gradient_norm_constraints is not None:
|
|
86
|
-
interpolator.
|
|
74
|
+
interpolator.set_normal_constraints(gradient_norm_constraints)
|
|
87
75
|
if gradient_constraints is not None:
|
|
88
|
-
interpolator.
|
|
76
|
+
interpolator.set_gradient_constraints(gradient_constraints)
|
|
77
|
+
interpolator.setup()
|
|
89
78
|
return interpolator
|
|
@@ -41,6 +41,10 @@ class BaseStructuredSupport(BaseSupport):
|
|
|
41
41
|
raise LoopException("nsteps cannot be zero")
|
|
42
42
|
if np.any(nsteps < 0):
|
|
43
43
|
raise LoopException("nsteps cannot be negative")
|
|
44
|
+
if np.any(nsteps < 3):
|
|
45
|
+
raise LoopException(
|
|
46
|
+
"step vector cannot be less than 3. Try increasing the resolution of the interpolator"
|
|
47
|
+
)
|
|
44
48
|
self._nsteps = np.array(nsteps, dtype=int) + 1
|
|
45
49
|
self._step_vector = np.array(step_vector)
|
|
46
50
|
self._origin = np.array(origin)
|
{loopstructural-1.6.5 → loopstructural-1.6.6}/LoopStructural/modelling/core/geological_model.py
RENAMED
|
@@ -1182,7 +1182,7 @@ class GeologicalModel:
|
|
|
1182
1182
|
logger.debug(f"Reached unconformity {f.name}")
|
|
1183
1183
|
break
|
|
1184
1184
|
logger.debug(f"Adding {uc_feature.name} as unconformity to {f.name}")
|
|
1185
|
-
if f.type == FeatureType.FAULT:
|
|
1185
|
+
if f.type == FeatureType.FAULT or f.type == FeatureType.INACTIVEFAULT:
|
|
1186
1186
|
continue
|
|
1187
1187
|
if f == feature:
|
|
1188
1188
|
continue
|
|
@@ -1417,7 +1417,7 @@ class GeologicalModel:
|
|
|
1417
1417
|
return fault
|
|
1418
1418
|
|
|
1419
1419
|
# TODO move rescale to bounding box/transformer
|
|
1420
|
-
def rescale(self, points: np.ndarray, inplace: bool =
|
|
1420
|
+
def rescale(self, points: np.ndarray, inplace: bool = False) -> np.ndarray:
|
|
1421
1421
|
"""
|
|
1422
1422
|
Convert from model scale to real world scale - in the future this
|
|
1423
1423
|
should also do transformations?
|
|
@@ -1440,7 +1440,7 @@ class GeologicalModel:
|
|
|
1440
1440
|
return points
|
|
1441
1441
|
|
|
1442
1442
|
# TODO move scale to bounding box/transformer
|
|
1443
|
-
def scale(self, points: np.ndarray, inplace: bool =
|
|
1443
|
+
def scale(self, points: np.ndarray, inplace: bool = False) -> np.ndarray:
|
|
1444
1444
|
"""Take points in UTM coordinates and reproject
|
|
1445
1445
|
into scaled model space
|
|
1446
1446
|
|
|
@@ -1824,6 +1824,7 @@ class GeologicalModel:
|
|
|
1824
1824
|
):
|
|
1825
1825
|
path = pathlib.Path(filename)
|
|
1826
1826
|
extension = path.suffix
|
|
1827
|
+
parent = path.parent
|
|
1827
1828
|
name = path.stem
|
|
1828
1829
|
stratigraphic_surfaces = self.get_stratigraphic_surfaces()
|
|
1829
1830
|
if fault_surfaces:
|
|
@@ -1832,19 +1833,19 @@ class GeologicalModel:
|
|
|
1832
1833
|
if extension == ".geoh5" or extension == '.omf':
|
|
1833
1834
|
s.save(filename)
|
|
1834
1835
|
else:
|
|
1835
|
-
s.save(f'{name}_{s.name}
|
|
1836
|
+
s.save(f'{parent}/{name}_{s.name}{extension}')
|
|
1836
1837
|
if stratigraphic_surfaces:
|
|
1837
1838
|
for s in self.get_stratigraphic_surfaces():
|
|
1838
1839
|
if extension == ".geoh5" or extension == '.omf':
|
|
1839
1840
|
s.save(filename)
|
|
1840
1841
|
else:
|
|
1841
|
-
s.save(f'{name}_{s.name}
|
|
1842
|
+
s.save(f'{parent}/{name}_{s.name}{extension}')
|
|
1842
1843
|
if block_model:
|
|
1843
1844
|
grid, ids = self.get_block_model()
|
|
1844
1845
|
if extension == ".geoh5" or extension == '.omf':
|
|
1845
1846
|
grid.save(filename)
|
|
1846
1847
|
else:
|
|
1847
|
-
grid.save(f'{name}_block_model
|
|
1848
|
+
grid.save(f'{parent}/{name}_block_model{extension}')
|
|
1848
1849
|
if stratigraphic_data:
|
|
1849
1850
|
if self.stratigraphic_column is not None:
|
|
1850
1851
|
for group in self.stratigraphic_column.keys():
|
|
@@ -1854,7 +1855,7 @@ class GeologicalModel:
|
|
|
1854
1855
|
if extension == ".geoh5" or extension == '.omf':
|
|
1855
1856
|
data.save(filename)
|
|
1856
1857
|
else:
|
|
1857
|
-
data.save(f'{name}_{group}_data
|
|
1858
|
+
data.save(f'{parent}/{name}_{group}_data{extension}')
|
|
1858
1859
|
if fault_data:
|
|
1859
1860
|
for f in self.fault_names():
|
|
1860
1861
|
for d in self.__getitem__(f).get_data():
|
|
@@ -1862,4 +1863,4 @@ class GeologicalModel:
|
|
|
1862
1863
|
|
|
1863
1864
|
d.save(filename)
|
|
1864
1865
|
else:
|
|
1865
|
-
d.save(f'{name}_{group}
|
|
1866
|
+
d.save(f'{parent}/{name}_{group}{extension}')
|
|
@@ -39,8 +39,16 @@ class AnalyticalGeologicalFeature(BaseFeature):
|
|
|
39
39
|
builder=None,
|
|
40
40
|
):
|
|
41
41
|
BaseFeature.__init__(self, name, model, faults, regions, builder)
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
try:
|
|
43
|
+
self.vector = np.array(vector, dtype=float).reshape(3)
|
|
44
|
+
except ValueError:
|
|
45
|
+
logger.error("AnalyticalGeologicalFeature: vector must be a 3 element array")
|
|
46
|
+
raise ValueError("vector must be a 3 element array")
|
|
47
|
+
try:
|
|
48
|
+
self.origin = np.array(origin, dtype=float).reshape(3)
|
|
49
|
+
except ValueError:
|
|
50
|
+
logger.error("AnalyticalGeologicalFeature: origin must be a 3 element array")
|
|
51
|
+
raise ValueError("origin must be a 3 element array")
|
|
44
52
|
self.type = FeatureType.ANALYTICAL
|
|
45
53
|
|
|
46
54
|
def to_json(self):
|
|
@@ -86,3 +94,16 @@ class AnalyticalGeologicalFeature(BaseFeature):
|
|
|
86
94
|
|
|
87
95
|
def get_data(self, value_map: Optional[dict] = None):
|
|
88
96
|
return
|
|
97
|
+
|
|
98
|
+
def copy(self, name: Optional[str] = None):
|
|
99
|
+
if name is None:
|
|
100
|
+
name = self.name
|
|
101
|
+
return AnalyticalGeologicalFeature(
|
|
102
|
+
name,
|
|
103
|
+
self.vector.copy(),
|
|
104
|
+
self.origin.copy(),
|
|
105
|
+
list(self.regions),
|
|
106
|
+
list(self.faults),
|
|
107
|
+
self.model,
|
|
108
|
+
self.builder,
|
|
109
|
+
)
|
|
@@ -296,7 +296,12 @@ class BaseFeature(metaclass=ABCMeta):
|
|
|
296
296
|
self.regions = [
|
|
297
297
|
r for r in self.regions if r.name != self.name and r.parent.name != self.name
|
|
298
298
|
]
|
|
299
|
-
|
|
299
|
+
|
|
300
|
+
callable = lambda xyz: (
|
|
301
|
+
self.evaluate_value(self.model.scale(xyz))
|
|
302
|
+
if self.model is not None
|
|
303
|
+
else self.evaluate_value(xyz)
|
|
304
|
+
)
|
|
300
305
|
isosurfacer = LoopIsosurfacer(bounding_box, callable=callable)
|
|
301
306
|
if name is None and self.name is not None:
|
|
302
307
|
name = self.name
|
|
@@ -375,3 +380,14 @@ class BaseFeature(metaclass=ABCMeta):
|
|
|
375
380
|
dictionary of data
|
|
376
381
|
"""
|
|
377
382
|
raise NotImplementedError
|
|
383
|
+
|
|
384
|
+
@abstractmethod
|
|
385
|
+
def copy(self, name: Optional[str] = None):
|
|
386
|
+
"""Copy the feature
|
|
387
|
+
|
|
388
|
+
Returns
|
|
389
|
+
-------
|
|
390
|
+
BaseFeature
|
|
391
|
+
copied feature
|
|
392
|
+
"""
|
|
393
|
+
raise NotImplementedError
|
|
@@ -98,3 +98,10 @@ class CrossProductGeologicalFeature(BaseFeature):
|
|
|
98
98
|
|
|
99
99
|
def get_data(self, value_map: Optional[dict] = None):
|
|
100
100
|
return
|
|
101
|
+
|
|
102
|
+
def copy(self, name: Optional[str] = None):
|
|
103
|
+
if name is None:
|
|
104
|
+
name = f'{self.name}_copy'
|
|
105
|
+
return CrossProductGeologicalFeature(
|
|
106
|
+
name, self.geological_feature_a, self.geological_feature_b
|
|
107
|
+
)
|
|
@@ -113,7 +113,9 @@ class GeologicalFeature(BaseFeature):
|
|
|
113
113
|
# if evaluation_points is not a numpy array try and convert
|
|
114
114
|
# otherwise error
|
|
115
115
|
evaluation_points = np.asarray(pos)
|
|
116
|
-
|
|
116
|
+
# if there is a builder lets make sure that the feature is up to date
|
|
117
|
+
if self.builder is not None:
|
|
118
|
+
self.builder.up_to_date()
|
|
117
119
|
# check if the points are within the display region
|
|
118
120
|
v = np.zeros(evaluation_points.shape[0])
|
|
119
121
|
v[:] = np.nan
|