LoopStructural 1.6.17__tar.gz → 1.6.19__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.17 → loopstructural-1.6.19}/LoopStructural/__init__.py +11 -0
  2. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/core/geological_model.py +74 -46
  3. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/core/stratigraphic_column.py +119 -16
  4. loopstructural-1.6.19/LoopStructural/modelling/features/_feature_converters.py +13 -0
  5. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/_geological_feature.py +1 -1
  6. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/builders/_folded_feature_builder.py +16 -1
  7. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/builders/_geological_feature_builder.py +3 -0
  8. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/fold/__init__.py +1 -0
  9. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/fold/_svariogram.py +3 -0
  10. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/input/process_data.py +2 -0
  11. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/observer.py +2 -2
  12. loopstructural-1.6.19/LoopStructural/version.py +1 -0
  13. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural.egg-info/PKG-INFO +1 -1
  14. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural.egg-info/SOURCES.txt +1 -0
  15. {loopstructural-1.6.17 → loopstructural-1.6.19}/PKG-INFO +1 -1
  16. loopstructural-1.6.17/LoopStructural/version.py +0 -1
  17. {loopstructural-1.6.17 → loopstructural-1.6.19}/LICENSE +0 -0
  18. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/__init__.py +0 -0
  19. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/_base.py +0 -0
  20. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/_example_models.py +0 -0
  21. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/claudius.csv +0 -0
  22. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/claudiusbb.txt +0 -0
  23. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/duplex.csv +0 -0
  24. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/duplexbb.txt +0 -0
  25. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/fault_trace/fault_trace.cpg +0 -0
  26. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/fault_trace/fault_trace.dbf +0 -0
  27. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/fault_trace/fault_trace.prj +0 -0
  28. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/fault_trace/fault_trace.shp +0 -0
  29. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/fault_trace/fault_trace.shx +0 -0
  30. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/geological_map_data/bbox.csv +0 -0
  31. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/geological_map_data/contacts.csv +0 -0
  32. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/geological_map_data/fault_displacement.csv +0 -0
  33. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/geological_map_data/fault_edges.txt +0 -0
  34. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/geological_map_data/fault_locations.csv +0 -0
  35. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/geological_map_data/fault_orientations.csv +0 -0
  36. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/geological_map_data/stratigraphic_order.csv +0 -0
  37. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/geological_map_data/stratigraphic_orientations.csv +0 -0
  38. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/geological_map_data/stratigraphic_thickness.csv +0 -0
  39. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/intrusion.csv +0 -0
  40. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/intrusionbb.txt +0 -0
  41. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/onefoldbb.txt +0 -0
  42. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/onefolddata.csv +0 -0
  43. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/refolded_bb.txt +0 -0
  44. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/refolded_fold.csv +0 -0
  45. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datasets/data/tabular_intrusion.csv +0 -0
  46. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datatypes/__init__.py +0 -0
  47. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datatypes/_bounding_box.py +0 -0
  48. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datatypes/_point.py +0 -0
  49. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datatypes/_structured_grid.py +0 -0
  50. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/datatypes/_surface.py +0 -0
  51. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/export/exporters.py +0 -0
  52. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/export/file_formats.py +0 -0
  53. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/export/geoh5.py +0 -0
  54. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/export/gocad.py +0 -0
  55. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/export/omf_wrapper.py +0 -0
  56. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/__init__.py +0 -0
  57. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_api.py +0 -0
  58. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_builders.py +0 -0
  59. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_constant_norm.py +0 -0
  60. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_cython/__init__.py +0 -0
  61. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_discrete_fold_interpolator.py +0 -0
  62. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_discrete_interpolator.py +0 -0
  63. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_finite_difference_interpolator.py +0 -0
  64. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_geological_interpolator.py +0 -0
  65. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_interpolator_builder.py +0 -0
  66. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_interpolator_factory.py +0 -0
  67. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_interpolatortype.py +0 -0
  68. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_operator.py +0 -0
  69. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_p1interpolator.py +0 -0
  70. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_p2interpolator.py +0 -0
  71. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/_surfe_wrapper.py +0 -0
  72. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/_2d_base_unstructured.py +0 -0
  73. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/_2d_p1_unstructured.py +0 -0
  74. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/_2d_p2_unstructured.py +0 -0
  75. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/_2d_structured_grid.py +0 -0
  76. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/_2d_structured_tetra.py +0 -0
  77. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/_3d_base_structured.py +0 -0
  78. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/_3d_p2_tetra.py +0 -0
  79. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/_3d_structured_grid.py +0 -0
  80. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/_3d_structured_tetra.py +0 -0
  81. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/_3d_unstructured_tetra.py +0 -0
  82. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/__init__.py +0 -0
  83. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/_aabb.py +0 -0
  84. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/_base_support.py +0 -0
  85. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/_face_table.py +0 -0
  86. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/interpolators/supports/_support_factory.py +0 -0
  87. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/__init__.py +0 -0
  88. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/core/__init__.py +0 -0
  89. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/core/fault_topology.py +0 -0
  90. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/__init__.py +0 -0
  91. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/_analytical_feature.py +0 -0
  92. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/_base_geological_feature.py +0 -0
  93. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/_cross_product_geological_feature.py +0 -0
  94. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/_lambda_geological_feature.py +0 -0
  95. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/_projected_vector_feature.py +0 -0
  96. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/_region.py +0 -0
  97. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/_structural_frame.py +0 -0
  98. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/_unconformity_feature.py +0 -0
  99. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/builders/__init__.py +0 -0
  100. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/builders/_base_builder.py +0 -0
  101. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/builders/_fault_builder.py +0 -0
  102. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/builders/_structural_frame_builder.py +0 -0
  103. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/fault/__init__.py +0 -0
  104. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/fault/_fault_function.py +0 -0
  105. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/fault/_fault_function_feature.py +0 -0
  106. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/fault/_fault_segment.py +0 -0
  107. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/fold/_fold.py +0 -0
  108. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/fold/_fold_rotation_angle_feature.py +0 -0
  109. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/fold/_foldframe.py +0 -0
  110. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/fold/fold_function/__init__.py +0 -0
  111. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/fold/fold_function/_base_fold_rotation_angle.py +0 -0
  112. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/fold/fold_function/_fourier_series_fold_rotation_angle.py +0 -0
  113. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/fold/fold_function/_lambda_fold_rotation_angle.py +0 -0
  114. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/features/fold/fold_function/_trigo_fold_rotation_angle.py +0 -0
  115. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/input/__init__.py +0 -0
  116. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/input/fault_network.py +0 -0
  117. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/input/map2loop_processor.py +0 -0
  118. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/input/project_file.py +0 -0
  119. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/intrusions/__init__.py +0 -0
  120. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/intrusions/geom_conceptual_models.py +0 -0
  121. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/intrusions/geometric_scaling_functions.py +0 -0
  122. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/intrusions/intrusion_builder.py +0 -0
  123. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/intrusions/intrusion_feature.py +0 -0
  124. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/intrusions/intrusion_frame_builder.py +0 -0
  125. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/modelling/intrusions/intrusion_support_functions.py +0 -0
  126. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/__init__.py +0 -0
  127. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/_surface.py +0 -0
  128. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/_transformation.py +0 -0
  129. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/colours.py +0 -0
  130. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/config.py +0 -0
  131. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/dtm_creator.py +0 -0
  132. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/exceptions.py +0 -0
  133. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/features.py +0 -0
  134. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/helper.py +0 -0
  135. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/json_encoder.py +0 -0
  136. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/linalg.py +0 -0
  137. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/logging.py +0 -0
  138. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/maths.py +0 -0
  139. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/regions.py +0 -0
  140. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/typing.py +0 -0
  141. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/utils/utils.py +0 -0
  142. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural/visualisation/__init__.py +0 -0
  143. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural.egg-info/dependency_links.txt +0 -0
  144. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural.egg-info/requires.txt +0 -0
  145. {loopstructural-1.6.17 → loopstructural-1.6.19}/LoopStructural.egg-info/top_level.txt +0 -0
  146. {loopstructural-1.6.17 → loopstructural-1.6.19}/README.md +0 -0
  147. {loopstructural-1.6.17 → loopstructural-1.6.19}/pyproject.toml +0 -0
  148. {loopstructural-1.6.17 → loopstructural-1.6.19}/setup.cfg +0 -0
  149. {loopstructural-1.6.17 → loopstructural-1.6.19}/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
