subsurface-terra 2025.1.0rc13__tar.gz → 2025.1.0rc15__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.
Files changed (131) hide show
  1. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/.teamcity/Subsurface/buildTypes/Subsurface_ReleaseSubsurface_2.xml +4 -12
  2. {subsurface_terra-2025.1.0rc13/subsurface_terra.egg-info → subsurface_terra-2025.1.0rc15}/PKG-INFO +1 -1
  3. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/_version.py +2 -2
  4. subsurface_terra-2025.1.0rc15/subsurface/core/geological_formats/boreholes/_map_attrs_to_survey.py +234 -0
  5. subsurface_terra-2025.1.0rc15/subsurface/core/geological_formats/boreholes/_survey_to_unstruct.py +163 -0
  6. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/geological_formats/boreholes/boreholes.py +32 -5
  7. subsurface_terra-2025.1.0rc15/subsurface/core/geological_formats/boreholes/survey.py +86 -0
  8. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15/subsurface_terra.egg-info}/PKG-INFO +1 -1
  9. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface_terra.egg-info/SOURCES.txt +2 -0
  10. subsurface_terra-2025.1.0rc13/subsurface/core/geological_formats/boreholes/survey.py +0 -380
  11. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/.env.example +0 -0
  12. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/.teamcity/Subsurface/buildTypes/Subsurface_ReleaseSubsurface.xml +0 -0
  13. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/.teamcity/Subsurface/buildTypes/Subsurface_Testing.xml +0 -0
  14. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/.teamcity/Subsurface/project-config.xml +0 -0
  15. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/.teamcity/Subsurface/vcsRoots/Subsurface_HttpsGithubComTerranigmaSolutionsSubsurfaceRefsHeadsMain.xml +0 -0
  16. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/.teamcity/Subsurface/vcsRoots/Subsurface_HttpsGithubComTerranigmaSolutionsSubsurfaceRefsHeadsMain1.xml +0 -0
  17. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/.teamcity/Subsurface/vcsRoots/Subsurface_HttpsGithubComTerranigmaSolutionsSubsurfaceRefsHeadsMain2.xml +0 -0
  18. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/LICENSE +0 -0
  19. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/README.rst +0 -0
  20. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/requirements/requirements.txt +0 -0
  21. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/requirements/requirements_all.txt +0 -0
  22. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/requirements/requirements_dev.txt +0 -0
  23. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/requirements/requirements_geospatial.txt +0 -0
  24. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/requirements/requirements_mesh.txt +0 -0
  25. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/requirements/requirements_opt.txt +0 -0
  26. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/requirements/requirements_plot.txt +0 -0
  27. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/requirements/requirements_traces.txt +0 -0
  28. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/requirements/requirements_volume.txt +0 -0
  29. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/requirements/requirements_wells.txt +0 -0
  30. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/setup.cfg +0 -0
  31. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/setup.py +0 -0
  32. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/__init__.py +0 -0
  33. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/api/__init__.py +0 -0
  34. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/api/interfaces/README.rst +0 -0
  35. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/api/interfaces/__init__.py +0 -0
  36. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/api/interfaces/stream.py +0 -0
  37. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/api/reader/__init__.py +0 -0
  38. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/api/reader/read_wells.py +0 -0
  39. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/__init__.py +0 -0
  40. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/geological_formats/__init__.py +0 -0
  41. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/geological_formats/boreholes/__init__.py +0 -0
  42. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/geological_formats/boreholes/_combine_trajectories.py +0 -0
  43. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/geological_formats/boreholes/collars.py +0 -0
  44. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/geological_formats/fault.py +0 -0
  45. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/reader_helpers/__init__.py +0 -0
  46. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/reader_helpers/reader_unstruct.py +0 -0
  47. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/reader_helpers/readers_data.py +0 -0
  48. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/reader_helpers/readers_wells.py +0 -0
  49. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/README.rst +0 -0
  50. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/__init__.py +0 -0
  51. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/base_structures/__init__.py +0 -0
  52. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/base_structures/_liquid_earth_mesh.py +0 -0
  53. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/base_structures/_unstructured_data_constructor.py +0 -0
  54. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/base_structures/base_structures_enum.py +0 -0
  55. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/base_structures/structured_data.py +0 -0
  56. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/base_structures/unstructured_data.py +0 -0
  57. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/structured_elements/__init__.py +0 -0
  58. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/structured_elements/octree_mesh.py +0 -0
  59. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/structured_elements/structured_grid.py +0 -0
  60. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/structured_elements/structured_mesh.py +0 -0
  61. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/unstructured_elements/__init__.py +0 -0
  62. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/unstructured_elements/line_set.py +0 -0
  63. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/unstructured_elements/point_set.py +0 -0
  64. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/unstructured_elements/tetrahedron_mesh.py +0 -0
  65. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/structs/unstructured_elements/triangular_surface.py +0 -0
  66. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/utils/__init__.py +0 -0
  67. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/core/utils/utils_core.py +0 -0
  68. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/__init__.py +0 -0
  69. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/README.rst +0 -0
  70. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/__init__.py +0 -0
  71. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/faults/__init__.py +0 -0
  72. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/faults/faults.py +0 -0
  73. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/from_binary.py +0 -0
  74. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/geo_object/__init__.py +0 -0
  75. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/mesh/NOTES.md +0 -0
  76. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/mesh/_GOCAD_mesh.py +0 -0
  77. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/mesh/__init__.py +0 -0
  78. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/mesh/_trimesh_reader.py +0 -0
  79. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/mesh/csv_mesh_reader.py +0 -0
  80. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/mesh/dxf_reader.py +0 -0
  81. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/mesh/glb_reader.py +0 -0
  82. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/mesh/mx_reader.py +0 -0
  83. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/mesh/obj_reader.py +0 -0
  84. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/mesh/omf_mesh_reader.py +0 -0
  85. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/mesh/surface_reader.py +0 -0
  86. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/mesh/surfaces_api.py +0 -0
  87. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/petrel/__init__.py +0 -0
  88. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/profiles/__init__.py +0 -0
  89. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/profiles/profiles_core.py +0 -0
  90. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/read_netcdf.py +0 -0
  91. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/topography/__init__.py +0 -0
  92. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/topography/topo_core.py +0 -0
  93. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/volume/__init__.py +0 -0
  94. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/volume/read_grav3d.py +0 -0
  95. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/volume/read_volume.py +0 -0
  96. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/volume/segy_reader.py +0 -0
  97. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/volume/seismic.py +0 -0
  98. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/volume/volume_utils.py +0 -0
  99. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/wells/DEP/__init__.py +0 -0
  100. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/wells/DEP/_well_files_reader.py +0 -0
  101. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/wells/DEP/_wells_api.py +0 -0
  102. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/wells/DEP/_welly_reader.py +0 -0
  103. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/wells/DEP/pandas_to_welly.py +0 -0
  104. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/wells/README.rst +0 -0
  105. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/wells/__init__.py +0 -0
  106. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/wells/_read_to_df.py +0 -0
  107. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/wells/read_borehole_interface.py +0 -0
  108. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/reader/wells/wells_utils.py +0 -0
  109. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/tools/__init__.py +0 -0
  110. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/tools/mocking_aux.py +0 -0
  111. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/visualization/__init__.py +0 -0
  112. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/visualization/to_pyvista.py +0 -0
  113. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/writer/__init__.py +0 -0
  114. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/writer/to_binary.py +0 -0
  115. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/writer/to_liquid_earth/__init__.py +0 -0
  116. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/writer/to_rex/__init__.py +0 -0
  117. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/writer/to_rex/common.py +0 -0
  118. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/writer/to_rex/data_struct.py +0 -0
  119. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/writer/to_rex/doc/rex-spec-v1.md +0 -0
  120. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/writer/to_rex/doc/right-handed.png +0 -0
  121. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/writer/to_rex/doc/sketchup_example.jpg +0 -0
  122. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/writer/to_rex/gempy_to_rexfile.py +0 -0
  123. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/writer/to_rex/material_encoder.py +0 -0
  124. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/writer/to_rex/mesh_encoder.py +0 -0
  125. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/writer/to_rex/to_rex.py +0 -0
  126. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/modules/writer/to_rex/utils.py +0 -0
  127. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface/optional_requirements.py +0 -0
  128. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface_terra.egg-info/dependency_links.txt +0 -0
  129. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface_terra.egg-info/not-zip-safe +0 -0
  130. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface_terra.egg-info/requires.txt +0 -0
  131. {subsurface_terra-2025.1.0rc13 → subsurface_terra-2025.1.0rc15}/subsurface_terra.egg-info/top_level.txt +0 -0
