From 768949a97274189076da51f1d2f7e3a4ca9a11bc Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 12 Jul 2019 17:08:17 -0500 Subject: [PATCH] Add support for non-Materials to be used in pin function Anything that can be filled by a cell can be passed to openmc.model.pin, including Universes and lattices. Checks are included for the volume division, as not all supported items, like Lattice instances, have volume attributes. A test was added to check this capability, where a universe is used as one of the interior elements for the pin. Various cosmetic changes to address reviewer comments. --- openmc/model/funcs.py | 54 ++++++++++++++++++------------------ tests/unit_tests/test_pin.py | 10 +++++++ 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/openmc/model/funcs.py b/openmc/model/funcs.py index 1912b4215d..865c3c4a9e 100644 --- a/openmc/model/funcs.py +++ b/openmc/model/funcs.py @@ -448,7 +448,7 @@ def subdivide(surfaces): return regions -def pin(surfaces, materials, subdivisions=None, divide_vols=True, +def pin(surfaces, items, subdivisions=None, divide_vols=True, **kwargs): """Convenience function for building a fuel pin @@ -456,22 +456,24 @@ def pin(surfaces, materials, subdivisions=None, divide_vols=True, ---------- surfaces : iterable of :class:`openmc.Cylinder` Cylinders used to define boundaries - between materials. All cylinders must be + between items. All cylinders must be concentric and of the same orientation, e.g. all :class:`openmc.ZCylinder` - materials : iterable of :class:`openmc.Material` - Materials to go between ``surfaces``. There must be one - more material than surfaces, corresponding to the material - that spans all space outside the final ring. + items : iterable + Objects to go between ``surfaces``. These can be anything + that can fill a :class:`openmc.Cell`, including + :class:`openmc.Material`, or other :class:`openmc.Universe` + objects. There must be one more item than surfaces, + which will span all space outside the final ring. subdivisions : None or dict of int to int Dictionary describing which rings to subdivide and how many times. Keys are indexes of the annular rings to be divided. Will construct equal area rings divide_vols : bool If this evaluates to ``True``, then volumes of subdivided - materials will also be divided by the number of divisions. - Otherwise the volume of the original material will not be - modified before subdivision + :class:`openmc.Material`s will also be divided by the + number of divisions. Otherwise the volume of the + original material will not be modified before subdivision kwargs: Additional key-word arguments to be passed to :class:`openmc.Universe`, like ``name="Fuel pin"`` @@ -480,13 +482,13 @@ def pin(surfaces, materials, subdivisions=None, divide_vols=True, ------- :class:`openmc.Universe` Universe of concentric cylinders filled with the desired - materials + items """ if "cells" in kwargs: raise SyntaxError( "Cells will be set by this function, not from input arguments.") - check_type("materials", materials, Iterable, Material) - check_length("surfaces", surfaces, len(materials) - 1, len(materials) - 1) + check_type("items", items, Iterable) + check_length("surfaces", surfaces, len(items) - 1, len(items) - 1) # Check that all surfaces are of similar orientation check_type("surface", surfaces[0], Cylinder) surf_type = type(surfaces[0]) @@ -511,8 +513,8 @@ def pin(surfaces, materials, subdivisions=None, divide_vols=True, if cur_rad <= prev_rad: raise ValueError( "Surfaces do not appear to be increasing in radius. " - "Surface {} at index {} has radius {:7.3E} compared to " - "previous radius of {:7.5E}".format( + "Surface {} at index {} has radius {:7.3e} compared to " + "previous radius of {:7.5e}".format( surf.id, ix, cur_rad, prev_rad)) prev_rad = cur_rad centers.add(center_getter(surf)) @@ -536,8 +538,8 @@ def pin(surfaces, materials, subdivisions=None, divide_vols=True, "outer ring", max(subdivisions), len(surfaces), equality=True) # ensure ability to concatenate - if not isinstance(materials, list): - materials = list(materials) + if not isinstance(items, list): + items = list(items) if not isinstance(surfaces, list): surfaces = list(surfaces) @@ -549,10 +551,8 @@ def pin(surfaces, materials, subdivisions=None, divide_vols=True, nr = subdivisions[ring_index] new_surfs = [] - if ring_index == 0: - lower_rad = 0.0 - else: - lower_rad = surfaces[ring_index - 1].r + lower_rad = 0.0 if ring_index == 0 else surfaces[ring_index - 1].r + upper_rad = surfaces[ring_index].r area_term = (upper_rad ** 2 - lower_rad ** 2) / nr @@ -564,15 +564,15 @@ def pin(surfaces, materials, subdivisions=None, divide_vols=True, surfaces = ( surfaces[:ring_index] + new_surfs + surfaces[ring_index:]) - if divide_vols and materials[ring_index].volume is not None: - materials[ring_index].volume /= nr + filler = items[ring_index] + if (divide_vols and hasattr(filler, "volume") + and filler.volume is not None): + filler.volume /= nr - materials = ( - materials[:ring_index] - + [materials[ring_index].clone() for _i in range(nr - 1)] - + materials[ring_index:]) + items[ring_index:ring_index] = [ + filler.clone() for _i in range(nr - 1)] # Build the universe regions = subdivide(surfaces) - cells = [Cell(fill=f, region=r) for r, f in zip(regions, materials)] + cells = [Cell(fill=f, region=r) for r, f in zip(regions, items)] return Universe(cells=cells, **kwargs) diff --git a/tests/unit_tests/test_pin.py b/tests/unit_tests/test_pin.py index 391ed816a0..42241de5f2 100644 --- a/tests/unit_tests/test_pin.py +++ b/tests/unit_tests/test_pin.py @@ -66,6 +66,16 @@ def test_failure(pin_mats, good_radii): pin(surfs, pin_mats, cells=[]) +def test_pins_of_universes(pin_mats, good_radii): + """Build a pin with a Universe in one ring""" + u1 = openmc.Universe(cells=[openmc.Cell(fill=pin_mats[1])]) + new_items = pin_mats[:1] + (u1, ) + pin_mats[2:] + new_pin = pin( + [openmc.ZCylinder(r=r) for r in good_radii], new_items, + subdivisions={0: 2}, divide_vols=True) + assert len(new_pin.cells) == len(pin_mats) + 1 + + @pytest.mark.parametrize( "surf_type", [openmc.ZCylinder, openmc.XCylinder, openmc.YCylinder]) def test_subdivide(pin_mats, good_radii, surf_type):