Skip to content

Commit bc9c31e

Browse files
get indices for rectilinear meshes (#3876)
Co-authored-by: Paul Romano <paul.k.romano@gmail.com>
1 parent dd6d31b commit bc9c31e

2 files changed

Lines changed: 75 additions & 4 deletions

File tree

openmc/mesh.py

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,10 +1688,47 @@ def to_xml_element(self):
16881688

16891689
return element
16901690

1691-
def get_indices_at_coords(self, coords: Sequence[float]) -> tuple:
1692-
raise NotImplementedError(
1693-
"get_indices_at_coords is not yet implemented for RectilinearMesh"
1694-
)
1691+
def get_indices_at_coords(self, coords: Sequence[float]) -> tuple[int, int, int]:
1692+
"""Find the mesh cell indices containing the specified coordinates.
1693+
1694+
.. versionadded:: 0.15.4
1695+
1696+
Parameters
1697+
----------
1698+
coords : Sequence[float]
1699+
Cartesian coordinates of the point as (x, y, z).
1700+
1701+
Returns
1702+
-------
1703+
tuple[int, int, int]
1704+
Mesh indices (ix, iy, iz).
1705+
1706+
Raises
1707+
------
1708+
ValueError
1709+
If coords does not contain exactly 3 values, or if a coordinate is
1710+
outside the mesh grid boundaries.
1711+
"""
1712+
if len(coords) != 3:
1713+
raise ValueError(
1714+
f"coords must contain exactly 3 values for a rectilinear mesh, "
1715+
f"got {len(coords)}"
1716+
)
1717+
1718+
grids = (self.x_grid, self.y_grid, self.z_grid)
1719+
indices = []
1720+
1721+
for grid, value in zip(grids, coords):
1722+
if value < grid[0] or value > grid[-1]:
1723+
raise ValueError(
1724+
f"Coordinate value {value} is outside the mesh grid boundaries: "
1725+
f"[{grid[0]}, {grid[-1]}]"
1726+
)
1727+
1728+
idx = np.searchsorted(grid, value, side="right") - 1
1729+
indices.append(int(min(idx, len(grid) - 2)))
1730+
1731+
return tuple(indices)
16951732

16961733

16971734
class CylindricalMesh(StructuredMesh):

tests/unit_tests/test_mesh.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -994,3 +994,37 @@ def test_regular_mesh_get_indices_at_coords():
994994
assert isinstance(result_1d, tuple)
995995
assert len(result_1d) == 1
996996
assert result_1d == (5,)
997+
998+
999+
def test_rectilinear_mesh_get_indices_at_coords():
1000+
"""Test get_indices_at_coords method for RectilinearMesh"""
1001+
# Create a 3x2x2 rectilinear mesh with non-uniform spacing
1002+
mesh = openmc.RectilinearMesh()
1003+
mesh.x_grid = [0., 1., 5., 10.]
1004+
mesh.y_grid = [-10., -5., 0.]
1005+
mesh.z_grid = [-100., 0., 100.]
1006+
1007+
# Test lower-left corner maps to first voxel (0, 0, 0)
1008+
assert mesh.get_indices_at_coords([0.0, -10., -100.]) == (0, 0, 0)
1009+
1010+
# Test centroid of first voxel
1011+
assert mesh.get_indices_at_coords([0.5, -7.5, -50.]) == (0, 0, 0)
1012+
1013+
# Test centroid of last voxel maps correctly
1014+
assert mesh.get_indices_at_coords([7.5, -2.5, 50.]) == (2, 1, 1)
1015+
1016+
# Test upper_right corner maps to last voxel
1017+
assert mesh.get_indices_at_coords([10., 0., 100.]) == (2, 1, 1)
1018+
1019+
# Test a middle voxel
1020+
assert mesh.get_indices_at_coords([2., -5., 0.]) == (1, 1, 1)
1021+
1022+
# Test coordinates outside mesh bounds raise ValueError
1023+
with pytest.raises(ValueError):
1024+
mesh.get_indices_at_coords([-0.5, 0.5, 0.5])
1025+
with pytest.raises(ValueError):
1026+
mesh.get_indices_at_coords([1.5, 0.5, 0.5])
1027+
with pytest.raises(ValueError):
1028+
mesh.get_indices_at_coords([0.5, -0.5, 110.])
1029+
with pytest.raises(ValueError):
1030+
mesh.get_indices_at_coords([0.5, -20., 110.])

0 commit comments

Comments
 (0)