@@ -1,9 +1,11 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <build-type xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" uuid="c15fb876-7044-47cd-a3b0-676767e4ca63" xsi:noNamespaceSchemaLocation="https://www.jetbrains.com/teamcity/schemas/2021.1/project-config.xsd">
2
+ <build-type xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" uuid="c15fb876-7044-47cd-a3b0-676767e4ca63" xsi:noNamespaceSchemaLocation="https://www.jetbrains.com/teamcity/schemas/2025.3/project-config.xsd">
3
3
  <name>Release Subsurface</name>
4
4
  <description />
5
5
  <settings ref="ReleasePythonPackage">
6
- <parameters />
6
+ <parameters>
7
+ <param name="env.org/repo" value="terranigma-solutions/subsurface" />
8
+ </parameters>
7
9
  <build-runners order="Git_Tagging, Build, Push_to_PyPi, Push_To_GitHub">
8
10
  <runner id="Build" name="Build" type="simpleRunner">
9
11
  <parameters>
@@ -18,20 +20,10 @@ python -m build]]></param>
18
20
  <param name="use.custom.script" value="true" />
19
21
  </parameters>
20
22
  </runner>
21
- <runner id="Push_To_GitHub" name="Push To GitHub" type="simpleRunner">
22
- <parameters>
23
- <param name="script.content" value="gh release create %env.PACKAGE_VERSION% dist/* --notes &quot;Release notes here&quot; --repo terranigma-solutions/subsurface" />
24
- <param name="teamcity.step.mode" value="default" />
25
- <param name="use.custom.script" value="true" />
26
- </parameters>
27
- </runner>
28
23
  </build-runners>
