LoopStructural 1.6.18__tar.gz → 1.6.20__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.

Files changed (149) hide show
  1. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/__init__.py +11 -0
  2. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_p1interpolator.py +3 -2
  3. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_p2interpolator.py +2 -1
  4. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/core/geological_model.py +96 -61
  5. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/core/stratigraphic_column.py +30 -4
  6. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/_base_geological_feature.py +2 -1
  7. loopstructural-1.6.20/LoopStructural/modelling/features/_feature_converters.py +36 -0
  8. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/_geological_feature.py +1 -1
  9. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/_structural_frame.py +2 -6
  10. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/builders/_folded_feature_builder.py +22 -4
  11. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/builders/_geological_feature_builder.py +3 -0
  12. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/builders/_structural_frame_builder.py +33 -0
  13. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/input/process_data.py +2 -0
  14. loopstructural-1.6.20/LoopStructural/version.py +1 -0
  15. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural.egg-info/PKG-INFO +1 -1
  16. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural.egg-info/SOURCES.txt +1 -0
  17. {loopstructural-1.6.18 → loopstructural-1.6.20}/PKG-INFO +1 -1
  18. loopstructural-1.6.18/LoopStructural/version.py +0 -1
  19. {loopstructural-1.6.18 → loopstructural-1.6.20}/LICENSE +0 -0
  20. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/__init__.py +0 -0
  21. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/_base.py +0 -0
  22. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/_example_models.py +0 -0
  23. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/claudius.csv +0 -0
  24. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/claudiusbb.txt +0 -0
  25. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/duplex.csv +0 -0
  26. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/duplexbb.txt +0 -0
  27. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/fault_trace/fault_trace.cpg +0 -0
  28. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/fault_trace/fault_trace.dbf +0 -0
  29. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/fault_trace/fault_trace.prj +0 -0
  30. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/fault_trace/fault_trace.shp +0 -0
  31. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/fault_trace/fault_trace.shx +0 -0
  32. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/geological_map_data/bbox.csv +0 -0
  33. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/geological_map_data/contacts.csv +0 -0
  34. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/geological_map_data/fault_displacement.csv +0 -0
  35. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/geological_map_data/fault_edges.txt +0 -0
  36. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/geological_map_data/fault_locations.csv +0 -0
  37. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/geological_map_data/fault_orientations.csv +0 -0
  38. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/geological_map_data/stratigraphic_order.csv +0 -0
  39. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/geological_map_data/stratigraphic_orientations.csv +0 -0
  40. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/geological_map_data/stratigraphic_thickness.csv +0 -0
  41. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/intrusion.csv +0 -0
  42. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/intrusionbb.txt +0 -0
  43. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/onefoldbb.txt +0 -0
  44. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/onefolddata.csv +0 -0
  45. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/refolded_bb.txt +0 -0
  46. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/refolded_fold.csv +0 -0
  47. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datasets/data/tabular_intrusion.csv +0 -0
  48. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datatypes/__init__.py +0 -0
  49. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datatypes/_bounding_box.py +0 -0
  50. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datatypes/_point.py +0 -0
  51. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datatypes/_structured_grid.py +0 -0
  52. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/datatypes/_surface.py +0 -0
  53. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/export/exporters.py +0 -0
  54. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/export/file_formats.py +0 -0
  55. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/export/geoh5.py +0 -0
  56. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/export/gocad.py +0 -0
  57. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/export/omf_wrapper.py +0 -0
  58. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/__init__.py +0 -0
  59. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_api.py +0 -0
  60. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_builders.py +0 -0
  61. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_constant_norm.py +0 -0
  62. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_cython/__init__.py +0 -0
  63. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_discrete_fold_interpolator.py +0 -0
  64. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_discrete_interpolator.py +0 -0
  65. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_finite_difference_interpolator.py +0 -0
  66. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_geological_interpolator.py +0 -0
  67. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_interpolator_builder.py +0 -0
  68. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_interpolator_factory.py +0 -0
  69. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_interpolatortype.py +0 -0
  70. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_operator.py +0 -0
  71. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/_surfe_wrapper.py +0 -0
  72. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/_2d_base_unstructured.py +0 -0
  73. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/_2d_p1_unstructured.py +0 -0
  74. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/_2d_p2_unstructured.py +0 -0
  75. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/_2d_structured_grid.py +0 -0
  76. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/_2d_structured_tetra.py +0 -0
  77. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/_3d_base_structured.py +0 -0
  78. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/_3d_p2_tetra.py +0 -0
  79. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/_3d_structured_grid.py +0 -0
  80. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/_3d_structured_tetra.py +0 -0
  81. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/_3d_unstructured_tetra.py +0 -0
  82. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/__init__.py +0 -0
  83. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/_aabb.py +0 -0
  84. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/_base_support.py +0 -0
  85. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/_face_table.py +0 -0
  86. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/interpolators/supports/_support_factory.py +0 -0
  87. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/__init__.py +0 -0
  88. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/core/__init__.py +0 -0
  89. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/core/fault_topology.py +0 -0
  90. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/__init__.py +0 -0
  91. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/_analytical_feature.py +0 -0
  92. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/_cross_product_geological_feature.py +0 -0
  93. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/_lambda_geological_feature.py +0 -0
  94. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/_projected_vector_feature.py +0 -0
  95. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/_region.py +0 -0
  96. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/_unconformity_feature.py +0 -0
  97. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/builders/__init__.py +0 -0
  98. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/builders/_base_builder.py +0 -0
  99. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/builders/_fault_builder.py +0 -0
  100. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/fault/__init__.py +0 -0
  101. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/fault/_fault_function.py +0 -0
  102. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/fault/_fault_function_feature.py +0 -0
  103. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/fault/_fault_segment.py +0 -0
  104. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/fold/__init__.py +1 -1
  105. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/fold/_fold.py +0 -0
  106. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/fold/_fold_rotation_angle_feature.py +0 -0
  107. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/fold/_foldframe.py +0 -0
  108. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/fold/_svariogram.py +0 -0
  109. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/fold/fold_function/__init__.py +0 -0
  110. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/fold/fold_function/_base_fold_rotation_angle.py +0 -0
  111. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/fold/fold_function/_fourier_series_fold_rotation_angle.py +0 -0
  112. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/fold/fold_function/_lambda_fold_rotation_angle.py +0 -0
  113. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/features/fold/fold_function/_trigo_fold_rotation_angle.py +0 -0
  114. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/input/__init__.py +0 -0
  115. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/input/fault_network.py +0 -0
  116. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/input/map2loop_processor.py +0 -0
  117. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/input/project_file.py +0 -0
  118. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/intrusions/__init__.py +0 -0
  119. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/intrusions/geom_conceptual_models.py +0 -0
  120. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/intrusions/geometric_scaling_functions.py +0 -0
  121. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/intrusions/intrusion_builder.py +0 -0
  122. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/intrusions/intrusion_feature.py +0 -0
  123. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/intrusions/intrusion_frame_builder.py +0 -0
  124. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/modelling/intrusions/intrusion_support_functions.py +0 -0
  125. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/__init__.py +0 -0
  126. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/_surface.py +0 -0
  127. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/_transformation.py +0 -0
  128. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/colours.py +0 -0
  129. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/config.py +0 -0
  130. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/dtm_creator.py +0 -0
  131. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/exceptions.py +0 -0
  132. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/features.py +0 -0
  133. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/helper.py +0 -0
  134. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/json_encoder.py +0 -0
  135. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/linalg.py +0 -0
  136. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/logging.py +0 -0
  137. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/maths.py +0 -0
  138. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/observer.py +0 -0
  139. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/regions.py +0 -0
  140. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/typing.py +0 -0
  141. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/utils/utils.py +0 -0
  142. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural/visualisation/__init__.py +0 -0
  143. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural.egg-info/dependency_links.txt +0 -0
  144. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural.egg-info/requires.txt +0 -0
  145. {loopstructural-1.6.18 → loopstructural-1.6.20}/LoopStructural.egg-info/top_level.txt +0 -0
  146. {loopstructural-1.6.18 → loopstructural-1.6.20}/README.md +0 -0
  147. {loopstructural-1.6.18 → loopstructural-1.6.20}/pyproject.toml +0 -0
  148. {loopstructural-1.6.18 → loopstructural-1.6.20}/setup.cfg +0 -0
  149. {loopstructural-1.6.18 → loopstructural-1.6.20}/setup.py +0 -0
