From 91fd60be69caf42b615f79f3b75c52843009033e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 10 Oct 2024 12:58:15 -0500 Subject: [PATCH] Immediately resolve complement operators for regions (#3145) --- openmc/model/surface_composite.py | 8 ----- openmc/region.py | 30 +++++++++---------- openmc/surface.py | 3 +- .../filter_mesh/inputs_true.dat | 2 +- .../filter_translations/inputs_true.dat | 2 +- .../mgxs_library_mesh/inputs_true.dat | 2 +- .../photon_production_inputs_true.dat | 2 +- .../photon_production/inputs_true.dat | 2 +- .../score_current/inputs_true.dat | 2 +- tests/unit_tests/test_region.py | 2 +- 10 files changed, 24 insertions(+), 31 deletions(-) diff --git a/openmc/model/surface_composite.py b/openmc/model/surface_composite.py index a2cb0243849..e2a5f49c4d0 100644 --- a/openmc/model/surface_composite.py +++ b/openmc/model/surface_composite.py @@ -778,12 +778,6 @@ def __init__(self, x0=0., y0=0., z0=0., r2=1., up=True, **kwargs): def __neg__(self): return -self.cone & (+self.plane if self.up else -self.plane) - def __pos__(self): - if self.up: - return (+self.cone & +self.plane) | -self.plane - else: - return (+self.cone & -self.plane) | +self.plane - class YConeOneSided(CompositeSurface): """One-sided cone parallel the y-axis @@ -836,7 +830,6 @@ def __init__(self, x0=0., y0=0., z0=0., r2=1., up=True, **kwargs): self.up = up __neg__ = XConeOneSided.__neg__ - __pos__ = XConeOneSided.__pos__ class ZConeOneSided(CompositeSurface): @@ -890,7 +883,6 @@ def __init__(self, x0=0., y0=0., z0=0., r2=1., up=True, **kwargs): self.up = up __neg__ = XConeOneSided.__neg__ - __pos__ = XConeOneSided.__pos__ class Polygon(CompositeSurface): diff --git a/openmc/region.py b/openmc/region.py index e509b152805..e1cb834757a 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -1,3 +1,4 @@ +from __future__ import annotations from abc import ABC, abstractmethod from collections.abc import MutableSequence from copy import deepcopy @@ -30,8 +31,9 @@ def __and__(self, other): def __or__(self, other): return Union((self, other)) - def __invert__(self): - return Complement(self) + @abstractmethod + def __invert__(self) -> Region: + pass @abstractmethod def __contains__(self, point): @@ -442,6 +444,9 @@ def __iand__(self, other): self.append(other) return self + def __invert__(self) -> Union: + return Union(~n for n in self) + # Implement mutable sequence protocol by delegating to list def __getitem__(self, key): return self._nodes[key] @@ -530,6 +535,9 @@ def __ior__(self, other): self.append(other) return self + def __invert__(self) -> Intersection: + return Intersection(~n for n in self) + # Implement mutable sequence protocol by delegating to list def __getitem__(self, key): return self._nodes[key] @@ -603,7 +611,7 @@ class Complement(Region): """ - def __init__(self, node): + def __init__(self, node: Region): self.node = node def __contains__(self, point): @@ -622,6 +630,9 @@ def __contains__(self, point): """ return point not in self.node + def __invert__(self) -> Region: + return self.node + def __str__(self): return '~' + str(self.node) @@ -637,18 +648,7 @@ def node(self, node): @property def bounding_box(self) -> BoundingBox: - # Use De Morgan's laws to distribute the complement operator so that it - # only applies to surface half-spaces, thus allowing us to calculate the - # bounding box in the usual recursive manner. - if isinstance(self.node, Union): - temp_region = Intersection(~n for n in self.node) - elif isinstance(self.node, Intersection): - temp_region = Union(~n for n in self.node) - elif isinstance(self.node, Complement): - temp_region = self.node.node - else: - temp_region = ~self.node - return temp_region.bounding_box + return (~self.node).bounding_box def get_surfaces(self, surfaces=None): """Recursively find and return all the surfaces referenced by the node diff --git a/openmc/surface.py b/openmc/surface.py index 2f10750a89b..537823ba16a 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -1,3 +1,4 @@ +from __future__ import annotations from abc import ABC, abstractmethod from collections.abc import Iterable from copy import deepcopy @@ -2631,7 +2632,7 @@ def __or__(self, other): else: return Union((self, other)) - def __invert__(self): + def __invert__(self) -> Halfspace: return -self.surface if self.side == '+' else +self.surface def __contains__(self, point): diff --git a/tests/regression_tests/filter_mesh/inputs_true.dat b/tests/regression_tests/filter_mesh/inputs_true.dat index a58d58bab95..0667c034148 100644 --- a/tests/regression_tests/filter_mesh/inputs_true.dat +++ b/tests/regression_tests/filter_mesh/inputs_true.dat @@ -12,7 +12,7 @@ - + diff --git a/tests/regression_tests/filter_translations/inputs_true.dat b/tests/regression_tests/filter_translations/inputs_true.dat index a80ccd87675..5004c3217ab 100644 --- a/tests/regression_tests/filter_translations/inputs_true.dat +++ b/tests/regression_tests/filter_translations/inputs_true.dat @@ -12,7 +12,7 @@ - + diff --git a/tests/regression_tests/mgxs_library_mesh/inputs_true.dat b/tests/regression_tests/mgxs_library_mesh/inputs_true.dat index bb9c99026d0..1ecb7a2d3b4 100644 --- a/tests/regression_tests/mgxs_library_mesh/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_mesh/inputs_true.dat @@ -12,7 +12,7 @@ - + diff --git a/tests/regression_tests/model_xml/photon_production_inputs_true.dat b/tests/regression_tests/model_xml/photon_production_inputs_true.dat index ee6cb88622b..10f0bad9841 100644 --- a/tests/regression_tests/model_xml/photon_production_inputs_true.dat +++ b/tests/regression_tests/model_xml/photon_production_inputs_true.dat @@ -9,7 +9,7 @@ - + diff --git a/tests/regression_tests/photon_production/inputs_true.dat b/tests/regression_tests/photon_production/inputs_true.dat index ee6cb88622b..10f0bad9841 100644 --- a/tests/regression_tests/photon_production/inputs_true.dat +++ b/tests/regression_tests/photon_production/inputs_true.dat @@ -9,7 +9,7 @@ - + diff --git a/tests/regression_tests/score_current/inputs_true.dat b/tests/regression_tests/score_current/inputs_true.dat index 9ea8e5e4ae1..ddbd6c24b05 100644 --- a/tests/regression_tests/score_current/inputs_true.dat +++ b/tests/regression_tests/score_current/inputs_true.dat @@ -12,7 +12,7 @@ - + diff --git a/tests/unit_tests/test_region.py b/tests/unit_tests/test_region.py index 8c9e0afe4d9..cbcd1983125 100644 --- a/tests/unit_tests/test_region.py +++ b/tests/unit_tests/test_region.py @@ -106,7 +106,7 @@ def test_complement(reset): assert_unbounded(outside_equiv) # string represention - assert str(inside) == '~(1 | -2 | 3)' + assert str(inside) == '(-1 2 -3)' # evaluate method assert (0, 0, 0) in inside