29
24
  <vcs-settings>
30
25
  <vcs-entry-ref root-id="Subsurface_HttpsGithubComTerranigmaSolutionsSubsurfaceRefsHeadsMain1" />
31
26
  </vcs-settings>
32
- <requirements />
33
- <build-triggers />
34
- <cleanup />
35
27
  </settings>
36
28
  </build-type>
37
29
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: subsurface_terra
3
- Version: 2025.1.0rc13
3
+ Version: 2025.1.0rc15
4
4
  Summary: Subsurface data types and utilities. This version is the one used by Terranigma Solutions. Please feel free to take anything in this repository for the original one.
5
5
  Home-page: https://softwareunderground.github.io/subsurface
6
6
  Author: Software Underground
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '2025.1.0rc13'
21
- __version_tuple__ = version_tuple = (2025, 1, 0, 'rc13')
20
+ __version__ = version = '2025.1.0rc15'
21
+ __version_tuple__ = version_tuple = (2025, 1, 0, 'rc15')
@@ -0,0 +1,234 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ import xarray as xr
4
+ from scipy.interpolate import interp1d
5
+ from typing import Tuple, Optional, Union, List, Any
6
+
7
+ from ...structs.base_structures import UnstructuredData
8
+ from ...structs.base_structures._unstructured_data_constructor import raw_attributes_to_dict_data_arrays
9
+ from ...structs.unstructured_elements import LineSet
10
+
11
+
12
+ def combine_survey_and_attrs(attrs: pd.DataFrame, survey_trajectory: LineSet,well_id_mapper: dict[str, int]) -> UnstructuredData:
13
+ # Import moved to top for clarity and possibly avoiding repeated imports if called multiple times
14
+
15
+ # Ensure all columns in lith exist in new_attrs, if not, add them as NaN
16
+ new_attrs = _map_attrs_to_measured_depths(attrs, survey_trajectory, well_id_mapper)
17
+
18
+ # Construct the final xarray dict without intermediate variable
19
+ points_attributes_xarray_dict: dict[str, xr.DataArray] = raw_attributes_to_dict_data_arrays(
20
+ default_attributes_name="vertex_attrs",
21
+ n_items=survey_trajectory.data.data["vertex_attrs"].shape[0], # TODO: Can I look this on new_attrs to remove line 11?
22
+ dims=["points", "vertex_attr"],
23
+ raw_attributes=new_attrs
24
+ )
25
+
26
+ # Inline construction of UnstructuredData
27
+ return UnstructuredData.from_data_arrays_dict(
28
+ xarray_dict={
29
+ "vertex" : survey_trajectory.data.data["vertex"],
30
+ "cells" : survey_trajectory.data.data["cells"],
31
+ "vertex_attrs": points_attributes_xarray_dict["vertex_attrs"],
32
+ "cell_attrs" : survey_trajectory.data.data["cell_attrs"]
33
+ },
34
+ xarray_attributes=survey_trajectory.data.data.attrs,
35
+ default_cells_attributes_name=survey_trajectory.data.cells_attr_name,
36
+ default_points_attributes_name=survey_trajectory.data.vertex_attr_name
37
+ )
38
+
39
+ def _prepare_categorical_data(attrs: pd.DataFrame) -> pd.DataFrame:
40
+ """
41
+ Prepare categorical data for interpolation by converting categorical columns to numeric IDs.
42
+
43
+ Args:
44
+ attrs: DataFrame containing attribute data
45
+
46
+ Returns:
47
+ Modified DataFrame with categorical data prepared for interpolation
48
+ """
49
+ # Create a copy to avoid modifying the original
50
+ attrs_copy = attrs.copy()
51
+
52
+ # If component lith exists but lith_ids doesn't, create lith_ids
53
+ if 'component lith' in attrs_copy.columns and 'lith_ids' not in attrs_copy.columns:
54
+ attrs_copy['lith_ids'], _ = pd.factorize(attrs_copy['component lith'], use_na_sentinel=True)
55
+
56
+ return attrs_copy
57
+
58
+
59
+ def _prepare_new_attributes(attrs: pd.DataFrame, survey_trajectory: LineSet) -> pd.DataFrame:
60
+ """
61
+ Prepare the new attributes DataFrame by adding missing columns from attrs.
62
+
63
+ Args:
64
+ attrs: DataFrame containing attribute data
65
+ survey_trajectory: LineSet containing trajectory data
66
+
67
+ Returns:
68
+ New attributes DataFrame with all necessary columns
69
+ """
70
+ # Start with a copy of the existing attributes DataFrame
71
+ new_attrs = survey_trajectory.data.points_attributes.copy()
72
+
73
+ # Add missing columns from attrs, preserving their dtypes
74
+ for col in attrs.columns.difference(new_attrs.columns):
75
+ new_attrs[col] = np.nan if pd.api.types.is_numeric_dtype(attrs[col]) else None
76
+
77
+ return new_attrs
78
+
79
+
80
+ def _get_interpolation_locations(attrs_well: pd.DataFrame, well_name: str) -> np.ndarray:
81
+ """
82
+ Determine the locations to use for interpolation based on top and base values.
83
+
84
+ Args:
85
+ attrs_well: DataFrame containing well attribute data
86
+ well_name: Name of the current well
87
+
88
+ Returns:
89
+ Array of location values to use for interpolation
90
+ """
91
+ if "base" not in attrs_well.columns:
92
+ raise ValueError(f"Base column must be present in the file for well '{well_name}'.")
93
+ elif "top" not in attrs_well.columns:
94
+ return attrs_well['base'].values
95
+ else:
96
+ return ((attrs_well['top'] + attrs_well['base']) / 2).values
97
+
98
+
99
+ def _nearest_neighbor_categorical_interpolation(
100
+ x_locations: np.ndarray,
101
+ y_values: np.ndarray,
102
+ target_depths: np.ndarray
103
+ ) -> np.ndarray:
104
+ """
105
+ Custom nearest neighbor interpolation for categorical data.
106
+
107
+ This function finds the nearest source point for each target point
108
+ and assigns the corresponding categorical value.
109
+
110
+ Args:
111
+ x_locations: Array of source locations
112
+ y_values: Array of categorical values at source locations
113
+ target_depths: Array of target depths for interpolation
114
+
115
+ Returns:
116
+ Array of interpolated categorical values
117
+ """
118
+ # Initialize output array with NaN or None values
119
+ result = np.full(target_depths.shape, np.nan, dtype=object)
120
+
121
+ # For each target depth, find the nearest source location
122
+ for i, depth in enumerate(target_depths):
123
+ # Calculate distances to all source locations
124
+ distances = np.abs(x_locations - depth)
125
+
126
+ # Find the index of the minimum distance
127
+ if len(distances) > 0:
128
+ nearest_idx = np.argmin(distances)
129
+ result[i] = y_values[nearest_idx]
130
+
131
+ return result
132
+
133
+
134
+ def _interpolate_attribute(
135
+ attr_values: pd.Series,
136
+ x_locations: np.ndarray,
137
+ target_depths: np.ndarray,
138
+ column_name: str,
139
+ is_categorical: bool
140
+ ) -> np.ndarray:
141
+ """
142
+ Interpolate attribute values to target depths.
143
+
144
+ Args:
145
+ attr_values: Series containing attribute values
146
+ x_locations: Array of source locations for interpolation
147
+ target_depths: Array of target depths for interpolation
148
+ column_name: Name of the column being interpolated
149
+ is_categorical: Whether the attribute is categorical
150
+
151
+ Returns:
152
+ Array of interpolated values
153
+ """
154
+ # For categorical data or specific columns, use custom nearest neighbor interpolation
155
+ if is_categorical or column_name in ['lith_ids', 'component lith']:
156
+ return _nearest_neighbor_categorical_interpolation(
157
+ x_locations=x_locations,
158
+ y_values=attr_values.values,
159
+ target_depths=target_depths
160
+ )
161
+ else:
162
+ # For numerical data, use scipy's interp1d with linear interpolation
163
+ interp_func = interp1d(
164
+ x=x_locations,
165
+ y=attr_values.values,
166
+ bounds_error=False,
167
+ fill_value=np.nan,
168
+ kind='linear'
169
+ )
170
+ return interp_func(target_depths)
171
+
172
+
173
+ def _map_attrs_to_measured_depths(attrs: pd.DataFrame, survey_trajectory: LineSet, well_id_mapper: dict[str, int]) -> pd.DataFrame:
174
+ """
175
+ Map attributes to measured depths for each well.
176
+
177
+ Args:
178
+ attrs: DataFrame containing attribute data
179
+ survey_trajectory: LineSet containing trajectory data
180
+ well_id_mapper: Dictionary mapping well names to IDs
181
+
182
+ Returns:
183
+ DataFrame with attributes mapped to measured depths
184
+ """
185
+ # Extract trajectory data
186
+ trajectory: xr.DataArray = survey_trajectory.data.data["vertex_attrs"]
187
+ trajectory_well_id: xr.DataArray = trajectory.sel({'vertex_attr': 'well_id'})
188
+ measured_depths: np.ndarray = trajectory.sel({'vertex_attr': 'measured_depths'}).values.astype(np.float64)
189
+
190
+ # Prepare data
191
+ attrs: pd.DataFrame = _prepare_categorical_data(attrs)
192
+ new_attrs: pd.DataFrame = _prepare_new_attributes(attrs, survey_trajectory)
193
+
194
+ # Process each well
195
+ for well_name in well_id_mapper:
196
+ # Skip wells not in the attributes DataFrame
197
+ if well_name not in attrs.index:
198
+ print(f"Well '{well_name}' does not exist in the attributes DataFrame.")
199
+ continue
200
+
201
+ # Get well data
202
+ attrs_well = attrs.loc[[well_name]]
203
+ well_id = well_id_mapper.get(well_name)
204
+ well_mask = (trajectory_well_id == well_id).values
205
+ well_depths = measured_depths[well_mask]
206
+
207
+ # Get interpolation locations
208
+ interp_locations = _get_interpolation_locations(attrs_well, well_name)
209
+
210
+ # Interpolate each attribute
211
+ for col in attrs_well.columns:
212
+ # Skip location and ID columns
213
+ if col in ['top', 'base', 'well_id']:
214
+ continue
215
+
216
+ attr_values = attrs_well[col]
217
+ is_categorical = attr_values.dtype == 'O' or isinstance(attr_values.dtype, pd.CategoricalDtype)
218
+
219
+ # Skip columns that can't be interpolated and aren't categorical
220
+ if is_categorical and col not in ['lith_ids', 'component lith']:
221
+ continue
222
+
223
+ # Interpolate and assign values
224
+ interpolated_values = _interpolate_attribute(
225
+ attr_values,
226
+ interp_locations,
227
+ well_depths,
228
+ col,
229
+ is_categorical
230
+ )
231
+
232
+ new_attrs.loc[well_mask, col] = interpolated_values
233
+
234
+ return new_attrs
@@ -0,0 +1,163 @@
1
+ from typing import Hashable, Optional
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+
6
+ from subsurface import optional_requirements
7
+ from ...structs.base_structures import UnstructuredData
8
+
9
+
10
+ def data_frame_to_unstructured_data(survey_df: 'pd.DataFrame', number_nodes: int, attr_df: Optional['pd.DataFrame'] = None,
11
+ duplicate_attr_depths: bool = False) -> UnstructuredData:
12
+ wp = optional_requirements.require_wellpathpy()
13
+
14
+ cum_vertex: np.ndarray = np.empty((0, 3), dtype=np.float32)
15
+ cells: np.ndarray = np.empty((0, 2), dtype=np.int_)
16
+ cell_attr: pd.DataFrame = pd.DataFrame(columns=['well_id'], dtype=np.float32)
17
+ vertex_attr: pd.DataFrame = pd.DataFrame()
18
+
19
+ for e, (borehole_id, data) in enumerate(survey_df.groupby(level=0)):
20
+ dev = wp.deviation(
21
+ md=data['md'].values,
22
+ inc=data['inc'].values,
23
+ azi=data['azi'].values
24
+ )
25
+
26
+ md_min = dev.md.min()
27
+ md_max = dev.md.max()
28
+
29
+ attr_depths = _grab_depths_from_attr(
30
+ attr_df=attr_df,
31
+ borehole_id=borehole_id,
32
+ duplicate_attr_depths=duplicate_attr_depths,
33
+ md_max=md_max,
34
+ md_min=md_min
35
+ )
36
+
37
+ # Now combine attr_depths with depths
38
+ md_min = dev.md.min()
39
+ md_max = dev.md.max()
40
+ depths = np.linspace(md_min, md_max, number_nodes)
41
+ depths = np.union1d(depths, attr_depths)
42
+ depths.sort()
43
+
44
+ # Resample positions at depths
45
+ pos = dev.minimum_curvature().resample(depths=depths)
46
+ vertex_count = cum_vertex.shape[0]
47
+
48
+ this_well_vertex = np.vstack([pos.easting, pos.northing, pos.depth]).T
49
+ cum_vertex = np.vstack([cum_vertex, this_well_vertex])
50
+ measured_depths = _calculate_distances(array_of_vertices=this_well_vertex)
51
+
52
+ n_vertex_shift_0 = np.arange(0, len(pos.depth) - 1, dtype=np.int_)
53
+ n_vertex_shift_1 = np.arange(1, len(pos.depth), dtype=np.int_)
54
+ cell_per_well = np.vstack([n_vertex_shift_0, n_vertex_shift_1]).T + vertex_count
55
+ cells = np.vstack([cells, cell_per_well])
56
+
57
+ attribute_values = np.isin(depths, attr_depths)
58
+
59
+ vertex_attr_per_well = pd.DataFrame({
60
+ 'well_id' : [e] * len(pos.depth),
61
+ 'measured_depths': measured_depths,
62
+ 'is_attr_point' : attribute_values,
63
+ })
64
+
65
+ vertex_attr = pd.concat([vertex_attr, vertex_attr_per_well], ignore_index=True)
66
+
67
+ # Add the id (e), to cell_attr
68
+ cell_attr = pd.concat([cell_attr, pd.DataFrame({'well_id': [e] * len(cell_per_well)})], ignore_index=True)
69
+
70
+ unstruct = UnstructuredData.from_array(
71
+ vertex=cum_vertex,
72
+ cells=cells.astype(int),
73
+ vertex_attr=vertex_attr.reset_index(drop=True),
74
+ cells_attr=cell_attr.reset_index(drop=True)
75
+ )
76
+
77
+ unstruct.data.attrs["well_id_mapper"] = {well_id: e for e, well_id in enumerate(survey_df.index.unique(level=0))}
78
+
79
+ return unstruct
80
+
81
+
82
+ def _grab_depths_from_attr(
83
+ attr_df: pd.DataFrame,
84
+ borehole_id: Hashable,
85
+ duplicate_attr_depths: bool,
86
+ md_max: float,
87
+ md_min: float
88
+ ) -> np.ndarray:
89
+ # Initialize attr_depths and attr_labels as empty arrays
90
+ attr_depths = np.array([], dtype=float)
91
+ attr_labels = np.array([], dtype='<U4') # Initialize labels for 'top' and 'base'
92
+
93
+ if attr_df is None or ("top" not in attr_df.columns and "base" not in attr_df.columns):
94
+ return attr_depths
95
+
96
+ try:
97
+ vals = attr_df.loc[borehole_id]
98
+
99
+ tops = np.array([], dtype=float)
100
+ bases = np.array([], dtype=float)
101
+
102
+ if 'top' in vals:
103
+ if isinstance(vals, pd.DataFrame):
104
+ tops = vals['top'].values.flatten()
105
+ else:
106
+ tops = np.array([vals['top']])
107
+ # Convert to float and remove NaNs
108
+ tops = tops.astype(float)
109
+ tops = tops[~np.isnan(tops)]
110
+ # Clip to within md range
111
+ tops = tops[(tops >= md_min) & (tops <= md_max)]
112
+
113
+ if 'base' in vals:
114
+ if isinstance(vals, pd.DataFrame):
115
+ bases = vals['base'].values.flatten()
116
+ else:
117
+ bases = np.array([vals['base']])
118
+ # Convert to float and remove NaNs
119
+ bases = bases.astype(float)
120
+ bases = bases[~np.isnan(bases)]
121
+ # Clip to within md range
122
+ bases = bases[(bases >= md_min) & (bases <= md_max)]
123
+
124
+ # Combine tops and bases into attr_depths with labels
125
+ attr_depths = np.concatenate((tops, bases))
126
+ attr_labels = np.array(['top'] * len(tops) + ['base'] * len(bases))
127
+
128
+ # Drop duplicates while preserving order
129
+ _, unique_indices = np.unique(attr_depths, return_index=True)
130
+ attr_depths = attr_depths[unique_indices]
131
+ attr_labels = attr_labels[unique_indices]
132
+
133
+ except KeyError:
134
+ # No attributes for this borehole_id or missing columns
135
+ attr_depths = np.array([], dtype=float)
136
+ attr_labels = np.array([], dtype='<U4')
137
+
138
+ # If duplicate_attr_depths is True, duplicate attr_depths with a tiny offset
139
+ if duplicate_attr_depths and len(attr_depths) > 0:
140
+ tiny_offset = (md_max - md_min) * 1e-6 # A tiny fraction of the depth range
141
+ # Create offsets: +tiny_offset for 'top', -tiny_offset for 'base'
142
+ offsets = np.where(attr_labels == 'top', tiny_offset, -tiny_offset)
143
+ duplicated_attr_depths = attr_depths + offsets
144
+ # Ensure the duplicated depths are within the md range
145
+ valid_indices = (duplicated_attr_depths >= md_min) & (duplicated_attr_depths <= md_max)
146
+ duplicated_attr_depths = duplicated_attr_depths[valid_indices]
147
+ # Original attribute depths
148
+ original_attr_depths = attr_depths
149
+ # Combine originals and duplicates
150
+ attr_depths = np.hstack([original_attr_depths, duplicated_attr_depths])
151
+
152
+ return attr_depths
153
+
154
+
155
+ def _calculate_distances(array_of_vertices: np.ndarray) -> np.ndarray:
156
+ # Calculate the differences between consecutive points
157
+ differences = np.diff(array_of_vertices, axis=0)
158
+
159
+ # Calculate the Euclidean distance for each pair of consecutive points
160
+ distances = np.linalg.norm(differences, axis=1)
161
+ # Insert a 0 at the beginning to represent the starting point at the surface
162
+ measured_depths = np.insert(np.cumsum(distances), 0, 0)
163
+ return measured_depths
@@ -1,7 +1,7 @@
1
1
  import numpy as np
