Source code for armi.physics.neutronics

# 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.

"""
The neutronics physics package in the ARMI framework.

Neutronics encompasses the modeling of nuclear chain reactions and their associated transmutation and decay.

The ARMI Framework comes with a neutronics plugin that introduces two
independent interfaces:

:py:mod:`~armi.physics.neutronics.fissionProductModel`
    Handles fission product modeling

:py:mod:`~armi.physics.neutronics.crossSectionGroupManager`
    Handles the management of different cross section "groups"

.. warning:: There is also some legacy and question-raising code in this module that
    is here temporarily while we finish untangling some of the neutronics
    plugins outside of ARMI.

"""

import os

import yamlize
import numpy
import tabulate

from armi import plugins
from armi.physics.neutronics.const import CONF_CROSS_SECTION
from armi.utils import directoryChangers
from armi import runLog


[docs]class NeutronicsPlugin(plugins.ArmiPlugin): """ The built-in neutronics plugin with a few capabilities and a lot of state parameter definitions. """
[docs] @staticmethod @plugins.HOOKIMPL def exposeInterfaces(cs): """ Collect and expose all of the interfaces that live under the built-in neutronics package """ from armi.physics.neutronics import crossSectionGroupManager from armi.physics.neutronics.fissionProductModel import fissionProductModel interfaceInfo = [] for mod in (crossSectionGroupManager, fissionProductModel): interfaceInfo += plugins.collectInterfaceDescriptions(mod, cs) return interfaceInfo
[docs] @staticmethod @plugins.HOOKIMPL def defineParameters(): from . import parameters as neutronicsParameters return neutronicsParameters.getNeutronicsParameterDefinitions()
[docs] @staticmethod @plugins.HOOKIMPL def defineEntryPoints(): from armi.physics.neutronics import diffIsotxs entryPoints = [diffIsotxs.CompareIsotxsLibraries] return entryPoints
[docs] @staticmethod @plugins.HOOKIMPL def defineSettings(): from . import settings as neutronicsSettings from armi.physics.neutronics import crossSectionSettings from armi.physics.neutronics.fissionProductModel import ( fissionProductModelSettings, ) settings = [ crossSectionSettings.XSSettingDef( CONF_CROSS_SECTION, ) ] settings += neutronicsSettings.defineSettings() settings += fissionProductModelSettings.defineSettings() return settings
[docs] @staticmethod @plugins.HOOKIMPL def defineSettingsValidators(inspector): """ Check neutronics settings. """ from armi.operators import settingsValidation # avoid cyclic import from armi.scripts.migration.crossSectionBlueprintsToSettings import ( migrateCrossSectionsFromBlueprints, ) queries = [] def blueprintsHasOldXSInput(path): with directoryChangers.DirectoryChanger(inspector.cs.inputDirectory): with open(os.path.expandvars(path)) as f: for line in f: if line.startswith("cross sections:"): return True return False queries.append( settingsValidation.Query( lambda: inspector.cs["loadingFile"] and blueprintsHasOldXSInput(inspector.cs["loadingFile"]), "The specified blueprints input file '{0}' contains compound cross section settings. " "".format(inspector.cs["loadingFile"]), "Automatically move them to the settings file, {}? WARNING: if multiple settings files point " "to this blueprints input you must manually update the others.".format( inspector.cs.path ), lambda: migrateCrossSectionsFromBlueprints(inspector.cs), ) ) return queries
[docs] @staticmethod @plugins.HOOKIMPL def onProcessCoreLoading(core, cs): applyEffectiveDelayedNeutronFractionToCore(core, cs)
[docs] @staticmethod @plugins.HOOKIMPL def getReportContents(r, cs, report, stage, blueprint): """ Generates the Report Content for the Neutronics Report """ from armi.physics.neutronics import reports return reports.insertNeutronicsReport(r, cs, report, stage)
from .const import ( GAMMA, NEUTRON, NEUTRONGAMMA, ALL, RESTARTFILES, INPUTOUTPUT, FLUXFILES, ) # ARC and CCCC cross section file format names COMPXS = "COMPXS" PMATRX = "PMATRX" GAMISO = "GAMISO" ISOTXS = "ISOTXS" # Constants for neutronics calculation types ADJOINT_CALC = "adjoint" REAL_CALC = "real" ADJREAL_CALC = "both" # Constants for boundary conditions # All external boundary conditions are set to zero outward current INFINITE = "Infinite" # "Planar" external boundaries conditions are set to zero outward current REFLECTIVE = "Reflective" # Generalized boundary conditions D * PHI PRIME + A * PHI = 0 where A is user-specified constant, # D is the diffusion coefficient, PHI PRIME and PHI are the outward current and flux at the # external boundaries. GENERAL_BC = "Generalized" # The following boundary conditions are three approximations of the vacuum boundary condition # in diffusion theory. # 'Extrapolated': sets A to 0.4692 (in generalized BC) to have the flux vanishing at # 0.7104*transport mean free path through linear extrapolation. Derived for plane # geometries - should be valid for complex geometries unless radius of curvature is # comparable to the mean free path. # 'ZeroSurfaceFlux': flux vanishes at the external boundary. # 'ZeroInwardCurrent': set A to 0.5 (in generalized BC) to have Jminus = 0 at the external boundaries. EXTRAPOLATED = "Extrapolated" ZEROFLUX = "ZeroSurfaceFlux" ZERO_INWARD_CURRENT = "ZeroInwardCurrent" # Common settings checks
[docs]def gammaTransportIsRequested(cs): """ Check if gamma transport was requested by the user. Arguments --------- cs : ARMI settings object Object containing the default and user-specified ARMI settings controlling the simulation Returns ------- flag : bool Returns true if gamma transport is requested. """ return GAMMA in cs["globalFluxActive"]
[docs]def gammaXsAreRequested(cs): """ Check if gamma cross-sections generation was requested by the user. Arguments --------- cs : ARMI settings object Object containing the default and user-specified ARMI settings controlling the simulation. Returns ------- flag : bool Returns true if gamma cross section generation is requested. """ return GAMMA in cs["genXS"]
[docs]def adjointCalculationRequested(cs): """Return true if an adjoint calculation is requested based on the ``neutronicsType`` setting.""" return cs["neutronicsType"] in [ADJOINT_CALC, ADJREAL_CALC]
[docs]def realCalculationRequested(cs): """Return true if a real calculation is requested based on the ``neutronicsType`` type setting.""" return cs["neutronicsType"] in ["real", "both"]
[docs]def applyEffectiveDelayedNeutronFractionToCore(core, cs): """Process the settings for the delayed neutron fraction and precursor decay constants.""" # Verify and set the core beta parameters based on the user-supplied settings beta = cs["beta"] decayConstants = cs["decayConstants"] # If beta is interpreted as a float, then assign it to # the total delayed neutron fraction parameter. Otherwise, setup the # group-wise delayed neutron fractions and precursor decay constants. reportTableData = [] if isinstance(beta, float): core.p.beta = beta reportTableData.append(("Total Delayed Neutron Fraction", core.p.beta)) elif isinstance(beta, list) and isinstance(decayConstants, list): if len(beta) != len(decayConstants): raise ValueError( f"The values for `beta` ({beta}) and `decayConstants` " f"({decayConstants}) are not consistent lengths." ) core.p.beta = sum(beta) core.p.betaComponents = numpy.array(beta) core.p.betaDecayConstants = numpy.array(decayConstants) reportTableData.append(("Total Delayed Neutron Fraction", core.p.beta)) reportTableData.append( ("Group-wise Delayed Neutron Fractions", core.p.betaComponents) ) reportTableData.append( ("Group-wise Precursor Decay Constants", core.p.betaDecayConstants) ) # Report to the user the values were not applied. if not reportTableData and (beta is not None or decayConstants is not None): runLog.warning( f"Delayed neutron fraction(s) - {beta} and decay constants" " - {decayConstants} have not been applied." ) else: runLog.extra( tabulate.tabulate( tabular_data=reportTableData, headers=["Component", "Value"], tablefmt="armi", ) )