@@ -7,6 +7,9 @@ LoopStructural
7
7
  import logging
8
8
  from logging.config import dictConfig
9
9
 
10
+ from dataclasses import dataclass
11
+
12
+
10
13
  __all__ = ["GeologicalModel"]
11
14
  import tempfile
12
15
  from pathlib import Path
@@ -18,6 +21,14 @@ formatter = logging.Formatter("%(levelname)s: %(asctime)s: %(filename)s:%(lineno
18
21
  ch.setFormatter(formatter)
19
22
  ch.setLevel(logging.WARNING)
20
23
  loggers = {}
24
+ @dataclass
25
+ class LoopStructuralConfig:
26
+ """
27
+ Configuration for LoopStructural
28
+ """
29
+
30
+ nelements: int = 10_000
31
+
21
32
  from .modelling.core.geological_model import GeologicalModel
22
33
  from .modelling.core.stratigraphic_column import StratigraphicColumn
23
34
  from .modelling.core.fault_topology import FaultTopology
@@ -6,8 +6,9 @@ import logging
6
6
 
7
7
  import numpy as np
8
8
 
9
- from ._discrete_interpolator import DiscreteInterpolator
10
9
 
10
+ from ._discrete_interpolator import DiscreteInterpolator
11
+ from . import InterpolatorType
11
12
  logger = logging.getLogger(__name__)
12
13
 
13
14
 
@@ -37,7 +38,7 @@ class P1Interpolator(DiscreteInterpolator):
37
38
  "tpw": 1.0,
38
39
  "ipw": 1.0,
39
40
  }
