LoopStructural 1.0.4__zip → 1.0.71.dev0__zip

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.
Files changed (158) hide show
  1. Miniconda/envs/loop/Lib/site-packages/LoopStructural/__init__.py +12 -7
  2. Miniconda/envs/loop/Lib/site-packages/LoopStructural/__pycache__/__init__.cpython-36.pyc +0 -0
  3. Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/__pycache__/{__init__.cpython-37.pyc → __init__.cpython-36.pyc} +0 -0
  4. Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/__pycache__/{_base.cpython-37.pyc → _base.cpython-36.pyc} +0 -0
  5. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__init__.py +3 -0
  6. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/__init__.cpython-36.pyc +0 -0
  7. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/base_structured_3d_support.cpython-36.pyc +0 -0
  8. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/discrete_fold_interpolator.cpython-36.pyc +0 -0
  9. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/discrete_interpolator.cpython-36.pyc +0 -0
  10. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/finite_difference_interpolator.cpython-36.pyc +0 -0
  11. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/geological_interpolator.cpython-36.pyc +0 -0
  12. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/operator.cpython-36.pyc +0 -0
  13. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/piecewiselinear_interpolator.cpython-36.pyc +0 -0
  14. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/structured_grid.cpython-36.pyc +0 -0
  15. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/structured_tetra.cpython-36.pyc +0 -0
  16. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/surfe_wrapper.cpython-36.pyc +0 -0
  17. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/base_structured_3d_support.py +101 -0
  18. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/cython/__pycache__/__init__.cpython-36.pyc +0 -0
  19. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/cython/dsi_helper.c +3899 -2455
  20. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/cython/dsi_helper.cp36-win_amd64.pyd +0 -0
  21. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/discrete_fold_interpolator.py +53 -22
  22. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/discrete_interpolator.py +61 -28
  23. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/finite_difference_interpolator.py +68 -11
  24. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/geological_interpolator.py +8 -1
  25. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/operator.py +2 -1
  26. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/piecewiselinear_interpolator.py +97 -8
  27. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/structured_grid.py +25 -69
  28. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/structured_tetra.py +86 -43
  29. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/surfe_wrapper.py +4 -3
  30. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/__pycache__/{__init__.cpython-37.pyc → __init__.cpython-36.pyc} +0 -0
  31. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/core/__pycache__/__init__.cpython-36.pyc +0 -0
  32. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/core/__pycache__/geological_model.cpython-36.pyc +0 -0
  33. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/core/__pycache__/geological_model_graph.cpython-36.pyc +0 -0
  34. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/core/__pycache__/stratigraphic_column.cpython-36.pyc +0 -0
  35. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/core/geological_model.py +303 -150
  36. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/core/geological_model_graph.py +881 -0
  37. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/core/stratigraphic_column.py +5 -0
  38. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__init__.py +1 -0
  39. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__pycache__/__init__.cpython-36.pyc +0 -0
  40. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__pycache__/fault_builder.cpython-36.pyc +0 -0
  41. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__pycache__/fault_function.cpython-36.pyc +0 -0
  42. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__pycache__/fault_function_feature.cpython-36.pyc +0 -0
  43. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__pycache__/fault_segment.cpython-36.pyc +0 -0
  44. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/fault_builder.py +127 -0
  45. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/fault_function.py +2 -1
  46. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/fault_function_feature.py +2 -1
  47. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/fault_segment.py +30 -3
  48. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__init__.py +1 -0
  49. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/__init__.cpython-36.pyc +0 -0
  50. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/cross_product_geological_feature.cpython-36.pyc +0 -0
  51. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/geological_feature.cpython-36.pyc +0 -0
  52. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/geological_feature_builder.cpython-36.pyc +0 -0
  53. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/lambda_geological_feature.cpython-36.pyc +0 -0
  54. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/{region_feature.cpython-37.pyc → region_feature.cpython-36.pyc} +0 -0
  55. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/structural_frame.cpython-36.pyc +0 -0
  56. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/structural_frame_builder.cpython-36.pyc +0 -0
  57. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/unconformity_feature.cpython-36.pyc +0 -0
  58. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/cross_product_geological_feature.py +18 -5
  59. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/geological_feature.py +10 -44
  60. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/geological_feature_builder.py +127 -43
  61. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/lambda_geological_feature.py +31 -0
  62. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/structural_frame.py +28 -11
  63. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/structural_frame_builder.py +25 -15
  64. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/unconformity_feature.py +6 -1
  65. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/{__init__.cpython-37.pyc → __init__.cpython-36.pyc} +0 -0
  66. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/fold.cpython-36.pyc +0 -0
  67. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/fold_rotation_angle.cpython-36.pyc +0 -0
  68. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/fold_rotation_angle_feature.cpython-36.pyc +0 -0
  69. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/foldframe.cpython-36.pyc +0 -0
  70. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/svariogram.cpython-36.pyc +0 -0
  71. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/fold.py +13 -5
  72. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/fold_rotation_angle.py +5 -4
  73. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/fold_rotation_angle_feature.py +2 -1
  74. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/foldframe.py +6 -5
  75. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/svariogram.py +2 -1
  76. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__init__.py +5 -1
  77. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/__init__.cpython-36.pyc +0 -0
  78. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/bounding_box.cpython-36.pyc +0 -0
  79. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/exceptions.cpython-36.pyc +0 -0
  80. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/helper.cpython-36.pyc +0 -0
  81. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/logging.cpython-36.pyc +0 -0
  82. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/map2loop.cpython-36.pyc +0 -0
  83. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/regions.cpython-36.pyc +0 -0
  84. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/utils.cpython-36.pyc +0 -0
  85. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/bounding_box.py +21 -0
  86. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/exceptions.py +2 -1
  87. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/helper.py +5 -1
  88. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/logging.py +60 -0
  89. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/map2loop.py +47 -19
  90. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/regions.py +11 -0
  91. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/utils.py +2 -53
  92. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/{__init__.cpython-37.pyc → __init__.cpython-36.pyc} +0 -0
  93. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/map_viewer.cpython-36.pyc +0 -0
  94. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/model_plotter.cpython-36.pyc +0 -0
  95. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/model_visualisation.cpython-36.pyc +0 -0
  96. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/rotation_angle_plotter.cpython-36.pyc +0 -0
  97. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/{sphinx_scraper.cpython-37.pyc → sphinx_scraper.cpython-36.pyc} +0 -0
  98. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/stratigraphic_column.cpython-36.pyc +0 -0
  99. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/map_viewer.py +17 -2
  100. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/model_plotter.py +2 -1
  101. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/model_visualisation.py +152 -84
  102. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/rotation_angle_plotter.py +2 -1
  103. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/stratigraphic_column.py +60 -0
  104. Miniconda/envs/loop/Lib/site-packages/{LoopStructural-1.0.4-py3.7.egg-info → LoopStructural-1.0.71.dev0-py3.6.egg-info}/PKG-INFO +1 -1
  105. Miniconda/envs/loop/Lib/site-packages/{LoopStructural-1.0.4-py3.7.egg-info → LoopStructural-1.0.71.dev0-py3.6.egg-info}/SOURCES.txt +10 -5
  106. Miniconda/envs/loop/Lib/site-packages/{LoopStructural-1.0.4-py3.7.egg-info → LoopStructural-1.0.71.dev0-py3.6.egg-info}/requires.txt +1 -1
  107. Miniconda/envs/loop/Lib/site-packages/tests/__pycache__/__init__.cpython-36.pyc +0 -0
  108. Miniconda/envs/loop/Lib/site-packages/LoopStructural/__pycache__/__init__.cpython-37.pyc +0 -0
  109. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/__init__.cpython-37.pyc +0 -0
  110. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/discrete_fold_interpolator.cpython-37.pyc +0 -0
  111. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/discrete_interpolator.cpython-37.pyc +0 -0
  112. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/finite_difference_interpolator.cpython-37.pyc +0 -0
  113. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/geological_interpolator.cpython-37.pyc +0 -0
  114. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/operator.cpython-37.pyc +0 -0
  115. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/piecewiselinear_interpolator.cpython-37.pyc +0 -0
  116. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/structured_grid.cpython-37.pyc +0 -0
  117. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/structured_tetra.cpython-37.pyc +0 -0
  118. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/surfe_wrapper.cpython-37.pyc +0 -0
  119. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/cython/__pycache__/__init__.cpython-37.pyc +0 -0
  120. Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/cython/dsi_helper.cp37-win_amd64.pyd +0 -0
  121. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/core/__pycache__/__init__.cpython-37.pyc +0 -0
  122. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/core/__pycache__/geological_model.cpython-37.pyc +0 -0
  123. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__pycache__/__init__.cpython-37.pyc +0 -0
  124. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__pycache__/fault_function.cpython-37.pyc +0 -0
  125. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__pycache__/fault_function_feature.cpython-37.pyc +0 -0
  126. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__pycache__/fault_segment.cpython-37.pyc +0 -0
  127. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/__init__.cpython-37.pyc +0 -0
  128. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/cross_product_geological_feature.cpython-37.pyc +0 -0
  129. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/geological_feature.cpython-37.pyc +0 -0
  130. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/geological_feature_builder.cpython-37.pyc +0 -0
  131. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/structural_frame.cpython-37.pyc +0 -0
  132. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/structural_frame_builder.cpython-37.pyc +0 -0
  133. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/unconformity_feature.cpython-37.pyc +0 -0
  134. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/fold.cpython-37.pyc +0 -0
  135. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/fold_rotation_angle.cpython-37.pyc +0 -0
  136. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/fold_rotation_angle_feature.cpython-37.pyc +0 -0
  137. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/foldframe.cpython-37.pyc +0 -0
  138. Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/svariogram.cpython-37.pyc +0 -0
  139. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/__init__.cpython-37.pyc +0 -0
  140. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/exceptions.cpython-37.pyc +0 -0
  141. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/helper.cpython-37.pyc +0 -0
  142. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/map2loop.cpython-37.pyc +0 -0
  143. Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/utils.cpython-37.pyc +0 -0
  144. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/map_viewer.cpython-37.pyc +0 -0
  145. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/model_plotter.cpython-37.pyc +0 -0
  146. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/model_visualisation.cpython-37.pyc +0 -0
  147. Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/rotation_angle_plotter.cpython-37.pyc +0 -0
  148. Miniconda/envs/loop/Lib/site-packages/tests/__pycache__/__init__.cpython-37.pyc +0 -0
  149. Miniconda/envs/loop/Lib/site-packages/tests/__pycache__/test_faults.cpython-37.pyc +0 -0
  150. Miniconda/envs/loop/Lib/site-packages/tests/__pycache__/test_fold.cpython-37.pyc +0 -0
  151. Miniconda/envs/loop/Lib/site-packages/tests/__pycache__/test_interpolator.cpython-37.pyc +0 -0
  152. Miniconda/envs/loop/Lib/site-packages/tests/__pycache__/test_refolded.cpython-37.pyc +0 -0
  153. Miniconda/envs/loop/Lib/site-packages/tests/test_faults.py +0 -17
  154. Miniconda/envs/loop/Lib/site-packages/tests/test_fold.py +0 -57
  155. Miniconda/envs/loop/Lib/site-packages/tests/test_interpolator.py +0 -88
  156. Miniconda/envs/loop/Lib/site-packages/tests/test_refolded.py +0 -22
  157. /Miniconda/envs/loop/Lib/site-packages/{LoopStructural-1.0.4-py3.7.egg-info → LoopStructural-1.0.71.dev0-py3.6.egg-info}/dependency_links.txt +0 -0
  158. /Miniconda/envs/loop/Lib/site-packages/{LoopStructural-1.0.4-py3.7.egg-info → LoopStructural-1.0.71.dev0-py3.6.egg-info}/top_level.txt +0 -0