2
2
  import pandas as pd
3
3
  from dataclasses import dataclass
4
- from typing import Hashable
4
+ from typing import Hashable, Literal
5
5
 
6
6
  from ._combine_trajectories import create_combined_trajectory, MergeOptions
7
7
  from .collars import Collars
@@ -69,10 +69,10 @@ class BoreholeSet:
69
69
  # I need to implement the survey to and then name the files accordingly
70
70
  bytearray_le_collars: bytes = self.collars.data.to_binary()
71
71
  bytearray_le_trajectory: bytes = self.combined_trajectory.data.to_binary()
72
-
72
+
73
73
  new_file = open(f"{path}_collars.le", "wb")
74
74
  new_file.write(bytearray_le_collars)
75
-
75
+
76
76
  new_file = open(f"{path}_trajectory.le", "wb")
77
77
  new_file.write(bytearray_le_trajectory)
78
78
  return True
@@ -88,10 +88,37 @@ class BoreholeSet:
88
88
 
89
89
  return component_lith_arrays
90
90
 
91
- def get_bottom_coords_for_each_lith(self) -> dict[Hashable, np.ndarray]:
91
+ def get_bottom_coords_for_each_lith(self, group_by: Literal['component lith', 'lith_ids'] = 'lith_ids') -> dict[Hashable, np.ndarray]:
92
+ """
93
+ Retrieves the bottom coordinates for each lithological component or lith ID from
94
+ the merged vertex data arrays.
95
+
96
+ This function groups the merged data by either 'component lith' or 'lith_ids',
97
+ then extracts the coordinates of the bottommost vertices for each well. It
98
+ returns a dictionary where keys are either lithological component identifiers
99
+ or lith IDs, and values are arrays of 3D coordinates representing the bottom
100
+ vertices.
101
+
102
+ Args:
103
+ group_by (Literal['component lith', 'lith_ids']): Specifies the grouping
104
+ column to use for lithological components. Acceptable values are either
105
+ 'component lith' or 'lith_ids'. Defaults to 'lith_ids'.
106
+
107
+ Returns:
108
+ dict[Hashable, np.ndarray]: A dictionary mapping the lithological component
109
+ or lith ID to an array of 3D coordinates ([X, Y, Z]) corresponding to the
110
+ bottom vertices for each well.
111
+
112
+ Raises:
113
+ ValueError: If no groups are found from the specified `group_by` column.
114
+ """
92
115
  merged_df = self._merge_vertex_data_arrays_to_dataframe()
