Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BOL HM mass parameter. #24

Merged
merged 3 commits into from
Feb 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 39 additions & 36 deletions armi/cases/suiteBuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,31 +307,33 @@ def __call__(self, cs, bp, geom):
class InputModifier(object):
"""
Object that modifies input definitions in some well-defined way.

(This class is abstract.)

Subclasses must implement a ``__call__`` method accepting a ``CaseSettings``, ``Blueprints``,
and ``SystemLayoutInput``.
Subclasses must implement a ``__call__`` method accepting a ``CaseSettings``,
``Blueprints``, and ``SystemLayoutInput``.

The class attribute ``FAIL_IF_AFTER`` should be a tuple defining what, if any,
modifications this should fail if performed after. For example, one should not
adjust the smear density (a function of Cladding ID) before adjusting the Cladding
ID.

The class attribute ``FAIL_IF_AFTER`` should be a tuple defining what, if any, modifications
this should fail if performed after. For example, one should not adjust the smear density (a
function of Cladding ID) before adjusting the Cladding ID.

Some subclasses are provided, but you are expected to make your own design-specific modifiers
in most cases.
Some subclasses are provided, but you are expected to make your own design-specific
modifiers in most cases.
"""

FAIL_IF_AFTER = ()

def __init__(self, independentVariable=None):
"""
Constuctor.

Parameters
----------
independentVariable : dict or None, optional
Name/value pairs to associate with the independent variable being modified by this object.
Will be analyzed and plotted against other modifiers with the same name.
Name/value pairs to associate with the independent variable being modified
by this object. Will be analyzed and plotted against other modifiers with
the same name.
"""
if independentVariable is None:
independentVariable = {}
Expand Down Expand Up @@ -383,11 +385,11 @@ class _PinTypeAssemblyModifier(InputModifier):
"""
Abstract class for modifying something about a pin, within a block.

This will construct blocks, determine if the block should be modified by checking the
``_getBlockTypesToModify``, and then run ``_adjustBlock(b)``. The ``Blueprints`` are then
updated based on the modification assuming that dimension names match exactly to
ComponenBlueprint attributes (which is true, because ComponentBlueprint attributes are
programmatically derived from Component constructors).
This will construct blocks, determine if the block should be modified by checking
the ``_getBlockTypesToModify``, and then run ``_adjustBlock(b)``. The ``Blueprints``
are then updated based on the modification assuming that dimension names match
exactly to ComponenBlueprint attributes (which is true, because ComponentBlueprint
attributes are programmatically derived from Component constructors).
"""

