From 80af9814ee81bb47ec03477d3bac4fb44f27e1d8 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 18 Nov 2025 11:16:31 -0800 Subject: [PATCH 1/5] Remove base class in favour of geoapps_utils.base.Driver --- grid_apps/block_model_to_octree/driver.py | 15 +++- grid_apps/block_models/driver.py | 27 ++++--- grid_apps/driver.py | 91 ----------------------- grid_apps/octree_creation/driver.py | 5 +- 4 files changed, 29 insertions(+), 109 deletions(-) delete mode 100644 grid_apps/driver.py diff --git a/grid_apps/block_model_to_octree/driver.py b/grid_apps/block_model_to_octree/driver.py index eb05bee..99a5386 100644 --- a/grid_apps/block_model_to_octree/driver.py +++ b/grid_apps/block_model_to_octree/driver.py @@ -15,13 +15,13 @@ import numpy as np from discretize import TreeMesh +from geoapps_utils.base import Driver as BaseDriver from geoh5py.data import FloatData, ReferencedData from geoh5py.objects import BlockModel, Octree from geoh5py.ui_json.utils import fetch_active_workspace from scipy.spatial import cKDTree from grid_apps.block_model_to_octree.options import BlockModel2OctreeOptions -from grid_apps.driver import BaseGridDriver from grid_apps.utils import ( block_model_to_discretize, boundary_value_indices, @@ -33,13 +33,24 @@ logger = logging.getLogger(__name__) -class Driver(BaseGridDriver): +class Driver(BaseDriver): """ Convert a BlockModel object to Octree with various refinement strategies. """ _params_class = BlockModel2OctreeOptions + def run(self): + """Create an octree mesh from input values.""" + with fetch_active_workspace(self.params.geoh5, mode="r+"): + logger.info("Converting BlockModel to Octree mesh . . .") + octree = self.make_grid() + output = self.params.out_group or octree + self.update_monitoring_directory(output) + logger.info("Done.") + + return octree + @staticmethod def block_model_to_treemesh( entity: BlockModel, diagonal_balance=True, finalize=True diff --git a/grid_apps/block_models/driver.py b/grid_apps/block_models/driver.py index 66f51f2..8153d97 100644 --- a/grid_apps/block_models/driver.py +++ b/grid_apps/block_models/driver.py @@ -15,20 +15,19 @@ import numpy as np from discretize.utils import mesh_utils -from geoapps_utils.driver.data import BaseData +from geoapps_utils.base import Driver as BaseDriver from geoh5py.objects import BlockModel from geoh5py.shared.utils import fetch_active_workspace from geoh5py.workspace import Workspace from scipy.spatial import cKDTree from grid_apps.block_models.options import BlockModelOptions -from grid_apps.driver import BaseGridDriver logger = logging.getLogger(__name__) -class Driver(BaseGridDriver): +class Driver(BaseDriver): """ Create BlockModel from parameters. @@ -37,6 +36,17 @@ class Driver(BaseGridDriver): _params_class = BlockModelOptions + def run(self): + """Create an octree mesh from input values.""" + with fetch_active_workspace(self.params.geoh5, mode="r+"): + logger.info("Creating BlockModel mesh from parameters . . .") + block = self.make_grid() + output = self.params.out_group or block + self.update_monitoring_directory(output) + logger.info("Done.") + + return block + def make_grid(self): """ Make block model object from input data. @@ -190,17 +200,6 @@ def get_block_model( # pylint: disable=too-many-arguments, too-many-positional- return object_out - @property - def params(self) -> BaseData: - """Application parameters.""" - return self._params - - @params.setter - def params(self, val: BaseData): - if not isinstance(val, BaseData): - raise TypeError("Parameters must be a BaseData subclass.") - self._params = val - if __name__ == "__main__": file = Path(sys.argv[1]).resolve() diff --git a/grid_apps/driver.py b/grid_apps/driver.py deleted file mode 100644 index 543ef25..0000000 --- a/grid_apps/driver.py +++ /dev/null @@ -1,91 +0,0 @@ -# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -# Copyright (c) 2024-2025 Mira Geoscience Ltd. ' -# ' -# This file is part of grid-apps package. ' -# ' -# grid-apps is distributed under the terms and conditions of the MIT License ' -# (see LICENSE file at the root of this source code package). ' -# ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -from __future__ import annotations - -import logging -import sys -import tempfile -from abc import abstractmethod -from pathlib import Path - -from geoapps_utils.driver.data import BaseData -from geoapps_utils.driver.driver import BaseDriver -from geoh5py.groups import UIJsonGroup -from geoh5py.objects import BlockModel, ObjectBase -from geoh5py.shared.utils import fetch_active_workspace - - -logger = logging.getLogger(__name__) - - -class BaseGridDriver(BaseDriver): - """ - Driver for the block model application. - - :param parameters: Application parameters. - """ - - _params_class: type[BaseData] - - def store(self, block_model: BlockModel): - """ - Update container group and monitoring directory. - - :param surface: Surface to store. - """ - with fetch_active_workspace(self.workspace, mode="r+") as workspace: - self.update_monitoring_directory( - block_model if self.out_group is None else self.out_group - ) - logger.info( - "Curve object '%s' saved to '%s'.", - self.params.output.export_as, - str(workspace.h5file), - ) - - @abstractmethod - def make_grid(self): - pass - - def run(self): - """Run the surface application driver.""" - logging.info("Begin Process ...") - block_model = self.make_grid() - logging.info("Process Complete.") - self.store(block_model) - - @property - def params(self) -> BaseData: - """Application parameters.""" - return self._params - - @params.setter - def params(self, val: BaseData): - if not isinstance(val, BaseData): - raise TypeError("Parameters must be a BaseData subclass.") - self._params = val - - def add_ui_json(self, entity: ObjectBase | UIJsonGroup) -> None: - """ - Add ui.json file to entity. - - :param entity: Object to add ui.json file to. - """ - - with tempfile.TemporaryDirectory() as temp_dir: - filepath = Path(temp_dir) / f"{self.params.name}.ui.json" - self.params.write_ui_json(filepath) - - entity.add_file(str(filepath)) - - -if __name__ == "__main__": - file = Path(sys.argv[1]).resolve() - BaseGridDriver.start(file) diff --git a/grid_apps/octree_creation/driver.py b/grid_apps/octree_creation/driver.py index 55e52e8..f9626aa 100644 --- a/grid_apps/octree_creation/driver.py +++ b/grid_apps/octree_creation/driver.py @@ -16,7 +16,7 @@ import numpy as np from discretize import TreeMesh from discretize.utils import mesh_builder_xyz -from geoapps_utils.driver.driver import BaseDriver +from geoapps_utils.base import Driver as BaseDriver from geoapps_utils.utils.locations import get_locations from geoh5py.objects import Curve, ObjectBase, Octree, Points, Surface from geoh5py.objects.surveys.direct_current import BaseElectrode @@ -46,7 +46,8 @@ def run(self) -> Octree: with fetch_active_workspace(self.params.geoh5, mode="r+"): logger.info("Creating octree mesh from params . . .") octree = self.octree_from_params(self.params) - self.update_monitoring_directory(octree) + output = self.params.out_group or octree + self.update_monitoring_directory(output) logger.info("Done.") return octree From 27b2245e52f402cd5438b9c5e9700a4509dfd095 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Tue, 18 Nov 2025 11:23:49 -0800 Subject: [PATCH 2/5] Update octree uijson --- grid_apps-assets/uijson/octree_mesh.ui.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/grid_apps-assets/uijson/octree_mesh.ui.json b/grid_apps-assets/uijson/octree_mesh.ui.json index 50362b1..dfa833f 100644 --- a/grid_apps-assets/uijson/octree_mesh.ui.json +++ b/grid_apps-assets/uijson/octree_mesh.ui.json @@ -231,10 +231,11 @@ "value": 1000.0 }, "out_group": { - "label": "group", + "group": "Output preferences", + "label": "UIJson group", "value": "", - "groupType": "{61FBB4E8-A480-11E3-8D5A-2776BDF4F982}", - "visible": false, + "groupType": "{BB50AC61-A657-4926-9C82-067658E246A0}", + "visible": true, "optional": true, "enabled": false } From 5d97936556f15cbf56b154f0e6136909fd961db5 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 24 Nov 2025 10:05:57 -0800 Subject: [PATCH 3/5] Pass diagonal_balance to all refinement functions --- grid_apps/octree_creation/driver.py | 69 ++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/grid_apps/octree_creation/driver.py b/grid_apps/octree_creation/driver.py index f9626aa..2e55349 100644 --- a/grid_apps/octree_creation/driver.py +++ b/grid_apps/octree_creation/driver.py @@ -54,7 +54,13 @@ def run(self) -> Octree: @staticmethod def octree_from_params(params: OctreeOptions) -> Octree: - """Create an Octree object from input parameters.""" + """ + Create an Octree object from input parameters. + + :param params: OctreeOptions containing the parameters for octree creation. + + :return: Octree object. + """ treemesh = OctreeDriver.treemesh_from_params(params) octree = treemesh_2_octree( params.geoh5, treemesh, name=params.ga_group_name, parent=params.out_group @@ -63,7 +69,13 @@ def octree_from_params(params: OctreeOptions) -> Octree: @staticmethod def treemesh_from_params(params: OctreeOptions) -> TreeMesh: - """Create a TreeMesh object from input parameters.""" + """ + Create a TreeMesh object from input parameters. + + :param params: OctreeOptions containing the parameters for mesh creation. + + :return: TreeMesh object. + """ logger.info("Setting the mesh extent . . .") mesh = OctreeDriver.base_treemesh(params) @@ -72,7 +84,9 @@ def treemesh_from_params(params: OctreeOptions) -> TreeMesh: logger.info("Applying extra refinements . . .") if params.refinements is not None: - OctreeDriver.refine_objects(mesh, params.refinements) + OctreeDriver.refine_objects( + mesh, params.refinements, diagonal_balance=params.diagonal_balance + ) logger.info("Finalizing . . .") mesh.finalize() @@ -115,13 +129,18 @@ def refine_minimum_level(mesh: TreeMesh, minimum_level: int) -> TreeMesh: @staticmethod def refine_objects( - mesh: TreeMesh, refinements: list[RefinementOptions | None] + mesh: TreeMesh, + refinements: list[RefinementOptions | None], + diagonal_balance: bool = True, ) -> TreeMesh: """ Refine by object or object + complement. :param mesh: Tree mesh to refine. :param refinements: List of refinements to apply. + :param diagonal_balance: Whether to apply diagonal balancing after refinement. + + :return: Refined tree mesh. """ for refinement in refinements: if refinement is None: @@ -139,6 +158,7 @@ def refine_objects( mesh = OctreeDriver.refine_by_object_type( mesh=mesh, refinement_object=obj, + diagonal_balance=diagonal_balance, **kwargs, ) @@ -157,8 +177,21 @@ def refine_by_object_type( *, horizon: bool, distance: float | None, + diagonal_balance: bool = True, ) -> TreeMesh: - """Refine Treemesh as a based on object type.""" + """ + Refine Treemesh as a based on object type. + + :param mesh: Tree mesh to refine. + :param refinement_object: Object to use for refinement. + :param levels: Number of cells requested at each refinement level. + Defined in reversed order from the highest octree to lowest. + :param horizon: Whether the refinement is a surface or radial. + :param distance: Distance from the object to refine. + :param diagonal_balance: Whether to apply diagonal balancing after refinement. + + :return: Refined tree mesh object. + """ if horizon: try: mesh = OctreeDriver.refine_tree_from_surface( @@ -166,6 +199,7 @@ def refine_by_object_type( refinement_object, levels, max_distance=np.inf if distance is None else distance, + diagonal_balance=diagonal_balance, ) except QhullError: base_cell_size = np.min([h.min() for h in mesh.h]) @@ -174,21 +208,22 @@ def refine_by_object_type( surface_strip(refinement_object, 2 * base_cell_size), levels, max_distance=np.inf if distance is None else distance, + diagonal_balance=diagonal_balance, ) elif isinstance(refinement_object, Curve): - mesh = OctreeDriver.refine_tree_from_curve(mesh, refinement_object, levels) + mesh = OctreeDriver.refine_tree_from_curve( + mesh, refinement_object, levels, diagonal_balance=diagonal_balance + ) elif isinstance(refinement_object, Surface): mesh = OctreeDriver.refine_tree_from_triangulation( - mesh, refinement_object, levels + mesh, refinement_object, levels, diagonal_balance=diagonal_balance ) elif isinstance(refinement_object, Points): mesh = OctreeDriver.refine_tree_from_points( - mesh, - refinement_object, - levels, + mesh, refinement_object, levels, diagonal_balance=diagonal_balance ) else: @@ -205,6 +240,7 @@ def refine_tree_from_curve( levels: list[int] | np.ndarray, *, finalize: bool = False, + diagonal_balance: bool = True, ) -> TreeMesh: """ Refine a tree mesh along the segments of a curve densified by the @@ -215,7 +251,9 @@ def refine_tree_from_curve( :param levels: Number of cells requested at each refinement level. Defined in reversed order from the highest octree to lowest. :param finalize: Finalize the tree mesh after refinement. + :param diagonal_balance: Whether to apply diagonal balancing after refinement. + :return: Refined tree mesh. """ if not isinstance(curve, Curve): raise TypeError("Refinement object must be a Curve.") @@ -232,7 +270,7 @@ def refine_tree_from_curve( locations = densify_curve(curve, mesh.h[0][0]) mesh = OctreeDriver.refine_tree_from_points( - mesh, locations, levels, finalize=False + mesh, locations, levels, finalize=False, diagonal_balance=diagonal_balance ) if finalize: @@ -247,6 +285,7 @@ def refine_tree_from_points( levels: list[int] | np.ndarray, *, finalize: bool = False, + diagonal_balance: bool = True, ) -> TreeMesh: """ Refine a tree mesh along the vertices of an object. @@ -256,6 +295,7 @@ def refine_tree_from_points( :param levels: Number of cells requested at each refinement level. Defined in reversed order from the highest octree to lowest. :param finalize: Finalize the tree mesh after refinement. + :param diagonal_balance: Whether to apply diagonal balancing after refinement. :return: Refined tree mesh. """ @@ -278,6 +318,7 @@ def refine_tree_from_points( distance, mesh.max_level - ii, finalize=False, + diagonal_balance=diagonal_balance, ) if finalize: @@ -293,6 +334,7 @@ def refine_tree_from_surface( # pylint: disable=too-many-locals *, max_distance: float = np.inf, finalize: bool = False, + diagonal_balance: bool = True, ) -> TreeMesh: """ Refine a tree mesh along the simplicies of a surface. @@ -303,6 +345,7 @@ def refine_tree_from_surface( # pylint: disable=too-many-locals Defined in reversed order from the highest octree to lowest. :param max_distance: Maximum distance from the surface to refine. :param finalize: Finalize the tree mesh after refinement. + :param diagonal_balance: Whether to apply diagonal balancing after refinement. :return: Refined tree mesh. """ @@ -348,6 +391,7 @@ def refine_tree_from_surface( # pylint: disable=too-many-locals np.c_[xy[keeper], elevation - depth], np.ones(nnz) * mesh.max_level - ind, finalize=False, + diagonal_balance=diagonal_balance, ) if finalize: @@ -361,6 +405,7 @@ def refine_tree_from_triangulation( surface, levels: list[int] | np.ndarray, finalize=False, + diagonal_balance: bool = True, ) -> TreeMesh: """ Refine a tree mesh along the simplicies of a surface. @@ -370,6 +415,7 @@ def refine_tree_from_triangulation( :param levels: Number of cells requested at each refinement level. Defined in reversed order from highest octree to lowest. :param finalize: Finalize the tree mesh after refinement. + :param diagonal_balance: Whether to apply diagonal balancing after refinement. :return: Refined tree mesh. """ @@ -407,6 +453,7 @@ def refine_tree_from_triangulation( (vertices, surface.cells), level=-level - 1, finalize=False, + diagonal_balance=diagonal_balance, ) vertices -= average_normals * base_cells * 2.0**level From 3b9309369f9b444f9301b1ad9eaacdc570cb65d5 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Mon, 24 Nov 2025 10:08:49 -0800 Subject: [PATCH 4/5] Fix bad tests --- tests/run_tests/block_2_octree_test.py | 10 ++- tests/run_tests/octree_creation/run_test.py | 95 ++++++--------------- 2 files changed, 35 insertions(+), 70 deletions(-) diff --git a/tests/run_tests/block_2_octree_test.py b/tests/run_tests/block_2_octree_test.py index 922efca..8aee1a5 100644 --- a/tests/run_tests/block_2_octree_test.py +++ b/tests/run_tests/block_2_octree_test.py @@ -10,6 +10,7 @@ import numpy as np from geoh5py import Workspace +from geoh5py.groups import UIJsonGroup from geoh5py.objects import BlockModel from geoh5py.ui_json import InputFile @@ -116,6 +117,7 @@ def test_integer_refine_octree(tmp_path): with Workspace.create(h5file_path) as workspace: block_model = generate_block_model(workspace) wave = gaussian_wave(block_model.centroids, width=50, amplitude=100) + out_group = UIJsonGroup.create(workspace, name="OctreeGroup") # Repeat with reference data wave[wave < 25] = 1 @@ -125,10 +127,16 @@ def test_integer_refine_octree(tmp_path): ) params = BlockModel2OctreeOptions.build( - **{"geoh5": workspace, "entity": block_model, "data": ref_data} + **{ + "geoh5": workspace, + "entity": block_model, + "data": ref_data, + "out_group": out_group, + } ) driver = BlockModelToOctreeDriver(params) octree = driver.make_grid() assert octree.n_cells == 5223 + assert octree.parent == out_group diff --git a/tests/run_tests/octree_creation/run_test.py b/tests/run_tests/octree_creation/run_test.py index 7ff397d..cfd3e2a 100644 --- a/tests/run_tests/octree_creation/run_test.py +++ b/tests/run_tests/octree_creation/run_test.py @@ -13,6 +13,7 @@ import numpy as np import pytest from discretize import TreeMesh +from geoh5py.groups import UIJsonGroup from geoh5py.objects import ( CurrentElectrode, Curve, @@ -21,7 +22,6 @@ PotentialElectrode, Surface, ) -from geoh5py.shared.utils import compare_entities from geoh5py.ui_json.utils import str2list from geoh5py.workspace import Workspace from scipy.spatial import Delaunay @@ -35,26 +35,11 @@ def test_create_octree_radial(tmp_path: Path, setup_test_octree): # pylint: disable=too-many-locals - (locations, refinement, treemesh, params_dict) = setup_test_octree + (locations, refinement, _, params_dict) = setup_test_octree - with Workspace.create(tmp_path / "testOctree.geoh5") as workspace: + with Workspace.create(tmp_path / f"{__name__}.geoh5") as workspace: points = Points.create(workspace, vertices=locations) - treemesh.refine( - treemesh.max_level - params_dict["minimum_level"] + 1, finalize=False - ) - treemesh = OctreeDriver.refine_tree_from_points( - treemesh, - points, - str2list(refinement), - finalize=True, - ) - octree = treemesh_2_octree(workspace, treemesh, name="Octree_Mesh") - - # Hard-wire the expected result - assert octree.n_cells == 164742 - - assert OctreeDriver.cell_size_from_level(treemesh, 1) == 10.0 - + out_group = UIJsonGroup.create(workspace, name="Octree Output Group") params_dict.update( { "geoh5": workspace, @@ -66,22 +51,26 @@ def test_create_octree_radial(tmp_path: Path, setup_test_octree): # pylint: dis "horizon": False, } ], + "out_group": out_group, + "diagonal_balance": False, + "ga_group_name": "Tester", } ) params = OctreeOptions(**params_dict) params.write_ui_json(tmp_path / "testOctree.ui.json") - # params.write_input_file(name="testOctree", path=tmp_path, validate=False) + driver = OctreeDriver(params) driver.run() - rec_octree = workspace.get_entity("Octree_Mesh")[0] - compare_entities(octree, rec_octree, ignore=["_uid"]) + rec_octree = workspace.get_entity("Tester")[0] + assert rec_octree.parent == out_group + assert rec_octree.n_cells == 164868 def test_create_octree_surface(tmp_path: Path, setup_test_octree): # pylint: disable=too-many-locals - (locations, refinement, treemesh, params_dict) = setup_test_octree + (locations, refinement, _, params_dict) = setup_test_octree - with Workspace.create(tmp_path / "testOctree.geoh5") as workspace: + with Workspace.create(tmp_path / f"{__name__}.geoh5") as workspace: simplices = np.unique( np.random.randint(0, locations.shape[0] - 1, (locations.shape[0], 3)), axis=1, @@ -92,25 +81,6 @@ def test_create_octree_surface(tmp_path: Path, setup_test_octree): # pylint: di vertices=locations, cells=simplices, ) - - treemesh.refine( - treemesh.max_level - params_dict["minimum_level"] + 1, - finalize=False, - ) - treemesh = OctreeDriver.refine_tree_from_surface( - treemesh, - surface, - str2list(refinement), - finalize=True, - ) - - octree = treemesh_2_octree(workspace, treemesh, name="Octree_Mesh") - - assert octree.n_cells in [ - 168627, - 168396, - ] # Different results on Linux and Windows - params_dict.update( { "geoh5": workspace, @@ -123,6 +93,8 @@ def test_create_octree_surface(tmp_path: Path, setup_test_octree): # pylint: di "distance": 1000.0, } ], + "ga_group_name": "Tester", + "diagonal_balance": False, } ) params = OctreeOptions(**params_dict) @@ -130,8 +102,8 @@ def test_create_octree_surface(tmp_path: Path, setup_test_octree): # pylint: di driver = OctreeDriver(params) driver.run() - rec_octree = workspace.get_entity("Octree_Mesh")[0] - compare_entities(octree, rec_octree, ignore=["_uid"]) + rec_octree = workspace.get_entity("Tester")[0] + assert rec_octree.n_cells == 168487 # Different results on Linux and Windows def test_create_octree_surface_straight_line(tmp_path: Path, setup_test_octree): @@ -157,7 +129,7 @@ def test_create_octree_surface_straight_line(tmp_path: Path, setup_test_octree): def test_create_octree_curve(tmp_path: Path, setup_test_octree): # pylint: disable=too-many-locals (locations, refinement, _, params_dict) = setup_test_octree - with Workspace.create(tmp_path / "testOctree.geoh5") as workspace: + with Workspace.create(tmp_path / f"{__name__}.geoh5") as workspace: curve = Curve.create(workspace, vertices=locations) curve.remove_cells([-1]) @@ -185,7 +157,7 @@ def test_create_octree_curve(tmp_path: Path, setup_test_octree): # pylint: disa def test_create_octree_empty_curve(tmp_path: Path, setup_test_octree): # pylint: disable=too-many-locals (locations, refinement, _, params_dict) = setup_test_octree - with Workspace.create(tmp_path / "testOctree.geoh5") as workspace: + with Workspace.create(tmp_path / f"{__name__}.geoh5") as workspace: # Create sources along line extent = Points.create(workspace, vertices=locations) curve = Curve.create(workspace, vertices=[(0, 0, 0), (0, 0, 0)]) @@ -218,7 +190,7 @@ def test_create_octree_dipoles(tmp_path: Path, setup_test_octree): # pylint: di (_, refinement, _, params_dict) = setup_test_octree n_data = 12 - with Workspace.create(tmp_path / "testOctree.geoh5") as workspace: + with Workspace.create(tmp_path / f"{__name__}.geoh5") as workspace: # Create sources along line x_loc, y_loc = np.meshgrid(np.arange(n_data), np.arange(-1, 3)) vertices = np.c_[x_loc.ravel(), y_loc.ravel(), np.zeros_like(x_loc).ravel()] @@ -272,7 +244,7 @@ def test_create_octree_dipoles(tmp_path: Path, setup_test_octree): # pylint: di def test_create_octree_triangulation(tmp_path: Path, setup_test_octree): # pylint: disable=too-many-locals - (locations, refinement, treemesh, params_dict) = setup_test_octree + (locations, refinement, _, params_dict) = setup_test_octree # Generate a sphere of points phi, theta = np.meshgrid( @@ -283,28 +255,13 @@ def test_create_octree_triangulation(tmp_path: Path, setup_test_octree): # pyli y = np.cos(phi) * np.sin(theta) * 200.0 z = np.sin(phi) * 200.0 # refinement = "1, 2" - with Workspace.create(tmp_path / "testOctree.geoh5") as workspace: + with Workspace.create(tmp_path / f"{__name__}.geoh5") as workspace: curve = Curve.create(workspace, vertices=locations) sphere = Surface.create( workspace, vertices=np.c_[x.flatten(), y.flatten(), z.flatten()], cells=surf.simplices, # pylint: disable=no-member ) - treemesh.refine( - treemesh.max_level - params_dict["minimum_level"] + 1, - diagonal_balance=False, - finalize=False, - ) - treemesh = OctreeDriver.refine_tree_from_triangulation( - treemesh, - sphere, - [3, 3], - finalize=True, - ) - octree = treemesh_2_octree(workspace, treemesh, name="Octree_Mesh") - - assert octree.n_cells == 267957 - params_dict.update( { "geoh5": workspace, @@ -322,8 +279,8 @@ def test_create_octree_triangulation(tmp_path: Path, setup_test_octree): # pyli driver = OctreeDriver(params) driver.run() - rec_octree = workspace.get_entity("Octree_Mesh")[0] - compare_entities(octree, rec_octree, ignore=["_uid"]) + rec_octree = workspace.get_entity("Octree Mesh")[0] + assert rec_octree.n_cells == 301788 @pytest.mark.parametrize( @@ -407,7 +364,7 @@ def test_octree_diagonal_balance( # pylint: disable=too-many-locals def test_refine_complement(tmp_path: Path, setup_test_octree): # pylint: disable=too-many-locals (locations, refinement, _, params_dict) = setup_test_octree - with Workspace.create(tmp_path / "testOctree.geoh5") as workspace: + with Workspace.create(tmp_path / f"{__name__}.geoh5") as workspace: points = Points.create(workspace, vertices=np.c_[locations[-1, :]].T) curve = Curve.create(workspace, vertices=locations) curve.remove_cells([-1]) @@ -457,7 +414,7 @@ def test_regular_grid(tmp_path: Path, setup_test_octree): # pylint: disable=too ) locations = np.c_[x.flatten(), y.flatten(), np.ones(400) * np.random.randn(1)] - with Workspace.create(tmp_path / "testOctree.geoh5") as workspace: + with Workspace.create(tmp_path / f"{__name__}.geoh5") as workspace: points = Points.create(workspace, vertices=locations) params_dict.update( From b01d0f319258b61e5652b11615a7a0969b120398 Mon Sep 17 00:00:00 2001 From: dominiquef Date: Thu, 27 Nov 2025 15:08:59 -0800 Subject: [PATCH 5/5] Change reference to Options class --- grid_apps/block_model_to_octree/options.py | 4 ++-- grid_apps/block_models/options.py | 4 ++-- grid_apps/octree_creation/options.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/grid_apps/block_model_to_octree/options.py b/grid_apps/block_model_to_octree/options.py index f38c534..3e4fe3d 100644 --- a/grid_apps/block_model_to_octree/options.py +++ b/grid_apps/block_model_to_octree/options.py @@ -12,7 +12,7 @@ from pathlib import Path from typing import ClassVar -from geoapps_utils.driver.data import BaseData +from geoapps_utils.base import Options from geoh5py.data import FloatData, ReferencedData from geoh5py.groups import UIJsonGroup from geoh5py.objects import BlockModel @@ -35,7 +35,7 @@ class OutputOptions(BaseModel): out_group: UIJsonGroup | None = None -class BlockModel2OctreeOptions(BaseData): +class BlockModel2OctreeOptions(Options): """ Block model parameters for use with `block_models.driver`. diff --git a/grid_apps/block_models/options.py b/grid_apps/block_models/options.py index 61cbe6a..0a0ccc5 100644 --- a/grid_apps/block_models/options.py +++ b/grid_apps/block_models/options.py @@ -12,7 +12,7 @@ from pathlib import Path from typing import ClassVar -from geoapps_utils.driver.data import BaseData +from geoapps_utils.base import Options from geoh5py.groups import UIJsonGroup from geoh5py.objects import CellObject, Points from geoh5py.objects.grid_object import GridObject @@ -84,7 +84,7 @@ class BlockModelOutputOptions(BaseModel): out_group: UIJsonGroup | None = None -class BlockModelOptions(BaseData): +class BlockModelOptions(Options): """ Block model parameters for use with `block_models.driver`. diff --git a/grid_apps/octree_creation/options.py b/grid_apps/octree_creation/options.py index 3b5a008..d4c5e3b 100644 --- a/grid_apps/octree_creation/options.py +++ b/grid_apps/octree_creation/options.py @@ -14,7 +14,7 @@ from typing import Any, ClassVar import numpy as np -from geoapps_utils.driver.data import BaseData +from geoapps_utils.base import Options from geoh5py.groups import UIJsonGroup from geoh5py.objects import Points from pydantic import ( @@ -29,7 +29,7 @@ from grid_apps import assets_path -class OctreeOptions(BaseData): +class OctreeOptions(Options): """ Octree creation parameters.