def test_growToFullCoreFromThirdCore(self): """Test that a hex core can be converted from a third core to a full core geometry.""" # Check the initialization of the third core model self.assertFalse(self.r.core.isFullCore) self.assertEqual( self.r.core.symmetry, geometry.SymmetryType(geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC), ) initialNumBlocks = len(self.r.core.getBlocks()) # Perform reactor conversion changer = geometryConverters.ThirdCoreHexToFullCoreChanger(self.o.cs) changer.convert(self.r) # Check the full core conversion is successful self.assertGreater(len(self.r.core.getBlocks()), initialNumBlocks) self.assertEqual(self.r.core.symmetry.domain, geometry.DomainType.FULL_CORE) # Check that the geometry can be restored to a third core changer.restorePreviousGeometry(self.o.cs, self.r) self.assertEqual(initialNumBlocks, len(self.r.core.getBlocks())) self.assertEqual( self.r.core.symmetry, geometry.SymmetryType(geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC), )
def test_checkValidGeomSymmetryCombo(self): geomHex = geometry.GeomType.HEX geomCart = geometry.GeomType.CARTESIAN geomRZT = geometry.GeomType.RZT geomRZ = geometry.GeomType.RZ fullCore = geometry.SymmetryType(geometry.DomainType.FULL_CORE, geometry.BoundaryType.NO_SYMMETRY) thirdPeriodic = geometry.SymmetryType(geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC) quarterCartesian = geometry.SymmetryType( geometry.DomainType.QUARTER_CORE, geometry.BoundaryType.REFLECTIVE) self.assertTrue( geometry.checkValidGeomSymmetryCombo(geomHex, thirdPeriodic)) self.assertTrue(geometry.checkValidGeomSymmetryCombo( geomHex, fullCore)) self.assertTrue( geometry.checkValidGeomSymmetryCombo(geomCart, quarterCartesian)) self.assertTrue( geometry.checkValidGeomSymmetryCombo(geomRZT, quarterCartesian)) self.assertTrue(geometry.checkValidGeomSymmetryCombo(geomRZ, fullCore)) with self.assertRaises(ValueError): _ = geometry.SymmetryType( geometry.DomainType.THIRD_CORE, geometry.BoundaryType.REFLECTIVE, False, ) with self.assertRaises(ValueError): geometry.checkValidGeomSymmetryCombo(geomHex, quarterCartesian) with self.assertRaises(ValueError): geometry.checkValidGeomSymmetryCombo(geomCart, thirdPeriodic)
def testBaseConstructor(self): self.assertEqual( geometry.SymmetryType(geometry.DomainType.SIXTEENTH_CORE, geometry.BoundaryType.REFLECTIVE).domain, geometry.DomainType.SIXTEENTH_CORE, ) self.assertEqual( str( geometry.SymmetryType( geometry.DomainType.FULL_CORE, geometry.BoundaryType.NO_SYMMETRY).boundary), "", )
def testSymmetryFactor(self): st = geometry.SymmetryType(geometry.DomainType.FULL_CORE, geometry.BoundaryType.NO_SYMMETRY) self.assertEqual(st.symmetryFactor(), 1.0) st = geometry.SymmetryType(geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC) self.assertEqual(st.symmetryFactor(), 3.0) st = geometry.SymmetryType(geometry.DomainType.QUARTER_CORE, geometry.BoundaryType.REFLECTIVE) self.assertEqual(st.symmetryFactor(), 4.0) st = geometry.SymmetryType(geometry.DomainType.EIGHTH_CORE, geometry.BoundaryType.REFLECTIVE) self.assertEqual(st.symmetryFactor(), 8.0) st = geometry.SymmetryType(geometry.DomainType.SIXTEENTH_CORE, geometry.BoundaryType.REFLECTIVE) self.assertEqual(st.symmetryFactor(), 16.0)
def testReadReactor(self): reactor = test_reactors.buildOperatorOfEmptyHexBlocks().r reactor.core.symmetry = geometry.SymmetryType( geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC) geom = SystemLayoutInput.fromReactor(reactor) self.assertEqual(geom.assemTypeByIndices[(2, 1)], "fuel") self.assertEqual(str(geom.geomType), geometry.HEX)
def __init__( self, name=None, geom=geometry.HEX, latticeMap=None, symmetry=str( geometry.SymmetryType(geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC)), gridContents=None, gridBounds=None, ): """ A Grid blueprint. Notes ----- yamlize does not call an __init__ method, instead it uses __new__ and setattr this is only needed for when you want to make this object from a non-YAML source. .. warning:: This is a Yamlize object, so ``__init__`` never really gets called. Only ``__new__`` does. """ self.name = name self.geom = str(geom) self.latticeMap = latticeMap self.symmetry = str(symmetry) self.gridContents = gridContents self.gridBounds = gridBounds
def expandToFull(self): """ Unfold the blueprints to represent full symmetry. .. note:: This relatively rudimentary, and copies entries from the currently-represented domain to their corresponding locations in full symmetry. This may not produce the desired behavior for some scenarios, such as when expanding fuel shuffling paths or the like. Future work may make this more sophisticated. """ if (geometry.SymmetryType.fromAny( self.symmetry).domain == geometry.DomainType.FULL_CORE): # No need! return grid = self.construct() newContents = copy.copy(self.gridContents) for idx, contents in self.gridContents.items(): equivs = grid.getSymmetricEquivalents(idx) for idx2 in equivs: newContents[idx2] = contents self.gridContents = newContents split = geometry.THROUGH_CENTER_ASSEMBLY in self.symmetry self.symmetry = str( geometry.SymmetryType( geometry.DomainType.FULL_CORE, geometry.BoundaryType.NO_SYMMETRY, throughCenterAssembly=split, ))
def growToFullCore(self): """ Convert geometry input to full core. Notes ----- This only works for Hex 1/3rd core geometry inputs. """ if self.symmetry.domain == geometry.DomainType.FULL_CORE: # already full core from geometry file. No need to copy symmetry over. runLog.important( "Detected that full core geometry already exists. Cannot expand." ) return elif ( self.symmetry.domain != geometry.DomainType.THIRD_CORE or self.symmetry.boundary != geometry.BoundaryType.PERIODIC ): raise ValueError( "Cannot convert shape `{}` to full core, must be {}".format( self.symmetry.domain, str( geometry.SymmetryType( geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC, ) ), ), ) grid = grids.HexGrid.fromPitch(1.0) grid._symmetry: str = str(self.symmetry) # need to cast to a list because we will modify during iteration for (ring, pos), specifierID in list(self.assemTypeByIndices.items()): indices = grids.HexGrid.getIndicesFromRingAndPos(ring, pos) for symmetricI, symmetricJ in grid.getSymmetricEquivalents(indices): symmetricRingPos = grids.HexGrid.indicesToRingPos( symmetricI, symmetricJ ) self.assemTypeByIndices[symmetricRingPos] = specifierID self.symmetry = geometry.SymmetryType( geometry.DomainType.FULL_CORE, geometry.BoundaryType.NO_SYMMETRY, )
def testLabel(self): st = geometry.SymmetryType(geometry.DomainType.FULL_CORE, geometry.BoundaryType.NO_SYMMETRY) self.assertEqual(st.domain.label, "Full") self.assertEqual(st.boundary.label, "No Symmetry") st = geometry.SymmetryType(geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC) self.assertEqual(st.domain.label, "Third") self.assertEqual(st.boundary.label, "Periodic") st = geometry.SymmetryType(geometry.DomainType.QUARTER_CORE, geometry.BoundaryType.REFLECTIVE) self.assertEqual(st.domain.label, "Quarter") self.assertEqual(st.boundary.label, "Reflective") st = geometry.SymmetryType(geometry.DomainType.EIGHTH_CORE, geometry.BoundaryType.REFLECTIVE) self.assertEqual(st.domain.label, "Eighth") st = geometry.SymmetryType(geometry.DomainType.SIXTEENTH_CORE, geometry.BoundaryType.REFLECTIVE) self.assertEqual(st.domain.label, "Sixteenth")
def getEmptyHexReactor(): """Make an empty hex reactor used in some tests.""" from armi.reactor import blueprints bp = blueprints.Blueprints() reactor = reactors.Reactor("Reactor", bp) reactor.add(reactors.Core("Core")) reactor.core.spatialGrid = grids.HexGrid.fromPitch(1.0) reactor.core.spatialGrid.symmetry = geometry.SymmetryType( geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC) reactor.core.spatialGrid.geomType = geometry.HEX reactor.core.spatialGrid.armiObject = reactor.core return reactor
def test_getSymmetricIdenticalsThird(self): grid = grids.HexGrid.fromPitch(1.0) grid.symmetry = str( geometry.SymmetryType(geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC)) self.assertEqual(grid.getSymmetricEquivalents((3, -2)), [(-1, 3), (-2, -1)]) self.assertEqual(grid.getSymmetricEquivalents((2, 1)), [(-3, 2), (1, -3)]) symmetrics = grid.getSymmetricEquivalents( grid.getIndicesFromRingAndPos(5, 3)) self.assertEqual([(5, 11), (5, 19)], [grid.getRingPos(indices) for indices in symmetrics])
def setUp(self): bp = blueprints.Blueprints() r = reactors.Reactor("zonetest", bp) r.add(reactors.Core("Core")) r.core.spatialGrid = grids.HexGrid.fromPitch(1.0) r.core.spatialGrid.symmetry = geometry.SymmetryType( geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC) r.core.spatialGrid.geomType = geometry.HEX aList = [] for ring in range(10): a = assemblies.HexAssembly("fuel") a.spatialLocator = r.core.spatialGrid[ring, 1, 0] a.parent = r.core aList.append(a) self.aList = aList
def getEmptyCartesianReactor(pitch=(10.0, 16.0)): """Return an empty Cartesian reactor used in some tests.""" from armi.reactor import blueprints bp = blueprints.Blueprints() reactor = reactors.Reactor("Reactor", bp) reactor.add(reactors.Core("Core")) reactor.core.spatialGrid = grids.CartesianGrid.fromRectangle(*pitch) reactor.core.spatialGrid.symmetry = geometry.SymmetryType( geometry.DomainType.QUARTER_CORE, geometry.BoundaryType.REFLECTIVE, throughCenterAssembly=True, ) reactor.core.spatialGrid.geomType = geometry.CARTESIAN reactor.core.spatialGrid.armiObject = reactor.core return reactor
def createDummyReactor(): """ Create a dummy reactor with a single fuel assembly and a single fuel block. Often, a reactor model like this is built directly from input files rather than from code as done here. """ bp = blueprints.Blueprints() cs = settings.Settings() r = reactors.Reactor("Reactor", bp) r.add(reactors.Core("Core")) r.core.spatialGrid = grids.HexGrid.fromPitch(1.0) r.core.spatialGrid.symmetry = geometry.SymmetryType( geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC) r.core.spatialGrid.geomType = geometry.GeomType.HEX r.core.spatialGrid.armiObject = r.core r.core.setOptionsFromCs(cs) # Create a single fuel assembly a = assemblies.HexAssembly("fuel assembly") a.spatialGrid = grids.axialUnitGrid(1) a.spatialLocator = r.core.spatialGrid[1, 0, 0] # Create a single fuel block b = blocks.HexBlock("fuel block") b.setType("fuel") # Create a single fuel component with UZr fuel. dims = {"Tinput": 20, "Thot": 900, "id": 0.0, "od": 2.9, "mult": 7} c = Circle("fuel", uZr.UZr(), **dims) b.add(c) # Create a single structure component with HT9. dims = {"Tinput": 20, "Thot": 600, "op": 16.0, "ip": 15.0, "mult": 1} c = Hexagon("structure", ht9.HT9(), **dims) b.add(c) # Fill in the rest of the block with sodium coolant. dims = {"Tinput": 600, "Thot": 600} c = DerivedShape("coolant", sodium.Sodium(), **dims) b.add(c) a.add(b) r.core.add(a) _addFlux(b) return r
def testFromAny(self): st = geometry.SymmetryType.fromAny( "eighth reflective through center assembly") self.assertTrue(st.isThroughCenterAssembly) self.assertEqual(st.domain, geometry.DomainType.EIGHTH_CORE) self.assertEqual(st.boundary, geometry.BoundaryType.REFLECTIVE) st = geometry.SymmetryType(geometry.DomainType.EIGHTH_CORE, geometry.BoundaryType.REFLECTIVE, True) self.assertTrue(st.isThroughCenterAssembly) self.assertEqual(st.domain, geometry.DomainType.EIGHTH_CORE) self.assertEqual(st.boundary, geometry.BoundaryType.REFLECTIVE) newST = geometry.SymmetryType.fromAny(st) self.assertTrue(newST.isThroughCenterAssembly) self.assertEqual(newST.domain, geometry.DomainType.EIGHTH_CORE) self.assertEqual(newST.boundary, geometry.BoundaryType.REFLECTIVE)
def _getGeomTypeAndSymmetryFromXml(self, root): """Read the geometry type and symmetry.""" try: self.geomType = geometry.GeomType.fromStr( str(root.attrib[INP_GEOM]).lower()) except ValueError: # will not execute if the geom was specified as thetarz, cartesian or anything else specific runLog.warning( "Could not find geometry type. Assuming hex geometry with third core periodic symmetry." ) self.geomType = geometry.GeomType.HEX self.symmetry = geometry.SymmetryType( geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC, ) else: inputString = str(root.attrib[INP_SYMMETRY]).lower() self.symmetry = geometry.SymmetryType.fromStr(inputString)
def test_skipGrowToFullCoreWhenAlreadyFullCore(self): """Test that hex core is not modified when third core to full core changer is called on an already full core geometry.""" # Check the initialization of the third core model and convert to a full core self.assertFalse(self.r.core.isFullCore) self.assertEqual( self.r.core.symmetry, geometry.SymmetryType( geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC ), ) changer = geometryConverters.ThirdCoreHexToFullCoreChanger(self.o.cs) changer.convert(self.r) # Check that the changer does not affect the full core model on converting and restoring initialNumBlocks = len(self.r.core.getBlocks()) self.assertEqual(self.r.core.symmetry.domain, geometry.DomainType.FULL_CORE) changer = geometryConverters.ThirdCoreHexToFullCoreChanger(self.o.cs) changer.convert(self.r) self.assertEqual(self.r.core.symmetry.domain, geometry.DomainType.FULL_CORE) self.assertEqual(initialNumBlocks, len(self.r.core.getBlocks())) changer.restorePreviousGeometry(self.o.cs, self.r) self.assertEqual(initialNumBlocks, len(self.r.core.getBlocks())) self.assertEqual(self.r.core.symmetry.domain, geometry.DomainType.FULL_CORE)
class GridBlueprint(yamlize.Object): """ A grid input blueprint. These directly build Grid objects and contain information about how to populate the Grid with child ArmiObjects for the Reactor Model. The grids get origins either from a parent block (for pin lattices) or from a System (for Cores, SFPs, and other components). Attributes ---------- name : str The grid name geom : str The geometry of the grid (e.g. 'cartesian') latticeMap : str An asciimap representation of the lattice contents latticeDimensions : Triplet An x/y/z Triplet with grid dimensions in cm. This is used to specify a uniform grid, such as Cartesian or Hex. Mutually exclusive with gridBounds. gridBounds : dict A dictionary containing explicit grid boundaries. Specific keys used will depend on the type of grid being defined. Mutually exclusive with latticeDimensions. symmetry : str A string defining the symmetry mode of the grid gridContents : dict A {(i,j): str} dictionary mapping spatialGrid indices in 2-D to string specifiers of what's supposed to be in the grid. """ name = yamlize.Attribute(key="name", type=str) geom = yamlize.Attribute(key="geom", type=str, default=geometry.HEX) latticeMap = yamlize.Attribute(key="lattice map", type=str, default=None) latticeDimensions = yamlize.Attribute(key="lattice pitch", type=Triplet, default=None) gridBounds = yamlize.Attribute(key="grid bounds", type=dict, default=None) symmetry = yamlize.Attribute( key="symmetry", type=str, default=str( geometry.SymmetryType(geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC)), ) # gridContents is the final form of grid contents information; # it is set regardless of how the input is read. This is how all # grid contents information is written out. gridContents = yamlize.Attribute(key="grid contents", type=dict, default=None) @gridContents.validator def gridContents(self, value): # pylint: disable=method-hidden if value is None: return True if not all(isinstance(key, tuple) for key in value.keys()): raise InputError( "Keys need to be presented as [i, j]. Check the blueprints.") def __init__( self, name=None, geom=geometry.HEX, latticeMap=None, symmetry=str( geometry.SymmetryType(geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC)), gridContents=None, gridBounds=None, ): """ A Grid blueprint. Notes ----- yamlize does not call an __init__ method, instead it uses __new__ and setattr this is only needed for when you want to make this object from a non-YAML source. .. warning:: This is a Yamlize object, so ``__init__`` never really gets called. Only ``__new__`` does. """ self.name = name self.geom = str(geom) self.latticeMap = latticeMap self.symmetry = str(symmetry) self.gridContents = gridContents self.gridBounds = gridBounds def construct(self): """Build a Grid from a grid definition.""" self._readGridContents() grid = self._constructSpatialGrid() return grid def _constructSpatialGrid(self): """ Build spatial grid. If you do not enter latticeDimensions, a unit grid will be produced which must be adjusted to the proper dimensions (often by inspection of children) at a later time. """ geom = self.geom maxIndex = self._getMaxIndex() runLog.extra("Creating the spatial grid") if geom in (geometry.RZT, geometry.RZ): if self.gridBounds is None: # This check is regrattably late. It would be nice if we could validate # that bounds are provided if R-Theta mesh is being used. raise InputError( "Grid bounds must be provided for `{}` to specify a grid with " "r-theta components.".format(self.name)) for key in ("theta", "r"): if key not in self.gridBounds: raise InputError( "{} grid bounds were not provided for `{}`.".format( key, self.name)) # convert to list, otherwise it is a CommentedSeq theta = numpy.array(self.gridBounds["theta"]) radii = numpy.array(self.gridBounds["r"]) for l, name in ((theta, "theta"), (radii, "radii")): if not _isMonotonicUnique(l): raise InputError( "Grid bounds for {}:{} is not sorted or contains " "duplicates. Check blueprints.".format( self.name, name)) spatialGrid = grids.ThetaRZGrid(bounds=(theta, radii, (0.0, 0.0))) if geom in (geometry.HEX, geometry.HEX_CORNERS_UP): pitch = self.latticeDimensions.x if self.latticeDimensions else 1.0 # add 2 for potential dummy assems spatialGrid = grids.HexGrid.fromPitch( pitch, numRings=maxIndex + 2, pointedEndUp=geom == geometry.HEX_CORNERS_UP, ) elif geom == geometry.CARTESIAN: # if full core or not cut-off, bump the first assembly from the center of # the mesh into the positive values. xw, yw = ((self.latticeDimensions.x, self.latticeDimensions.y) if self.latticeDimensions else (1.0, 1.0)) isOffset = (self.symmetry and geometry.THROUGH_CENTER_ASSEMBLY not in self.symmetry) spatialGrid = grids.CartesianGrid.fromRectangle(xw, yw, numRings=maxIndex + 1, isOffset=isOffset) runLog.debug("Built grid: {}".format(spatialGrid)) # set geometric metadata on spatialGrid. This information is needed in various # parts of the code and is best encapsulated on the grid itself rather than on # the container state. spatialGrid._geomType: str = str(self.geom) spatialGrid._symmetry: str = str(self.symmetry) return spatialGrid def _getMaxIndex(self): """ Find the max index in the grid contents. Used to limit the size of the spatialGrid. Used to be called maxNumRings. """ if self.gridContents: return max(itertools.chain(*zip(*self.gridContents.keys()))) else: return 6 def expandToFull(self): """ Unfold the blueprints to represent full symmetry. .. note:: This relatively rudimentary, and copies entries from the currently-represented domain to their corresponding locations in full symmetry. This may not produce the desired behavior for some scenarios, such as when expanding fuel shuffling paths or the like. Future work may make this more sophisticated. """ if (geometry.SymmetryType.fromAny( self.symmetry).domain == geometry.DomainType.FULL_CORE): # No need! return grid = self.construct() newContents = copy.copy(self.gridContents) for idx, contents in self.gridContents.items(): equivs = grid.getSymmetricEquivalents(idx) for idx2 in equivs: newContents[idx2] = contents self.gridContents = newContents split = geometry.THROUGH_CENTER_ASSEMBLY in self.symmetry self.symmetry = str( geometry.SymmetryType( geometry.DomainType.FULL_CORE, geometry.BoundaryType.NO_SYMMETRY, throughCenterAssembly=split, )) def _readGridContents(self): """ Read the specifiers as a function of grid position. The contents can either be provided as: * A dict mapping indices to specifiers (default output of this) * An asciimap The output will always be stored in ``self.gridContents``. """ if self.gridContents: return elif self.latticeMap: self._readGridContentsLattice() if self.gridContents is None: # Make sure we have at least something; clients shouldn't have to worry # about whether gridContents exist at all. self.gridContents = dict() def _readGridContentsLattice(self): """Read an ascii map of grid contents. This update the gridContents attribute, which is a dict mapping grid i,j,k indices to textual specifiers (e.g. ``IC``)) """ latticeCls = asciimaps.asciiMapFromGeomAndSym(self.geom, self.symmetry) asciimap = latticeCls() asciimap.readAscii(self.latticeMap) self.gridContents = dict() for (i, j), spec in asciimap.items(): if spec == "-": # skip placeholders continue self.gridContents[i, j] = spec def getLocators(self, spatialGrid: grids.Grid, latticeIDs: list): """ Return spatialLocators in grid corresponding to lattice IDs. This requires a fully-populated ``gridContents`` attribute. """ if latticeIDs is None: return [] if self.gridContents is None: return [] # tried using yamlize to coerce ints to strings but failed # after much struggle, so we just auto-convert here to deal # with int-like specifications. # (yamlize.StrList fails to coerce when ints are provided) latticeIDs = [str(i) for i in latticeIDs] locators = [] for (i, j), spec in self.gridContents.items(): locator = spatialGrid[i, j, 0] if spec in latticeIDs: locators.append(locator) return locators def getMultiLocator(self, spatialGrid, latticeIDs): """Create a MultiIndexLocation based on lattice IDs.""" spatialLocator = grids.MultiIndexLocation(grid=spatialGrid) spatialLocator.extend(self.getLocators(spatialGrid, latticeIDs)) return spatialLocator
def setUp(self): self.name = "A0015" self.assemNum = 15 self.height = 10 self.cs = settings.getMasterCs() # Print nothing to the screen that would normally go to the log. runLog.setVerbosity("error") self.r = tests.getEmptyHexReactor() self.r.core.symmetry = geometry.SymmetryType( geometry.DomainType.THIRD_CORE, geometry.BoundaryType.PERIODIC) self.assembly = makeTestAssembly(NUM_BLOCKS, self.assemNum, r=self.r) self.r.core.add(self.assembly) # Use these if they are needed self.blockParams = { "height": self.height, "avgFuelTemp": 873.0, "bondRemoved": 0.0, "bu": 15.1, "buGroupNum": 0, "buLimit": 35, "buRate": 0.0, "eqRegion": -1, "id": 212.0, "pdens": 10.0, "percentBu": 25.3, "power": 100000.0, "residence": 4.0, "smearDensity": 0.6996721711791459, "timeToLimit": 2.7e5, "xsTypeNum": 40, "zbottom": 97.3521, "ztop": 111.80279999999999, } self.blockSettings = { "axMesh": 1, "baseBu": 0.0, "basePBu": 0.0, "bondBOL": 0.0028698019026172574, "buGroup": "A", "height": 14.4507, "molesHmAtBOL": 65.8572895758245, "nHMAtBOL": 0.011241485251783766, "nPins": 169.0, "name": "B0011F", "newDPA": 0.0, "pitch": 16.79, "regName": False, "topIndex": 5, "tsIndex": 0, "type": "igniter fuel", "xsType": "C", "z": 104.57745, } # add some blocks with a component self.blockList = [] for i in range(NUM_BLOCKS): b = blocks.HexBlock("TestHexBlock") b.setHeight(self.height) self.hexDims = { "Tinput": 273.0, "Thot": 273.0, "op": 0.76, "ip": 0.0, "mult": 1.0, } h = components.Hexagon("fuel", "UZr", **self.hexDims) # non-flaggy name important for testing b.setType("igniter fuel unitst") b.add(h) b.parent = self.assembly b.setName(b.makeName(self.assembly.getNum(), i)) self.assembly.add(b) self.blockList.append(b) self.assembly.calculateZCoords()
def testSymmetry(self): # PERIODIC, no split grid = grids.CartesianGrid.fromRectangle( 1.0, 1.0, symmetry=str( geometry.SymmetryType(geometry.DomainType.QUARTER_CORE, geometry.BoundaryType.PERIODIC)), ) expected = { (0, 0): {(-1, 0), (-1, -1), (0, -1)}, (1, 0): {(-1, 1), (-2, -1), (0, -2)}, (2, 1): {(-2, 2), (-3, -2), (1, -3)}, (2, 2): {(-3, 2), (-3, -3), (2, -3)}, (0, 1): {(-2, 0), (-1, -2), (1, -1)}, (-2, 2): {(-3, -2), (1, -3), (2, 1)}, } for idx, expectedEq in expected.items(): equivalents = {i for i in grid.getSymmetricEquivalents(idx)} self.assertEqual(expectedEq, equivalents) # PERIODIC, split grid = grids.CartesianGrid.fromRectangle( 1.0, 1.0, symmetry=geometry.SymmetryType( geometry.DomainType.QUARTER_CORE, geometry.BoundaryType.PERIODIC, throughCenterAssembly=True, ), ) expected = { (0, 0): set(), (1, 0): {(0, 1), (-1, 0), (0, -1)}, (2, 2): {(-2, 2), (-2, -2), (2, -2)}, (2, 1): {(-1, 2), (-2, -1), (1, -2)}, (-1, 3): {(-3, -1), (1, -3), (3, 1)}, (0, 2): {(-2, 0), (0, -2), (2, 0)}, } for idx, expectedEq in expected.items(): equivalents = {i for i in grid.getSymmetricEquivalents(idx)} self.assertEqual(expectedEq, equivalents) # REFLECTIVE, no split grid = grids.CartesianGrid.fromRectangle( 1.0, 1.0, symmetry=geometry.SymmetryType(geometry.DomainType.QUARTER_CORE, geometry.BoundaryType.REFLECTIVE), ) expected = { (0, 0): {(-1, 0), (-1, -1), (0, -1)}, (1, 0): {(-2, 0), (-2, -1), (1, -1)}, (-2, 2): {(-2, -3), (1, -3), (1, 2)}, } for idx, expectedEq in expected.items(): equivalents = {i for i in grid.getSymmetricEquivalents(idx)} self.assertEqual(expectedEq, equivalents) # REFLECTIVE, split grid = grids.CartesianGrid.fromRectangle( 1.0, 1.0, symmetry=geometry.SymmetryType( geometry.DomainType.QUARTER_CORE, geometry.BoundaryType.REFLECTIVE, throughCenterAssembly=True, ), ) expected = { (0, 0): set(), (1, 0): {(-1, 0)}, (-1, 2): {(-1, -2), (1, -2), (1, 2)}, (-2, 0): {(2, 0)}, (0, -2): {(0, 2)}, } for idx, expectedEq in expected.items(): equivalents = {i for i in grid.getSymmetricEquivalents(idx)} self.assertEqual(expectedEq, equivalents) # Full core grid = grids.CartesianGrid.fromRectangle( 1.0, 1.0, symmetry=geometry.FULL_CORE, ) self.assertEqual(grid.getSymmetricEquivalents((5, 6)), []) # 1/8 core not supported yet grid = grids.CartesianGrid.fromRectangle( 1.0, 1.0, symmetry=geometry.SymmetryType( geometry.DomainType.EIGHTH_CORE, geometry.BoundaryType.REFLECTIVE, ), ) with self.assertRaises(NotImplementedError): grid.getSymmetricEquivalents((5, 6))