40
-
41
+ self.type = InterpolatorType.PIECEWISE_LINEAR
41
42
  def add_gradient_constraints(self, w=1.0):
42
43
  pass
43
44
 
@@ -8,6 +8,7 @@ from typing import Optional, Callable
8
8
  import numpy as np
9
9
 
10
10
  from ..interpolators import DiscreteInterpolator
11
+ from . import InterpolatorType
11
12
 
12
13
  logger = logging.getLogger(__name__)
13
14
 
@@ -41,7 +42,7 @@ class P2Interpolator(DiscreteInterpolator):
41
42
  "tpw": 1.0,
42
43
  "ipw": 1.0,
43
44
  }
44
-
45
+ self.type = InterpolatorType.PIECEWISE_QUADRATIC
45
46
  def setup_interpolator(self, **kwargs):
46
47
  """
47
48
  Searches through kwargs for any interpolation weights and updates
@@ -2,6 +2,7 @@
2
2
  Main entry point for creating a geological model
3
3
  """
4
4
 
5
+ from LoopStructural import LoopStructuralConfig
5
6
  from ...utils import getLogger
6
7
 
7
8
  import numpy as np
@@ -20,6 +21,7 @@ from ...modelling.features import (
20
21
  UnconformityFeature,
21
22
  StructuralFrame,
22
23
  GeologicalFeature,
24
+ BaseFeature,
23
25
  FeatureType,
24
26
  )
25
27
  from ...modelling.features.fold import (
@@ -330,7 +332,21 @@ class GeologicalModel:
330
332
  name of the feature to return
331
333
  """
332
334
  return self.get_feature_by_name(feature_name)
335
+ def __setitem__(self, feature_name, feature):
336
+ """Set a feature in the model using feature_name_index
333
337
 
338
+ Parameters
339
+ ----------
340
+ feature_name : string
341
+ name of the feature to set
342
+ feature : GeologicalFeature
343
+ the geological feature to set
344
+ """
345
+ if not issubclass(type(feature), BaseFeature):
346
+ raise TypeError("feature must be a GeologicalFeature")
347
+ if feature.name != feature_name:
348
+ raise ValueError("feature name does not match key")
349
+ self._add_feature(feature)
334
350
  def __contains__(self, feature_name):
335
351
  return feature_name in self.feature_name_index
336
352
 
@@ -426,7 +442,7 @@ class GeologicalModel:
426
442
  except pickle.PicklingError:
427
443
  logger.error("Error saving file")
428
444
 
429
- def _add_feature(self, feature):
445
+ def _add_feature(self, feature, index: Optional[int] = None):
430
446
  """
431
447
  Add a feature to the model stack
432
448
 
@@ -443,9 +459,18 @@ class GeologicalModel:
443
459
  )
444
460
  self.features[self.feature_name_index[feature.name]] = feature
445
461
  else:
446
- self.features.append(feature)
447
- self.feature_name_index[feature.name] = len(self.features) - 1
448
- logger.info(f"Adding {feature.name} to model at location {len(self.features)}")
462
+ if index is not None:
463
+ if index < 0 or index > len(self.features):
464
+ raise IndexError(f"Index {index} out of bounds for features list")
465
+ self.features.insert(index, feature)
466
+ self.feature_name_index[feature.name] = index
467
+ logger.info(f"Adding {feature.name} to model at location {index}")
468
+ for index, feature in enumerate(self.features):
469
+ self.feature_name_index[feature.name] = index
470
+ else:
471
+ self.features.append(feature)
472
+ self.feature_name_index[feature.name] = len(self.features) - 1
473
+ logger.info(f"Adding {feature.name} to model at location {len(self.features)}")
449
474
  self._add_domain_fault_above(feature)
450
475
  if feature.type == FeatureType.INTERPOLATED:
451
476
  self._add_unconformity_above(feature)
@@ -553,7 +578,7 @@ class GeologicalModel:
553
578
  }
554
579
 