@@ -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
@@ -330,7 +331,21 @@ class GeologicalModel:
330
331
  name of the feature to return
331
332
  """
332
333
  return self.get_feature_by_name(feature_name)
334
+ def __setitem__(self, feature_name, feature):
335
+ """Set a feature in the model using feature_name_index
333
336
 
337
+ Parameters
338
+ ----------
339
+ feature_name : string
340
+ name of the feature to set
341
+ feature : GeologicalFeature
342
+ the geological feature to set
343
+ """
344
+ if not isinstance(feature, GeologicalFeature):
345
+ raise TypeError("feature must be a GeologicalFeature")
346
+ if feature.name != feature_name:
347
+ raise ValueError("feature name does not match key")
348
+ self._add_feature(feature)
334
349
  def __contains__(self, feature_name):
335
350
  return feature_name in self.feature_name_index
336
351
 
@@ -426,7 +441,7 @@ class GeologicalModel:
426
441
  except pickle.PicklingError:
427
442
  logger.error("Error saving file")
428
443
 
429
- def _add_feature(self, feature):
444
+ def _add_feature(self, feature, index: Optional[int] = None):
430
445
  """
431
446
  Add a feature to the model stack
432
447
 
@@ -443,9 +458,18 @@ class GeologicalModel:
443
458
  )