93
116
  component_lith_arrays = {}
94
- for lith, group in merged_df.groupby('component lith'):
117
+ group = merged_df.groupby(group_by)
118
+
119
+ if group.ngroups == 0:
120
+ raise ValueError("No components found")
121
+ for lith, group in group:
95
122
  lith = int(lith)
96
123
  first_vertices = group.groupby('well_id').last().reset_index()
97
124
  array = first_vertices[['X', 'Y', 'Z']].values
@@ -0,0 +1,86 @@
1
+ from dataclasses import dataclass
2
+ from typing import Union, Hashable, Optional
3
+
4
+ import pandas as pd
5
+
6
+ from ._map_attrs_to_survey import combine_survey_and_attrs
7
+ from ._survey_to_unstruct import data_frame_to_unstructured_data
8
+ from ...structs.base_structures import UnstructuredData
9
+ from ...structs.unstructured_elements import LineSet
10
+
11
+ NUMBER_NODES = 30
12
+ RADIUS = 10
13
+
14
+
15
+ @dataclass
16
+ class Survey:
17
+ ids: list[str]
18
+ survey_trajectory: LineSet
19
+ well_id_mapper: dict[str, int] = None #: This is following the order of the survey csv that can be different that the collars
20
+
21
+ @property
22
+ def id_to_well_id(self):
23
+ # Reverse the well_id_mapper dictionary to map IDs to well names
24
+ id_to_well_name_mapper = {v: k for k, v in self.well_id_mapper.items()}
25
+ return id_to_well_name_mapper
26
+
27
+ @classmethod
28
+ def from_df(cls, survey_df: 'pd.DataFrame', attr_df: Optional['pd.DataFrame'] = None, number_nodes: Optional[int] = NUMBER_NODES,
29
+ duplicate_attr_depths: bool = False) -> 'Survey':
30
+ """
31
+ Create a Survey object from two DataFrames containing survey and attribute data.
32
+
33
+ :param survey_df: DataFrame containing survey data.
34
+ :param attr_df: DataFrame containing attribute data. This is used to make sure the raw data is perfectly aligned.
35
+ :param number_nodes: Optional parameter specifying the number of nodes.
36
+ :return: A Survey object representing the input data.
37
+
38
+ """
39
+ trajectories: UnstructuredData = data_frame_to_unstructured_data(
40
+ survey_df=_correct_angles(survey_df),
41
+ attr_df=attr_df,
42
+ number_nodes=number_nodes,
43
+ duplicate_attr_depths=duplicate_attr_depths
44
+ )
45
+ # Grab the unique ids
46
+ unique_ids = trajectories.points_attributes["well_id"].unique()
47
+
48
+ return cls(
49
+ ids=unique_ids,
50
+ survey_trajectory=LineSet(data=trajectories, radius=RADIUS),
51
+ well_id_mapper=trajectories.data.attrs["well_id_mapper"]
52
+ )
53
+
54
+ def get_well_string_id(self, well_id: int) -> str:
55
+ return self.ids[well_id]
56
+
57
+ def get_well_num_id(self, well_string_id: Union[str, Hashable]) -> int:
58
+ return self.well_id_mapper.get(well_string_id, None)
59
+
60
+ def update_survey_with_lith(self, lith: pd.DataFrame):
61
+ unstruct: UnstructuredData = combine_survey_and_attrs(lith, self.survey_trajectory, self.well_id_mapper)
62
+ self.survey_trajectory.data = unstruct
63
+
64
+ def update_survey_with_attr(self, attrs: pd.DataFrame):
65
+ self.survey_trajectory.data = combine_survey_and_attrs(attrs, self.survey_trajectory, self.well_id_mapper)
66
+
67
+
68
+ def _correct_angles(df: pd.DataFrame) -> pd.DataFrame:
69
+ def correct_inclination(inc: float) -> float:
70
+ if inc < 0:
71
+ inc = inc % 360 # Normalize to 0-360 range first if negative
72
+ if 0 <= inc <= 180:
73
+ # add or subtract a very small number to make sure that 0 or 180 are never possible
74
+ return inc + 1e-10 if inc == 0 else inc - 1e-10
75
+ elif 180 < inc < 360:
76
+ return 360 - inc # Reflect angles greater than 180 back into the 0-180 range
77
+ else:
78
+ raise ValueError(f'Inclination value {inc} is out of the expected range of 0 to 360 degrees')
79
+
80
+ def correct_azimuth(azi: float) -> float:
81
+ return azi % 360 # Normalize azimuth to 0-360 range
82
+
83
+ df['inc'] = df['inc'].apply(correct_inclination)
84
+ df['azi'] = df['azi'].apply(correct_azimuth)
85
+
86
+ return df
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: subsurface_terra
3
- Version: 2025.1.0rc13
3
+ Version: 2025.1.0rc15
4
4
  Summary: Subsurface data types and utilities. This version is the one used by Terranigma Solutions. Please feel free to take anything in this repository for the original one.
5
5
  Home-page: https://softwareunderground.github.io/subsurface
6
6
  Author: Software Underground
@@ -33,6 +33,8 @@ subsurface/core/geological_formats/__init__.py
33
33
  subsurface/core/geological_formats/fault.py
34
34
  subsurface/core/geological_formats/boreholes/__init__.py
35
35
  subsurface/core/geological_formats/boreholes/_combine_trajectories.py
36
+ subsurface/core/geological_formats/boreholes/_map_attrs_to_survey.py
37
+ subsurface/core/geological_formats/boreholes/_survey_to_unstruct.py
36
38
  subsurface/core/geological_formats/boreholes/boreholes.py
37
39
  subsurface/core/geological_formats/boreholes/collars.py
38
40
  subsurface/core/geological_formats/boreholes/survey.py