555
580
  """
556
- self.stratigraphic_column.clear()
581
+ self.stratigraphic_column.clear(basement=False)
557
582
  # if the colour for a unit hasn't been specified we can just sample from
558
583
  # a colour map e.g. tab20
559
584
  logger.info("Adding stratigraphic column to model")
@@ -561,6 +586,9 @@ class GeologicalModel:
561
586
  "set_stratigraphic_column is deprecated, use model.stratigraphic_column.add_units instead"
562
587
  )
563
588
  for i, g in enumerate(stratigraphic_column.keys()):
589
+ if g == 'faults':
590
+ logger.info('Not adding faults to stratigraphic column')
591
+ continue
564
592
  for u in stratigraphic_column[g].keys():
565
593
  thickness = 0
566
594
  if "min" in stratigraphic_column[g][u] and "max" in stratigraphic_column[g][u]:
@@ -582,15 +610,16 @@ class GeologicalModel:
582
610
  self.stratigraphic_column.add_unconformity(
583
611
  name=''.join([g, 'unconformity']),
584
612
  )
585
- self.stratigraphic_column.group_mapping[f'Group_{i+1}'] = g
613
+ self.stratigraphic_column.group_mapping[f'Group_{i}'] = g
586
614
 
587
615
  def create_and_add_foliation(
588
616
  self,
589
617
  series_surface_name: str,
590
618
  *,
591
- series_surface_data: pd.DataFrame = None,
619
+ index: Optional[int] = None,
620
+ data: Optional[pd.DataFrame] = None,
592
621
  interpolatortype: str = "FDI",
593
- nelements: int = 1000,
622
+ nelements: int = LoopStructuralConfig.nelements,
594
623
  tol=None,
595
624
  faults=None,
596
625
  **kwargs,
@@ -643,13 +672,13 @@ class GeologicalModel:
643
672
  **kwargs,
644
673
  )
645
674
  # add data
646
- if series_surface_data is None:
647
- series_surface_data = self.data.loc[self.data["feature_name"] == series_surface_name]
675
+ if data is None:
676
+ data = self.data.loc[self.data["feature_name"] == series_surface_name]
648
677
 
649
- if series_surface_data.shape[0] == 0:
678
+ if data.shape[0] == 0:
650
679
  logger.warning("No data for {series_surface_data}, skipping")
651
680
  return
652
- series_builder.add_data_from_data_frame(self.prepare_data(series_surface_data))
681
+ series_builder.add_data_from_data_frame(self.prepare_data(data))
653
682
  self._add_faults(series_builder, features=faults)
654
683
 
655
684
  # build feature
@@ -660,16 +689,17 @@ class GeologicalModel:
660
689
  # could just pass a regular grid of points - mask by any above unconformities??
661
690
 
662
691
  series_feature.type = FeatureType.INTERPOLATED
663
- self._add_feature(series_feature)
692
+ self._add_feature(series_feature,index=index)
664
693
  return series_feature
665
694
 
666
695
  def create_and_add_fold_frame(
667
696
  self,
668
697
  fold_frame_name: str,
669
698
  *,
670
- fold_frame_data=None,
699
+ index: Optional[int] = None,
700
+ data=None,
671
701
  interpolatortype="FDI",
672
- nelements=1000,
702
+ nelements=LoopStructuralConfig.nelements,
673
703
  tol=None,
674
704
  buffer=0.1,
675
705
  **kwargs,
@@ -717,12 +747,12 @@ class GeologicalModel:
717
747
  **kwargs,
718
748
  )
719
749
  # add data
720
- if fold_frame_data is None:
721
- fold_frame_data = self.data.loc[self.data["feature_name"] == fold_frame_name]
722
- if fold_frame_data.shape[0] == 0:
750
+ if data is None:
751
+ data = self.data.loc[self.data["feature_name"] == fold_frame_name]
752
+ if data.shape[0] == 0:
723
753
  logger.warning(f"No data for {fold_frame_name}, skipping")
724
754
  return
725
- fold_frame_builder.add_data_from_data_frame(self.prepare_data(fold_frame_data))
755
+ fold_frame_builder.add_data_from_data_frame(self.prepare_data(data))
726
756
  self._add_faults(fold_frame_builder[0])
727
757
  self._add_faults(fold_frame_builder[1])
728
758
  self._add_faults(fold_frame_builder[2])
@@ -732,7 +762,7 @@ class GeologicalModel:
732
762
 
733
763
  fold_frame.type = FeatureType.STRUCTURALFRAME
734
764
  fold_frame.builder = fold_frame_builder
735
- self._add_feature(fold_frame)
765
+ self._add_feature(fold_frame,index=index)
736
766
 
737
767
  return fold_frame
738
768
 
@@ -740,9 +770,10 @@ class GeologicalModel:
740
770
  self,
741
771
  foliation_name,
742
772
  *,
743
- foliation_data=None,
773
+ index: Optional[int] = None,
774
+ data=None,
744
775
  interpolatortype="DFI",
745
- nelements=10000,
776
+ nelements=LoopStructuralConfig.nelements,
746
777
  buffer=0.1,
747
778
  fold_frame=None,
748
779
  svario=True,
@@ -786,7 +817,7 @@ class GeologicalModel:
786
817
  fold_frame = self.features[-1]
787
818
  assert isinstance(fold_frame, FoldFrame), "Please specify a FoldFrame"
788
819
 
789
- fold = FoldEvent(fold_frame, name=f"Fold_{foliation_data}", invert_norm=invert_fold_norm)
820
+ fold = FoldEvent(fold_frame, name=f"Fold_{foliation_name}", invert_norm=invert_fold_norm)
790
821
 
791
822
  if interpolatortype != "DFI":
792
823
  logger.warning("Folded foliation only supports DFI interpolator, changing to DFI")
@@ -801,12 +832,12 @@ class GeologicalModel:
801
832
  model=self,
802
833
  **kwargs,
803
834
  )
804
- if foliation_data is None:
805
- foliation_data = self.data.loc[self.data["feature_name"] == foliation_name]
806
- if foliation_data.shape[0] == 0:
835
+ if data is None:
836
+ data = self.data.loc[self.data["feature_name"] == foliation_name]
837
+ if data.shape[0] == 0:
807
838
  logger.warning(f"No data for {foliation_name}, skipping")
808
839
  return
809
- series_builder.add_data_from_data_frame(self.prepare_data(foliation_data))
840
+ series_builder.add_data_from_data_frame(self.prepare_data(data))
810
841
 
811
842
  self._add_faults(series_builder)
812
843
  # series_builder.add_data_to_interpolator(True)
@@ -817,19 +848,20 @@ class GeologicalModel:
817
848
  # series_feature = series_builder.build(**kwargs)
818
849
  series_feature = series_builder.feature
819
850
  series_builder.update_build_arguments(kwargs)
820
- series_feature.type = FeatureType.INTERPOLATED
851
+ series_feature.type = FeatureType.FOLDED
821
852
  series_feature.fold = fold
822
853
 
823
- self._add_feature(series_feature)
854
+ self._add_feature(series_feature,index)
824
855
  return series_feature
825
856
 
826
857
  def create_and_add_folded_fold_frame(
827
858
  self,
828
859
  fold_frame_name: str,
829
860
  *,
830
- fold_frame_data: Optional[pd.DataFrame] = None,
861
+ index: Optional[int] = None,
862
+ data: Optional[pd.DataFrame] = None,
831
863
  interpolatortype="FDI",
832
- nelements=10000,
864
+ nelements=LoopStructuralConfig.nelements,
833
865
  fold_frame=None,
834
866
  tol=None,
835
867
  **kwargs,
@@ -882,7 +914,7 @@ class GeologicalModel:
882
914
  logger.info("Using last feature as fold frame")
883
915
  fold_frame = self.features[-1]
884
916
  assert isinstance(fold_frame, FoldFrame), "Please specify a FoldFrame"
885
- fold = FoldEvent(fold_frame, name=f"Fold_{fold_frame_data}")
917
+ fold = FoldEvent(fold_frame, name=f"Fold_{fold_frame_name}")
886
918
 
887
919
  interpolatortypes = [
888
920
  "DFI",
@@ -899,9 +931,9 @@ class GeologicalModel:
899
931
  model=self,
900
932
  **kwargs,
901
933
  )
902
- if fold_frame_data is None:
903
- fold_frame_data = self.data[self.data["feature_name"] == fold_frame_name]
904
- fold_frame_builder.add_data_from_data_frame(self.prepare_data(fold_frame_data))
934
+ if data is None:
935
+ data = self.data[self.data["feature_name"] == fold_frame_name]
936
+ fold_frame_builder.add_data_from_data_frame(self.prepare_data(data))
905
937
 
906
938
  for i in range(3):
907
939
  self._add_faults(fold_frame_builder[i])
@@ -915,7 +947,7 @@ class GeologicalModel:
915
947
 
916
948
  folded_fold_frame.type = FeatureType.STRUCTURALFRAME
917
949
 
918
- self._add_feature(folded_fold_frame)
950
+ self._add_feature(folded_fold_frame,index=index)
919
951
 
920
952
  return folded_fold_frame
921
953
 
@@ -978,14 +1010,14 @@ class GeologicalModel:
978
1010
 
979
1011
  interpolatortype = kwargs.get("interpolatortype", "PLI")
980
1012
  # buffer = kwargs.get("buffer", 0.1)
981
- nelements = kwargs.get("nelements", 1e2)
1013
+ nelements = kwargs.get("nelements", LoopStructuralConfig.nelements)
982
1014
 
983
1015
  weights = [gxxgz, gxxgy, gyxgz]
984
1016
 
985
1017
  intrusion_frame_builder = IntrusionFrameBuilder(
986
1018
  interpolatortype=interpolatortype,
987
1019
  bounding_box=self.bounding_box.with_buffer(kwargs.get("buffer", 0.1)),
988
- nelements=kwargs.get("nelements", 1e2),
1020
+ nelements=kwargs.get("nelements", LoopStructuralConfig.nelements),
989
1021
  name=intrusion_frame_name,
990
1022
  model=self,
991
1023
  **kwargs,
@@ -1128,7 +1160,7 @@ class GeologicalModel:
1128
1160
  feature.add_region(f)
1129
1161
  break
1130
1162
 
1131
- def add_unconformity(self, feature: GeologicalFeature, value: float) -> UnconformityFeature:
1163
+ def add_unconformity(self, feature: GeologicalFeature, value: float, index: Optional[int] = None) -> UnconformityFeature:
1132
1164
  """
