Skip to content

Commit

Permalink
Use ENDF/B-VII.1 MC2-3 nuclide IDs (#1982)
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronjamesreynolds authored Nov 8, 2024
1 parent 6ad5fa5 commit 864106e
Show file tree
Hide file tree
Showing 7 changed files with 697 additions and 38 deletions.
2 changes: 1 addition & 1 deletion armi/bookkeeping/db/tests/test_comparedb3.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def test_compareDatabaseSim(self):
dbs[1]._fullPath,
timestepCompare=[(0, 0), (0, 1)],
)
self.assertEqual(len(diffs.diffs), 477)
self.assertEqual(len(diffs.diffs), 480)
# Cycle length is only diff (x3)
self.assertEqual(diffs.nDiffs(), 3)

Expand Down
126 changes: 103 additions & 23 deletions armi/nucDirectory/nuclideBases.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class which is used to organize and store metadata about each nuclide. The
* ``byLabel`` (keyed by label, e.g., ``U235``)
* ``byMcc2Id`` (keyed by MC\ :sup:`2`-2 ID, e.g., ``U-2355``)
* ``byMcc3Id`` (keyed by MC\ :sup:`2`-3 ID, e.g., ``U235_7``)
* ``byMcc3IdEndfbVII0`` (keyed by MC\ :sup:`2`-3 ID, e.g., ``U235_7``)
* ``byMcc3IdEndfbVII1`` (keyed by MC\ :sup:`2`-3 ID, e.g., ``U235_7``)
* ``byMcnpId`` (keyed by MCNP ID, e.g., ``92235``)
* ``byAAAZZZSId`` (keyed by AAAZZZS, e.g., ``2350920``)
Expand Down Expand Up @@ -78,7 +80,7 @@ class which is used to organize and store metadata about each nuclide. The
Retrieve U-235 by the MC2-3 ID:
>>> nuclideBases.byMcc3Id['U235_7']
>>> nuclideBases.byMcc3IdEndfVII0['U235_7']
<NuclideBase U235: Z:92, A:235, S:0, W:2.350439e+02, Label:U235>, HL:2.22160758861e+16, Abund:7.204000e-03>
Retrieve U-235 by the MCNP ID:
Expand Down Expand Up @@ -120,7 +122,9 @@ class which is used to organize and store metadata about each nuclide. The
byDBName = {}
byLabel = {}
byMcc2Id = {}
byMcc3Id = {}
byMcc3Id = {} # for backwards compatibility. Identical to byMcc3IdEndfbVII1
byMcc3IdEndfbVII0 = {}
byMcc3IdEndfbVII1 = {}
byMcnpId = {}
byAAAZZZSId = {}

Expand Down Expand Up @@ -168,9 +172,17 @@ def getMcc2Id(self):
return NotImplementedError

