subsurface-terra 2025.1.0rc19__tar.gz → 2026.1.0__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.
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/.teamcity/Subsurface/buildTypes/Subsurface_Testing.xml +1 -1
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/PKG-INFO +1 -1
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/_version.py +3 -3
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/geological_formats/boreholes/_map_attrs_to_survey.py +6 -1
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/base_structures/structured_data.py +43 -2
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/mesh/mx_reader.py +11 -6
- subsurface_terra-2026.1.0/subsurface/modules/reader/volume/read_volume.py +109 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/wells/_read_to_df.py +1 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface_terra.egg-info/PKG-INFO +1 -1
- subsurface_terra-2025.1.0rc19/subsurface/modules/reader/volume/read_volume.py +0 -331
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/.env.example +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/.teamcity/Subsurface/buildTypes/Subsurface_ReleaseSubsurface.xml +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/.teamcity/Subsurface/buildTypes/Subsurface_ReleaseSubsurface_2.xml +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/.teamcity/Subsurface/project-config.xml +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/.teamcity/Subsurface/vcsRoots/Subsurface_HttpsGithubComTerranigmaSolutionsSubsurfaceRefsHeadsMain.xml +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/.teamcity/Subsurface/vcsRoots/Subsurface_HttpsGithubComTerranigmaSolutionsSubsurfaceRefsHeadsMain1.xml +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/.teamcity/Subsurface/vcsRoots/Subsurface_HttpsGithubComTerranigmaSolutionsSubsurfaceRefsHeadsMain2.xml +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/LICENSE +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/README.rst +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements.txt +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_all.txt +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_dev.txt +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_geospatial.txt +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_mesh.txt +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_opt.txt +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_plot.txt +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_traces.txt +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_volume.txt +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_wells.txt +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/setup.cfg +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/setup.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/api/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/api/interfaces/README.rst +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/api/interfaces/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/api/interfaces/stream.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/api/reader/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/api/reader/read_wells.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/geological_formats/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/geological_formats/boreholes/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/geological_formats/boreholes/_combine_trajectories.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/geological_formats/boreholes/_survey_to_unstruct.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/geological_formats/boreholes/boreholes.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/geological_formats/boreholes/collars.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/geological_formats/boreholes/survey.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/geological_formats/fault.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/reader_helpers/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/reader_helpers/reader_unstruct.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/reader_helpers/readers_data.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/reader_helpers/readers_wells.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/README.rst +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/base_structures/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/base_structures/_aux.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/base_structures/_liquid_earth_mesh.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/base_structures/_unstructured_data_constructor.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/base_structures/base_structures_enum.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/base_structures/unstructured_data.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/structured_elements/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/structured_elements/octree_mesh.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/structured_elements/structured_grid.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/structured_elements/structured_mesh.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/unstructured_elements/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/unstructured_elements/line_set.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/unstructured_elements/point_set.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/unstructured_elements/tetrahedron_mesh.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/unstructured_elements/triangular_surface.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/utils/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/utils/utils_core.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/README.rst +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/faults/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/faults/faults.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/from_binary.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/geo_object/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/mesh/NOTES.md +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/mesh/_GOCAD_mesh.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/mesh/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/mesh/_trimesh_reader.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/mesh/csv_mesh_reader.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/mesh/dxf_reader.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/mesh/glb_reader.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/mesh/obj_reader.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/mesh/omf_mesh_reader.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/mesh/surface_reader.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/mesh/surfaces_api.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/petrel/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/profiles/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/profiles/profiles_core.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/read_netcdf.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/topography/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/topography/topo_core.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/volume/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/volume/read_grav3d.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/volume/segy_reader.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/volume/seismic.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/volume/volume_utils.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/wells/DEP/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/wells/DEP/_well_files_reader.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/wells/DEP/_wells_api.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/wells/DEP/_welly_reader.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/wells/DEP/pandas_to_welly.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/wells/README.rst +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/wells/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/wells/read_borehole_interface.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/wells/wells_utils.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/tools/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/tools/mocking_aux.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/visualization/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/visualization/to_pyvista.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/to_binary.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/to_liquid_earth/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/to_rex/__init__.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/to_rex/common.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/to_rex/data_struct.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/to_rex/doc/rex-spec-v1.md +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/to_rex/doc/right-handed.png +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/to_rex/doc/sketchup_example.jpg +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/to_rex/gempy_to_rexfile.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/to_rex/material_encoder.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/to_rex/mesh_encoder.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/to_rex/to_rex.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/to_rex/utils.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/optional_requirements.py +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface_terra.egg-info/SOURCES.txt +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface_terra.egg-info/dependency_links.txt +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface_terra.egg-info/not-zip-safe +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface_terra.egg-info/requires.txt +0 -0
- {subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface_terra.egg-info/top_level.txt +0 -0
|
@@ -66,7 +66,7 @@ VENVPY="venv/bin/python -E -s"
|
|
|
66
66
|
VENVPIP="venv/bin/python -E -s -m pip"
|
|
67
67
|
|
|
68
68
|
$VENVPIP install --upgrade pip setuptools wheel
|
|
69
|
-
$VENVPIP install --verbose -r requirements/requirements_dev.txt
|
|
69
|
+
$VENVPIP install --verbose --pre -r requirements/requirements_dev.txt
|
|
70
70
|
$VENVPIP install --verbose teamcity-messages
|
|
71
71
|
|
|
72
72
|
# Sanity probe
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: subsurface_terra
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2026.1.0
|
|
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
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '
|
|
32
|
-
__version_tuple__ = version_tuple = (
|
|
31
|
+
__version__ = version = '2026.1.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (2026, 1, 0)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g6895b391e'
|
|
@@ -216,7 +216,7 @@ def _map_attrs_to_measured_depths(attrs: pd.DataFrame, survey_trajectory: LineSe
|
|
|
216
216
|
continue
|
|
217
217
|
|
|
218
218
|
attr_values = attrs_well[col]
|
|
219
|
-
is_categorical = attr_values.dtype == 'O' or isinstance(attr_values.dtype, pd.CategoricalDtype)
|
|
219
|
+
is_categorical = attr_values.dtype == 'O' or isinstance(attr_values.dtype, pd.CategoricalDtype) or isinstance(attr_values.dtype, pd.StringDtype)
|
|
220
220
|
|
|
221
221
|
# Skip columns that can't be interpolated and aren't categorical
|
|
222
222
|
if is_categorical and col not in ['lith_ids', 'component lith']:
|
|
@@ -231,6 +231,11 @@ def _map_attrs_to_measured_depths(attrs: pd.DataFrame, survey_trajectory: LineSe
|
|
|
231
231
|
is_categorical
|
|
232
232
|
)
|
|
233
233
|
|
|
234
|
+
# Convert to appropriate dtype to avoid pandas 3.0 dtype coercion errors
|
|
235
|
+
target_dtype = new_attrs[col].dtype
|
|
236
|
+
if pd.api.types.is_numeric_dtype(target_dtype) and not is_categorical:
|
|
237
|
+
interpolated_values = np.asarray(interpolated_values, dtype=target_dtype)
|
|
238
|
+
|
|
234
239
|
new_attrs.loc[well_mask, col] = interpolated_values
|
|
235
240
|
|
|
236
241
|
return new_attrs
|
|
@@ -14,6 +14,10 @@ class StructuredDataType(enum.Enum):
|
|
|
14
14
|
IRREGULAR_AXIS_ALIGNED = 2 #: Irregular axis aligned grid. Distance between consecutive points is not constant
|
|
15
15
|
IRREGULAR_AXIS_UNALIGNED = 3 #: Irregular axis unaligned grid. Distance between consecutive points is not constant
|
|
16
16
|
|
|
17
|
+
# [CLN] This terminology looks odd to me.
|
|
18
|
+
# "Uniform" vs. "non-uniform" is what PyVista uses instead of "regular" vs. "irregular".
|
|
19
|
+
# "Rectilinear" vs. "curvilinear" is what Pyvista uses instead of "axis-aligned" vs "axis-unaligned".
|
|
20
|
+
# As of right now it's not clear to me that anything other than REGULAR_AXIS_ALIGNED is actually valid in this file.
|
|
17
21
|
|
|
18
22
|
@dataclass(frozen=False)
|
|
19
23
|
class StructuredData:
|
|
@@ -85,12 +89,49 @@ class StructuredData:
|
|
|
85
89
|
return cls(dataset, data_array_name)
|
|
86
90
|
|
|
87
91
|
@classmethod
|
|
88
|
-
def
|
|
92
|
+
def from_pyvista(
|
|
89
93
|
cls,
|
|
90
|
-
|
|
94
|
+
pyvista_object: 'pyvista.DataSet',
|
|
91
95
|
data_array_name: str = "data_array"
|
|
92
96
|
):
|
|
93
97
|
pyvista = require_pyvista()
|
|
98
|
+
|
|
99
|
+
def rectilinear_is_uniform(
|
|
100
|
+
rectilinear_grid: pyvista.RectilinearGrid,
|
|
101
|
+
relative_tolerance: float = 1e-6,
|
|
102
|
+
absolute_tolerance: float = 1e-12,
|
|
103
|
+
) -> bool:
|
|
104
|
+
|
|
105
|
+
def axis_is_uniform(v: np.ndarray) -> bool:
|
|
106
|
+
v = np.asarray(v, dtype=float)
|
|
107
|
+
if v.size <= 2:
|
|
108
|
+
# 0, 1 or 2 points → treat as uniform for our purposes
|
|
109
|
+
return True
|
|
110
|
+
diffs = np.diff(v)
|
|
111
|
+
first = diffs[0]
|
|
112
|
+
return np.allclose(diffs, first, rtol=relative_tolerance, atol=absolute_tolerance)
|
|
113
|
+
|
|
114
|
+
return (axis_is_uniform(rectilinear_grid.x)
|
|
115
|
+
and axis_is_uniform(rectilinear_grid.y)
|
|
116
|
+
and axis_is_uniform(rectilinear_grid.z))
|
|
117
|
+
|
|
118
|
+
extended_help_message = "Only uniform rectilinear grids are currently supported. The VTK format is developed by KitWare and you can use their free software ParaView to further inspect your file. In ParaView, in Information > Data Statistics, the Type must be Image (Uniform Rectilinear Grid). Furthermore, you can use ParaView to interpolate your data on to a uniform rectilinear grid and to export it as Image type."
|
|
119
|
+
|
|
120
|
+
match pyvista_object:
|
|
121
|
+
case pyvista.UnstructuredGrid():
|
|
122
|
+
# In a previous version of Subsurface there was an ill-formed attempt at supporting some unstructured grids here.
|
|
123
|
+
# I've left this function to minimize downstream changes and also in case we decide to revive anything in that direction.
|
|
124
|
+
raise ValueError(f"Cannot generally convert unstructured grids to structured grids. {extended_help_message}")
|
|
125
|
+
case pyvista.ImageData():
|
|
126
|
+
pass
|
|
127
|
+
case pyvista.RectilinearGrid() as rectilinear:
|
|
128
|
+
if not rectilinear_is_uniform(rectilinear):
|
|
129
|
+
raise NotImplementedError(f"Non-uniform rectilinear grid conversion is not yet implemented. {extended_help_message}")
|
|
130
|
+
case _:
|
|
131
|
+
raise ValueError(f"Unexpected VTK grid type. {extended_help_message}")
|
|
132
|
+
|
|
133
|
+
grid = pyvista_object.cast_to_structured_grid()
|
|
134
|
+
|
|
94
135
|
# Extract p
|
|
95
136
|
|
|
96
137
|
# Extract cell data and point data (if any)
|
|
@@ -82,7 +82,7 @@ def _process_mesh(mesh_lines) -> Optional[GOCADMesh]:
|
|
|
82
82
|
in_header = False
|
|
83
83
|
in_coord_sys = False
|
|
84
84
|
in_property_class_header = False
|
|
85
|
-
|
|
85
|
+
in_geometry = False
|
|
86
86
|
current_property_class_header = {}
|
|
87
87
|
vertex_list = []
|
|
88
88
|
vertex_indices = []
|
|
@@ -152,11 +152,16 @@ def _process_mesh(mesh_lines) -> Optional[GOCADMesh]:
|
|
|
152
152
|
current_property_class_header[line.strip()] = None
|
|
153
153
|
continue
|
|
154
154
|
|
|
155
|
-
if
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
if not in_geometry:
|
|
156
|
+
if line == 'TFACE':
|
|
157
|
+
in_geometry = True
|
|
158
|
+
continue
|
|
159
|
+
if line.startswith(("VRTX", "PVRTX", "ATOM", "TRGL", "BSTONE", "BORDER")):
|
|
160
|
+
# Some TSurf files omit TFACE; geometry can start immediately.
|
|
161
|
+
in_geometry = True
|
|
162
|
+
# Do not `continue`. The geometry is already in the current line.
|
|
158
163
|
|
|
159
|
-
if
|
|
164
|
+
if in_geometry:
|
|
160
165
|
if line.startswith('VRTX') or line.startswith('PVRTX'):
|
|
161
166
|
# Parse vertex line
|
|
162
167
|
parts = line.split()
|
|
@@ -207,7 +212,7 @@ def _process_mesh(mesh_lines) -> Optional[GOCADMesh]:
|
|
|
207
212
|
mesh.borders.append({'id': int(bid), 'v1': int(v1), 'v2': int(v2)})
|
|
208
213
|
continue
|
|
209
214
|
elif line == 'END':
|
|
210
|
-
|
|
215
|
+
in_geometry = False
|
|
211
216
|
continue
|
|
212
217
|
else:
|
|
213
218
|
pass
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from io import BytesIO
|
|
3
|
+
from typing import Union
|
|
4
|
+
|
|
5
|
+
from subsurface.core.structs import StructuredData
|
|
6
|
+
|
|
7
|
+
from .... import optional_requirements
|
|
8
|
+
from ....core.structs import UnstructuredData
|
|
9
|
+
from subsurface.core.reader_helpers.readers_data import GenericReaderFilesHelper
|
|
10
|
+
import numpy as np
|
|
11
|
+
import pandas as pd
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def read_VTK_structured_grid(file_or_buffer: Union[str, BytesIO], active_scalars: str) -> StructuredData:
|
|
15
|
+
pv = optional_requirements.require_pyvista()
|
|
16
|
+
|
|
17
|
+
if isinstance(file_or_buffer, BytesIO):
|
|
18
|
+
# If file_or_buffer is a BytesIO, write it to a temporary file
|
|
19
|
+
from tempfile import NamedTemporaryFile
|
|
20
|
+
with NamedTemporaryFile('wb', suffix='.vtk', delete=False) as temp_file:
|
|
21
|
+
# Write the BytesIO content to the temporary file
|
|
22
|
+
getvalue: bytes = file_or_buffer.getvalue()
|
|
23
|
+
temp_file.write(getvalue)
|
|
24
|
+
temp_file.flush() # Make sure all data is written
|
|
25
|
+
temp_file_name = temp_file.name # Store the temporary file name
|
|
26
|
+
try:
|
|
27
|
+
# Use pyvista.read() to read from the temporary file
|
|
28
|
+
pyvista_obj = pv.read(temp_file_name)
|
|
29
|
+
finally:
|
|
30
|
+
# Ensure the temporary file is deleted after reading
|
|
31
|
+
os.remove(temp_file_name)
|
|
32
|
+
else:
|
|
33
|
+
# If it's a file path, read directly
|
|
34
|
+
pyvista_obj = pv.read(file_or_buffer)
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
struct: StructuredData = StructuredData.from_pyvista(
|
|
38
|
+
pyvista_object=pyvista_obj,
|
|
39
|
+
data_array_name=active_scalars
|
|
40
|
+
)
|
|
41
|
+
except Exception as e:
|
|
42
|
+
raise ValueError(f"Failed to convert to StructuredData: {e}")
|
|
43
|
+
|
|
44
|
+
return struct
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def read_volumetric_mesh_to_subsurface(reader_helper_coord: GenericReaderFilesHelper,
|
|
48
|
+
reader_helper_attr: GenericReaderFilesHelper) -> UnstructuredData:
|
|
49
|
+
df_coord = read_volumetric_mesh_coord_file(reader_helper_coord)
|
|
50
|
+
if len(df_coord.columns) == 1:
|
|
51
|
+
raise ValueError(
|
|
52
|
+
"The attributes file has only one column, probably the columns are not being separated correctly. Use 'sep' in Additional Reader Arguments"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
df_attr = read_volumetric_mesh_attr_file(reader_helper_attr)
|
|
56
|
+
# Check if there are more than one column and if it is only one raise an error that probably the columns have not been properly separated. Use "sep" in Additional Reader Arguments
|
|
57
|
+
if len(df_attr.columns) == 1:
|
|
58
|
+
raise ValueError(
|
|
59
|
+
"The attributes file has only one column, probably the columns are not being separated correctly. Use 'sep' in Additional Reader Arguments"
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
combined_df = df_coord.merge(df_attr, left_index=True, right_index=True)
|
|
63
|
+
ud = UnstructuredData.from_array(
|
|
64
|
+
vertex=combined_df[['x', 'y', 'z']], cells="points",
|
|
65
|
+
attributes=combined_df[['pres', 'temp', 'sg', 'xco2']]
|
|
66
|
+
)
|
|
67
|
+
return ud
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def read_volumetric_mesh_coord_file(reader_helper: GenericReaderFilesHelper) -> pd.DataFrame:
|
|
71
|
+
df = pd.read_csv(
|
|
72
|
+
filepath_or_buffer=reader_helper.file_or_buffer,
|
|
73
|
+
**reader_helper.pandas_reader_kwargs
|
|
74
|
+
)
|
|
75
|
+
if reader_helper.columns_map is not None:
|
|
76
|
+
df.rename(
|
|
77
|
+
mapper=reader_helper.columns_map,
|
|
78
|
+
axis="columns",
|
|
79
|
+
inplace=True
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
df.dropna(axis=0, inplace=True)
|
|
83
|
+
|
|
84
|
+
df.x = df.x.astype(float)
|
|
85
|
+
df.y = df.y.astype(float)
|
|
86
|
+
df.z = df.z.astype(float)
|
|
87
|
+
# Throw error if empty
|
|
88
|
+
if df.empty:
|
|
89
|
+
raise ValueError("The file is empty")
|
|
90
|
+
|
|
91
|
+
return df
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def read_volumetric_mesh_attr_file(reader_helper: GenericReaderFilesHelper) -> pd.DataFrame:
|
|
95
|
+
df = pd.read_table(reader_helper.file_or_buffer, **reader_helper.pandas_reader_kwargs)
|
|
96
|
+
df.columns = df.columns.astype(str).str.strip()
|
|
97
|
+
return df
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def pv_cast_to_structured_grid(pyvista_object: 'pv.DataSet') -> 'pv.StructuredGrid':
|
|
101
|
+
pv = optional_requirements.require_pyvista()
|
|
102
|
+
|
|
103
|
+
match pyvista_object:
|
|
104
|
+
case pv.UnstructuredGrid():
|
|
105
|
+
# In a previous version of Subsurface there was an ill-formed attempt at supporting some unstructured grids here.
|
|
106
|
+
# I've left this function to minimize downstream changes and also in case we decide to revive anything in that direction.
|
|
107
|
+
raise ValueError("Cannot generally convert unstructured grids to structured grids.")
|
|
108
|
+
case _:
|
|
109
|
+
return pyvista_object.cast_to_structured_grid()
|
|
@@ -16,6 +16,7 @@ def check_format_and_read_to_df(reader_helper: GenericReaderFilesHelper) -> pd.D
|
|
|
16
16
|
d = reader(
|
|
17
17
|
filepath_or_buffer=reader_helper.file_or_buffer,
|
|
18
18
|
sep=reader_helper.separator,
|
|
19
|
+
engine='python',
|
|
19
20
|
**reader_helper.pandas_reader_kwargs
|
|
20
21
|
)
|
|
21
22
|
case (bytes() | io.BytesIO() | io.StringIO() | io.TextIOWrapper()), _:
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface_terra.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: subsurface_terra
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2026.1.0
|
|
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
|
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from io import BytesIO
|
|
3
|
-
from typing import Union
|
|
4
|
-
|
|
5
|
-
from subsurface.core.structs import StructuredData
|
|
6
|
-
|
|
7
|
-
from .... import optional_requirements
|
|
8
|
-
from ....core.structs import UnstructuredData
|
|
9
|
-
from subsurface.core.reader_helpers.readers_data import GenericReaderFilesHelper
|
|
10
|
-
import numpy as np
|
|
11
|
-
import pandas as pd
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def read_VTK_structured_grid(file_or_buffer: Union[str, BytesIO], active_scalars: str) -> StructuredData:
|
|
15
|
-
pv = optional_requirements.require_pyvista()
|
|
16
|
-
|
|
17
|
-
if isinstance(file_or_buffer, BytesIO):
|
|
18
|
-
# If file_or_buffer is a BytesIO, write it to a temporary file
|
|
19
|
-
from tempfile import NamedTemporaryFile
|
|
20
|
-
with NamedTemporaryFile('wb', suffix='.vtk', delete=False) as temp_file:
|
|
21
|
-
# Write the BytesIO content to the temporary file
|
|
22
|
-
getvalue: bytes = file_or_buffer.getvalue()
|
|
23
|
-
temp_file.write(getvalue)
|
|
24
|
-
temp_file.flush() # Make sure all data is written
|
|
25
|
-
temp_file_name = temp_file.name # Store the temporary file name
|
|
26
|
-
try:
|
|
27
|
-
# Use pyvista.read() to read from the temporary file
|
|
28
|
-
pyvista_obj = pv.read(temp_file_name)
|
|
29
|
-
finally:
|
|
30
|
-
# Ensure the temporary file is deleted after reading
|
|
31
|
-
os.remove(temp_file_name)
|
|
32
|
-
else:
|
|
33
|
-
# If it's a file path, read directly
|
|
34
|
-
pyvista_obj = pv.read(file_or_buffer)
|
|
35
|
-
try:
|
|
36
|
-
pyvista_struct: pv.ExplicitStructuredGrid = pv_cast_to_explicit_structured_grid(pyvista_obj)
|
|
37
|
-
except Exception as e:
|
|
38
|
-
raise ValueError(f"The file is not a structured grid: {e}")
|
|
39
|
-
|
|
40
|
-
if PLOT := False:
|
|
41
|
-
pyvista_struct.set_active_scalars(active_scalars)
|
|
42
|
-
pyvista_struct.plot()
|
|
43
|
-
|
|
44
|
-
struct: StructuredData = StructuredData.from_pyvista_structured_grid(
|
|
45
|
-
grid=pyvista_struct,
|
|
46
|
-
data_array_name=active_scalars
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
return struct
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def read_volumetric_mesh_to_subsurface(reader_helper_coord: GenericReaderFilesHelper,
|
|
53
|
-
reader_helper_attr: GenericReaderFilesHelper) -> UnstructuredData:
|
|
54
|
-
df_coord = read_volumetric_mesh_coord_file(reader_helper_coord)
|
|
55
|
-
if len(df_coord.columns) == 1:
|
|
56
|
-
raise ValueError(
|
|
57
|
-
"The attributes file has only one column, probably the columns are not being separated correctly. Use 'sep' in Additional Reader Arguments"
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
df_attr = read_volumetric_mesh_attr_file(reader_helper_attr)
|
|
61
|
-
# Check if there are more than one column and if it is only one raise an error that probably the columns have not been properly separated. Use "sep" in Additional Reader Arguments
|
|
62
|
-
if len(df_attr.columns) == 1:
|
|
63
|
-
raise ValueError(
|
|
64
|
-
"The attributes file has only one column, probably the columns are not being separated correctly. Use 'sep' in Additional Reader Arguments"
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
combined_df = df_coord.merge(df_attr, left_index=True, right_index=True)
|
|
68
|
-
ud = UnstructuredData.from_array(
|
|
69
|
-
vertex=combined_df[['x', 'y', 'z']], cells="points",
|
|
70
|
-
attributes=combined_df[['pres', 'temp', 'sg', 'xco2']]
|
|
71
|
-
)
|
|
72
|
-
return ud
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def read_volumetric_mesh_coord_file(reader_helper: GenericReaderFilesHelper) -> pd.DataFrame:
|
|
76
|
-
df = pd.read_csv(
|
|
77
|
-
filepath_or_buffer=reader_helper.file_or_buffer,
|
|
78
|
-
**reader_helper.pandas_reader_kwargs
|
|
79
|
-
)
|
|
80
|
-
if reader_helper.columns_map is not None:
|
|
81
|
-
df.rename(
|
|
82
|
-
mapper=reader_helper.columns_map,
|
|
83
|
-
axis="columns",
|
|
84
|
-
inplace=True
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
df.dropna(axis=0, inplace=True)
|
|
88
|
-
|
|
89
|
-
df.x = df.x.astype(float)
|
|
90
|
-
df.y = df.y.astype(float)
|
|
91
|
-
df.z = df.z.astype(float)
|
|
92
|
-
# Throw error if empty
|
|
93
|
-
if df.empty:
|
|
94
|
-
raise ValueError("The file is empty")
|
|
95
|
-
|
|
96
|
-
return df
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
def read_volumetric_mesh_attr_file(reader_helper: GenericReaderFilesHelper) -> pd.DataFrame:
|
|
100
|
-
df = pd.read_table(reader_helper.file_or_buffer, **reader_helper.pandas_reader_kwargs)
|
|
101
|
-
df.columns = df.columns.astype(str).str.strip()
|
|
102
|
-
return df
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def pv_cast_to_explicit_structured_grid(pyvista_object: 'pv.DataSet') -> 'pv.ExplicitStructuredGrid':
|
|
106
|
-
pv = optional_requirements.require_pyvista()
|
|
107
|
-
|
|
108
|
-
match pyvista_object:
|
|
109
|
-
case pv.RectilinearGrid() as rectl_grid:
|
|
110
|
-
return __pv_convert_rectilinear_to_explicit(rectl_grid)
|
|
111
|
-
case pv.UnstructuredGrid() as unstr_grid:
|
|
112
|
-
return __pv_convert_unstructured_to_explicit(unstr_grid)
|
|
113
|
-
case _:
|
|
114
|
-
return pyvista_object.cast_to_explicit_structured_grid()
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
def __pv_convert_unstructured_to_explicit(unstr_grid):
|
|
118
|
-
"""
|
|
119
|
-
Convert a PyVista UnstructuredGrid to an ExplicitStructuredGrid if possible.
|
|
120
|
-
"""
|
|
121
|
-
pv = optional_requirements.require_pyvista()
|
|
122
|
-
|
|
123
|
-
# First check if the grid has the necessary attributes to be treated as structured
|
|
124
|
-
if not hasattr(unstr_grid, 'n_cells') or unstr_grid.n_cells == 0:
|
|
125
|
-
raise ValueError("The unstructured grid has no cells.")
|
|
126
|
-
|
|
127
|
-
# Try to detect if the grid has a structured topology
|
|
128
|
-
# Check if the grid has cell type 11 (VTK_VOXEL) or 12 (VTK_HEXAHEDRON)
|
|
129
|
-
cell_types = unstr_grid.celltypes
|
|
130
|
-
|
|
131
|
-
# Voxels (11) and hexahedra (12) are the cell types used in structured grids
|
|
132
|
-
if not all(ct in [11, 12] for ct in cell_types):
|
|
133
|
-
raise ValueError("The unstructured grid contains non-hexahedral cells and cannot be converted to explicit structured.")
|
|
134
|
-
|
|
135
|
-
# Try to infer dimensions from the grid
|
|
136
|
-
try:
|
|
137
|
-
# Method 1: Try PyVista's built-in conversion if available
|
|
138
|
-
return unstr_grid.cast_to_explicit_structured_grid()
|
|
139
|
-
except (AttributeError, TypeError):
|
|
140
|
-
pass
|
|
141
|
-
|
|
142
|
-
try:
|
|
143
|
-
# Method 2: If the grid has dimensions stored as field data
|
|
144
|
-
if "dimensions" in unstr_grid.field_data:
|
|
145
|
-
dims = unstr_grid.field_data["dimensions"]
|
|
146
|
-
if len(dims) == 3:
|
|
147
|
-
nx, ny, nz = dims
|
|
148
|
-
# Verify that dimensions match the number of cells
|
|
149
|
-
if (nx-1)*(ny-1)*(nz-1) != unstr_grid.n_cells:
|
|
150
|
-
raise ValueError("Stored dimensions do not match the number of cells.")
|
|
151
|
-
|
|
152
|
-
# Extract points and reorder if needed
|
|
153
|
-
points = unstr_grid.points.reshape((nx, ny, nz, 3))
|
|
154
|
-
|
|
155
|
-
# Create explicit structured grid
|
|
156
|
-
explicit_grid = pv.ExplicitStructuredGrid((nx, ny, nz), points.reshape((-1, 3)))
|
|
157
|
-
explicit_grid.compute_connectivity()
|
|
158
|
-
|
|
159
|
-
# Transfer data arrays
|
|
160
|
-
for name, array in unstr_grid.cell_data.items():
|
|
161
|
-
explicit_grid.cell_data[name] = array.copy()
|
|
162
|
-
for name, array in unstr_grid.point_data.items():
|
|
163
|
-
explicit_grid.point_data[name] = array.copy()
|
|
164
|
-
for name, array in unstr_grid.field_data.items():
|
|
165
|
-
if name != "dimensions": # Skip dimensions field
|
|
166
|
-
explicit_grid.field_data[name] = array.copy()
|
|
167
|
-
|
|
168
|
-
return explicit_grid
|
|
169
|
-
except (ValueError, KeyError):
|
|
170
|
-
pass
|
|
171
|
-
|
|
172
|
-
# If none of the above methods work, use PyVista's extract_cells function
|
|
173
|
-
# to reconstruct the structured grid if possible
|
|
174
|
-
try:
|
|
175
|
-
# This is a best-effort approach that tries multiple strategies
|
|
176
|
-
return pv.core.filters.convert_unstructured_to_structured_grid(unstr_grid)
|
|
177
|
-
except Exception as e:
|
|
178
|
-
raise ValueError(f"Failed to convert unstructured grid to explicit structured grid: {e}")
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
def __pv_convert_rectilinear_to_explicit(rectl_grid, *, temp_dtype=None):
|
|
182
|
-
"""
|
|
183
|
-
Convert a PyVista RectilinearGrid to an ExplicitStructuredGrid with low peak memory.
|
|
184
|
-
|
|
185
|
-
Behavior:
|
|
186
|
-
- Output points are in world coordinates, dtype matches rectl_grid.points.dtype.
|
|
187
|
-
- Data arrays are shallow-transferred (no deep copies).
|
|
188
|
-
- temp_dtype controls the large temporary `corners` buffer dtype.
|
|
189
|
-
* If temp_dtype is None (default), use float32 when the output dtype is wider (e.g., float64),
|
|
190
|
-
else use the output dtype. This reduces peak memory automatically.
|
|
191
|
-
* If temp_dtype < output dtype, coordinates are recentred for precision and origin is added back after.
|
|
192
|
-
|
|
193
|
-
Parameters
|
|
194
|
-
----------
|
|
195
|
-
rectl_grid : pv.RectilinearGrid
|
|
196
|
-
temp_dtype : numpy dtype or None
|
|
197
|
-
Dtype for building the temporary `corners` array. Examples:
|
|
198
|
-
- None (default): auto -> float32 if output dtype is wider, else output dtype.
|
|
199
|
-
- np.float32: memory-friendly; auto recenters & restores origin.
|
|
200
|
-
- np.float64: highest precision (more memory).
|
|
201
|
-
|
|
202
|
-
Returns
|
|
203
|
-
-------
|
|
204
|
-
pv.ExplicitStructuredGrid
|
|
205
|
-
"""
|
|
206
|
-
import numpy as np
|
|
207
|
-
pv = optional_requirements.require_pyvista()
|
|
208
|
-
|
|
209
|
-
# Output dtype follows source grid points (usually float64)
|
|
210
|
-
out_dtype = getattr(rectl_grid.points, "dtype", np.float64)
|
|
211
|
-
|
|
212
|
-
# Auto-pick temp dtype: prefer float32 when output is wider (e.g., float64)
|
|
213
|
-
if temp_dtype is None:
|
|
214
|
-
temp_dtype = np.float32 if (
|
|
215
|
-
np.dtype(out_dtype).kind == 'f' and np.dtype(out_dtype).itemsize > 4) else out_dtype
|
|
216
|
-
|
|
217
|
-
# Coordinate arrays
|
|
218
|
-
x = np.asarray(rectl_grid.x)
|
|
219
|
-
y = np.asarray(rectl_grid.y)
|
|
220
|
-
z = np.asarray(rectl_grid.z)
|
|
221
|
-
|
|
222
|
-
# Decide if we must recenter (when temp dtype is lower precision than output dtype)
|
|
223
|
-
def _is_lower_precision(src, dst):
|
|
224
|
-
s, d = np.dtype(src), np.dtype(dst)
|
|
225
|
-
if s.kind != 'f' or d.kind != 'f':
|
|
226
|
-
return s != d
|
|
227
|
-
return s.itemsize < d.itemsize
|
|
228
|
-
|
|
229
|
-
if _is_lower_precision(temp_dtype, out_dtype):
|
|
230
|
-
origin = np.array([x[0], y[0], z[0]], dtype=np.float64)
|
|
231
|
-
x_base, y_base, z_base = x - origin[0], y - origin[1], z - origin[2]
|
|
232
|
-
else:
|
|
233
|
-
origin = None
|
|
234
|
-
x_base, y_base, z_base = x, y, z
|
|
235
|
-
|
|
236
|
-
# Double coordinates (interior duplication expected by ExplicitStructuredGrid ctor)
|
|
237
|
-
def _doubled(arr):
|
|
238
|
-
# [a,b,c,d] -> [a, b,b, c,c, d]
|
|
239
|
-
return np.repeat(arr, 2)[1:-1]
|
|
240
|
-
|
|
241
|
-
xcorn = _doubled(x_base)
|
|
242
|
-
ycorn = _doubled(y_base)
|
|
243
|
-
zcorn = _doubled(z_base)
|
|
244
|
-
|
|
245
|
-
nx2, ny2, nz2 = len(xcorn), len(ycorn), len(zcorn)
|
|
246
|
-
slab = ny2 * nz2
|
|
247
|
-
N = nx2 * slab
|
|
248
|
-
|
|
249
|
-
# Build corners via slab/chunked fill (avoids N-sized intermediates)
|
|
250
|
-
yz = np.empty((slab, 2), dtype=temp_dtype)
|
|
251
|
-
yz[:, 0] = np.repeat(ycorn, nz2).astype(temp_dtype, copy=False) # Y pattern
|
|
252
|
-
yz[:, 1] = np.tile(zcorn, ny2).astype(temp_dtype, copy=False) # Z pattern
|
|
253
|
-
|
|
254
|
-
corners = np.empty((N, 3), dtype=temp_dtype)
|
|
255
|
-
for i, xv in enumerate(xcorn):
|
|
256
|
-
start = i * slab
|
|
257
|
-
end = start + slab
|
|
258
|
-
corners[start:end, 0] = xv
|
|
259
|
-
corners[start:end, 1:3] = yz
|
|
260
|
-
|
|
261
|
-
# Construct explicit grid
|
|
262
|
-
dims = (len(x), len(y), len(z))
|
|
263
|
-
explicit = pv.ExplicitStructuredGrid(dims, corners)
|
|
264
|
-
explicit.compute_connectivity()
|
|
265
|
-
|
|
266
|
-
# Always return world coordinates; add origin back and cast to out_dtype in one fused pass
|
|
267
|
-
if origin is not None:
|
|
268
|
-
new_pts = np.empty_like(explicit.points, dtype=out_dtype)
|
|
269
|
-
np.add(explicit.points, origin, out=new_pts, dtype=out_dtype)
|
|
270
|
-
explicit.points = new_pts
|
|
271
|
-
else:
|
|
272
|
-
if explicit.points.dtype != out_dtype:
|
|
273
|
-
explicit.points = explicit.points.astype(out_dtype, copy=False)
|
|
274
|
-
|
|
275
|
-
# Shallow-transfer all data arrays (no deep copies)
|
|
276
|
-
for name, arr in rectl_grid.cell_data.items():
|
|
277
|
-
explicit.cell_data[name] = arr
|
|
278
|
-
for name, arr in rectl_grid.point_data.items():
|
|
279
|
-
explicit.point_data[name] = arr
|
|
280
|
-
for name, arr in rectl_grid.field_data.items():
|
|
281
|
-
explicit.field_data[name] = arr
|
|
282
|
-
|
|
283
|
-
__validate_rectilinear_to_explicit_conversion(rectl_grid, explicit)
|
|
284
|
-
|
|
285
|
-
return explicit
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
def __validate_rectilinear_to_explicit_conversion(rectl_grid, explicit_grid, *, atol=1e-6, rtol=1e-8) -> None:
|
|
289
|
-
"""
|
|
290
|
-
Validate core equivalence between a RectilinearGrid and its ExplicitStructuredGrid.
|
|
291
|
-
Raises ValueError on mismatch. Avoids large 3D uniques / big temporaries.
|
|
292
|
-
"""
|
|
293
|
-
import numpy as np
|
|
294
|
-
|
|
295
|
-
# dims & counts
|
|
296
|
-
nx, ny, nz = map(int, rectl_grid.dimensions)
|
|
297
|
-
if tuple(map(int, explicit_grid.dimensions)) != (nx, ny, nz):
|
|
298
|
-
raise ValueError(f"Dimensions differ: explicit {tuple(explicit_grid.dimensions)} vs rect {tuple(rectl_grid.dimensions)}")
|
|
299
|
-
|
|
300
|
-
expected_cells = (nx - 1) * (ny - 1) * (nz - 1)
|
|
301
|
-
if explicit_grid.n_cells != expected_cells:
|
|
302
|
-
raise ValueError(f"Cell count mismatch: explicit {explicit_grid.n_cells} vs expected {expected_cells}")
|
|
303
|
-
|
|
304
|
-
# Accept either nodes (M) or corners (N) for n_points, depending on PyVista/VTK version
|
|
305
|
-
M = nx * ny * nz
|
|
306
|
-
N = (2 * (nx - 1)) * (2 * (ny - 1)) * (2 * (nz - 1))
|
|
307
|
-
if explicit_grid.n_points not in (M, N):
|
|
308
|
-
raise ValueError(
|
|
309
|
-
f"Point count unexpected: explicit {explicit_grid.n_points}; expected either nodes {M} or corners {N}"
|
|
310
|
-
)
|
|
311
|
-
|
|
312
|
-
# bounds
|
|
313
|
-
if not np.allclose(explicit_grid.bounds, rectl_grid.bounds, rtol=rtol, atol=atol):
|
|
314
|
-
raise ValueError(f"Bounds differ: explicit {explicit_grid.bounds} vs rect {rectl_grid.bounds}")
|
|
315
|
-
|
|
316
|
-
# axis coordinates (order-independent, light memory use: 1D uniques per axis)
|
|
317
|
-
pts = explicit_grid.points # may be M×3 (unique nodes) or N×3 (corner lattice)
|
|
318
|
-
x_exp = np.unique(pts[:, 0])
|
|
319
|
-
y_exp = np.unique(pts[:, 1])
|
|
320
|
-
z_exp = np.unique(pts[:, 2])
|
|
321
|
-
|
|
322
|
-
x_rect = np.asarray(rectl_grid.x)
|
|
323
|
-
y_rect = np.asarray(rectl_grid.y)
|
|
324
|
-
z_rect = np.asarray(rectl_grid.z)
|
|
325
|
-
|
|
326
|
-
if len(x_exp) != len(x_rect) or not np.allclose(x_exp, x_rect, rtol=rtol, atol=atol):
|
|
327
|
-
raise ValueError("X axis coordinates differ.")
|
|
328
|
-
if len(y_exp) != len(y_rect) or not np.allclose(y_exp, y_rect, rtol=rtol, atol=atol):
|
|
329
|
-
raise ValueError("Y axis coordinates differ.")
|
|
330
|
-
if len(z_exp) != len(z_rect) or not np.allclose(z_exp, z_rect, rtol=rtol, atol=atol):
|
|
331
|
-
raise ValueError("Z axis coordinates differ.")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/.teamcity/Subsurface/project-config.xml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_all.txt
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_dev.txt
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_geospatial.txt
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_mesh.txt
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_opt.txt
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_plot.txt
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_traces.txt
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_volume.txt
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/requirements/requirements_wells.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/api/interfaces/README.rst
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/api/interfaces/__init__.py
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/api/interfaces/stream.py
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/api/reader/__init__.py
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/api/reader/read_wells.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/README.rst
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/structs/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/utils/__init__.py
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/core/utils/utils_core.py
RENAMED
|
File without changes
|
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/README.rst
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/from_binary.py
RENAMED
|
File without changes
|
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/mesh/NOTES.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/reader/read_netcdf.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/tools/__init__.py
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/tools/mocking_aux.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/__init__.py
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/modules/writer/to_binary.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface/optional_requirements.py
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface_terra.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface_terra.egg-info/not-zip-safe
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface_terra.egg-info/requires.txt
RENAMED
|
File without changes
|
{subsurface_terra-2025.1.0rc19 → subsurface_terra-2026.1.0}/subsurface_terra.egg-info/top_level.txt
RENAMED
|
File without changes
|