grid-apps 0.1.0b1__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2025 Mira Geoscience
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,105 @@
1
+ Metadata-Version: 2.4
2
+ Name: grid-apps
3
+ Version: 0.1.0b1
4
+ Summary: Grid creation and manipulation using GEOH5 format.
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ License-File: docs/source/THIRD_PARTY_SOFTWARE.rst
8
+ Keywords: geology,geophysics,earth sciences
9
+ Author: Mira Geoscience
10
+ Author-email: support@mirageoscience.com
11
+ Maintainer: Benjamin Kary
12
+ Maintainer-email: benjamink@mirageoscience.com
13
+ Requires-Python: >=3.10,<4.0
14
+ Classifier: Development Status :: 2 - Pre-Alpha
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Natural Language :: English
17
+ Classifier: Operating System :: MacOS
18
+ Classifier: Operating System :: Microsoft :: Windows
19
+ Classifier: Operating System :: POSIX
20
+ Classifier: Operating System :: Unix
21
+ Classifier: Programming Language :: Python
22
+ Classifier: Programming Language :: Python :: 3
23
+ Classifier: Programming Language :: Python :: 3.10
24
+ Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Programming Language :: Python :: 3.13
27
+ Classifier: Programming Language :: Python :: 3.14
28
+ Classifier: Topic :: Scientific/Engineering
29
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
30
+ Classifier: Topic :: Scientific/Engineering :: Physics
31
+ Requires-Dist: discretize (>=0.11.0,<0.12.dev)
32
+ Requires-Dist: geoapps-utils (>=0.6.0b1,<0.7.dev)
33
+ Requires-Dist: geoh5py (>=0.12.0b1,<0.13.dev)
34
+ Requires-Dist: numpy (>=1.26.0,<1.27.0)
35
+ Requires-Dist: pydantic (>=2.5.2,<3.0.0)
36
+ Requires-Dist: scipy (>=1.14.0,<1.15.0)
37
+ Project-URL: Documentation, https://mirageoscience-grid-apps.readthedocs-hosted.com/
38
+ Project-URL: Homepage, https://www.mirageoscience.com/mining-industry-software/python-integration/
39
+ Project-URL: Repository, https://github.com/MiraGeoscience/grid-apps
40
+ Description-Content-Type: text/x-rst
41
+
42
+ grid-apps
43
+ =========
44
+
45
+ The **grid-apps** library offers tools for the creation and manipulation of grid objects (Octree, BlockModel, Grid2D, DrapeModel) using various Python libraries and `geoh5py <https://mirageoscience-geoh5py.readthedocs-hosted.com/>`_.
46
+
47
+ Installation
48
+ ^^^^^^^^^^^^
49
+ **grid-apps** is currently written for Python 3.10 or higher.
50
+
51
+ Install **grid-apps** from PyPI::
52
+
53
+ $ pip install grid-apps
54
+
55
+
56
+ Feedback
57
+ ^^^^^^^^
58
+ Have comments or suggestions? Submit feedback.
59
+ All the content can be found on the github_ repository.
60
+
61
+ .. _github: https://github.com/MiraGeoscience/grid-apps
62
+
63
+
64
+ Visit `Mira Geoscience website <https://mirageoscience.com/>`_ to learn more about our products
65
+ and services.
66
+
67
+
68
+ License
69
+ ^^^^^^^
70
+ MIT License
71
+
72
+ Copyright (c) 2024-2025 Mira Geoscience
73
+
74
+ Permission is hereby granted, free of charge, to any person obtaining a copy
75
+ of this software and associated documentation files (the "Software"), to deal
76
+ in the Software without restriction, including without limitation the rights
77
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
78
+ copies of the Software, and to permit persons to whom the Software is
79
+ furnished to do so, subject to the following conditions:
80
+
81
+ The above copyright notice and this permission notice shall be included in all
82
+ copies or substantial portions of the Software.
83
+
84
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
85
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
86
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
87
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
88
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
89
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
90
+ SOFTWARE.
91
+
92
+ Third Party Software
93
+ ^^^^^^^^^^^^^^^^^^^^
94
+ The grid-apps Software may provide links to third party libraries or code (collectively “Third Party Software”)
95
+ to implement various functions. Third Party Software does not comprise part of the Software.
96
+ The use of Third Party Software is governed by the terms of such software license(s).
97
+ Third Party Software notices and/or additional terms and conditions are located in the
98
+ `THIRD_PARTY_SOFTWARE.rst`_ file.
99
+
100
+ .. _THIRD_PARTY_SOFTWARE.rst: docs/source/THIRD_PARTY_SOFTWARE.rst
101
+
102
+ Copyright
103
+ ^^^^^^^^^
104
+ Copyright (c) 2024-2025 Mira Geoscience Ltd.
105
+
@@ -0,0 +1,28 @@
1
+ Third Party Software
2
+ ====================
3
+
4
+ The octree-creation-app repository and source distributions bundle several libraries that are
5
+ compatibly licensed. We list these here.
6
+
7
+ .. list-table::
8
+ :widths: 30 30 60
9
+ :header-rows: 1
10
+
11
+ * - Name
12
+ - License
13
+ - Description
14
+ * - `discretize <https://simpeg.xyz/>`_
15
+ - MIT
16
+ - Discretization tools for finite volume and inverse problems
17
+ * - `geoh5py <https://github.com/MiraGeoscience/geoh5py>`_
18
+ - LGPL-3.0-or-later
19
+ - Python API for geoh5, an open file format for geoscientific data
20
+ * - `geoapps-utils <https://github.com/MiraGeoscience/geoapps-utils>`_
21
+ - MIT
22
+ - Utilities for geoscientific applications.
23
+ * - `numpy <https://github.com/numpy/numpy>`_
24
+ - BSD-3-Clause
25
+ - Fundamental package for array computing in Python
26
+ * - `scipy <https://github.com/scipy/scipy>`_
27
+ - BSD-3-Clause
28
+ - Fundamental algorithms for scientific computing in Python
@@ -0,0 +1,37 @@
1
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
2
+ # Copyright (c) 2022-2025 Mira Geoscience Ltd. '
3
+ # '
4
+ # This file is part of grid-apps package. '
5
+ # '
6
+ # grid-apps is distributed under the terms and conditions of the MIT License '
7
+ # (see LICENSE file at the root of this source code package). '
8
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
9
+
10
+ from __future__ import annotations
11
+
12
+ import logging
13
+ from pathlib import Path
14
+
15
+
16
+ try:
17
+ from ._version import __version__
18
+ except ModuleNotFoundError:
19
+ from datetime import datetime
20
+
21
+ __date_str = datetime.today().strftime("%Y%m%d")
22
+ __version__ = "0.0.0.dev0+" + __date_str
23
+
24
+
25
+ logging.basicConfig(level=logging.INFO)
26
+
27
+
28
+ def assets_path() -> Path:
29
+ """Return the path to the assets folder."""
30
+
31
+ parent = Path(__file__).parent
32
+ folder_name = f"{parent.name}-assets"
33
+ assets_folder = parent.parent / folder_name
34
+ if not assets_folder.is_dir():
35
+ raise RuntimeError(f"Assets folder not found: {assets_folder}")
36
+
37
+ return assets_folder
@@ -0,0 +1,2 @@
1
+ # Version placeholder that will be replaced during substitution
2
+ __version__ = "0.1.0b1"
@@ -0,0 +1,8 @@
1
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
2
+ # Copyright (c) 2024-2025 Mira Geoscience Ltd. '
3
+ # '
4
+ # This file is part of grid-apps package. '
5
+ # '
6
+ # grid-apps is distributed under the terms and conditions of the MIT License '
7
+ # (see LICENSE file at the root of this source code package). '
8
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
@@ -0,0 +1,234 @@
1
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
2
+ # Copyright (c) 2024-2025 Mira Geoscience Ltd. '
3
+ # '
4
+ # This file is part of grid-apps package. '
5
+ # '
6
+ # grid-apps is distributed under the terms and conditions of the MIT License '
7
+ # (see LICENSE file at the root of this source code package). '
8
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
9
+
10
+ from __future__ import annotations
11
+
12
+ import logging
13
+ import sys
14
+ from pathlib import Path
15
+
16
+ import numpy as np
17
+ from discretize import TreeMesh
18
+ from geoh5py.data import FloatData, ReferencedData
19
+ from geoh5py.objects import BlockModel, Octree
20
+ from geoh5py.ui_json.utils import fetch_active_workspace
21
+ from scipy.spatial import cKDTree
22
+
23
+ from grid_apps.block_model_to_octree.options import BlockModel2OctreeOptions
24
+ from grid_apps.driver import BaseGridDriver
25
+ from grid_apps.utils import (
26
+ block_model_to_discretize,
27
+ boundary_value_indices,
28
+ tensor_mesh_ordering,
29
+ treemesh_2_octree,
30
+ )
31
+
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+
36
+ class Driver(BaseGridDriver):
37
+ """
38
+ Convert a BlockModel object to Octree with various refinement strategies.
39
+ """
40
+
41
+ _params_class = BlockModel2OctreeOptions
42
+
43
+ @staticmethod
44
+ def block_model_to_treemesh(
45
+ entity: BlockModel, diagonal_balance=True, finalize=True
46
+ ) -> TreeMesh:
47
+ """
48
+ Convert a block model to an octree mesh with the same base cell size and
49
+ centered.
50
+
51
+ :param entity: BlockModel object to be converted
52
+ :param diagonal_balance: Whether to balance the mesh diagonally.
53
+ :param finalize: Whether to finalize the treemesh after creation.
54
+
55
+ :return: TreeMesh object.
56
+ """
57
+ origin = []
58
+ octree_cells = []
59
+ for ii, ax in zip("xyz", "uvz", strict=True):
60
+ cell_sizes = np.abs(getattr(entity, f"{ax}_cells"))
61
+ h_core = cell_sizes.min()
62
+
63
+ # Compute number of octree cells to span the extent
64
+ n_c = np.ceil(np.log2(np.sum(cell_sizes) / h_core))
65
+ cell_sizes_octree = np.ones(int(2**n_c)) * h_core
66
+ octree_cells.append(cell_sizes_octree)
67
+
68
+ # Colocate the center of the octree with the center of the block model
69
+ ind_core = np.where(cell_sizes == h_core)[0]
70
+ center = (
71
+ entity.origin[ii]
72
+ + entity.local_axis_centers(ax)[ind_core[len(ind_core) // 2]]
73
+ )
74
+
75
+ axis_center = len(cell_sizes_octree) // 2
76
+ origin.append(center - np.sum(cell_sizes_octree[:axis_center]) - h_core / 2)
77
+
78
+ treemesh = TreeMesh(
79
+ octree_cells,
80
+ x0=origin,
81
+ finalize=finalize,
82
+ diagonal_balance=diagonal_balance,
83
+ )
84
+
85
+ return treemesh
86
+
87
+ def make_grid(self) -> Octree:
88
+ """
89
+ Convert the block model and output the octree mesh.
90
+
91
+ :return: Octree object refined by the cell volumes or gradient of the data.
92
+ """
93
+ with fetch_active_workspace(self.params.geoh5, mode="r+"):
94
+ entity = self.params.entity
95
+
96
+ treemesh = Driver.block_model_to_treemesh(entity, finalize=False)
97
+ model = None
98
+ if self.params.data is None:
99
+ treemesh = Driver.refine_by_cell_volumes(
100
+ treemesh, entity, finalize=True
101
+ )
102
+ else:
103
+ treemesh = Driver.refine_by_values(
104
+ treemesh, self.params.data, finalize=True
105
+ )
106
+ # Transfer the model
107
+ ind = treemesh.get_containing_cells(entity.centroids)
108
+ model = (
109
+ np.ones(treemesh.n_cells, dtype=self.params.data.values.dtype)
110
+ * self.params.data.nan_value
111
+ )
112
+ model[ind] = self.params.data.values
113
+
114
+ nan_vals = (model == self.params.data.nan_value) | np.isnan(model)
115
+ if np.any(nan_vals):
116
+ tree = cKDTree(entity.centroids)
117
+ ind = tree.query(treemesh.cell_centers[nan_vals])[1]
118
+ model[nan_vals] = self.params.data.values[ind]
119
+
120
+ octree = treemesh_2_octree(
121
+ self.params.geoh5,
122
+ treemesh,
123
+ parent=self.params.output.out_group,
124
+ name=self.params.output.export_as or entity.name + "_octree",
125
+ )
126
+
127
+ if model is not None and self.params.data is not None:
128
+ octree.add_data(
129
+ {
130
+ self.params.data.name: {
131
+ "values": model,
132
+ "entity_type": self.params.data.entity_type,
133
+ }
134
+ }
135
+ )
136
+
137
+ return octree
138
+
139
+ @staticmethod
140
+ def refine_by_cell_volumes(
141
+ mesh: TreeMesh,
142
+ entity: BlockModel,
143
+ finalize: bool = True,
144
+ mask: np.ndarray | None = None,
145
+ ) -> TreeMesh:
146
+ """
147
+ Refine the octree mesh by the cell volumes of the block model.
148
+
149
+ :param mesh: TreeMesh object to be refined.
150
+ :param entity: BlockModel object to be used for refinement.
151
+ :param finalize: Whether to finalize the treemesh after refinement.
152
+ :param mask: Optional mask on the block model centroids to apply the refinement over.
153
+
154
+ :return: TreeMesh object with refined levels.
155
+ """
156
+ if not isinstance(entity, BlockModel):
157
+ raise TypeError("entity must be an instance of BlockModel.")
158
+
159
+ tensor_oct_level = []
160
+ for ax in "uvz":
161
+ cell_sizes = np.abs(getattr(entity, f"{ax}_cells"))
162
+ h_core = cell_sizes.min()
163
+ # Find the core region
164
+ tensor_oct_level.append(np.log2(cell_sizes / h_core).astype(int))
165
+
166
+ e_x, e_y, e_z = np.meshgrid(*tensor_oct_level)
167
+ max_level = np.c_[np.ravel(e_x), np.ravel(e_y), np.ravel(e_z)].max(axis=1)
168
+
169
+ locations = entity.centroids
170
+ if mask is not None:
171
+ locations = locations[mask]
172
+ max_level = max_level[mask]
173
+
174
+ mesh.insert_cells(locations, mesh.max_level - max_level, finalize=finalize)
175
+
176
+ return mesh
177
+
178
+ @staticmethod
179
+ def refine_by_values(
180
+ mesh: TreeMesh, data: FloatData | ReferencedData, finalize=True
181
+ ) -> TreeMesh:
182
+ """
183
+ Increase the mesh resolution based on the gradient of data values.
184
+
185
+ :param mesh: Input TreeMesh object.
186
+ :param data: FloatData or ReferencedData object containing the values to
187
+ be used for refinement.
188
+ :param finalize: Whether to finalize the treemesh after refinement.
189
+
190
+ :return: TreeMesh object with refined levels.
191
+ """
192
+ if not isinstance(data, FloatData | ReferencedData):
193
+ raise TypeError(
194
+ "Argument 'data' must be an instance of FloatData or ReferencedData."
195
+ )
196
+
197
+ entity = data.parent
198
+ if not isinstance(entity, BlockModel):
199
+ raise TypeError("The parent of 'data' must be an instance of BlockModel.")
200
+
201
+ tensor = block_model_to_discretize(entity)
202
+ indices = tensor_mesh_ordering(entity)
203
+
204
+ gradients = np.abs(tensor.cell_gradient @ data.values[indices])
205
+ levels = np.zeros(gradients.shape, dtype=int)
206
+ isnan = np.isnan(gradients)
207
+
208
+ if isinstance(data, FloatData):
209
+ actives = gradients[~isnan]
210
+ bins = np.percentile(
211
+ actives[actives > 0], np.linspace(5, 95, mesh.max_level)
212
+ )
213
+ levels[~isnan] = np.searchsorted(bins, actives)
214
+ else:
215
+ levels[gradients > 0] = mesh.max_level
216
+
217
+ # Refine on the value/nan interface, without boundary cells
218
+ if any(isnan):
219
+ horizon = boundary_value_indices(
220
+ tensor, data.values[indices], data.nan_value
221
+ )
222
+ mesh = Driver.refine_by_cell_volumes(
223
+ mesh, entity, finalize=False, mask=horizon[np.argsort(indices)]
224
+ )
225
+
226
+ locs = tensor.average_cell_to_face @ tensor.cell_centers
227
+ mesh.insert_cells(locs[~isnan], levels[~isnan].astype(int), finalize=finalize)
228
+
229
+ return mesh
230
+
231
+
232
+ if __name__ == "__main__":
233
+ file = Path(sys.argv[1]).resolve()
234
+ Driver.start(file)
@@ -0,0 +1,60 @@
1
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
2
+ # Copyright (c) 2024-2025 Mira Geoscience Ltd. '
3
+ # '
4
+ # This file is part of grid-apps package. '
5
+ # '
6
+ # grid-apps is distributed under the terms and conditions of the MIT License '
7
+ # (see LICENSE file at the root of this source code package). '
8
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
9
+
10
+ from __future__ import annotations
11
+
12
+ from pathlib import Path
13
+ from typing import ClassVar
14
+
15
+ from geoapps_utils.driver.data import BaseData
16
+ from geoh5py.data import FloatData, ReferencedData
17
+ from geoh5py.groups import UIJsonGroup
18
+ from geoh5py.objects import BlockModel
19
+ from pydantic import BaseModel, ConfigDict
20
+
21
+ from grid_apps import assets_path
22
+
23
+
24
+ class OutputOptions(BaseModel):
25
+ """
26
+ Output parameters for block model creation.
27
+
28
+ :param export_as: Name of the output entity.
29
+ :param out_group: Output UIJson group.
30
+ """
31
+
32
+ model_config = ConfigDict(arbitrary_types_allowed=True)
33
+
34
+ export_as: str | None = None
35
+ out_group: UIJsonGroup | None = None
36
+
37
+
38
+ class BlockModel2OctreeOptions(BaseData):
39
+ """
40
+ Block model parameters for use with `block_models.driver`.
41
+
42
+ :param entity: BlockModel source object.
43
+ :param data: Optional data to refine the octree mesh.
44
+ :param output: Output options.
45
+ """
46
+
47
+ model_config = ConfigDict(arbitrary_types_allowed=True)
48
+
49
+ name: ClassVar[str] = "block_model_to_octree"
50
+ default_ui_json: ClassVar[Path] = (
51
+ assets_path() / "uijson/block_model_to_octree.ui.json"
52
+ )
53
+ title: ClassVar[str] = "Block Model to Octree Conversion"
54
+ run_command: ClassVar[str] = "grid_apps.block_model_to_octree.driver"
55
+ conda_environment: str = "grid_apps"
56
+
57
+ entity: BlockModel
58
+ data: FloatData | ReferencedData | None = None
59
+
60
+ output: OutputOptions = OutputOptions()
@@ -0,0 +1,8 @@
1
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
2
+ # Copyright (c) 2024-2025 Mira Geoscience Ltd. '
3
+ # '
4
+ # This file is part of grid-apps package. '
5
+ # '
6
+ # grid-apps is distributed under the terms and conditions of the MIT License '
7
+ # (see LICENSE file at the root of this source code package). '
8
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''