1133
1165
  Use an existing feature to add an unconformity to the model.
1134
1166
 
@@ -1165,10 +1197,10 @@ class GeologicalModel:
1165
1197
  else:
1166
1198
  f.add_region(uc_feature)
1167
1199
  # now add the unconformity to the feature list
1168
- self._add_feature(uc_feature)
1200
+ self._add_feature(uc_feature,index=index)
1169
1201
  return uc_feature
1170
1202
 
1171
- def add_onlap_unconformity(self, feature: GeologicalFeature, value: float) -> GeologicalFeature:
1203
+ def add_onlap_unconformity(self, feature: GeologicalFeature, value: float, index: Optional[int] = None) -> GeologicalFeature:
1172
1204
  """
1173
1205
  Use an existing feature to add an unconformity to the model.
1174
1206
 
@@ -1196,12 +1228,18 @@ class GeologicalModel:
1196
1228
  continue
1197
1229
  if f != feature:
1198
1230
  f.add_region(uc_feature)
1199
- self._add_feature(uc_feature.inverse())
1231
+ self._add_feature(uc_feature.inverse(),index=index)
1200
1232
 
1201
1233
  return uc_feature
1202
1234
 
1203
1235
  def create_and_add_domain_fault(
1204
- self, fault_surface_data, *, nelements=10000, interpolatortype="FDI", **kwargs
1236
+ self,
1237
+ fault_surface_data,
1238
+ *,
1239
+ nelements=LoopStructuralConfig.nelements,
1240
+ interpolatortype="FDI",
1241
+ index: Optional[int] = None,
1242
+ **kwargs,
1205
1243
  ):
1206
1244
  """