def __init__(self, value):
Expand All @@ -398,19 +400,20 @@ def __call__(self, cs, blueprints, geom):
for bDesign in blueprints.blockDesigns:
# bDesign construct requires lots of arguments, many of which have no impact.
# The following can safely be defaulted to meaningless inputs:
# axialIndex: a block can be reused at any axial index, modifications made dependent on
# will not translate back to the input in a meaningful fashion
# axialMeshPoints: similar to above, this is specified by the assembly, and a block can
# be within any section of an assembly.
# height: similar to above. a block can have any height specified by an assembly. if
# height-specific modifications are required, then a new block definition should be
# created in the input
# xsType: similar to above. a block can have any xsType specified through the assembly
# definition assembly. if xsType-specific modifications are required, then a new
# axialIndex: a block can be reused at any axial index, modifications made
# dependent on will not translate back to the input in a meaningful
# fashion
# axialMeshPoints: similar to above, this is specified by the assembly, and
# a block can be within any section of an assembly.
# height: similar to above. a block can have any height specified by an
# assembly. if height-specific modifications are required, then a new
# block definition should be created in the input
# materialInput: this is the materialModifications from the assembly definition. if
# material modifications are required on a block-specific basis, they should be
# edited directly
# xsType: similar to above. a block can have any xsType specified through
# the assembly definition assembly. if xsType-specific modifications are
# required, then a new block definition should be created in the input
# materialInput: this is the materialModifications from the assembly
# definition. if material modifications are required on a block-specific
# basis, they should be edited directly
b = bDesign.construct(
cs,
blueprints,
Expand Down Expand Up @@ -449,10 +452,10 @@ def _adjustBlock(self, b):
class SmearDensityModifier(_PinTypeAssemblyModifier):
"""
Adjust the smeared density to the specified value.
This is effectively how much of the space inside the cladding tube
is occupied by fuel at fabrication.

This is effectively how much of the space inside the cladding tube is occupied by
fuel at fabrication.

See Also
--------
armi.reactor.blocks.Block.adjustSmearDensity
Expand Down Expand Up @@ -502,9 +505,9 @@ class NeutronicConvergenceModifier(InputModifier):
"""
Adjust the neutronics convergence parameters ``epsEig``, ``epsFSAvg``, and ``epsFSPoint``.

The supplied value is used for ``epsEig``. ``epsFSAvg`` and ``epsFSPoint`` are set to 100 times
the supplied value.
The supplied value is used for ``epsEig``. ``epsFSAvg`` and ``epsFSPoint`` are set
to 100 times the supplied value.

This can be used to perform sensitivity studies on convergence criteria.
"""

Expand Down
7 changes: 7 additions & 0 deletions armi/reactor/blockParameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,13 @@ def detailedNDens(self, value):
default=None,
)

pb.defParam(
"massHmBOL",
units="grams",
description="Mass of heavy metal at BOL",
default=None,
)

pb.defParam(
"molesHmBOLByPin",
units="mole",
Expand Down
23 changes: 12 additions & 11 deletions armi/reactor/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ def __init__(self, name, height=1.0, location=None):
composites.Composite.__init__(self, name)
self.makeUnique()
self.p.height = height
self.massHMBOL = 0.0 # in grams

if location:
k = location.axial
Expand Down Expand Up @@ -1090,14 +1089,15 @@ def completeInitialLoading(self, bolBlock=None):
"""
Does some BOL bookkeeping to track things like BOL HM density for burnup tracking.

runs after this block is loaded up at BOC (called from Reactor.initialLoading(Axial))
This should run after this block is loaded up at BOC (called from
Reactor.initialLoading).

original purpose of this was to get the moles HM at BOC for the moles Pu/moles HM at BOL
calculation
The original purpose of this was to get the moles HM at BOC for the moles
Pu/moles HM at BOL calculation.

This also must be called after modifying something like the smear density or zr fraction in
an optimization case. In ECPT cases, a BOL block must be passed or else the burnup will
try to get based on a pre-burned value.
This also must be called after modifying something like the smear density or zr
fraction in an optimization case. In ECPT cases, a BOL block must be passed or
else the burnup will try to get based on a pre-burned value.

Parameters
----------
Expand Down Expand Up @@ -1127,11 +1127,12 @@ def completeInitialLoading(self, bolBlock=None):
except ValueError:
pass
self.p.enrichmentBOL = self.getEnrichment()
self.massHMBOL = 0.0
massHmBOL = 0.0
sf = self.getSymmetryFactor()
for child in self:
child.massHMBOL = child.getHMMass() * sf # scale to full block
self.massHMBOL += child.massHMBOL
child.p.massHmBOL = child.getHMMass() * sf # scale to full block
massHmBOL += child.p.massHmBOL
self.p.massHmBOL = massHmBOL
return hmDens

def replaceBlockWithBlock(self, bReplacement):
Expand Down Expand Up @@ -2344,7 +2345,7 @@ def breakFuelComponentsIntoIndividuals(self):
for pinNum, pin in enumerate(self.iterComponents(Flags.FUEL)):
pin.p.flags = fuelFlags # Update the fuel component flags to be the same as before the split (i.e., DEPLETABLE)
self.p.molesHmBOLByPin.append(pin.getHMMoles())
pin.massHMBOL /= nPins
pin.p.massHmBOL /= nPins

def getIntegratedMgFlux(self, adjoint=False, gamma=False):
"""
Expand Down
3 changes: 1 addition & 2 deletions armi/reactor/blueprints/assemblyBlueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,8 @@ def _createBlock(self, cs, blueprint, bDesign, axialIndex):
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)
b.completeInitialLoading()
return b

def _checkParamConsistency(self, a):
Expand Down
1 change: 0 additions & 1 deletion armi/reactor/components/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@ def __init__(
self.setType(name)
self.p.mergeWith = mergeWith
self.p.customIsotopicsName = isotopics
self.massHMBOL = 0.0 # in grams

@property
def temperatureInC(self):
Expand Down
7 changes: 7 additions & 0 deletions armi/reactor/components/componentParameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ def getComponentParameterDefinitions():
default=0.0,
)

pb.defParam(
"massHmBOL",
units="grams",
description="Mass of heavy metal at BOL",
default=None,
)

pb.defParam(
"burnupMWdPerKg",
units="MWd/kg",
Expand Down
3 changes: 2 additions & 1 deletion armi/reactor/tests/test_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,7 @@ def test_completeInitialLoading(self):
}
)

self.Block.completeInitialLoading(bolBlock=self.Block)
self.Block.completeInitialLoading()

cur = self.Block.p.molesHmBOL
ref = self.Block.getHMDens() / MOLES_PER_CC_TO_ATOMS_PER_BARN_CM * height * area
Expand Down Expand Up @@ -1412,6 +1412,7 @@ def test_breakFuelComponentsIntoIndividuals(self):
fuel = self.Block.getComponent(Flags.FUEL)
mult = fuel.getDimension("mult")
self.assertGreater(mult, 1.0)
self.Block.completeInitialLoading()
self.Block.breakFuelComponentsIntoIndividuals()
self.assertEqual(fuel.getDimension("mult"), 1.0)

Expand Down