def _constructAssembly(self, cs, blueprint): """Construct the current assembly.""" blocks = [] for axialIndex, bDesign in enumerate(self.blocks): b = self._createBlock(cs, blueprint, bDesign, axialIndex) blocks.append(b) assemblyClass = self.getAssemClass(blocks) a = assemblyClass(self.name) # set a basic grid with the right number of blocks with bounds to be adjusted. a.spatialGrid = grids.axialUnitGrid(len(blocks)) a.spatialGrid.armiObject = a # TODO: Remove mesh points from blueprints entirely. Submeshing should be # handled by specific physics interfaces radMeshPoints = self.radialMeshPoints or 1 a.p.RadMesh = radMeshPoints aziMeshPoints = self.azimuthalMeshPoints or 1 a.p.AziMesh = aziMeshPoints # loop a second time because we needed all the blocks before choosing the # assembly class. for axialIndex, block in enumerate(blocks): b.p.assemNum = a.p.assemNum b.name = b.makeName(a.p.assemNum, axialIndex) a.add(block) # Assign values for the parameters if they are defined on the blueprints for paramDef in a.p.paramDefs.inCategory( parameters.Category.assignInBlueprints): val = getattr(self, paramDef.name) if val is not None: a.p[paramDef.name] = val return a
def doubleResolution(self): """ Turns each block into two half-size blocks. Notes ----- Used for mesh sensitivity studies. .. warning:: This is likely destined for a geometry converter rather than this instance method. """ newBlockStack = [] topIndex = -1 for b in self: b0 = b b1 = copy.deepcopy(b) for bx in [b0, b1]: newHeight = bx.getHeight() / 2.0 bx.p.height = newHeight bx.p.heightBOL = newHeight topIndex += 1 bx.p.topIndex = topIndex newBlockStack.append(bx) bx.clearCache() self.removeAll() self.spatialGrid = grids.axialUnitGrid(len(newBlockStack)) for b in newBlockStack: self.add(b) self.reestablishBlockOrder()
def test_setMass(self): """ test: setMass setMasses """ loc = locations.Location(i1=1, i2=1, axial=1) mass = 1.0 aB = batch.Batch("testBatch") c = shapes.UnshapedVolumetricComponent( "batchMassAdditionComponent", custom.Custom(), 0.0, 0.0, volume=1 ) b = blocks.Block("testBlock", location=loc) b.add(c) a = assemblies.Assembly("testAssembly") a.spatialGrid = grids.axialUnitGrid(1, a) a.add(b) r = getEmptyHexReactor() a.spatialLocator = r.core.spatialGrid[0, 0, 0] r.core.add(a) # these armi objects have setMass implemented for armiObj in [aB, c, b]: for nucName in ["U235"]: masses = {nucName: mass} armiObj.setMasses(masses) self.assertAlmostEqual(armiObj.getMass(nucName), mass, 6)
def buildOperatorOfEmptyHexBlocks(customSettings=None): """ Builds a operator w/ a reactor object with some hex assemblies and blocks, but all are empty Doesn't depend on inputs and loads quickly. Params ------ customSettings : dict Dictionary of off-default settings to update """ settings.setMasterCs(None) # clear cs = settings.getMasterCs() # fetch new cs["db"] = False # stop use of database if customSettings is not None: cs.update(customSettings) r = tests.getEmptyHexReactor() r.core.setOptionsFromCs(cs) o = operators.Operator(cs) o.initializeInterfaces(r) a = assemblies.HexAssembly("fuel") a.spatialGrid = grids.axialUnitGrid(1) b = blocks.HexBlock("TestBlock") b.setType("fuel") dims = {"Tinput": 600, "Thot": 600, "op": 16.0, "ip": 1, "mult": 1} c = Hexagon("fuel", uZr.UZr(), **dims) b.add(c) a.add(b) a.spatialLocator = r.core.spatialGrid[1, 0, 0] o.r.core.add(a) return o
def _constructAssembly(self, cs, blueprint): """Construct the current assembly.""" blocks = [] for axialIndex, bDesign in enumerate(self.blocks): b = self._createBlock(cs, blueprint, bDesign, axialIndex) blocks.append(b) assemblyClass = self.getAssemClass(blocks) a = assemblyClass(self.name) # set a basic grid with the right number of blocks with bounds to be adjusted. a.spatialGrid = grids.axialUnitGrid(len(blocks)) a.spatialGrid.armiObject = a # loop a second time because we needed all the blocks before choosing the assembly class. for axialIndex, block in enumerate(blocks): b.p.assemNum = a.p.assemNum b.name = b.makeName(a.p.assemNum, axialIndex) a.add(block) # Assign values for the parameters if they are defined on the blueprints for paramDef in a.p.paramDefs.inCategory( parameters.Category.assignInBlueprints): val = getattr(self, paramDef.name) if val is not None: a.p[paramDef.name] = val return a
def setUp(self): r""" Build a dummy reactor without using input files. There are some igniters and feeds but none of these have any number densities. """ self.o, self.r = test_reactors.loadTestReactor( self.directoryChanger.destination ) blockList = self.r.core.getBlocks() for bi, b in enumerate(blockList): b.p.flux = 5e10 if b.isFuel(): b.p.percentBu = 30.0 * bi / len(blockList) self.nfeed = len(self.r.core.getAssemblies(Flags.FEED)) self.nigniter = len(self.r.core.getAssemblies(Flags.IGNITER)) self.nSfp = len(self.r.core.sfp) # generate a reactor with assemblies # generate components with materials nPins = 271 fuelDims = {"Tinput": 273.0, "Thot": 273.0, "od": 1.0, "id": 0.0, "mult": nPins} fuel = components.Circle("fuel", "UZr", **fuelDims) cladDims = {"Tinput": 273.0, "Thot": 273.0, "od": 1.1, "id": 1.0, "mult": nPins} clad = components.Circle("clad", "HT9", **cladDims) interDims = { "Tinput": 273.0, "Thot": 273.0, "op": 16.8, "ip": 16.0, "mult": 1.0, } interSodium = components.Hexagon("interCoolant", "Sodium", **interDims) # generate a block self.block = blocks.HexBlock("TestHexBlock", self.o.cs) self.block.setType("fuel") self.block.setHeight(10.0) self.block.add(fuel) self.block.add(clad) self.block.add(interSodium) # generate an assembly self.assembly = assemblies.HexAssembly("TestAssemblyType") self.assembly.spatialGrid = grids.axialUnitGrid(1) for _ in range(1): self.assembly.add(copy.deepcopy(self.block)) # copy the assembly to make a list of assemblies and have a reference assembly self.aList = [] for _ in range(6): self.aList.append(copy.deepcopy(self.assembly)) self.refAssembly = copy.deepcopy(self.assembly) self.directoryChanger.open()
def test_badIndices(self): grid = grids.hexGridFromPitch(1.0, numRings=3) # this is actually ok because step-defined grids are infinite self.assertEqual(grid.getCoordinates((-100, 2000, 5))[2], 0.0) grid = grids.axialUnitGrid(10) with self.assertRaises(IndexError): grid.getCoordinates((0, 5, -1))
def test_ordering(self): a = assemblies.Assembly("dummy") a.spatialGrid = grids.axialUnitGrid(2, armiObject=a) otherBlock = deepcopy(self.Block) a.add(self.Block) a.add(otherBlock) self.assertTrue(self.Block < otherBlock) locator = self.Block.spatialLocator self.Block.spatialLocator = otherBlock.spatialLocator otherBlock.spatialLocator = locator self.assertTrue(otherBlock < self.Block)
def test_addMass(self): """ test: addMasses addMass removeMass getMasses right now it doesn't make sense to add mass to anything other than a component, some one else can implement addMass and update this test on block, assembly and reactor. """ loc = locations.Location(i1=1, i2=1, axial=1) mass = 1.0 aB = batch.Batch("testBatch") c = shapes.UnshapedVolumetricComponent("batchMassAdditionComponent", custom.Custom(), 0.0, 0.0, volume=1) b = blocks.Block("testBlock", location=loc) b.add(c) a = assemblies.Assembly("testAssembly") a.spatialGrid = grids.axialUnitGrid(1) a.add(b) r = getEmptyHexReactor() a.spatialLocator = r.core.spatialGrid[0, 0, 0] r.core.add(a) # these armi objects have addMass implemented for armiObj in [aB, c]: for nucName in ["U235"]: masses = {nucName: mass} armiObj.addMasses(masses) self.assertAlmostEqual(armiObj.getMass(nucName), mass, 6) armiObj.removeMass(nucName, mass) self.assertAlmostEqual(armiObj.getMass(nucName), 0, 6) # create a global lumped fission product collection with a single lfp Fpdf = test_lumpedFissionProduct.getDummyLFPFile() cLfps = Fpdf.createSingleLFPCollectionFromFile("LFP35") self.assertAlmostEqual(aB.getMass(), 0, 6) aB.addMass("LFP35", mass, lumpedFissionProducts=cLfps) self.assertAlmostEqual(aB.getMass(), mass, 6) self.assertAlmostEqual(c.getMass(), 0, 6) c.addMass("LFP35", mass, lumpedFissionProducts=cLfps) self.assertAlmostEqual(c.getMass(), mass, 6)
def test_summing(self): a = assemblies.Assembly("dummy") a.spatialGrid = grids.axialUnitGrid(2, armiObject=a) otherBlock = deepcopy(self.Block) a.add(self.Block) a.add(otherBlock) b = self.Block + otherBlock self.assertEqual(len(b), 26) self.assertFalse(b[0].is3D) self.assertIn("Circle", str(b[0])) self.assertFalse(b[-1].is3D) self.assertIn("Hexagon", str(b[-1]))
def adjustResolution(self, refA): """ Split the blocks in this assembly to have the same mesh structure as refA. """ newBlockStack = [] newBlocks = 0 # number of new blocks we've added so far. for i, b in enumerate(self): refB = refA[ i + newBlocks] # pick the block that is "supposed to" line up with refB. # runLog.important('Dealing with {0}, ref b {1}'.format(b,refB)) if refB.getHeight() == b.getHeight(): # these blocks line up # runLog.important('They are the same.') newBlockStack.append(b) continue elif refB.getHeight() > b.getHeight(): raise RuntimeError( "can't split {0} ({1}cm) into larger blocks to match ref block {2} ({3}cm)" "".format(b, b.getHeight(), refB, refB.getHeight())) else: # b is larger than refB. Split b up by splitting it into several smaller # blocks of refBs heightToChop = b.getHeight() heightChopped = 0.0 while (abs(heightChopped - heightToChop) > 1e-5): # stop when they are equal. floating point. # update which ref block we're on (does nothing on the first pass) refB = refA[i + newBlocks] newB = copy.deepcopy(b) newB.setHeight( refB.getHeight()) # make block match ref mesh newBlockStack.append(newB) heightChopped += refB.getHeight() newBlocks += 1 runLog.important( "Added a new block {0} of height {1}".format( newB, newB.getHeight())) runLog.important("Chopped {0} of {1}".format( heightChopped, heightToChop)) newBlocks -= ( 1 # subtract one because we eliminated the original b completely. ) self.removeAll() self.spatialGrid = grids.axialUnitGrid(len(newBlockStack)) for b in newBlockStack: self.add(b) self.reestablishBlockOrder()
def reestablishBlockOrder(self): """ After children have been mixed up axially, this re-locates each block with the proper axial mesh. See Also -------- calculateZCoords : updates the ztop/zbottom params on each block after reordering. """ # replace grid with one that has the right number of locations self.spatialGrid = grids.axialUnitGrid(len(self)) self.spatialGrid.armiObject = self for zi, b in enumerate(self): b.spatialLocator = self.spatialGrid[0, 0, zi] # update the name too. NOTE: You must update the history tracker. b.setName(b.makeName(self.p.assemNum, zi))
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 buildOperatorOfEmptyCartesianBlocks(customSettings=None): """ Builds a operator w/ a reactor object with some Cartesian assemblies and blocks, but all are empty Doesn't depend on inputs and loads quickly. Params ------ customSettings : dict Dictionary of off-default settings to update """ settings.setMasterCs(None) # clear cs = settings.getMasterCs() # fetch new if customSettings is None: customSettings = {} customSettings["db"] = False # stop use of database cs = cs.modified(newSettings=customSettings) settings.setMasterCs(cs) # reset r = tests.getEmptyCartesianReactor() r.core.setOptionsFromCs(cs) o = operators.Operator(cs) o.initializeInterfaces(r) a = assemblies.CartesianAssembly("fuel") a.spatialGrid = grids.axialUnitGrid(1) b = blocks.CartesianBlock("TestBlock") b.setType("fuel") dims = { "Tinput": 600, "Thot": 600, "widthOuter": 16.0, "lengthOuter": 10.0, "widthInner": 1, "lengthInner": 1, "mult": 1, } c = Rectangle("fuel", uZr.UZr(), **dims) b.add(c) a.add(b) a.spatialLocator = r.core.spatialGrid[1, 0, 0] o.r.core.add(a) return o
def _createNewAssembly(sourceAssembly): a = sourceAssembly.__class__(sourceAssembly.getType()) a.spatialGrid = grids.axialUnitGrid(len(sourceAssembly)) a.setName(sourceAssembly.getName()) return a
def test_getReactionRates(self): """ test: getReactionRates getReactionRates """ mgFlux1 = [ 0.0860473241399844, 0.104859413902775, 0.958730499751868, 0.0608613995961131, 0.286847241591555, 0.255889308191141, 0.0116901206385536, 0.713409716738126, 0.430296361167501, 0.807797711781478, 0.0337645123548413, 0.486499349955704, 0.734614285636136, 0.74230952191973, 0.262181249681019, 0.499163237742064, 0.522320530090222, 0.269684933319214, 0.286697941919085, 0.173049285638012, 0.881264543688633, 0.99461769495224, 0.267737005223648, 0.957400117341211, 0.767927939604005, 0.149702253058259, 0.332924880721111, 0.611969570430789, 0.227989279697323, 0.411852641375799, 0.500275641106796, 0.654655431372318, 0.223981131922656, ] lib = isotxs.readBinary(ISOAA_PATH) loc = locations.Location(i1=1, i2=1, axial=1) nDens = 0.02 # arbitrary number density for U235 c = UnshapedVolumetricComponent("testComponent", "Custom", 0.0, 0.0, volume=1) c.setNumberDensity("U235", nDens) b = blocks.Block("testBlock", location=loc) b.add(c) b.p.mgFlux = mgFlux1[:33] b.p.xsType = "A" a = assemblies.Assembly("testAssembly") a.spatialGrid = grids.axialUnitGrid(1, a) a.add(b) r = getEmptyHexReactor() a.spatialLocator = r.core.spatialGrid[0, 0, 0] r.core.add(a) r.core.lib = lib aB = batch.Batch("testBatch") aB.add(b) # reference data made with this ISOTXS and this MG flux spectrum referenceRxRateData = { "nG": 2.10693674, "nF": 6.500339249, "n2n": 0.001446367, "nA": 0, "nP": 0, "n3n": 0, } referenceXsData = { "nG": 7.162060679, "nF": 22.09645085, "n2n": 0.004916601, "nA": 0, "nP": 0, "n3n": 0, } u235 = lib["U235AA"] assert not hasattr(u235.micros, "n3n") for armiObject in [c, b, a, r, aB]: rxnRates = armiObject.getReactionRates("U235") for rxName, rxRate in rxnRates.items(): self.assertAlmostEqual(rxRate, referenceRxRateData[rxName], 6) xsTable = armiObject.getCrossSectionTable(nuclides=["U235"]) u235Zaid = 92235 for rxName, rxRate in xsTable[u235Zaid].items(): self.assertAlmostEqual(rxRate, referenceXsData[rxName], 6)
def test_getMgFluxes(self): """ test: getMgFlux getIntegratedMgFlux """ mgFlux1 = [ 0.0860473241399844, 0.104859413902775, 0.958730499751868, 0.0608613995961131, 0.286847241591555, 0.255889308191141, 0.0116901206385536, 0.713409716738126, 0.430296361167501, 0.807797711781478, 0.0337645123548413, 0.486499349955704, 0.734614285636136, 0.74230952191973, 0.262181249681019, 0.499163237742064, 0.522320530090222, 0.269684933319214, 0.286697941919085, 0.173049285638012, 0.881264543688633, 0.99461769495224, 0.267737005223648, 0.957400117341211, 0.767927939604005, 0.149702253058259, 0.332924880721111, 0.611969570430789, 0.227989279697323, 0.411852641375799, 0.500275641106796, 0.654655431372318, 0.223981131922656, ] loc = locations.Location(i1=1, i2=1, axial=1) c = UnshapedVolumetricComponent("testComponent", "Custom", 0.0, 0.0, volume=1) b = blocks.Block("testBlock", location=loc) b.add(c) b.p.mgFlux = mgFlux1 a = assemblies.Assembly("testAssembly") a.spatialGrid = grids.axialUnitGrid(1, a) a.add(b) r = getEmptyHexReactor() a.spatialLocator = r.core.spatialGrid[0, 0, 0] r.core.add(a) aB = batch.Batch("testBatch") aB.add(b) for armiObject in [c, b, a, r, aB]: for refFlux, testFlux in zip(mgFlux1, armiObject.getIntegratedMgFlux()): err = math.fabs((testFlux - refFlux) / refFlux) try: assert err < 1e-6 except AssertionError: raise AssertionError( "Integrated MgFlux test is failing for {}".format( type(armiObject) ) ) for refFlux, testFlux in zip(mgFlux1, armiObject.getMgFlux()): err = math.fabs((testFlux - refFlux) / refFlux) try: assert err < 1e-6 except AssertionError: raise AssertionError( "Integrated MgFlux test is failing for {}".format( type(armiObject) ) )
def test_isAxialOnly(self): grid = grids.hexGridFromPitch(1.0, numRings=3) self.assertEqual(grid.isAxialOnly, False) grid2 = grids.axialUnitGrid(10) self.assertEqual(grid2.isAxialOnly, True)