1207
1245
  Parameters
@@ -1242,7 +1280,7 @@ class GeologicalModel:
1242
1280
  domain_fault = domain_fault_feature_builder.feature
1243
1281
  domain_fault_feature_builder.update_build_arguments(kwargs)
1244
1282
  domain_fault.type = FeatureType.DOMAINFAULT
1245
- self._add_feature(domain_fault)
1283
+ self._add_feature(domain_fault, index=index)
1246
1284
  self._add_domain_fault_below(domain_fault)
1247
1285
 
1248
1286
  domain_fault_uc = UnconformityFeature(domain_fault, 0)
@@ -1255,7 +1293,8 @@ class GeologicalModel:
1255
1293
  fault_name: str,
1256
1294
  displacement: float,
1257
1295
  *,
1258
- fault_data: Optional[pd.DataFrame] = None,
1296
+ index: Optional[int] = None,
1297
+ data: Optional[pd.DataFrame] = None,
1259
1298
  interpolatortype="FDI",
1260
1299
  tol=None,
1261
1300
  fault_slip_vector=None,
@@ -1344,14 +1383,14 @@ class GeologicalModel:
1344
1383
  fault_frame_builder = FaultBuilder(
1345
1384
  interpolatortype,
1346
1385
  bounding_box=self.bounding_box,
1347
- nelements=kwargs.pop("nelements", 1e4),
1386
+ nelements=kwargs.pop("nelements", LoopStructuralConfig.nelements),
1348
1387
  name=fault_name,
1349
1388
  model=self,
1350
1389
  **kwargs,
1351
1390
  )
1352
- if fault_data is None:
1353
- fault_data = self.data.loc[self.data["feature_name"] == fault_name]
1354
- if fault_data.shape[0] == 0:
1391
+ if data is None:
1392
+ data = self.data.loc[self.data["feature_name"] == fault_name]
1393
+ if data.shape[0] == 0:
1355
1394
  logger.warning(f"No data for {fault_name}, skipping")
1356
1395
  return
1357
1396
 
@@ -1367,7 +1406,7 @@ class GeologicalModel:
1367
1406
  if intermediate_axis:
1368
1407
  intermediate_axis = intermediate_axis