444
459
  self.features[self.feature_name_index[feature.name]] = feature
445
460
  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)}")
461
+ if index is not None:
462
+ if index < 0 or index > len(self.features):
463
+ raise IndexError(f"Index {index} out of bounds for features list")
464
+ self.features.insert(index, feature)
465
+ self.feature_name_index[feature.name] = index
466
+ logger.info(f"Adding {feature.name} to model at location {index}")
467
+ for index, feature in enumerate(self.features):
468
+ self.feature_name_index[feature.name] = index
469
+ else:
470
+ self.features.append(feature)
471
+ self.feature_name_index[feature.name] = len(self.features) - 1
472
+ logger.info(f"Adding {feature.name} to model at location {len(self.features)}")
449
473
  self._add_domain_fault_above(feature)
450
474
  if feature.type == FeatureType.INTERPOLATED:
451
475
  self._add_unconformity_above(feature)
@@ -553,21 +577,24 @@ class GeologicalModel:
553
577
  }
554
578
 
555
579
  """
556
- self.stratigraphic_column.clear()
580
+ self.stratigraphic_column.clear(basement=False)
557
581
  # if the colour for a unit hasn't been specified we can just sample from
558
582
  # a colour map e.g. tab20
559
583
  logger.info("Adding stratigraphic column to model")
560
584
  DeprecationWarning(
561
585
  "set_stratigraphic_column is deprecated, use model.stratigraphic_column.add_units instead"
562
586
  )
563
- for g in stratigraphic_column.keys():
587
+ for i, g in enumerate(stratigraphic_column.keys()):
588
+ if g == 'faults':
589
+ logger.info('Not adding faults to stratigraphic column')
590
+ continue
564
591
  for u in stratigraphic_column[g].keys():
565
592
  thickness = 0
566
593
  if "min" in stratigraphic_column[g][u] and "max" in stratigraphic_column[g][u]:
567
594
  min_val = stratigraphic_column[g][u]["min"]
568
595
  max_val = stratigraphic_column[g][u].get("max", None)
569
596
  thickness = max_val - min_val if max_val is not None else None
570
- logger.warning(
597
+ logger.info(
571
598
  f"""
572
599
  model.stratigraphic_column.add_unit({u},
573
600
  colour={stratigraphic_column[g][u].get("colour", None)},
@@ -578,17 +605,20 @@ class GeologicalModel:
578
605
  colour=stratigraphic_column[g][u].get("colour", None),
579
606
  thickness=thickness,
580
607
  )
608
+
581
609
  self.stratigraphic_column.add_unconformity(
582
610
  name=''.join([g, 'unconformity']),
583
611
  )
612
+ self.stratigraphic_column.group_mapping[f'Group_{i}'] = g
584
613
 
