Skip to content

Commit

Permalink
allowing varible offsets for polygon.offset (openmc-dev#3120)
Browse files Browse the repository at this point in the history
Co-authored-by: Paul Romano <[email protected]>
  • Loading branch information
shimwell and paulromano authored Nov 8, 2024
1 parent 754f6fa commit 9983ee1
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 8 deletions.
27 changes: 23 additions & 4 deletions openmc/model/surface_composite.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
from abc import ABC, abstractmethod
from collections.abc import Iterable, Sequence
from copy import copy
Expand Down Expand Up @@ -1316,25 +1317,43 @@ def _decompose_polygon_into_convex_sets(self):
surfsets.append(surf_ops)
return surfsets

def offset(self, distance):
def offset(self, distance: float | Sequence[float] | np.ndarray) -> Polygon:
"""Offset this polygon by a set distance
Parameters
----------
distance : float
distance : float or sequence of float or np.ndarray
The distance to offset the polygon by. Positive is outward
(expanding) and negative is inward (shrinking).
(expanding) and negative is inward (shrinking). If a float is
provided, the same offset is applied to all vertices. If a list or
tuple is provided, each vertex gets a different offset. If an
iterable or numpy array is provided, each vertex gets a different
offset.
Returns
-------
offset_polygon : openmc.model.Polygon
"""

if isinstance(distance, float):
distance = np.full(len(self.points), distance)
elif isinstance(distance, Sequence):
distance = np.array(distance)
elif not isinstance(distance, np.ndarray):
raise TypeError("Distance must be a float or sequence of float.")

if len(distance) != len(self.points):
raise ValueError(
f"Length of distance {len(distance)} array must "
f"match number of polygon points {len(self.points)}"
)

normals = np.insert(self._normals, 0, self._normals[-1, :], axis=0)
cos2theta = np.sum(normals[1:, :]*normals[:-1, :], axis=-1, keepdims=True)
costheta = np.cos(np.arccos(cos2theta) / 2)
nvec = (normals[1:, :] + normals[:-1, :])
unit_nvec = nvec / np.linalg.norm(nvec, axis=-1, keepdims=True)
disp_vec = distance / costheta * unit_nvec
disp_vec = distance[:, np.newaxis] / costheta * unit_nvec

return type(self)(self.points + disp_vec, basis=self.basis)

Expand Down
11 changes: 7 additions & 4 deletions tests/unit_tests/test_surface_composite.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,10 +347,13 @@ def test_polygon():
assert any([points_in[i] in reg for reg in star_poly.regions])
assert points_in[i] not in +star_poly
assert (0, 0, 0) not in -star_poly
if basis != 'rz':
offset_star = star_poly.offset(.6)
assert (0, 0, 0) in -offset_star
assert any([(0, 0, 0) in reg for reg in offset_star.regions])
if basis != "rz":
for offsets in [0.6, np.array([0.6] * 10), [0.6] * 10]:
offset_star = star_poly.offset(offsets)
assert (0, 0, 0) in -offset_star
assert any([(0, 0, 0) in reg for reg in offset_star.regions])
with pytest.raises(ValueError):
star_poly.offset([0.6, 0.6])

# check invalid Polygon input points
# duplicate points not just at start and end
Expand Down

0 comments on commit 9983ee1

Please sign in to comment.