diff --git a/openmc/mesh.py b/openmc/mesh.py index 435a44d2c8a..a12bd58534c 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -1,3 +1,4 @@ +from __future__ import annotations import typing import warnings from abc import ABC, abstractmethod @@ -35,6 +36,9 @@ class MeshBase(IDManagerMixin, ABC): Unique identifier for the mesh name : str Name of the mesh + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the mesh as defined by the upper-right and + lower-left coordinates. """ @@ -58,6 +62,10 @@ def name(self, name: str): else: self._name = '' + @property + def bounding_box(self) -> openmc.BoundingBox: + return openmc.BoundingBox(self.lower_left, self.upper_right) + def __repr__(self): string = type(self).__name__ + '\n' string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id) @@ -507,9 +515,9 @@ class RegularMesh(StructuredMesh): upper_right : Iterable of float The upper-right corner of the structured mesh. If only two coordinate are given, it is assumed that the mesh is an x-y mesh. - bounding_box: openmc.BoundingBox - Axis-aligned bounding box of the cell defined by the upper-right and lower- - left coordinates + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the mesh as defined by the upper-right and + lower-left coordinates. width : Iterable of float The width of mesh cells in each direction. indices : Iterable of tuple @@ -660,12 +668,6 @@ def _grids(self): x1, = self.upper_right return (np.linspace(x0, x1, nx + 1),) - @property - def bounding_box(self): - return openmc.BoundingBox( - np.array(self.lower_left), np.array(self.upper_right) - ) - def __repr__(self): string = super().__repr__() string += '{0: <16}{1}{2}\n'.format('\tDimensions', '=\t', self.n_dimension) @@ -1005,6 +1007,9 @@ class RectilinearMesh(StructuredMesh): indices : Iterable of tuple An iterable of mesh indices for each mesh element, e.g. [(1, 1, 1), (2, 1, 1), ...] + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the mesh as defined by the upper-right and + lower-left coordinates. """ @@ -1056,6 +1061,14 @@ def z_grid(self, grid): def _grids(self): return (self.x_grid, self.y_grid, self.z_grid) + @property + def lower_left(self): + return np.array([self.x_grid[0], self.y_grid[0], self.z_grid[0]]) + + @property + def upper_right(self): + return np.array([self.x_grid[-1], self.y_grid[-1], self.z_grid[-1]]) + @property def volumes(self): """Return Volumes for every mesh cell @@ -1222,9 +1235,9 @@ class CylindricalMesh(StructuredMesh): upper_right : Iterable of float The upper-right corner of the structured mesh. If only two coordinate are given, it is assumed that the mesh is an x-y mesh. - bounding_box: openmc.OpenMC - Axis-aligned cartesian bounding box of cell defined by upper-right and lower- - left coordinates + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the mesh as defined by the upper-right and + lower-left coordinates. """ @@ -1321,10 +1334,6 @@ def upper_right(self): self.origin[2] + self.z_grid[-1] )) - @property - def bounding_box(self): - return openmc.BoundingBox(self.lower_left, self.upper_right) - def __repr__(self): fmt = '{0: <16}{1}{2}\n' string = super().__repr__() @@ -1666,8 +1675,8 @@ class SphericalMesh(StructuredMesh): The upper-right corner of the structured mesh. If only two coordinate are given, it is assumed that the mesh is an x-y mesh. bounding_box : openmc.BoundingBox - Axis-aligned bounding box of the cell defined by the upper-right and lower- - left coordinates + Axis-aligned bounding box of the mesh as defined by the upper-right and + lower-left coordinates. """ @@ -1758,10 +1767,6 @@ def upper_right(self): r = self.r_grid[-1] return np.array((self.origin[0] + r, self.origin[1] + r, self.origin[2] + r)) - @property - def bounding_box(self): - return openmc.BoundingBox(self.lower_left, self.upper_right) - def __repr__(self): fmt = '{0: <16}{1}{2}\n' string = super().__repr__() @@ -1943,8 +1948,8 @@ class UnstructuredMesh(MeshBase): library : {'moab', 'libmesh'} Mesh library used for the unstructured mesh tally output : bool - Indicates whether or not automatic tally output should - be generated for this mesh + Indicates whether or not automatic tally output should be generated for + this mesh volumes : Iterable of float Volumes of the unstructured mesh elements centroids : numpy.ndarray @@ -1964,6 +1969,10 @@ class UnstructuredMesh(MeshBase): .. versionadded:: 0.13.1 total_volume : float Volume of the unstructured mesh in total + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the mesh as defined by the upper-right and + lower-left coordinates. + """ _UNSUPPORTED_ELEM = -1 @@ -2096,6 +2105,14 @@ def __repr__(self): self.length_multiplier) return string + @property + def lower_left(self): + return self.vertices.min(axis=0) + + @property + def upper_right(self): + return self.vertices.max(axis=0) + def centroid(self, bin: int): """Return the vertex averaged centroid of an element diff --git a/tests/unit_tests/test_mesh.py b/tests/unit_tests/test_mesh.py index 2a4ff6cbbd9..50e1236a829 100644 --- a/tests/unit_tests/test_mesh.py +++ b/tests/unit_tests/test_mesh.py @@ -4,7 +4,6 @@ import pytest import openmc -from openmc import RegularMesh, RectilinearMesh, CylindricalMesh, SphericalMesh @pytest.mark.parametrize("val_left,val_right", [(0, 0), (-1., -1.), (2.0, 2)]) def test_raises_error_when_flat(val_left, val_right): @@ -49,6 +48,17 @@ def test_regular_mesh_bounding_box(): np.testing.assert_array_equal(bb.upper_right, (2, 3, 5)) +def test_rectilinear_mesh_bounding_box(): + mesh = openmc.RectilinearMesh() + mesh.x_grid = [0., 1., 5., 10.] + mesh.y_grid = [-10., -5., 0.] + mesh.z_grid = [-100., 0., 100.] + bb = mesh.bounding_box + assert isinstance(bb, openmc.BoundingBox) + np.testing.assert_array_equal(bb.lower_left, (0., -10. ,-100.)) + np.testing.assert_array_equal(bb.upper_right, (10., 0., 100.)) + + def test_cylindrical_mesh_bounding_box(): # test with mesh at origin (0, 0, 0) mesh = openmc.CylindricalMesh(