585
614
  def create_and_add_foliation(
586
615
  self,
587
616
  series_surface_name: str,
588
617
  *,
589
- series_surface_data: pd.DataFrame = None,
618
+ index: Optional[int] = None,
619
+ series_surface_data: Optional[pd.DataFrame] = None,
590
620
  interpolatortype: str = "FDI",
591
- nelements: int = 1000,
621
+ nelements: int = LoopStructuralConfig.nelements,
592
622
  tol=None,
593
623
  faults=None,
594
624
  **kwargs,
@@ -658,16 +688,17 @@ class GeologicalModel:
658
688
  # could just pass a regular grid of points - mask by any above unconformities??
659
689
 
660
690
  series_feature.type = FeatureType.INTERPOLATED
661
- self._add_feature(series_feature)
691
+ self._add_feature(series_feature,index=index)
662
692
  return series_feature
663
693
 
664
694
  def create_and_add_fold_frame(
665
695
  self,
666
696
  fold_frame_name: str,
667
697
  *,
698
+ index: Optional[int] = None,
668
699
  fold_frame_data=None,
669
700
  interpolatortype="FDI",
670
- nelements=1000,
701
+ nelements=LoopStructuralConfig.nelements,
671
702
  tol=None,
672
703
  buffer=0.1,
673
704
  **kwargs,
@@ -730,7 +761,7 @@ class GeologicalModel:
730
761
 
731
762
  fold_frame.type = FeatureType.STRUCTURALFRAME
732
763
  fold_frame.builder = fold_frame_builder
733
- self._add_feature(fold_frame)
764
+ self._add_feature(fold_frame,index=index)
734
765
 
735
766
  return fold_frame
736
767
 
@@ -738,9 +769,10 @@ class GeologicalModel:
738
769
  self,
739
770
  foliation_name,
740
771
  *,
772
+ index: Optional[int] = None,
741
773
  foliation_data=None,
742
774
  interpolatortype="DFI",
743
- nelements=10000,
775
+ nelements=LoopStructuralConfig.nelements,
744
776
  buffer=0.1,
745
777
  fold_frame=None,
746
778
  svario=True,
@@ -818,16 +850,17 @@ class GeologicalModel:
818
850
  series_feature.type = FeatureType.INTERPOLATED
819
851
  series_feature.fold = fold
820
852
 
821
- self._add_feature(series_feature)
853
+ self._add_feature(series_feature,index)
822
854
  return series_feature
823
855
 
824
856
  def create_and_add_folded_fold_frame(
825
857
  self,
826
858
  fold_frame_name: str,
827
859
  *,
860
+ index: Optional[int] = None,
828
861
  fold_frame_data: Optional[pd.DataFrame] = None,
829
862
  interpolatortype="FDI",
830
- nelements=10000,
863
+ nelements=LoopStructuralConfig.nelements,
831
864
  fold_frame=None,
832
865
  tol=None,
833
866
  **kwargs,
@@ -913,7 +946,7 @@ class GeologicalModel:
913
946
 
914
947
  folded_fold_frame.type = FeatureType.STRUCTURALFRAME
915
948
 
916
- self._add_feature(folded_fold_frame)
949
+ self._add_feature(folded_fold_frame,index=index)
917
950
 
918
951
  return folded_fold_frame
919
952
 
@@ -976,14 +1009,14 @@ class GeologicalModel:
976
1009
 
977
1010
  interpolatortype = kwargs.get("interpolatortype", "PLI")
978
1011
  # buffer = kwargs.get("buffer", 0.1)
979
- nelements = kwargs.get("nelements", 1e2)
1012
+ nelements = kwargs.get("nelements", LoopStructuralConfig.nelements)
980
1013
 
981
1014
  weights = [gxxgz, gxxgy, gyxgz]
982
1015
 
983
1016
  intrusion_frame_builder = IntrusionFrameBuilder(
984
1017
  interpolatortype=interpolatortype,
985
1018
  bounding_box=self.bounding_box.with_buffer(kwargs.get("buffer", 0.1)),
986
- nelements=kwargs.get("nelements", 1e2),
1019
+ nelements=kwargs.get("nelements", LoopStructuralConfig.nelements),
987
1020
  name=intrusion_frame_name,
988
1021
  model=self,
989
1022
  **kwargs,
@@ -1126,7 +1159,7 @@ class GeologicalModel:
1126
1159
  feature.add_region(f)
1127
1160
  break
1128
1161
 
1129
- def add_unconformity(self, feature: GeologicalFeature, value: float) -> UnconformityFeature:
1162
+ def add_unconformity(self, feature: GeologicalFeature, value: float, index: Optional[int] = None) -> UnconformityFeature:
1130
1163
  """
1131
1164
  Use an existing feature to add an unconformity to the model.
1132
1165
 
@@ -1163,10 +1196,10 @@ class GeologicalModel:
1163
1196
  else:
1164
1197
  f.add_region(uc_feature)
1165
1198
  # now add the unconformity to the feature list
1166
- self._add_feature(uc_feature)
1199
+ self._add_feature(uc_feature,index=index)
1167
1200
  return uc_feature
1168
1201
 
1169
- def add_onlap_unconformity(self, feature: GeologicalFeature, value: float) -> GeologicalFeature:
1202
+ def add_onlap_unconformity(self, feature: GeologicalFeature, value: float, index: Optional[int] = None) -> GeologicalFeature:
1170
1203
  """
1171
1204
  Use an existing feature to add an unconformity to the model.
1172
1205
 
@@ -1194,12 +1227,18 @@ class GeologicalModel:
1194
1227
  continue
1195
1228
  if f != feature:
1196
1229
  f.add_region(uc_feature)
1197
- self._add_feature(uc_feature.inverse())
1230
+ self._add_feature(uc_feature.inverse(),index=index)
1198
1231
 
1199
1232
  return uc_feature
1200
1233
 
1201
1234
  def create_and_add_domain_fault(
1202
- self, fault_surface_data, *, nelements=10000, interpolatortype="FDI", **kwargs
1235
+ self,
1236
+ fault_surface_data,
1237
+ *,
1238
+ nelements=LoopStructuralConfig.nelements,
1239
+ interpolatortype="FDI",
1240
+ index: Optional[int] = None,
1241
+ **kwargs,
1203
1242
  ):
1204
1243
  """
1205
1244
  Parameters
@@ -1240,7 +1279,7 @@ class GeologicalModel:
1240
1279
  domain_fault = domain_fault_feature_builder.feature
1241
1280
  domain_fault_feature_builder.update_build_arguments(kwargs)
1242
1281
  domain_fault.type = FeatureType.DOMAINFAULT
1243
- self._add_feature(domain_fault)
1282
+ self._add_feature(domain_fault, index=index)
1244
1283
  self._add_domain_fault_below(domain_fault)
1245
1284
 
1246
1285
  domain_fault_uc = UnconformityFeature(domain_fault, 0)
@@ -1253,6 +1292,7 @@ class GeologicalModel:
1253
1292
  fault_name: str,
1254
1293
  displacement: float,
1255
1294
  *,
1295
+ index: Optional[int] = None,
1256
1296
  fault_data: Optional[pd.DataFrame] = None,
1257
1297
  interpolatortype="FDI",
1258
1298
  tol=None,
@@ -1342,7 +1382,7 @@ class GeologicalModel:
1342
1382
  fault_frame_builder = FaultBuilder(
1343
1383
  interpolatortype,
1344
1384
  bounding_box=self.bounding_box,
1345
- nelements=kwargs.pop("nelements", 1e4),
1385
+ nelements=kwargs.pop("nelements", LoopStructuralConfig.nelements),
1346
1386
  name=fault_name,
1347
1387
  model=self,
1348
1388
  **kwargs,
@@ -1397,7 +1437,7 @@ class GeologicalModel:
1397
1437
  break
1398
1438
  if displacement == 0:
1399
1439
  fault.type = FeatureType.INACTIVEFAULT
1400
- self._add_feature(fault)
1440
+ self._add_feature(fault,index=index)
1401
1441
 
1402
1442
  return fault
1403
1443
 
@@ -1513,18 +1553,18 @@ class GeologicalModel:
1513
1553
  if self.stratigraphic_column is None:
1514
1554
  logger.warning("No stratigraphic column defined")
1515
1555
  return strat_id
1516
-
1556
+
1517
1557
  s_id = 0
1518
1558
  for g in reversed(self.stratigraphic_column.get_groups()):
1519
1559
  feature_id = self.feature_name_index.get(g.name, -1)
1520
1560
  if feature_id >= 0:
1521
1561
  vals = self.features[feature_id].evaluate_value(xyz)
1522
1562
  for u in g.units:
1523
- strat_id[np.logical_and(vals < u.max, vals > u.min)] = s_id
1563
+ strat_id[np.logical_and(vals < u.max(), vals > u.min())] = s_id
1524
1564
  s_id += 1
1525
1565
  if feature_id == -1:
1526
1566
  logger.error(f"Model does not contain {g.name}")
1527
-
1567
+
1528
1568
  return strat_id
1529
1569
 
1530
1570
  def evaluate_model_gradient(self, points: np.ndarray, *, scale: bool = True) -> np.ndarray:
@@ -1546,16 +1586,13 @@ class GeologicalModel:
1546
1586
  if scale:
1547
1587
  xyz = self.scale(xyz, inplace=False)
1548
1588
  grad = np.zeros(xyz.shape)
1549
- for group in reversed(self.stratigraphic_column.keys()):
1550
- if group == "faults":
1551
- continue
1552
- feature_id = self.feature_name_index.get(group, -1)
1589
+ for g in reversed(self.stratigraphic_column.get_groups()):
1590
+ feature_id = self.feature_name_index.get(g.name, -1)
1553
1591
  if feature_id >= 0:
1554
- feature = self.features[feature_id]
1555
- gradt = feature.evaluate_gradient(xyz)
1592
+ gradt = self.features[feature_id].evaluate_gradient(xyz)
1556
1593
  grad[~np.isnan(gradt).any(axis=1)] = gradt[~np.isnan(gradt).any(axis=1)]
1557
1594
  if feature_id == -1:
1558
- logger.error(f"Model does not contain {group}")
1595
+ logger.error(f"Model does not contain {g.name}")
1559
1596
 
1560
1597
  return grad
1561
1598
 
@@ -1725,16 +1762,7 @@ class GeologicalModel:
1725
1762
  ids : list
1726
1763
  list of unique stratigraphic ids, featurename, unit name and min and max scalar values
1727
1764
  """
1728
- ids = []
1729
- if self.stratigraphic_column is None:
1730
- logger.warning('No stratigraphic column defined')
1731
- return ids
1732
- for group in self.stratigraphic_column.keys():
1733
- if group == "faults":
1734
- continue
1735
- for name, series in self.stratigraphic_column[group].items():
1736
- ids.append([series["id"], group, name, series['min'], series['max']])
1737
- return ids
1765
+ return self.stratigraphic_column.get_stratigraphic_ids()
1738
1766
 
1739
1767
  def get_fault_surfaces(self, faults: List[str] = []):
1740
1768
  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):
@@ -39,24 +39,59 @@ class StratigraphicColumnElement:
39
39
  self.uuid = uuid
40
40
 
41
41
 
42
- class StratigraphicUnit(StratigraphicColumnElement):
42
+ class StratigraphicUnit(StratigraphicColumnElement, Observable['StratigraphicUnit']):
43
43
  """
44
44
  A class to represent a stratigraphic unit.
45
45
  """
46
46
 
47
- def __init__(self, *, uuid=None, name=None, colour=None, thickness=None, data=None):
47
+ def __init__(self, *, uuid=None, name=None, colour=None, thickness=None, data=None, id=None):
48
48
  """
49
49
  Initializes the StratigraphicUnit with a name and an optional description.
50
50
  """
51
- super().__init__(uuid)
51
+ StratigraphicColumnElement.__init__(self, uuid)
52
+ Observable.__init__(self)
52
53
  self.name = name
53
54
  if colour is None:
54
55
  colour = rng.random(3)
55
56
  self.colour = colour
56
- self.thickness = thickness
57
+ self._thickness = thickness
57
58
  self.data = data
58
59
  self.element_type = StratigraphicColumnElementType.UNIT
59
-
60
+ self.id = id
61
+ self.min_value = None # Minimum scalar field value for the unit
62
+ self.max_value = None # Maximum scalar field value for the unit
63
+ @property
64
+ def id(self):
65
+ return self._id
66
+ @property
67
+ def thickness(self):
68
+ return self._thickness
69
+ @thickness.setter
70
+ def thickness(self, value):
71
+ """
72
+ Sets the thickness of the unit.
73
+ """
74
+ self._thickness = value
75
+ self.notify('unit/thickness_updated', unit=self)
76
+ @id.setter
77
+ def id(self, value):
78
+ """
79
+ Sets the ID of the unit.
80
+ """
81
+ if not isinstance(value, int):
82
+ raise TypeError("ID must be an integer")
83
+ self._id = value
84
+ self.notify('unit/id_updated', unit=self)
85
+ def min(self):
86
+ """
87
+ Returns the minimum value of the unit.
88
+ """
89
+ return self.min_value if self.min_value is not None else 0
90
+ def max(self):
91
+ """
92
+ Returns the maximum value of the unit.
93
+ """
94
+ return self.max_value if self.max_value is not None else np.inf
60
95
  def to_dict(self):
61
96
  """
62
97
  Converts the stratigraphic unit to a dictionary representation.
@@ -64,7 +99,7 @@ class StratigraphicUnit(StratigraphicColumnElement):
64
99
  colour = self.colour
65
100
  if isinstance(colour, np.ndarray):
66
101
  colour = colour.astype(float).tolist()
67
- 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}
68
103
 
69
104
  @classmethod
70
105
  def from_dict(cls, data):
@@ -77,7 +112,7 @@ class StratigraphicUnit(StratigraphicColumnElement):
77
112
  colour = data.get("colour")
78
113
  thickness = data.get("thickness", None)
79
114
  uuid = data.get("uuid", None)
80
- 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))
81
116
 
82
117
  def __str__(self):
83
118
  """
@@ -164,20 +199,37 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
164
199
  Initializes the StratigraphicColumn with a name and a list of layers.
165
200
  """
166
201
  super().__init__()
167
- self.order = [StratigraphicUnit(name='Basement', colour='grey', thickness=np.inf),StratigraphicUnconformity(name='Base Unconformity', unconformity_type=UnconformityType.ERODE)]
202
+ self.order = []
203
+ self.add_basement()
168
204
  self.group_mapping = {}
169
- def clear(self,basement=True):
205
+
206
+ def get_new_id(self):
207
+ """
208
+ Generates a new unique ID for a stratigraphic unit.
209
+ """
210
+ if not self.order:
211
+ return 0
212
+ return max([u.id for u in self.order if isinstance(u, StratigraphicUnit)], default=0) + 1
213
+ def add_basement(self):
214
+ self.add_unit(name='Basement', colour='grey', thickness=np.inf)
215
+ self.add_unconformity(
216
+ name='Base Unconformity', unconformity_type=UnconformityType.ERODE
217
+ )
218
+ def clear(self, basement=True):
170
219
  """
171
220
  Clears the stratigraphic column, removing all elements.
172
221
  """
173
222
  if basement:
174
- self.order = [StratigraphicUnit(name='Basement', colour='grey', thickness=np.inf),StratigraphicUnconformity(name='Base Unconformity', unconformity_type=UnconformityType.ERODE)]
223
+ self.add_basement()
224
+
175
225
  else:
176
226
  self.order = []
177
227
  self.group_mapping = {}
178
228
  self.notify('column_cleared')
179
- def add_unit(self, name,*, colour=None, thickness=None, where='top'):
180
- unit = StratigraphicUnit(name=name, colour=colour, thickness=thickness)
229
+ def add_unit(self, name,*, colour=None, thickness=None, where='top',id=None):
230
+ if id is None:
231
+ id = self.get_new_id()
232
+ unit = StratigraphicUnit(name=name, colour=colour, thickness=thickness, id=id)
181
233
 
182
234
  if where == 'top':
183
235
  self.order.append(unit)
@@ -185,7 +237,9 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
185
237
  self.order.insert(0, unit)
186
238
  else:
187
239
  raise ValueError("Invalid 'where' argument. Use 'top' or 'bottom'.")
240
+ unit.attach(self.update_unit_values,'unit/*')
188
241
  self.notify('unit_added', unit=unit)
242
+ self.update_unit_values() # Update min and max values after adding a unit
189
243
  return unit
190
244
 
191
245
  def remove_unit(self, uuid):
@@ -197,7 +251,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
197
251
  del self.order[i]
198
252
  self.notify('unit_removed', uuid=uuid)
199
253
  return True
200
-
254
+
201
255
  return False
202
256
 
203
257
  def add_unconformity(self, name, *, unconformity_type=UnconformityType.ERODE, where='top' ):
@@ -249,7 +303,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
249
303
  if element.uuid == uuid:
250
304
  return element
251
305
  raise KeyError(f"No element found with uuid: {uuid}")
252
-
306
+
253
307
  def get_group_for_unit_name(self, unit_name:str) -> Optional[StratigraphicGroup]:
254
308
  """
255
309
  Retrieves the group for a given unit name.
@@ -300,7 +354,15 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
300
354
  if group:
301
355
  groups.append(group)
302
356
  return groups
357
+ def get_stratigraphic_ids(self) -> List[List[str]]:
358
+ ids = []
359
+ for group in self.get_groups():
360
+ if group == "faults":
361
+ continue
303
362
 
363
+ for unit in group.units:
364
+ ids.append([unit.id, group, unit.name, unit.min(), unit.max()])
365
+ return ids
304
366
  def get_unitname_groups(self):
305
367
  groups = self.get_groups()
306
368
  groups_list = []
@@ -309,7 +371,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
309
371
  group = [u.name for u in g.units if isinstance(u, StratigraphicUnit)]
310
372
  groups_list.append(group)
311
373
  return groups_list
312
-
374
+
313
375
  def get_group_unit_pairs(self) -> List[Tuple[str,str]]:
314
376
  """
315
377
  Returns a list of tuples containing group names and unit names.
@@ -341,6 +403,20 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
341
403
  self.__getitem__(uuid) for uuid in new_order if self.__getitem__(uuid) is not None
342
404
  ]
343
405
  self.notify('order_updated', new_order=self.order)
406
+ self.update_unit_values() # Update min and max values after updating the order
407
+ def update_unit_values(self, *, observable: Optional["Observable"] = None, event: Optional[str]= None):
408
+ """
409
+ Updates the min and max values for each unit based on their position in the column.
410
+ """
411
+ # If the event is not 'unit/*', skip the update
412
+ if event is not None and event != 'unit/*':
413
+ return
414
+ cumulative_thickness = 0
415
+ for element in self.order:
416
+ if isinstance(element, StratigraphicUnit):
417
+ element.min_value = cumulative_thickness
418
+ element.max_value = cumulative_thickness + (element.thickness or 0)
419
+ cumulative_thickness = element.max_value
344
420
 
345
421
  def update_element(self, unit_data: Dict):
346
422
  """
@@ -360,6 +436,7 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
360
436
  unit_data.get('unconformity_type', element.unconformity_type.value)
361
437
  )
362
438
  self.notify('element_updated', element=element)
439
+ self.update_unit_values() # Update min and max values after updating an element
363
440
 
364
441
  def __str__(self):
365
442
  """
@@ -498,3 +575,29 @@ class StratigraphicColumn(Observable['StratigraphicColumn']):
498
575
  ax.axis("off")
499
576
 
500
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
@@ -0,0 +1,13 @@
1
+ from LoopStructural.modelling.features.fold import FoldEvent
2
+ from LoopStructural.modelling.features.builders import FoldedFeatureBuilder
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
@@ -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
 
@@ -56,7 +56,22 @@ class FoldedFeatureBuilder(GeologicalFeatureBuilder):
56
56
  self.svario = svario
57
57
  self.axis_profile_type = axis_profile_type
58
58
  self.limb_profile_type = limb_profile_type
59
-
59
+ @classmethod
60
+ def from_feature_builder(cls, feature_builder, fold, **kwargs):
61
+ """Create a FoldedFeatureBuilder from an existing feature builder"""
62
+ if not isinstance(feature_builder, GeologicalFeatureBuilder):
63
+ logger.error(f'Feature builder is {type(feature_builder)} not GeologicalFeatureBuilder')
64
+ raise TypeError("feature_builder must be an instance of GeologicalFeatureBuilder")
65
+ builder = cls(
66
+ interpolatortype='DFI',
67
+ bounding_box=feature_builder.model.bounding_box,
68
+ fold=fold,
69
+ nelements=feature_builder.interpolator.n_elements,
70
+ name=feature_builder.name,
71
+ **kwargs
72
+ )
73
+ builder.data = feature_builder.data
74
+ return builder
60
75
  @property
61
76
  def fold_axis_rotation(self):
62
77
  if self.fold.fold_axis_rotation is None:
@@ -168,6 +168,9 @@ class GeologicalFeatureBuilder(BaseBuilder):
168
168
  -------
169
169
 
170
170
  """
171
+ logger.info('Adding data to interpolator for {}'.format(self.name))
172
+ logger.info(f"Data shape: {self.data.shape}")
173
+ logger.info(f'Constrained: {constrained}, force_constrained: {force_constrained}')
171
174
  if self.data_added:
172
175
  logger.info("Data already added to interpolator")
173
176
  return
@@ -4,3 +4,4 @@ from ._fold import FoldEvent
4
4
  from ._svariogram import SVariogram
5
5
  from ._fold_rotation_angle_feature import FoldRotationAngleFeature
6
6
  from ._foldframe import FoldFrame
7
+ from ._fold import FoldEvent
@@ -189,6 +189,9 @@ class SVariogram:
189
189
  # find the extrema of the average curve
190
190
  res = find_peaks_and_troughs(np.array(averagex), np.array(averagey))
191
191
  px2, py2 = res
192
+ logger.info(f"Found {len(px2)} peaks and troughs in the s-variogram")
193
+ for i in range(len(px2)):
194
+ logger.info(f"Peak {i}: {px2[i]} {py2[i]}")
192
195
  wl1 = 0.0
193
196
  wl1py = 0.0
194
197
  for i in range(len(px)):