@@ -0,0 +1,881 @@
1
+ """
2
+ Main entry point for creating a geological model
3
+ """
4
+ import logging
5
+
6
+ import numpy as np
7
+ import pandas as pd
8
+ import networkx as nx
9
+
10
+ from LoopStructural.datasets import normal_vector_headers
11
+ from LoopStructural.interpolators.discrete_fold_interpolator import \
12
+ DiscreteFoldInterpolator as DFI
13
+ from LoopStructural.interpolators.finite_difference_interpolator import \
14
+ FiniteDifferenceInterpolator as FDI
15
+ from LoopStructural.interpolators.piecewiselinear_interpolator import \
16
+ PiecewiseLinearInterpolator as PLI
17
+
18
+ try:
19
+ from LoopStructural.interpolators.surfe_wrapper import \
20
+ SurfeRBFInterpolator as Surfe
21
+
22
+ surfe = True
23
+
24
+ except ImportError:
25
+ surfe = False
26
+
27
+ from LoopStructural.interpolators.structured_grid import StructuredGrid
28
+ from LoopStructural.interpolators.structured_tetra import TetMesh
29
+ from LoopStructural.modelling.fault.fault_segment import FaultSegment
30
+ from LoopStructural.modelling.features import (GeologicalFeatureInterpolator,
31
+ RegionFeature,
32
+ StructuralFrameBuilder,
33
+ UnconformityFeature)
34
+ from LoopStructural.modelling.fold import FoldRotationAngle
35
+ from LoopStructural.modelling.fold.fold import FoldEvent
36
+ from LoopStructural.modelling.fold.foldframe import FoldFrame
37
+ from LoopStructural.utils.exceptions import LoopBaseException
38
+ from LoopStructural.utils.helper import (all_heading, gradient_vec_names,
39
+ strike_dip_vector)
40
+
41
+ from LoopStructural.utils import getLogger, log_to_file
42
+ logger = getLogger(__name__)
43
+ if not surfe:
44
+ logger.warning("Cannot import Surfe")
45
+
46
+
47
+ def _calculate_average_intersection(series_builder, fold_frame, fold,
48
+ **kwargs):
49
+ """
50
+
51
+ Parameters
52
+ ----------
53
+ series_builder
54
+ fold_frame
55
+ fold
56
+
57
+ Returns
58
+ -------
59
+
60
+ """
61
+ l2 = fold_frame.calculate_intersection_lineation(
62
+ series_builder)
63
+ fold.fold_axis = np.mean(l2, axis=0)
64
+
65
+
66
+ class GeologicalModel:
67
+ """
68
+ A geological model is the recipe for building a 3D model and can include
69
+ the rescaling of the model between 0 and 1.
70
+
71
+ Attributes
72
+ ----------
73
+ features : list
74
+ Contains all features youngest to oldest
75
+ feature_name_index : dict
76
+ maps feature name to the list index of the features
77
+ data : pandas dataframe
78
+ the dataframe used for building the geological model
79
+ nsteps : tuple/np.array(3,dtype=int)
80
+ the number of steps x,y,z to evaluate the model
81
+ origin : tuple/np.array(3,dtype=doubles)
82
+ the origin of the model box
83
+ parameters : dict
84
+ a dictionary tracking the parameters used to build the model
85
+ scale_factor : double
86
+ the scale factor used to rescale the model
87
+
88
+
89
+ """
90
+ def __init__(self, origin, maximum, rescale=True, nsteps=(40, 40, 40),
91
+ reuse_supports=False, logfile=None, loglevel='info'):
92
+ """
93
+ Parameters
94
+ ----------
95
+ origin : numpy array
96
+ specifying the origin of the model
97
+ maximum : numpy array
98
+ specifying the maximum extent of the model
99
+ rescale : bool
100
+ whether to rescale the model to between 0/1
101
+
102
+ Examples
103
+ --------
104
+ Demo data
105
+
106
+ >>> from LoopStructural.datasets import load_claudius
107
+ >>> from LoopStructural import GeologicalModel
108
+
109
+ >>> data, bb = load_claudius()
110
+
111
+ >>> model = GeologicalModel(bb[:,0],bb[:,1]
112
+ >>> model.set_model_data(data)
113
+ >>> model.create_and_add_foliation('strati')
114
+
115
+ >>> y = np.linspace(model.bounding_box[0, 1], model.bounding_box[1, 1],
116
+ nsteps[1])
117
+ >>> z = np.linspace(model.bounding_box[1, 2], model.bounding_box[0, 2],
118
+ nsteps[2])
119
+ >>> xx, yy, zz = np.meshgrid(x, y, z, indexing='ij')
120
+ >>> xyz = np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T
121
+ >>> model.evaluate_feature_value('strati',xyz,scale=False)
122
+
123
+
124
+ """
125
+ if logfile:
126
+ self.logfile = logfile
127
+ log_to_file(logfile,loglevel)
128
+
129
+ logger.info('Initialising geological model')
130
+ self.features = []
131
+ self.feature_name_index = {}
132
+ self.data = None
133
+ self.nsteps = nsteps
134
+ self._str = 'Instance of LoopStructural.GeologicalModel \n'
135
+ self._str += '------------------------------------------ \n'
136
+ # we want to rescale the model area so that the maximum length is
137
+ # 1
138
+ self.origin = np.array(origin).astype(float)
139
+ originstr = 'Model origin: {} {} {}'.format(self.origin[0],self.origin[1],self.origin[2])
140
+ logger.info(originstr)
141
+ self._str+=originstr+'\n'
142
+ self.maximum = np.array(maximum).astype(float)
143
+ maximumstr = 'Model maximum: {} {} {}'.format(self.maximum[0],self.maximum[1],self.maximum[2])
144
+ logger.info(maximumstr)
145
+ self._str+=maximumstr+'\n'
146
+
147
+ lengths = self.maximum - self.origin
148
+ self.scale_factor = 1.
149
+ self.bounding_box = np.zeros((2, 3))
150
+ self.bounding_box[1, :] = self.maximum - self.origin
151
+ self.bounding_box[1, :] = self.maximum - self.origin
152
+ if rescale:
153
+ self.scale_factor = np.max(lengths)
154
+ logger.info('Rescaling model using scale factor {}'.format(self.scale_factor))
155
+ self._str+='Model rescale factor: {} \n'.format(self.scale_factor)
156
+ self._str+='The model contains {} GeologicalFeatures \n'.format(len(self.features))
157
+ self._str+=''
158
+ self._str += '------------------------------------------ \n'
159
+ self._str += ''
160
+ self.bounding_box /= self.scale_factor
161
+ self.support = {}
162
+ self.reuse_supports = reuse_supports
163
+ if self.reuse_supports:
164
+ logger.warning("Supports are shared between geological features \n"
165
+ "this may cause unexpected behaviour and should only\n"
166
+ "be use by advanced users")
167
+ logger.info('Reusing interpolation supports: {}'.format(self.reuse_supports))
168
+ self.stratigraphic_column = None
169
+ self.feature_graph = nx.DiGraph()
170
+ self.parameters = {'features': [], 'model': {'bounding_box': self.origin.tolist() + self.maximum.tolist(),
171
+ 'rescale': rescale,
172
+ 'nsteps': nsteps,
173
+ 'reuse_supports': reuse_supports}}
174
+
175
+ def __str__(self):
176
+ return self._str
177
+
178
+ def _ipython_key_completions_(self):
179
+ return self.feature_name_index.keys()
180
+
181
+ @classmethod
182
+ def from_map2loop_directory(cls, m2l_directory,**kwargs):
183
+ """Alternate constructor for a geological model using m2l output
184
+
185
+ Uses the information saved in the map2loop files to build a geological model.
186
+ You can specify kwargs for building foliation using foliation_params and for
187
+ faults using fault_params. faults is a flag that allows for the faults to be skipped.
188
+
189
+ Parameters
190
+ ----------
191
+ m2l_directory : string
192
+ path to map2loop directory
193
+
194
+ Returns
195
+ -------
196
+ (GeologicalModel, dict)
197
+ the created geological model and a dictionary of the map2loop data
198
+ """
199
+ from LoopStructural.utils import build_model, process_map2loop
200
+ logger.info('LoopStructural model initialised from m2l directory: {}'.format(m2l_directory))
201
+ m2lflags = kwargs.pop('m2lflags',{})
202
+ m2l_data = process_map2loop(m2l_directory,m2lflags)
203
+ return build_model(m2l_data,**kwargs), m2l_data
204
+
205
+ @classmethod
206
+ def from_file(cls, file):
207
+ """Load a geological model from file
208
+
209
+ Parameters
210
+ ----------
211
+ file : string
212
+ path to the file
213
+
214
+ Returns
215
+ -------
216
+ GeologicalModel
217
+ the geological model object
218
+ """
219
+ try:
220
+ import dill as pickle
221
+ except ImportError:
222
+ logger.error("Cannot import from file, dill not installed")
223
+ return None
224
+ model = pickle.load(open(file,'rb'))
225
+ if type(model) == GeologicalModel:
226
+ logger.info('GeologicalModel initialised from file')
227
+ return model
228
+ else:
229
+ logger.error('{} does not contain a geological model'.format(file))
230
+ return None
231
+
232
+ def __getitem__(self, feature_name):
233
+ """Accessor for feature in features using feature_name_index
234
+
235
+ Parameters
236
+ ----------
237
+ feature_name : string
238
+ name of the feature to return
239
+ """
240
+ return self.get_feature_by_name(feature_name)
241
+
242
+ def feature_names(self):
243
+ return self.feature_name_index.keys()
244
+
245
+ def fault_names(self):
246
+ pass
247
+
248
+ def check_inialisation(self):
249
+ if self.data is None:
250
+ logger.error("Data not associated with GeologicalModel. Run set_data")
251
+ return False
252
+
253
+ def to_file(self, file):
254
+ """Save a model to a pickle file requires dill
255
+
256
+ Parameters
257
+ ----------
258
+ file : string
259
+ path to file location
260
+ """
261
+ try:
262
+ import dill as pickle
263
+ except ImportError:
264
+ logger.error("Cannot write to file, dill not installed \n"
265
+ "pip install dill")
266
+ return
267
+ try:
268
+ logger.info('Writing GeologicalModel to: {}'.format(file))
269
+ pickle.dump(self,open(file,'wb'))
270
+ except pickle.PicklingError:
271
+ logger.error('Error saving file')
272
+
273
+ def _add_feature(self, feature):
274
+ """
275
+ Add a feature to the model stack
276
+
277
+ Parameters
278
+ ----------
279
+ feature : GeologicalFeature
280
+ the geological feature to add
281
+
282
+ """
283
+
284
+ if feature.name in self.feature_name_index:
285
+ logger.info("Feature %s already exists at %i, overwriting" %
286
+ (feature.name, self.feature_name_index[feature.name]))
287
+ self.features[self.feature_name_index[feature.name]] = feature
288
+ else:
289
+ self._str += 'GeologicalFeature: {} of type - {} \n'.format(feature.name,feature.type)
290
+ self.features.append(feature)
291
+ self.feature_name_index[feature.name] = len(self.features) - 1
292
+ logger.info("Adding %s to model at location %i" % (
293
+ feature.name, len(self.features)))
294
+ # self._add_domain_fault_above(feature)
295
+ # self._add_unconformity_above(feature)
296
+ feature.set_model(self)
297
+
298
+ def _add_faults(self, feature_builder, features=None):
299
+ """Adds all existing faults to a geological feature builder
300
+
301
+ Parameters
302
+ ----------
303
+ feature_builder : GeologicalFeatureInterpolator/StructuralFrameBuilder
304
+ The feature buider to add the faults to
305
+ features : list, optional
306
+ A specific list of features rather than all features in the model
307
+ Returns
308
+ -------
309
+
310
+ """
311
+ if features is None:
312
+ features = self.features
313
+ for f in reversed(features):
314
+ if f.type == 'fault':
315
+ feature_builder.add_fault(f)
316
+ # if f.type == 'unconformity':
317
+ # break
318
+
319
+ def data_for_feature(self,feature_name):
320
+ return self.data.loc[self.data['feature_name'] == feature_name,:]
321
+
322
+ def set_model_data(self, data):
323
+ """
324
+ Set the data array for the model
325
+
326
+ Parameters
327
+ ----------
328
+ data : pandas data frame
329
+ with column headers corresponding to the
330
+ type, X, Y, Z, nx, ny, nz, val, strike, dip, dip_dir, plunge,
331
+ plunge_dir, azimuth
332
+
333
+ Returns
334
+ -------
335
+ Note
336
+ ----
337
+ Type can be any unique identifier for the feature the data point
338
+ 'eg' 'S0', 'S2', 'F1_axis'
339
+ it is then used by the create functions to get the correct data
340
+ """
341
+ if type(data) != pd.DataFrame:
342
+ logger.warning(
343
+ "Data is not a pandas data frame, trying to read data frame "
344
+ "from csv")
345
+ try:
346
+ data = pd.read_csv(data)
347
+ except:
348
+ logger.error("Could not load pandas data frame from data")
349
+ logger.info('Adding data to GeologicalModel with {} data points'.format(len(data)))
350
+ self.data = data.copy()
351
+ self.data['X'] -= self.origin[0]
352
+ self.data['Y'] -= self.origin[1]
353
+ self.data['Z'] -= self.origin[2]
354
+ self.data['X'] /= self.scale_factor
355
+ self.data['Y'] /= self.scale_factor
356
+ self.data['Z'] /= self.scale_factor
357
+ if 'type' in self.data:
358
+ logger.warning("'type' is depreciated replace with 'feature_name' \n")
359
+ self.data.rename(columns={'type':'feature_name'},inplace=True)
360
+ for h in all_heading():
361
+ if h not in self.data:
362
+ self.data[h] = np.nan
363
+ if h == 'w':
364
+ self.data[h] = 1.
365
+ if h == 'coord':
366
+ self.data[h] = 0
367
+
368
+ if 'strike' in self.data and 'dip' in self.data:
369
+ logger.info('Converting strike and dip to vectors')
370
+ mask = np.all(~np.isnan(self.data.loc[:, ['strike', 'dip']]),
371
+ axis=1)
372
+ self.data.loc[mask, gradient_vec_names()] = strike_dip_vector(
373
+ self.data.loc[mask, 'strike'], self.data.loc[mask, 'dip'])
374
+ self.data.drop(['strike', 'dip'], axis=1, inplace=True)
375
+ # self.data.loc
376
+ # if 'nx' in self.data and 'ny' in self.data and 'nz' in self.data:
377
+ # mask = np.all(~np.isnan(self.data.loc[:, ['nx', 'ny','nz']]),
378
+ # axis=1)
379
+ # self.data.loc[mask,['nx', 'ny','nz']] /= self.scale_factor
380
+
381
+ def set_stratigraphic_column(self, stratigraphic_column,cmap='tab20'):
382
+ """
383
+ Adds a stratigraphic column to the model
384
+
385
+ Parameters
386
+ ----------
387
+ stratigraphic_column : dictionary
388
+ cmap : matplotlib.cmap
389
+ Returns
390
+ -------
391
+
392
+ Notes
393
+ -----
394
+ stratigraphic_column is a nested dictionary with the format
395
+ {'group':
396
+ {'series1':
397
+ {'min':0., 'max':10.,'id':0,'colour':}
398
+ }
399
+ }
400
+
401
+ """
402
+ # if the colour for a unit hasn't been specified we can just sample from
403
+ # a colour map e.g. tab20
404
+ logger.info('Adding stratigraphic column to model')
405
+ random_colour = True
406
+ n_units=0
407
+ for g in stratigraphic_column.keys():
408
+ for u in stratigraphic_column[g].keys():
409
+ if 'colour' in stratigraphic_column[g][u]:
410
+ random_colour = False
411
+ break
412
+ n_units+=1
413
+ if random_colour:
414
+ import matplotlib.cm as cm
415
+ cmap = cm.get_cmap(cmap,n_units)
416
+ cmap_colours = cmap.colors
417
+ ci = 0
418
+ for g in stratigraphic_column.keys():
419
+ for u in stratigraphic_column[g].keys():
420
+ stratigraphic_column[g][u]['colour'] = cmap_colours[ci,:]
421
+
422
+ self.stratigraphic_column = stratigraphic_column
423
+
424
+ def get_interpolator(self, interpolatortype='PLI', nelements=1e5,
425
+ buffer=0.2, element_volume = None, **kwargs):
426
+ """
427
+ Returns an interpolator given the arguments, also constructs a
428
+ support for a discrete interpolator
429
+
430
+ Parameters
431
+ ----------
432
+ interpolatortype : string
433
+ define the interpolator type
434
+ nelements : int
435
+ number of elements in the interpolator
436
+ buffer : double or numpy array 3x1
437
+ value(s) between 0,1 specifying the buffer around the bounding box
438
+ data_bb : bool
439
+ whether to use the model boundary or the boundary around
440
+ kwargs : no kwargs used, this just catches any additional arguments
441
+
442
+ Returns
443
+ -------
444
+ """
445
+ # get an interpolator for
446
+ interpolator = None
447
+ bb = np.copy(self.bounding_box)
448
+ # add a buffer to the interpolation domain, this is necessary for
449
+ # faults but also generally a good
450
+ # idea to avoid boundary problems
451
+ # buffer = bb[1, :]
452
+ buffer = (bb[1,:]-bb[0,:])*buffer
453
+ bb[0, :] -= buffer # *(bb[1,:]-bb[0,:])
454
+ bb[1, :] += buffer # *(bb[1,:]-bb[0,:])
455
+ box_vol = (bb[1, 0]-bb[0, 0]) * (bb[1, 1]-bb[0, 1]) * (bb[1, 2]-bb[0, 2])
456
+ if interpolatortype == "PLI":
457
+ if element_volume is None:
458
+ nelements /= 5
459
+ element_volume = box_vol / nelements
460
+ # calculate the step vector of a regular cube
461
+ step_vector = np.zeros(3)
462
+ step_vector[:] = element_volume ** (1. / 3.)
463
+ # step_vector /= np.array([1,1,2])
464
+ # number of steps is the length of the box / step vector
465
+ nsteps = np.ceil((bb[1, :] - bb[0, :]) / step_vector).astype(int)
466
+ # create a structured grid using the origin and number of steps
467
+ if self.reuse_supports:
468
+ mesh_id = 'mesh_{}'.format(nelements)
469
+ mesh = self.support.get(mesh_id,
470
+ TetMesh(origin=bb[0, :], nsteps=nsteps,
471
+ step_vector=step_vector))
472
+ if mesh_id not in self.support:
473
+ self.support[mesh_id] = mesh
474
+ else:
475
+ mesh = TetMesh(origin=bb[0, :], nsteps=nsteps, step_vector=step_vector)
476
+ logger.info("Creating regular tetrahedron mesh with %i elements \n"
477
+ "for modelling using PLI" % (mesh.ntetra))
478
+
479
+ return PLI(mesh)
480
+
481
+ if interpolatortype == 'FDI':
482
+
483
+ # find the volume of one element
484
+ if element_volume is None:
485
+ element_volume = box_vol / nelements
486
+ # calculate the step vector of a regular cube
487
+ step_vector = np.zeros(3)
488
+ step_vector[:] = element_volume ** (1. / 3.)
489
+ # number of steps is the length of the box / step vector
490
+ nsteps = np.ceil((bb[1, :] - bb[0, :]) / step_vector).astype(int)
491
+ if np.any(np.less(nsteps, 3)):
492
+ logger.error("Cannot create interpolator: number of steps is too small")
493
+ return None
494
+ # create a structured grid using the origin and number of steps
495
+ if self.reuse_supports:
496
+ grid_id = 'grid_{}'.format(nelements)
497
+ grid = self.support.get(grid_id, StructuredGrid(origin=bb[0, :],
498
+ nsteps=nsteps,
499
+ step_vector=step_vector))
500
+ if grid_id not in self.support:
501
+ self.support[grid_id] = grid
502
+ else:
503
+ grid = StructuredGrid(origin=bb[0, :], nsteps=nsteps,step_vector=step_vector)
504
+ logger.info("Creating regular grid with %i elements \n"
505
+ "for modelling using FDI" % grid.n_elements)
506
+ return FDI(grid)
507
+
508
+ if interpolatortype == "DFI": # "fold" in kwargs:
509
+ if element_volume is None:
510
+ nelements /= 5
511
+ element_volume = box_vol / nelements
512
+ # calculate the step vector of a regular cube
513
+ step_vector = np.zeros(3)
514
+ step_vector[:] = element_volume ** (1. / 3.)
515
+ # number of steps is the length of the box / step vector
516
+ nsteps = np.ceil((bb[1, :] - bb[0, :]) / step_vector).astype(int)
517
+ # create a structured grid using the origin and number of steps
518
+ mesh = kwargs.get('mesh', TetMesh(origin=bb[0, :], nsteps=nsteps,
519
+ step_vector=step_vector))
520
+ logger.info("Creating regular tetrahedron mesh with %i elements \n"
521
+ "for modelling using DFI" % mesh.ntetra)
522
+ return DFI(mesh, kwargs['fold'])
523
+ if interpolatortype == 'Surfe' or interpolatortype == 'surfe' and \
524
+ surfe:
525
+ method = kwargs.get('method', 'single_surface')
526
+ logger.info("Using surfe interpolator")
527
+ return Surfe(method)
528
+ logger.warning("No interpolator")
529
+ return interpolator
530
+
531
+ def create_and_add_foliation(self, series_surface_data, **kwargs):
532
+ """
533
+ Parameters
534
+ ----------
535
+ series_surface_data : string
536
+ corresponding to the feature_name in the data
537
+ kwargs
538
+
539
+ Returns
540
+ -------
541
+ feature : GeologicalFeature
542
+ the created geological feature
543
+ """
544
+ if self.check_inialisation() == False:
545
+ return False
546
+ interpolator = self.get_interpolator(**kwargs)
547
+ series_builder = GeologicalFeatureInterpolator(interpolator,
548
+ name=series_surface_data,
549
+ **kwargs)
550
+ # add data
551
+ series_data = self.data[self.data['feature_name'] == series_surface_data]
552
+ if series_data.shape[0] == 0:
553
+ logger.warning("No data for %s, skipping" % series_surface_data)
554
+ return
555
+ series_builder.add_data_from_data_frame(series_data)
556
+ self._add_faults(series_builder)
557
+
558
+ series_builder.build_arguments = kwargs
559
+ self._add_feature(series_builder.feature)
560
+ return series_builder.feature
561
+
562
+
563
+ def _add_unconformity_above(self, feature):
564
+ """
565
+
566
+ Adds a region to the feature to prevent the value from being
567
+ interpolated where the unconformities exists above e.g.
568
+ if there is another feature above and the unconformity is at 0
569
+ then the features added below (after) will only be visible where the
570
+ uncomformity is <0
571
+
572
+ Parameters
573
+ ----------
574
+ feature - GeologicalFeature
575
+
576
+ Returns
577
+ -------
578
+
579
+ """
580
+ for f in reversed(self.features):
581
+ if f.type == 'unconformity':
582
+ feature.add_region(lambda pos: f.evaluate(pos))
583
+ break
584
+
585
+ def _add_unconformity_below(self, feature):
586
+ """
587
+ Adds a region to the features that represents the
588
+ unconformity so it is not evaluated below the unconformity
589
+
590
+ Parameters
591
+ ----------
592
+ feature
593
+
594
+ Returns
595
+ -------
596
+
597
+ """
598
+ for f in self.features:
599
+ if f.type == 'series' and feature.feature.name != f.name:
600
+ f.add_region(lambda pos: ~feature.evaluate(pos))
601
+
602
+ def add_unconformity(self, feature, value):
603
+ """
604
+ Use an existing feature to add an unconformity to the model.
605
+
606
+ Parameters
607
+ ----------
608
+ feature : GeologicalFeature
609
+ existing geological feature
610
+ value : float
611
+ scalar value of isosurface that represents
612
+
613
+ Returns
614
+ -------
615
+ unconformity : GeologicalFeature
616
+ unconformity feature
617
+
618
+ """
619
+ self.parameters['features'].append({'feature_type': 'unconformity', 'feature': feature, 'value': value})
620
+ uc_feature = UnconformityFeature(feature, value)
621
+
622
+ # for f in self.features:
623
+ # f.add_region(lambda pos: uc_feature.evaluate(pos))
624
+
625
+ # see if any unconformities are above this feature if so add region
626
+ # self._add_unconformity_above(uc_feature)
627
+ # self._add_unconformity_below(feature)#, uc_feature)
628
+ self._add_feature(uc_feature)
629
+
630
+
631
+ return uc_feature
632
+
633
+ def add_onlap_unconformity(self, feature, value):
634
+ """
635
+ Use an existing feature to add an unconformity to the model.
636
+
637
+ Parameters
638
+ ----------
639
+ feature : GeologicalFeature
640
+ existing geological feature
641
+ value : float
642
+ scalar value of isosurface that represents
643
+
644
+ Returns
645
+ -------
646
+ unconformity_feature : GeologicalFeature
647
+ the created unconformity
648
+
649
+ """
650
+ self.parameters['features'].append({'feature_type': 'onlap', 'feature': feature, 'value': value})
651
+
652
+ uc_feature = UnconformityFeature(feature, value)
653
+
654
+ # for f in self.features:
655
+ # f.add_region(lambda pos: uc_feature.evaluate(pos))
656
+
657
+ # see if any unconformities are above this feature if so add region
658
+ # self._add_unconformity_above(uc_feature)
659
+ self._add_unconformity_below(uc_feature) # , uc_feature)
660
+ self._add_feature(uc_feature)
661
+
662
+
663
+ return uc_feature
664
+
665
+ def create_and_add_fault(self, fault_surface_data, displacement, renormalise=True, **kwargs):
666
+ """
667
+ Parameters
668
+ ----------
669
+ fault_surface_data : string
670
+ name of the fault surface data in the dataframe
671
+ displacement : displacement magnitude
672
+ kwargs : additional kwargs for Fault and interpolators
673
+
674
+ Returns
675
+ -------
676
+ fault : FaultSegment
677
+ created fault
678
+ """
679
+ self.parameters['features'].append(
680
+ {'feature_type': 'fault', 'feature_name': fault_surface_data, 'displacement': displacement, **kwargs})
681
+
682
+ displacement_scaled = displacement / self.scale_factor
683
+ # create fault frame
684
+ interpolator = self.get_interpolator(**kwargs)
685
+ fault_frame_builder = StructuralFrameBuilder(interpolator,
686
+ name=fault_surface_data,
687
+ **kwargs)
688
+ # add data
689
+ fault_frame_data = self.data[
690
+ self.data['feature_name'] == fault_surface_data].copy()
691
+ if 'coord' not in fault_frame_data:
692
+ fault_frame_data['coord'] = 0
693
+ vals = fault_frame_data['val']
694
+ fault_frame_builder.add_data_from_data_frame(fault_frame_data)
695
+ # if there is no fault slip data then we could find the strike of
696
+ # the fault and build
697
+ # the second coordinate
698
+ # if we add a region to the fault then the fault operator doesn't
699
+ # work but for visualisation
700
+ # we want to add a region!
701
+ # check if this fault overprint any existing faults exist in the stack
702
+
703
+ fault_frame = fault_frame_builder.build(**kwargs)
704
+
705
+
706
+ fault = FaultSegment(fault_frame, displacement=displacement_scaled,
707
+ **kwargs)
708
+ # for f in reversed(self.features):
709
+ # if f.type == 'unconformity':
710
+ # fault.add_region(lambda pos: f.evaluate_value(pos) <= 0)
711
+ # break
712
+ # if displacement == 0:
713
+ # fault.type = 'fault_inactive'
714
+ # self._add_feature(fault)
715
+ self._add_feature(fault)
716
+
717
+ return fault
718
+
719
+ def rescale(self, points, inplace=True):
720
+ """
721
+ Convert from model scale to real world scale - in the future this
722
+ should also do transformations?
723
+
724
+ Parameters
725
+ ----------
726
+ points : np.array((N,3),dtype=double)
727
+ inplace : boolean
728
+ whether to return a modified copy or modify the original array
729
+
730
+ Returns
731
+ -------
732
+ points : np.array((N,3),dtype=double)
733
+
734
+ """
735
+ if inplace == False:
736
+ points = points.copy()
737
+ points *= self.scale_factor
738
+ points += self.origin
739
+ return points
740
+
741
+ def scale(self, points, inplace=True):
742
+ """ Take points in UTM coordinates and reproject
743
+ into scaled model space
744
+
745
+ Parameters
746
+ ----------
747
+ points : np.array((N,3),dtype=float)
748
+ points to
749
+ inplace : bool, optional default = True
750
+ whether to copy the points array or update the passed array
751
+ Returns
752
+ -------
753
+ points : np.array((N,3),dtype=double)
754
+
755
+ """
756
+ if inplace==False:
757
+ points = points.copy()
758
+
759
+ points[:, :] -= self.origin
760
+ points /= self.scale_factor
761
+ return points
762
+
763
+
764
+ def regular_grid(self, nsteps=(50, 50, 25), shuffle = True, rescale=False):
765
+ """
766
+ Return a regular grid within the model bounding box
767
+
768
+ Parameters
769
+ ----------
770
+ nsteps : tuple
771
+ number of cells in x,y,z
772
+
773
+ Returns
774
+ -------
775
+ xyz : np.array((N,3),dtype=float)
776
+ locations of points in regular grid
777
+ """
778
+ x = np.linspace(self.bounding_box[0, 0], self.bounding_box[1, 0],
779
+ nsteps[0])
780
+ y = np.linspace(self.bounding_box[0, 1], self.bounding_box[1, 1],
781
+ nsteps[1])
782
+ z = np.linspace(self.bounding_box[1, 2], self.bounding_box[0, 2],
783
+ nsteps[2])
784
+ xx, yy, zz = np.meshgrid(x, y, z, indexing='ij')
785
+ locs = np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T
786
+ if shuffle:
787
+ logger.info("Shuffling points")
788
+ np.random.shuffle(locs)
789
+ if rescale:
790
+ locs = self.rescale(locs)
791
+ return locs
792
+
793
+ def evaluate_model(self, xyz, scale=True):
794
+ """Evaluate the stratigraphic id at each location
795
+
796
+
797
+ Parameters
798
+ ----------
799
+ xyz : np.array((N,3),dtype=float)
800
+ locations
801
+ scale : bool
802
+ whether to rescale the xyz before evaluating model
803
+
804
+ Returns
805
+ -------
806
+ stratigraphic_id : np.array(N,dtype=int)
807
+ the stratigraphic index for locations
808
+
809
+ Examples
810
+ --------
811
+ Evaluate on a voxet
812
+
813
+ >>> x = np.linspace(model.bounding_box[0, 0], model.bounding_box[1, 0],
814
+ nsteps[0])
815
+ >>> y = np.linspace(model.bounding_box[0, 1], model.bounding_box[1, 1],
816
+ nsteps[1])
817
+ >>> z = np.linspace(model.bounding_box[1, 2], model.bounding_box[0, 2],
818
+ nsteps[2])
819
+ >>> xx, yy, zz = np.meshgrid(x, y, z, indexing='ij')
820
+ >>> xyz = np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T
821
+ >>> model.evaluate_model(xyz)
822
+
823
+ Evaluate on points defined by regular grid function
824
+
825
+ >>> model.evaluate_model(model.regular_grid())
826
+
827
+
828
+ Evaluate on a map
829
+
830
+ >>> x = np.linspace(self.bounding_box[0, 0], self.bounding_box[1, 0],
831
+ nsteps[0])
832
+ >>> y = np.linspace(self.bounding_box[0, 1], self.bounding_box[1, 1],
833
+ nsteps[1])
834
+ >>> xx, yy = np.meshgrid(x, y, indexing='ij')
835
+ >>> zz = np.zeros_like(yy)
836
+ >>> xyz = np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T
837
+ >>> model.evaluate_model(xyz)
838
+
839
+ """
840
+ if scale:
841
+ xyz = self.scale(xyz,inplace=False)
842
+ strat_id = np.zeros(xyz.shape[0],dtype=int)
843
+ for group in self.stratigraphic_column.keys():
844
+ if group == 'faults':
845
+ continue
846
+ feature_id = self.feature_name_index.get(group, -1)
847
+ if feature_id >= 0:
848
+ feature = self.features[feature_id]
849
+ vals = feature.evaluate_value(xyz)
850
+ for series in self.stratigraphic_column[group].values():
851
+ strat_id[np.logical_and(vals < series.get('max',feature.max()), vals > series.get('min',feature.min()))] = series['id']
852
+ if feature_id == -1:
853
+ logger.error('Model does not contain {}'.format(group))
854
+ return strat_id
855
+
856
+ def evaluate_fault_displacements(self,points,scale=True):
857
+ """Evaluate the fault displacement magnitude at each location
858
+
859
+
860
+ Parameters
861
+ ----------
862
+ xyz : np.array((N,3),dtype=float)
863
+ locations
864
+ scale : bool
865
+ whether to rescale the xyz before evaluating model
866
+
867
+ Returns
868
+ -------
869
+ fault_displacement : np.array(N,dtype=float)
870
+ the fault displacement magnitude
871
+ """
872
+ if scale:
873
+ points = self.scale(points,inplace=False)
874
+ vals = np.zeros(points.shape[0])
875
+ for f in self.features:
876
+ if f.type == 'fault':
877
+ disp = f.displacementfeature.evaluate_value(points)
878
+ vals[~np.isnan(disp)] += disp[~np.isnan(disp)]
879
+ return vals*-self.scale_factor # convert from restoration magnutude to displacement
880
+
881
+