LoopStructural 1.6.13__tar.gz → 1.6.15__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.13 → loopstructural-1.6.15}/LoopStructural/datatypes/_bounding_box.py +23 -13
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datatypes/_point.py +0 -1
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/export/exporters.py +2 -2
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/__init__.py +43 -32
- loopstructural-1.6.15/LoopStructural/interpolators/_constant_norm.py +205 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/_discrete_interpolator.py +15 -14
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/_finite_difference_interpolator.py +27 -21
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/_geological_interpolator.py +1 -1
- loopstructural-1.6.15/LoopStructural/interpolators/_interpolatortype.py +22 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/_p1interpolator.py +7 -3
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/_surfe_wrapper.py +4 -1
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/_2d_base_unstructured.py +1 -1
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/_2d_structured_grid.py +16 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/_3d_base_structured.py +16 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/_3d_structured_grid.py +3 -2
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/_3d_structured_tetra.py +7 -3
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/__init__.py +11 -3
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/core/geological_model.py +187 -234
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/_base_geological_feature.py +38 -2
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/builders/_geological_feature_builder.py +2 -2
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/fault/_fault_function.py +1 -1
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/intrusions/intrusion_builder.py +1 -1
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/intrusions/intrusion_frame_builder.py +1 -1
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/__init__.py +1 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/helper.py +1 -24
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/maths.py +74 -17
- loopstructural-1.6.15/LoopStructural/version.py +1 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural.egg-info/PKG-INFO +2 -2
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural.egg-info/SOURCES.txt +2 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural.egg-info/requires.txt +1 -1
- {loopstructural-1.6.13 → loopstructural-1.6.15}/PKG-INFO +2 -2
- {loopstructural-1.6.13 → loopstructural-1.6.15}/pyproject.toml +1 -1
- loopstructural-1.6.13/LoopStructural/version.py +0 -1
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LICENSE +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/__init__.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/__init__.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/_base.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/_example_models.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/claudius.csv +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/claudiusbb.txt +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/duplex.csv +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/duplexbb.txt +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/fault_trace/fault_trace.cpg +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/fault_trace/fault_trace.dbf +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/fault_trace/fault_trace.prj +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/fault_trace/fault_trace.shp +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/fault_trace/fault_trace.shx +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/geological_map_data/bbox.csv +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/geological_map_data/contacts.csv +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/geological_map_data/fault_displacement.csv +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/geological_map_data/fault_edges.txt +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/geological_map_data/fault_locations.csv +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/geological_map_data/fault_orientations.csv +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/geological_map_data/stratigraphic_order.csv +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/geological_map_data/stratigraphic_orientations.csv +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/geological_map_data/stratigraphic_thickness.csv +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/intrusion.csv +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/intrusionbb.txt +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/onefoldbb.txt +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/onefolddata.csv +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/refolded_bb.txt +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/refolded_fold.csv +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datasets/data/tabular_intrusion.csv +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datatypes/__init__.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datatypes/_structured_grid.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/datatypes/_surface.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/export/file_formats.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/export/geoh5.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/export/gocad.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/export/omf_wrapper.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/_api.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/_builders.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/_cython/__init__.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/_discrete_fold_interpolator.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/_interpolator_builder.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/_interpolator_factory.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/_operator.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/_p2interpolator.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/_2d_p1_unstructured.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/_2d_p2_unstructured.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/_2d_structured_tetra.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/_3d_p2_tetra.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/_3d_unstructured_tetra.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/__init__.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/_aabb.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/_base_support.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/_face_table.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/interpolators/supports/_support_factory.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/core/__init__.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/__init__.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/_analytical_feature.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/_cross_product_geological_feature.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/_geological_feature.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/_lambda_geological_feature.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/_projected_vector_feature.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/_region.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/_structural_frame.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/_unconformity_feature.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/builders/__init__.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/builders/_base_builder.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/builders/_fault_builder.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/builders/_folded_feature_builder.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/builders/_structural_frame_builder.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/fault/__init__.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/fault/_fault_function_feature.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/fault/_fault_segment.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/fold/__init__.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/fold/_fold.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/fold/_fold_rotation_angle_feature.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/fold/_foldframe.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/fold/_svariogram.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/fold/fold_function/__init__.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/fold/fold_function/_base_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/fold/fold_function/_fourier_series_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/fold/fold_function/_lambda_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/features/fold/fold_function/_trigo_fold_rotation_angle.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/input/__init__.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/input/fault_network.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/input/map2loop_processor.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/input/process_data.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/input/project_file.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/intrusions/__init__.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/intrusions/geom_conceptual_models.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/intrusions/geometric_scaling_functions.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/intrusions/intrusion_feature.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/modelling/intrusions/intrusion_support_functions.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/_surface.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/_transformation.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/colours.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/config.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/dtm_creator.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/exceptions.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/features.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/json_encoder.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/linalg.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/logging.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/regions.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/typing.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/utils/utils.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural/visualisation/__init__.py +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural.egg-info/dependency_links.txt +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/LoopStructural.egg-info/top_level.txt +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/README.md +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/setup.cfg +0 -0
- {loopstructural-1.6.13 → loopstructural-1.6.15}/setup.py +0 -0
|
@@ -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)
|
|
@@ -281,6 +285,7 @@ class BoundingBox:
|
|
|
281
285
|
origin=origin,
|
|
282
286
|
maximum=maximum,
|
|
283
287
|
global_origin=self.global_origin,
|
|
288
|
+
nsteps=self.nsteps,
|
|
284
289
|
dimensions=self.dimensions,
|
|
285
290
|
)
|
|
286
291
|
|
|
@@ -499,48 +504,53 @@ class BoundingBox:
|
|
|
499
504
|
name=name,
|
|
500
505
|
)
|
|
501
506
|
|
|
502
|
-
def project(self, xyz):
|
|
507
|
+
def project(self, xyz, inplace=False):
|
|
503
508
|
"""Project a point into the bounding box
|
|
504
509
|
|
|
505
510
|
Parameters
|
|
506
511
|
----------
|
|
507
512
|
xyz : np.ndarray
|
|
508
513
|
point to project
|
|
514
|
+
inplace : bool, optional
|
|
515
|
+
Whether to modify the input array in place, by default False
|
|
509
516
|
|
|
510
517
|
Returns
|
|
511
518
|
-------
|
|
512
519
|
np.ndarray
|
|
513
520
|
projected point
|
|
514
521
|
"""
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
) # 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)
|
|
519
526
|
|
|
520
527
|
def scale_by_projection_factor(self, value):
|
|
521
528
|
return value / np.max((self.global_maximum - self.global_origin))
|
|
522
529
|
|
|
523
|
-
def reproject(self, xyz):
|
|
530
|
+
def reproject(self, xyz, inplace=False):
|
|
524
531
|
"""Reproject a point from the bounding box to the global space
|
|
525
532
|
|
|
526
533
|
Parameters
|
|
527
534
|
----------
|
|
528
535
|
xyz : np.ndarray
|
|
529
536
|
point to reproject
|
|
530
|
-
|
|
537
|
+
inplace : bool, optional
|
|
538
|
+
Whether to modify the input array in place, by default False
|
|
531
539
|
Returns
|
|
532
540
|
-------
|
|
533
541
|
np.ndarray
|
|
534
542
|
reprojected point
|
|
535
543
|
"""
|
|
536
|
-
|
|
537
|
-
|
|
544
|
+
if inplace:
|
|
545
|
+
xyz += self.global_origin
|
|
546
|
+
return xyz
|
|
547
|
+
return xyz + self.global_origin
|
|
538
548
|
|
|
539
549
|
def __repr__(self):
|
|
540
|
-
return f"BoundingBox({self.origin}, {self.maximum}, {self.nsteps})"
|
|
550
|
+
return f"BoundingBox(origin:{self.origin}, maximum:{self.maximum}, nsteps:{self.nsteps})"
|
|
541
551
|
|
|
542
552
|
def __str__(self):
|
|
543
|
-
return f"BoundingBox({self.origin}, {self.maximum}, {self.nsteps})"
|
|
553
|
+
return f"BoundingBox(origin:{self.origin}, maximum:{self.maximum}, nsteps:{self.nsteps})"
|
|
544
554
|
|
|
545
555
|
def __eq__(self, other):
|
|
546
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,12 +53,38 @@ 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:
|
|
86
|
-
|
|
87
|
-
|
|
60
|
+
class SurfeRBFInterpolator(GeologicalInterpolator):
|
|
61
|
+
"""
|
|
62
|
+
Dummy class to handle the case where Surfe is not installed.
|
|
63
|
+
This will raise a warning when used.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def __init__(self, *args, **kwargs):
|
|
67
|
+
raise ImportError(
|
|
68
|
+
"Surfe cannot be imported. Please install Surfe. pip install surfe/ conda install -c loop3d surfe"
|
|
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
|
|
88
88
|
interpolator_map = {
|
|
89
89
|
InterpolatorType.BASE: GeologicalInterpolator,
|
|
90
90
|
InterpolatorType.BASE_DISCRETE: DiscreteInterpolator,
|
|
@@ -94,6 +94,8 @@ interpolator_map = {
|
|
|
94
94
|
InterpolatorType.PIECEWISE_QUADRATIC: P2Interpolator,
|
|
95
95
|
InterpolatorType.BASE_DATA_SUPPORTED: GeologicalInterpolator,
|
|
96
96
|
InterpolatorType.SURFE: SurfeRBFInterpolator,
|
|
97
|
+
InterpolatorType.PIECEWISE_LINEAR_CONSTANT_NORM: ConstantNormP1Interpolator,
|
|
98
|
+
InterpolatorType.FINITE_DIFFERENCE_CONSTANT_NORM: ConstantNormFDIInterpolator,
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
support_interpolator_map = {
|
|
@@ -111,9 +113,18 @@ support_interpolator_map = {
|
|
|
111
113
|
3: SupportType.DataSupported,
|
|
112
114
|
2: SupportType.DataSupported,
|
|
113
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
|
+
}
|
|
114
124
|
}
|
|
115
125
|
|
|
116
126
|
from ._interpolator_factory import InterpolatorFactory
|
|
117
127
|
from ._interpolator_builder import InterpolatorBuilder
|
|
118
128
|
|
|
119
|
-
|
|
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
|