1369
1408
  fault_frame_builder.create_data_from_geometry(
1370
- fault_frame_data=self.prepare_data(fault_data),
1409
+ fault_frame_data=self.prepare_data(data),
1371
1410
  fault_center=fault_center,
1372
1411
  fault_normal_vector=fault_normal_vector,
1373
1412
  fault_slip_vector=fault_slip_vector,
@@ -1399,7 +1438,7 @@ class GeologicalModel:
1399
1438
  break
1400
1439
  if displacement == 0:
1401
1440
  fault.type = FeatureType.INACTIVEFAULT
1402
- self._add_feature(fault)
1441
+ self._add_feature(fault,index=index)
1403
1442
 
1404
1443
  return fault
1405
1444
 
@@ -1515,7 +1554,7 @@ class GeologicalModel:
1515
1554
  if self.stratigraphic_column is None:
1516
1555
  logger.warning("No stratigraphic column defined")
1517
1556
  return strat_id
1518
-
1557
+
1519
1558
  s_id = 0
1520
1559
  for g in reversed(self.stratigraphic_column.get_groups()):
1521
1560
  feature_id = self.feature_name_index.get(g.name, -1)
@@ -1526,7 +1565,7 @@ class GeologicalModel:
1526
1565
  s_id += 1
1527
1566
  if feature_id == -1:
1528
1567
  logger.error(f"Model does not contain {g.name}")
1529
-
1568
+
1530
1569
  return strat_id
1531
1570
 
1532
1571
  def evaluate_model_gradient(self, points: np.ndarray, *, scale: bool = True) -> np.ndarray:
@@ -1548,16 +1587,13 @@ class GeologicalModel:
1548
1587
  if scale:
1549
1588
  xyz = self.scale(xyz, inplace=False)
1550
1589
  grad = np.zeros(xyz.shape)
1551
- for group in reversed(self.stratigraphic_column.keys()):
1552
- if group == "faults":
1553
- continue
1554
- feature_id = self.feature_name_index.get(group, -1)
1590
+ for g in reversed(self.stratigraphic_column.get_groups()):
1591
+ feature_id = self.feature_name_index.get(g.name, -1)
1555
1592
  if feature_id >= 0:
1556
- feature = self.features[feature_id]
1557
- gradt = feature.evaluate_gradient(xyz)
1593
+ gradt = self.features[feature_id].evaluate_gradient(xyz)
1558
1594
  grad[~np.isnan(gradt).any(axis=1)] = gradt[~np.isnan(gradt).any(axis=1)]
1559
1595
  if feature_id == -1:
1560
- logger.error(f"Model does not contain {group}")
1596
+ logger.error(f"Model does not contain {g.name}")
1561
1597
 
1562
1598
  return grad
1563
1599
 
@@ -1728,7 +1764,6 @@ class GeologicalModel:
1728
1764
  list of unique stratigraphic ids, featurename, unit name and min and max scalar values
1729
1765
  """
1730
1766
  return self.stratigraphic_column.get_stratigraphic_ids()
1731
-
1732
1767
 
1733
1768
  def get_fault_surfaces(self, faults: List[str] = []):
1734
1769
  surfaces = []
@@ -1,7 +1,7 @@
1
1
  import enum
2
2
  from typing import Dict, Optional, List, Tuple
3
3
  import numpy as np
4
- from LoopStructural.utils import rng, getLogger, Observable
4
+ from LoopStructural.utils import rng, getLogger, Observable, random_colour
5
5
  logger = getLogger(__name__)
6
6
  logger.info("Imported LoopStructural Stratigraphic Column module")
7
7
  class UnconformityType(enum.Enum):
@@ -57,7 +57,7 @@ class StratigraphicUnit(StratigraphicColumnElement, Observable['StratigraphicUni
57
57
  self._thickness = thickness
58
58
  self.data = data
59
59
  self.element_type = StratigraphicColumnElementType.UNIT
60
- self._id = id
60
+ self.id = id
61
61
  self.min_value = None # Minimum scalar field value for the unit
62
62
  self.max_value = None # Maximum scalar field value for the unit
63
63
  @property
@@ -99,7 +99,7 @@ class StratigraphicUnit(StratigraphicColumnElement, Observable['StratigraphicUni
99
99
  colour = self.colour
100
100
  if isinstance(colour, np.ndarray):
101
101
  colour = colour.astype(float).tolist()
102
- return {"name": self.name, "colour": colour, "thickness": self.thickness, 'uuid': self.uuid}
102
+ return {"name": self.name, "colour": colour, "thickness": self.thickness, 'uuid': self.uuid, 'id': self.id}
103
103
 
104
104
  @classmethod
105
105
  def from_dict(cls, data):
@@ -112,7 +112,7 @@ class StratigraphicUnit(StratigraphicColumnElement, Observable['StratigraphicUni
112
112
  colour = data.get("colour")
113
113
  thickness = data.get("thickness", None)
114
114
  uuid = data.get("uuid", None)
115
- return cls(uuid=uuid, name=name, colour=colour, thickness=thickness)
115
+ return cls(uuid=uuid, name=name, colour=colour, thickness=thickness, id=data.get("id", None))
116
116
 
117
117
  def __str__(self):
118
118
  """
@@ -575,3 +575,29 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
575
575
  ax.axis("off")
576
576
 
577
577
  return fig
578
+
579
+ def cmap(self):
580
+ try:
581
+ import matplotlib.colors as colors
582
+
583
+ colours = []
584
+ boundaries = []
585
+ data = []
586
+ for group in self.get_groups():
587
+ for u in group.units:
588
+ colour = u.colour
589
+ if not isinstance(colour, str):
590
+ try:
591
+ u.colour = colors.to_hex(colour)
592
+ except ValueError:
593
+ logger.warning(f"Cannot convert colour {colour} to hex, using default")
594
+ u.colour = random_colour()
595
+ data.append((u.id, u.colour))
596
+ colours.append(u.colour)
597
+ boundaries.append(u.id)
598
+ # print(u,v)
599
+ cmap = colors.ListedColormap(colours)
600
+ except ImportError:
601
+ logger.warning("Cannot use predefined colours as I can't import matplotlib")
602
+ cmap = "tab20"
603
+ return cmap
@@ -271,7 +271,7 @@ class BaseFeature(metaclass=ABCMeta):
271
271
 
272
272
  def surfaces(
273
273
  self,
274
- value: Union[float, int, List[Union[float, int]]],
274
+ value: Optional[Union[float, int, List[Union[float, int]]]] = None,
275
275
  bounding_box=None,
276
276
  name: Optional[Union[List[str], str]] = None,
277
277
  colours: Optional[Union[str, np.ndarray]] = None,
@@ -293,6 +293,7 @@ class BaseFeature(metaclass=ABCMeta):
293
293
  raise ValueError("Must specify bounding box")
294
294
  bounding_box = self.model.bounding_box
295
295
  regions = self.regions
296
+
296
297
  try:
297
298
  self.regions = [
298
299
  r for r in self.regions if r.name != self.name and r.parent.name != self.name
@@ -0,0 +1,36 @@
1
+ from LoopStructural.modelling.features.fold import FoldEvent
2
+ from LoopStructural.modelling.features.builders import FoldedFeatureBuilder, StructuralFrameBuilder
3
+ def add_fold_to_feature(feature, fold_frame,**kwargs):
4
+ fold = FoldEvent(fold_frame, name=f"Fold_{feature.name}", invert_norm=kwargs.get('invert_fold_norm', False))
5
+
6
+ builder = FoldedFeatureBuilder.from_feature_builder(
7
+ feature.builder,
8
+ fold,
9
+ **kwargs
10
+ )
11
+ feature = builder.feature
12
+ feature.fold = fold
13
+ return feature
14
+
15
+ def convert_feature_to_structural_frame(feature, **kwargs):
16
+ """
17
+ Convert a geological feature to a structural frame by adding the feature to the frame
18
+
19
+ Parameters
20
+ ----------
21
+ feature : GeologicalFeature
22
+ the geological feature to convert
23
+
24
+ Returns
25
+ -------
26
+ StructuralFrame
27
+ the updated structural frame with the feature added
28
+ """
29
+ builder = feature.builder
30
+
31
+ new_builder = StructuralFrameBuilder.from_feature_builder(
32
+ builder,
33
+ **kwargs
34
+ )
35
+ return new_builder.frame
36
+
@@ -77,7 +77,7 @@ class GeologicalFeature(BaseFeature):
77
77
  print(self.name, json)
78
78
  json["interpolator"] = self.interpolator.to_json()
79
79
  return json
80
-
80
+
81
81
  def is_valid(self):
82
82
  return self.interpolator.valid
83
83
 
@@ -134,7 +134,7 @@ class StructuralFrame(BaseFeature):
134
134
  v[:, 0] = self.features[0].evaluate_value(pos, ignore_regions=ignore_regions)
135
135
  v[:, 1] = self.features[1].evaluate_value(pos, ignore_regions=ignore_regions)
136
136
  v[:, 2] = self.features[2].evaluate_value(pos, ignore_regions=ignore_regions)
137
- return v
137
+ return v[:,0]
138
138
 
139
139
  def evaluate_gradient(self, pos, i=None, ignore_regions=False):
140
140
  """
@@ -152,11 +152,7 @@ class StructuralFrame(BaseFeature):
152
152
  """
153
153
  if i is not None:
154
154
  return self.features[i].support.evaluate_gradient(pos, ignore_regions=ignore_regions)
155
- return (
156
- self.features[0].support.evaluate_gradient(pos, ignore_regions=ignore_regions),
157
- self.features[1].support.evaluate_gradient(pos, ignore_regions=ignore_regions),
158
- self.features[2].support.evaluate_gradient(pos, ignore_regions=ignore_regions),
159
- )
155
+ return self.features[0].support.evaluate_gradient(pos, ignore_regions=ignore_regions)
160
156
 
161
157
  def get_data(self, value_map: Optional[dict] = None) -> List[Union[ValuePoints, VectorPoints]]:
162
158
  """Return the data associated with the features in the