Source code for armi.reactor.blueprints.assemblyBlueprint

# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
This module defines the blueprints input object for assemblies.

In addition to defining the input format, the ``AssemblyBlueprint`` class is responsible for constructing ``Assembly``
objects. An attempt has been made to decouple ``Assembly`` construction from the rest of ARMI as much as possible. For
example, an assembly does not require a reactor to be constructed, or a geometry file (but uses ``geomType`` string as a
surrogate).
"""
import yamlize

import armi
from armi import runLog
from armi.reactor import assemblies

# justification=required to populate assembly parameter definitions
from armi.reactor import parameters
from armi.reactor.blueprints import blockBlueprint
from armi.reactor import grids


def _configureAssemblyTypes():
    assemTypes = dict()
    pm = armi.getPluginManagerOrFail()
    for pluginAssemTypes in pm.hook.defineAssemblyTypes():
        for blockType, assemType in pluginAssemTypes:
            assemTypes[blockType] = assemType

    return assemTypes


[docs]class MaterialModifications(yamlize.Map): key_type = yamlize.Typed(str) value_type = yamlize.Sequence
[docs]class AssemblyBlueprint(yamlize.Object): """ A data container for holding information needed to construct an ARMI assembly. This class utilizes ``yamlize`` to enable serialization to and from the blueprints YAML file. """ name = yamlize.Attribute(type=str) specifier = yamlize.Attribute(type=str) blocks = yamlize.Attribute(type=blockBlueprint.BlockList) height = yamlize.Attribute(type=yamlize.FloatList) axialMeshPoints = yamlize.Attribute(key="axial mesh points", type=yamlize.IntList) materialModifications = yamlize.Attribute( key="material modifications", type=MaterialModifications, default=None ) xsTypes = yamlize.Attribute(key="xs types", type=yamlize.StrList) # note: yamlizable does not call an __init__ method, instead it uses __new__ and setattr _assemTypes = _configureAssemblyTypes()
[docs] @classmethod def getAssemClass(cls, blocks): """ Get the ARMI ``Assembly`` class for the specified geomType Parameters ---------- geomType : str Geometry type string. """ blockClasses = {b.__class__ for b in blocks} for bType, aType in cls._assemTypes.items(): if bType in blockClasses: return aType raise ValueError( 'Unsupported block geometries in {}: "{}"'.format(cls.name, blocks) )
[docs] def construct(self, cs, blueprint): """ Construct an instance of this specific assembly blueprint. Parameters ---------- cs : CaseSettings CaseSettings object which containing relevant modeling options. blueprint : Blueprint Root blueprint object containing relevant modeling options. """ runLog.info("Constructing assembly `{}`".format(self.name)) a = self._constructAssembly(cs, blueprint) self._checkParamConsistency(a) a.calculateZCoords() return a
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 _createBlock(self, cs, blueprint, bDesign, axialIndex): """Create a block based on the block design and the axial index.""" materialInputs = self.materialModifications or {} meshPoints = self.axialMeshPoints[axialIndex] height = self.height[axialIndex] xsType = self.xsTypes[axialIndex] materialInput = { modName: modList[axialIndex] for modName, modList in materialInputs.items() if modList[axialIndex] != "" } b = bDesign.construct( cs, blueprint, axialIndex, meshPoints, height, xsType, materialInput ) # always just use B as the BOL block at this BOL point. # TODO: remove when the plugin system is fully set up? b.completeInitialLoading(bolBlock=b) return b def _checkParamConsistency(self, a): """Check that the number of block params specified is equal to the number of blocks specified.""" materialInputs = self.materialModifications or {} paramsToCheck = { "mesh points": self.axialMeshPoints, "heights": self.height, "xs types": self.xsTypes, } for modName, modList in materialInputs.items(): paramName = "material modifications for {}".format(modName) paramsToCheck[paramName] = modList for paramName, blockVals in paramsToCheck.items(): if len(self.blocks) != len(blockVals): raise ValueError( "Assembly {} had {} blocks, but {} {}. These numbers should be equal. " "Check input for errors.".format( a, len(self.blocks), len(blockVals), paramName ) )
for paramDef in parameters.forType(assemblies.Assembly).inCategory( parameters.Category.assignInBlueprints ): setattr( AssemblyBlueprint, paramDef.name, yamlize.Attribute(name=paramDef.name, default=None), )
[docs]class AssemblyKeyedList(yamlize.KeyedList): """ Effectively and OrderedDict of assembly items, keyed on the assembly name. This uses yamlize KeyedList for YAML serialization. """ item_type = AssemblyBlueprint key_attr = AssemblyBlueprint.name heights = yamlize.Attribute(type=yamlize.FloatList, default=None) axialMeshPoints = yamlize.Attribute( key="axial mesh points", type=yamlize.IntList, default=None ) # note: yamlize does not call an __init__ method, instead it uses __new__ and setattr @property def bySpecifier(self): """Used by the reactor to _loadAssembliesIntoCore later, specifiers are two character strings""" return {aDesign.specifier: aDesign for aDesign in self}