def getMcc3Id(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.1 cross section library."""
return NotImplementedError

def getMcc3IdEndfbVII0(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.0 cross section library."""
return NotImplementedError

def getMcc3IdEndfbVII1(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.1 cross section library."""
return NotImplementedError

def getSerpentId(self):
"""Get the Serpent nuclide identification label."""
raise NotImplementedError
Expand Down Expand Up @@ -243,8 +255,16 @@ def getMcc2Id(self):
return self._base.getMcc2Id()

def getMcc3Id(self):
"""Return the MC2-3 nuclide based on the ENDF/B-VII.1 cross section library."""
return self.getMcc3IdEndfbVII1()

def getMcc3IdEndfbVII0(self):
"""Return the MC2-3 nuclide based on the ENDF/B-VII.0 cross section library."""
return self._base.getMcc3Id()
return self._base.getMcc3IdEndfbVII0()

def getMcc3IdEndfbVII1(self):
"""Return the MC2-3 nuclide based on the ENDF/B-VII.1 cross section library."""
return self._base.getMcc3IdEndfbVII1()

def getNaturalIsotopics(self):
"""Return the natural isotopics root :py:class:`~elements.Element`."""
Expand Down Expand Up @@ -312,7 +332,8 @@ def __init__(
name,
label,
mcc2id=None,
mcc3id=None,
mcc3idEndfbVII0=None,
mcc3idEndfbVII1=None,
):
"""
Create an instance of an INuclide.
Expand Down Expand Up @@ -348,7 +369,8 @@ def __init__(
self.label = label
self.nuSF = 0.0
self.mcc2id = mcc2id or ""
self.mcc3id = mcc3id or ""
self.mcc3idEndfbVII0 = mcc3idEndfbVII0 or ""
self.mcc3idEndfbVII1 = mcc3idEndfbVII1 or ""
addGlobalNuclide(self)
self.element.append(self)

Expand Down Expand Up @@ -593,18 +615,36 @@ def getMcc2Id(self):
return self.mcc2id

def getMcc3Id(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.1 cross section library."""
return self.getMcc3IdEndfbVII1()

def getMcc3IdEndfbVII0(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.0 cross section library.
.. impl:: Isotopes and isomers can be queried by MC2-3 ID.
.. impl:: Isotopes and isomers can be queried by MC2-3 ENDF/B-VII.0 ID.
:id: I_ARMI_ND_ISOTOPES3
:implements: R_ARMI_ND_ISOTOPES
This method returns the ``mcc3id`` attribute of a
This method returns the ``mcc3idEndfbVII0`` attribute of a
:py:class:`NuclideBase <armi.nucDirectory.nuclideBases.NuclideBase>`
instance. This attribute is initially populated by reading from the
mcc-nuclides.yaml file in the ARMI resources folder.
"""
return self.mcc3id
return self.mcc3idEndfbVII0

def getMcc3IdEndfbVII1(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.1 cross section library.
.. impl:: Isotopes and isomers can be queried by MC2-3 ENDF/B-VII.1 ID.
:id: I_ARMI_ND_ISOTOPES7
:implements: R_ARMI_ND_ISOTOPES
This method returns the ``mcc3idEndfbVII1`` attribute of a
:py:class:`NuclideBase <armi.nucDirectory.nuclideBases.NuclideBase>`
instance. This attribute is initially populated by reading from the
mcc-nuclides.yaml file in the ARMI resources folder.
"""
return self.mcc3idEndfbVII1

def getMcnpId(self):
"""
Expand Down Expand Up @@ -783,8 +823,16 @@ def getMcc2Id(self):
return self.mcc2id

def getMcc3Id(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.1 cross section library."""
return self.getMcc3IdEndfbVII1()

def getMcc3IdEndfbVII0(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.0 cross section library."""
return self.mcc3id
return self.mcc3idEndfbVII0

def getMcc3IdEndfbVII1(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.1 cross section library."""
return self.mcc3idEndfbVII1

def getSerpentId(self):
"""Gets the SERPENT ID for this natural nuclide.
Expand Down Expand Up @@ -871,8 +919,16 @@ def getMcc2Id(self):
return self.mcc2id

def getMcc3Id(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.1 cross section library."""
return self.getMcc3IdEndfbVII1()

def getMcc3IdEndfbVII0(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.0 cross section library."""
return self.mcc3id
return self.mcc3idEndfbVII0

def getMcc3IdEndfbVII1(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.1 cross section library."""
return self.mcc3idEndfbVII1


class LumpNuclideBase(INuclide):
Expand Down Expand Up @@ -937,8 +993,16 @@ def getMcc2Id(self):
return self.mcc2id

def getMcc3Id(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.1 cross section library."""
return self.getMcc3IdEndfbVII1()

def getMcc3IdEndfbVII0(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.0 cross section library."""
return self.mcc3id
return self.mcc3idEndfbVII0

def getMcc3IdEndfbVII1(self):
"""Return the MC2-3 nuclide identification label based on the ENDF/B-VII.1 cross section library."""
return self.mcc3idEndfbVII1


def initReachableActiveNuclidesThroughBurnChain(numberDensityDict, activeNuclides):
Expand Down Expand Up @@ -1156,15 +1220,15 @@ def factory():
Reads NIST, MC**2 and burn chain data files to instantiate the :py:class:`INuclides <INuclide>`.
Also clears and fills in the
:py:data:`~armi.nucDirectory.nuclideBases.instances`,
:py:data:`byName`, :py:attr:`byLabel`, and
:py:data:`byMcc3Id` module attributes. This method is automatically run upon
:py:data:`byName`, :py:attr:`byLabel`, :py:data:`byMcc3IdEndfbVII0`, and
:py:data:`byMcc3IdEndfbVII1` module attributes. This method is automatically run upon
loading the module, hence it is not usually necessary to re-run it unless there is a
change to the data files, which should not happen during run time, or a *bad*
:py:class`INuclide` is created.
Notes
-----
This may cannot be run more than once. NuclideBase instances are used throughout the ARMI
This cannot be run more than once. NuclideBase instances are used throughout the ARMI
ecosystem and are even class attributes in some cases. Re-instantiating them would orphan
any existing ones and break everything.
"""
Expand Down Expand Up @@ -1269,27 +1333,39 @@ def readMCCNuclideData():
This function reads the mcc-nuclides.yaml file from the ARMI resources
folder. This file contains the MC\ :sup:`2`-2 ID (from ENDF/B-V.2) and MC\ :sup:`2`-3 ID
(from ENDF/B-VII.0) for all nuclides in MC\ :sup:`2`. The ``mcc2id`` and
``mcc3id`` attributes of each :py:class:`NuclideBase
(from ENDF/B-VII.0) for all nuclides in MC\ :sup:`2`. The ``mcc2id``,
``mcc3idEndfVII0``, and ``mcc3idEndfVII1`` attributes of each :py:class:`NuclideBase
<armi.nucDirectory.nuclideBases.NuclideBase>` instance are updated as
the data is read, and the global dictionaries ``byMcc2Id`` and
``byMcc3Id`` are populated with the nuclide bases keyed by their
corresponding ID for each code.
the data is read, and the global dictionaries ``byMcc2Id``
``byMcc3IdEndfVII0`` and ``byMcc3IdEndfVII1`` are populated with the nuclide bases
keyed by their corresponding ID for each code.
"""
global byMcc2Id
global byMcc3Id
global byMcc3IdEndfbVII0
global byMcc3IdEndfbVII1

with open(os.path.join(context.RES, "mcc-nuclides.yaml"), "r") as f:
yaml = YAML(typ="rt")
nuclides = yaml.load(f)

for n in nuclides:
nb = byName[n]
mcc2id = nuclides[n]["ENDF/B-V.2"]
mcc3id = nuclides[n]["ENDF/B-VII.0"]
mcc3idEndfbVII0 = nuclides[n]["ENDF/B-VII.0"]
mcc3idEndfbVII1 = nuclides[n]["ENDF/B-VII.1"]
if mcc2id is not None:
nb.mcc2id = mcc2id
byMcc2Id[nb.getMcc2Id()] = nb
if mcc3id is not None:
nb.mcc3id = mcc3id
byMcc3Id[nb.getMcc3Id()] = nb
if mcc3idEndfbVII0 is not None:
nb.mcc3idEndfbVII0 = mcc3idEndfbVII0
byMcc3IdEndfbVII0[nb.getMcc3IdEndfbVII0()] = nb
if mcc3idEndfbVII1 is not None:
nb.mcc3idEndfbVII1 = mcc3idEndfbVII1
byMcc3IdEndfbVII1[nb.getMcc3IdEndfbVII1()] = nb

# Have the byMcc3Id dictionary be VII.1 IDs.
byMcc3Id = byMcc3IdEndfbVII1


def updateNuclideBasesForSpecialCases():
Expand Down Expand Up @@ -1379,6 +1455,8 @@ def destroyGlobalNuclides():
global byLabel
global byMcc2Id
global byMcc3Id
global byMcc3IdEndfbVII0
global byMcc3IdEndfbVII1
global byMcnpId
global byAAAZZZSId

Expand All @@ -1388,5 +1466,7 @@ def destroyGlobalNuclides():
byLabel.clear()
byMcc2Id.clear()
byMcc3Id.clear()
byMcc3IdEndfbVII1.clear()
byMcc3IdEndfbVII0.clear()
byMcnpId.clear()
byAAAZZZSId.clear()
46 changes: 37 additions & 9 deletions armi/nucDirectory/tests/test_nuclideBases.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,9 +382,9 @@ def test_curieDefinitionWithRa226(self):
self.assertAlmostEqual(activity, 0.9885593, places=6)

def test_loadMcc2Data(self):
"""Tests consistency with the `mcc-nuclides.yaml` input and the nuclides in the data model.
"""Tests consistency with the `mcc-nuclides.yaml` input and the ENDF/B-V.2 nuclides in the data model.
.. test:: Test that MCC v2 IDs can be queried by nuclides.
.. test:: Test that MCC v2 ENDF/B-V.2 IDs can be queried by nuclides.
:id: T_ARMI_ND_ISOTOPES3
:tests: R_ARMI_ND_ISOTOPES
"""
Expand All @@ -402,14 +402,14 @@ def test_loadMcc2Data(self):

self.assertEqual(len(nuclideBases.byMcc2Id), len(expectedNuclides))

def test_loadMcc3Data(self):
"""Tests consistency with the `mcc-nuclides.yaml` input and the nuclides in the data model.
def test_loadMcc3EndfVII0Data(self):
"""Tests consistency with the `mcc-nuclides.yaml` input and the ENDF/B-VII.0 nuclides in the data model.
.. test:: Test that MCC v3 IDs can be queried by nuclides.
.. test:: Test that MCC v3 ENDF/B-VII.0 IDs can be queried by nuclides.
:id: T_ARMI_ND_ISOTOPES4
:tests: R_ARMI_ND_ISOTOPES
.. test:: Test the MCC nuclide data that was read from file instead of code.
.. test:: Test the MCC ENDF/B-VII.0 nuclide data that was read from file instead of code.
:id: T_ARMI_ND_DATA1
:tests: R_ARMI_ND_DATA
"""
Expand All @@ -420,13 +420,41 @@ def test_loadMcc3Data(self):
[nuc for nuc in data.keys() if data[nuc]["ENDF/B-VII.0"] is not None]
)

for nuc, nb in nuclideBases.byMcc3Id.items():
for nuc, nb in nuclideBases.byMcc3IdEndfbVII0.items():
self.assertIn(nb.name, expectedNuclides)
self.assertEqual(nb.getMcc3Id(), nb.mcc3id)
self.assertEqual(nb.getMcc3IdEndfbVII0(), nb.mcc3idEndfbVII0)
self.assertEqual(nb.getMcc3IdEndfbVII0(), nuc)

# Subtract 1 nuclide due to DUMP2.
self.assertEqual(len(nuclideBases.byMcc3IdEndfbVII0), len(expectedNuclides) - 1)

def test_loadMcc3EndfVII1Data(self):
"""Tests consistency with the `mcc-nuclides.yaml` input and the ENDF/B-VII.1 nuclides in the data model.
.. test:: Test that MCC v3 ENDF/B-VII.1 IDs can be queried by nuclides.
:id: T_ARMI_ND_ISOTOPES6
:tests: R_ARMI_ND_ISOTOPES
.. test:: Test the MCC ENDF/B-VII.1 nuclide data that was read from file instead of code.
:id: T_ARMI_ND_DATA2
:tests: R_ARMI_ND_DATA
"""
with open(os.path.join(RES, "mcc-nuclides.yaml")) as f:
yaml = YAML(typ="rt")
data = yaml.load(f)
expectedNuclides = set(
[nuc for nuc in data.keys() if data[nuc]["ENDF/B-VII.1"] is not None]
)

for nuc, nb in nuclideBases.byMcc3IdEndfbVII1.items():
self.assertIn(nb.name, expectedNuclides)
self.assertEqual(nb.getMcc3IdEndfbVII1(), nb.mcc3idEndfbVII1)
self.assertEqual(nb.getMcc3IdEndfbVII1(), nuc)
self.assertEqual(nb.getMcc3Id(), nb.mcc3idEndfbVII1)
self.assertEqual(nb.getMcc3Id(), nuc)

# Subtract 1 nuclide due to DUMP2.
self.assertEqual(len(nuclideBases.byMcc3Id), len(expectedNuclides) - 1)
self.assertEqual(len(nuclideBases.byMcc3IdEndfbVII1), len(expectedNuclides) - 1)


class TestAAAZZZSId(unittest.TestCase):
Expand Down
3 changes: 2 additions & 1 deletion armi/physics/neutronics/tests/test_crossSectionManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,8 @@ def setUp(self):
sodiumDensity = {"NA23": 0.022166571826233578}
steelDensity = {
"C": 0.0007685664978992269,
"V": 0.0002718224847461385,
"V50": 6.795562118653462e-07,
"V51": 0.0002711429285342731,
"SI28": 0.0003789374369638149,
"SI29": 1.924063709833714e-05,
"SI30": 1.268328992580968e-05,
Expand Down
6 changes: 5 additions & 1 deletion armi/reactor/blueprints/isotopicOptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,10 +552,14 @@ def eleExpandInfoBasedOnCodeENDF(cs):
)
)

elif cs[CONF_XS_KERNEL] in ["", "SERPENT", "MC2v3", "MC2v3-PARTISN"]:
elif cs[CONF_XS_KERNEL] == "SERPENT":
elementalsToKeep.update(endf70Elementals)
expansionStrings.update(mc2Expansions)

elif cs[CONF_XS_KERNEL] in ["", "MC2v3", "MC2v3-PARTISN"]:
elementalsToKeep.update(endf71Elementals)
expansionStrings.update(mc2Expansions)

elif cs[CONF_XS_KERNEL] == "DRAGON":
# Users need to use default nuclear lib name. This is documented.
dragLib = cs["dragonDataPath"]
Expand Down
Loading

0 comments on commit 864106e

Please sign in to comment.