Skip to content

Commit faed748

Browse files
jakehaderopotowskymgjarrett
authored
Fission Product Model with Explicit Fission Products for all Depletable Components (#1067)
* Update the fission product model to fix a bug where all nuclides were not being initialized in non-fuel depletable components when using the `explicitFissionProducts` model. Add testing for the updated implementation. * Update release notes * Bug fix * Update interactDistributeState * Skip nuclides with 0 ndens in reaction rate calc * Black formatting * Add limiter on the interactCoupled method for the LatticePhysicsInterface to only run coupled cross section generation at time node 0. * Address reviewer comment * Update docstring * Add dummy nuclides for all XS types * Fix dummy nuclides for ISOTXS * Improve test coverage. * More test coverage * Black formatting * Rename files to test file path case sensitivity on Linux * Update expected filename to be all caps * One last name update. Sorry, can't test this locally on Windows! Co-authored-by: Arrielle Opotowsky <[email protected]> Co-authored-by: Michael Jarrett <[email protected]>
1 parent 4272611 commit faed748

File tree

16 files changed

+324
-93
lines changed

16 files changed

+324
-93
lines changed

armi/nuclearDataIO/cccc/isotxs.py

+55-2
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,59 @@ def compareNuclideXS(nuc1, nuc2, tolerance=0.0, verbose=False):
133133
return equal
134134

135135

136+
def addDummyNuclidesToLibrary(lib, dummyNuclides):
137+
"""
138+
This method adds DUMMY nuclides to the current ISOTXS library.
139+
140+
Parameters
141+
----------
142+
lib : obj
143+
ISOTXS library object
144+
145+
dummyNuclides: list
146+
List of DUMMY nuclide objects that will be copied and added to the GAMISO file
147+
148+
Notes
149+
-----
150+
Since MC2-3 does not write DUMMY nuclide information for GAMISO files, this is necessary to provide a
151+
consistent set of nuclide-level data across all the nuclides in a
152+
:py:class:`~armi.nuclearDataIO.xsLibraries.XSLibrary`.
153+
"""
154+
if not dummyNuclides:
155+
runLog.important("No dummy nuclide data provided to be added to {}".format(lib))
156+
return False
157+
elif len(lib.xsIDs) > 1:
158+
runLog.warning(
159+
"Cannot add dummy nuclide data to ISOTXS library {} containing data for more than 1 XS ID.".format(
160+
lib
161+
)
162+
)
163+
return False
164+
165+
dummyNuclideKeysAddedToLibrary = []
166+
for dummyNuclide in dummyNuclides:
167+
dummyKey = dummyNuclide.nucLabel
168+
if len(lib.xsIDs):
169+
dummyKey += lib.xsIDs[0]
170+
if dummyKey in lib:
171+
continue
172+
173+
newDummy = xsNuclides.XSNuclide(lib, dummyKey)
174+
# Copy isotxs metadata from the isotxs metadata of the given dummy nuclide
175+
for kk, vv in dummyNuclide.isotxsMetadata.items():
176+
if kk in ["jj", "jband"]:
177+
newDummy.isotxsMetadata[kk] = {}
178+
for mm in vv:
179+
newDummy.isotxsMetadata[kk][mm] = 1
180+
else:
181+
newDummy.isotxsMetadata[kk] = vv
182+
183+
lib[dummyKey] = newDummy
184+
dummyNuclideKeysAddedToLibrary.append(dummyKey)
185+
186+
return any(dummyNuclideKeysAddedToLibrary)
187+
188+
136189
class _IsotxsIO(cccc.Stream):
137190
"""
138191
A semi-abstract stream for reading and writing to a :py:class:`~armi.nuclearDataIO.isotxs.Isotxs`.
@@ -313,10 +366,10 @@ def _computeNuclideRecordOffset(self):
313366
This is not used within ARMI, because it can compute it arbitrarily. Other codes use this to seek to a
314367
specific position within an ISOTXS file.
315368
"""
316-
recordsPerNuclude = [
369+
recordsPerNuclide = [
317370
self._computeNumIsotxsRecords(nuc) for nuc in self._lib.nuclides
318371
]
319-
return [sum(recordsPerNuclude[0:ii]) for ii in range(len(self._lib))]
372+
return [sum(recordsPerNuclide[0:ii]) for ii in range(len(self._lib))]
320373

321374
def _computeNumIsotxsRecords(self, nuclide):
322375
"""Compute the number of ISOTXS records for a specific nuclide."""

armi/nuclearDataIO/cccc/tests/test_gamiso.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
THIS_DIR = os.path.dirname(__file__)
2626
FIXTURE_DIR = os.path.join(THIS_DIR, "..", "..", "tests", "fixtures")
27-
GAMISO_AA = os.path.join(FIXTURE_DIR, "mc2v3-AA.gamiso")
27+
GAMISO_AA = os.path.join(FIXTURE_DIR, "AA.GAMISO")
2828

2929

3030
class TestGamiso(unittest.TestCase):

armi/nuclearDataIO/tests/.gitignore

-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
*isotxs*
2-
*gamiso*
3-
*pmatrx*
41
*dlayxs*
52
*.out
63
*.sum
90.4 KB
Binary file not shown.
78 KB
Binary file not shown.
90.4 KB
Binary file not shown.
78 KB
Binary file not shown.
189 KB
Binary file not shown.
189 KB
Binary file not shown.

armi/nuclearDataIO/tests/test_xsLibraries.py

+58-9
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,18 @@
4040
# CCCC fixtures are less fancy than these merging ones.
4141
FIXTURE_DIR_CCCC = os.path.join(os.path.dirname(isotxs.__file__), "tests", "fixtures")
4242

43-
ISOTXS_AA = os.path.join(FIXTURE_DIR, "mc2v3-AA.isotxs")
44-
ISOTXS_AB = os.path.join(FIXTURE_DIR, "mc2v3-AB.isotxs")
43+
ISOTXS_AA = os.path.join(FIXTURE_DIR, "ISOAA")
44+
ISOTXS_AB = os.path.join(FIXTURE_DIR, "ISOAB")
4545
ISOTXS_AA_AB = os.path.join(FIXTURE_DIR, "combined-AA-AB.isotxs")
4646
ISOTXS_LUMPED = os.path.join(FIXTURE_DIR, "combined-and-lumped-AA-AB.isotxs")
4747

48-
PMATRX_AA = os.path.join(FIXTURE_DIR, "mc2v3-AA.pmatrx")
49-
PMATRX_AB = os.path.join(FIXTURE_DIR, "mc2v3-AB.pmatrx")
48+
PMATRX_AA = os.path.join(FIXTURE_DIR, "AA.PMATRX")
49+
PMATRX_AB = os.path.join(FIXTURE_DIR, "AB.PMATRX")
5050
PMATRX_AA_AB = os.path.join(FIXTURE_DIR, "combined-AA-AB.pmatrx")
5151
PMATRX_LUMPED = os.path.join(FIXTURE_DIR, "combined-and-lumped-AA-AB.pmatrx")
5252

53-
GAMISO_AA = os.path.join(FIXTURE_DIR, "mc2v3-AA.gamiso")
54-
GAMISO_AB = os.path.join(FIXTURE_DIR, "mc2v3-AB.gamiso")
53+
GAMISO_AA = os.path.join(FIXTURE_DIR, "AA.GAMISO")
54+
GAMISO_AB = os.path.join(FIXTURE_DIR, "AB.GAMISO")
5555
GAMISO_AA_AB = os.path.join(FIXTURE_DIR, "combined-AA-AB.gamiso")
5656
GAMISO_LUMPED = os.path.join(FIXTURE_DIR, "combined-and-lumped-AA-AB.gamiso")
5757

@@ -260,7 +260,7 @@ def test_mergeFailsWithNonIsotxsFiles(self):
260260
lib = xsLibraries.IsotxsLibrary()
261261
xsLibraries.mergeXSLibrariesInWorkingDirectory(lib)
262262
self.assertIn(
263-
f"Ignoring file {dummyFileName} in the merging of ISOXX files",
263+
f"{dummyFileName} in the merging of ISOXX files",
264264
log.getStdoutValue(),
265265
)
266266
finally:
@@ -401,8 +401,6 @@ def assert_contains_only(self, container, shouldBeThere, shouldNotBeThere):
401401
self.assertEqual(set(), container & set(shouldNotBeThere))
402402

403403

404-
# LOOK OUT, THIS GETS DELETED LATER ON SO IT DOESN'T RUN... IT IS AN ABSTRACT CLASS!!
405-
# LOOK OUT, THIS GETS DELETED LATER ON SO IT DOESN'T RUN... IT IS AN ABSTRACT CLASS!!
406404
# LOOK OUT, THIS GETS DELETED LATER ON SO IT DOESN'T RUN... IT IS AN ABSTRACT CLASS!!
407405
class TestXSlibraryMerging(unittest.TestCase, TempFileMixin):
408406
"""A shared class that defines tests that should be true for all IsotxsLibrary merging."""
@@ -604,6 +602,57 @@ def getLibLumpedPath(self):
604602
return GAMISO_LUMPED
605603

606604

605+
class Combined_merge_Tests(unittest.TestCase):
606+
@classmethod
607+
def setUpClass(cls):
608+
cls.isotxsAA = None
609+
cls.isotxsAB = None
610+
cls.gamisoAA = None
611+
cls.gamisoAB = None
612+
cls.pmatrxAA = None
613+
cls.pmatrxAB = None
614+
cls.libCombined = None
615+
616+
@classmethod
617+
def tearDownClass(cls):
618+
cls.isotxsAA = None
619+
cls.isotxsAB = None
620+
cls.gamisoAA = None
621+
cls.gamisoAB = None
622+
cls.pmatrxAA = None
623+
cls.pmatrxAB = None
624+
cls.libCombined = None
625+
del cls.isotxsAA
626+
del cls.isotxsAB
627+
del cls.gamisoAA
628+
del cls.gamisoAB
629+
del cls.pmatrxAA
630+
del cls.pmatrxAB
631+
del cls.libCombined
632+
633+
def setUp(self):
634+
# load a library that is in the ARMI tree. This should
635+
# be a small library with LFPs, Actinides, structure, and coolant
636+
for attrName, path, readFunc in [
637+
("isotxsAA", ISOTXS_AA, isotxs.readBinary),
638+
("gamisoAA", GAMISO_AA, gamiso.readBinary),
639+
("pmatrxAA", PMATRX_AA, pmatrx.readBinary),
640+
("isotxsAB", ISOTXS_AB, isotxs.readBinary),
641+
("gamisoAB", GAMISO_AB, gamiso.readBinary),
642+
("pmatrxAB", PMATRX_AB, pmatrx.readBinary),
643+
("libCombined", ISOTXS_AA_AB, isotxs.readBinary),
644+
]:
645+
if getattr(self.__class__, attrName) is None:
646+
setattr(self.__class__, attrName, readFunc(path))
647+
648+
def test_mergeAllXSLibFiles(self):
649+
lib = xsLibraries.IsotxsLibrary()
650+
xsLibraries.mergeXSLibrariesInWorkingDirectory(
651+
lib, xsLibrarySuffix="", mergeGammaLibs=True, alternateDirectory=FIXTURE_DIR
652+
)
653+
self.assertEqual(set(lib.nuclideLabels), set(self.libCombined.nuclideLabels))
654+
655+
607656
# Remove the abstract class, so that it does not run (all tests would fail)
608657
del TestXSlibraryMerging
609658

armi/nuclearDataIO/xsLibraries.py

+70-23
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from armi import runLog
2828
from armi.nucDirectory import nuclideBases
2929
from armi.nuclearDataIO.nuclearFileMetadata import NuclideXSMetadata, RegionXSMetadata
30+
from armi.nuclearDataIO import xsNuclides
3031
from armi.utils import properties
3132

3233
_ISOTXS_EXT = "ISO"
@@ -144,10 +145,22 @@ def getISOTXSLibrariesToMerge(xsLibrarySuffix, xsLibFileNames):
144145
return isosToMerge
145146

146147

147-
def mergeXSLibrariesInWorkingDirectory(lib, xsLibrarySuffix="", mergeGammaLibs=False):
148+
def mergeXSLibrariesInWorkingDirectory(
149+
lib,
150+
xsLibrarySuffix="",
151+
mergeGammaLibs=False,
152+
alternateDirectory=None,
153+
):
148154
"""
149155
Merge neutron (ISOTXS) and gamma (GAMISO/PMATRX) library data into the provided library.
150156
157+
Notes
158+
-----
159+
Convention is for fuel XS id to come first alphabetically (A, B, C, etc.) and then be
160+
followed by non-fuel. This should allow `referenceDummyNuclide` to be defined before
161+
it is needed by a non-fuel cross section, but if the convention is not followed then
162+
this could cause an issue.
163+
151164
Parameters
152165
----------
153166
lib : obj
@@ -161,18 +174,25 @@ def mergeXSLibrariesInWorkingDirectory(lib, xsLibrarySuffix="", mergeGammaLibs=F
161174
mergeGammaLibs : bool, optional
162175
If True, the GAMISO and PMATRX files that correspond to the ISOTXS library will be merged. Note: if these
163176
files do not exist this will fail.
177+
178+
alternateDirectory : str, optional
179+
An alternate directory in which to search for files other than the working directory. The main purpose
180+
of this is for testing, but it could also be useful to users.
164181
"""
165182
# pylint: disable=import-outside-toplevel) ; avoid cyclic import with isotxs bringing this in for data structure
166183
from armi.nuclearDataIO.cccc import isotxs
167184
from armi.nuclearDataIO.cccc import gamiso
168185
from armi.nuclearDataIO.cccc import pmatrx
169186
from armi import nuclearDataIO
170187

188+
baseDir = alternateDirectory or os.getcwd()
189+
globPath = os.path.join(baseDir, _ISOTXS_EXT + "*")
171190
xsLibFiles = getISOTXSLibrariesToMerge(
172-
xsLibrarySuffix, [iso for iso in glob.glob(_ISOTXS_EXT + "*")]
191+
xsLibrarySuffix, [iso for iso in glob.glob(globPath)]
173192
)
174193
librariesToMerge = []
175194
neutronVelocities = {} # Dictionary of neutron velocities from each ISOTXS file
195+
referenceDummyNuclides = None
176196
for xsLibFilePath in sorted(xsLibFiles):
177197
try:
178198
xsID = re.search("ISO([A-Z0-9]{2})", xsLibFilePath).group(
@@ -197,21 +217,48 @@ def mergeXSLibrariesInWorkingDirectory(lib, xsLibrarySuffix="", mergeGammaLibs=F
197217
)
198218
)
199219
continue
220+
200221
neutronLibrary = isotxs.readBinary(xsLibFilePath)
201222
neutronVelocities[xsID] = neutronLibrary.neutronVelocity
202-
librariesToMerge.append(neutronLibrary)
223+
224+
dummyNuclidesInNeutron = [
225+
nuc
226+
for nuc in neutronLibrary.nuclides
227+
if isinstance(nuc._base, nuclideBases.DummyNuclideBase)
228+
]
229+
if not dummyNuclidesInNeutron:
230+
runLog.info(f"Adding dummy nuclides to library {xsID}")
231+
addedDummyData = isotxs.addDummyNuclidesToLibrary(
232+
neutronLibrary, referenceDummyNuclides
233+
) # Add DUMMY nuclide data not produced by MC2-3
234+
isotxsLibraryPath = os.path.join(
235+
baseDir,
236+
nuclearDataIO.getExpectedISOTXSFileName(
237+
suffix=xsLibrarySuffix, xsID=xsID
238+
),
239+
)
240+
isotxsDummyPath = isotxsLibraryPath
241+
isotxs.writeBinary(neutronLibrary, isotxsDummyPath)
242+
neutronLibraryDummyData = isotxs.readBinary(isotxsDummyPath)
243+
librariesToMerge.append(neutronLibraryDummyData)
244+
dummyNuclidesInNeutron = referenceDummyNuclides
245+
else:
246+
librariesToMerge.append(neutronLibrary)
247+
if not referenceDummyNuclides:
248+
referenceDummyNuclides = dummyNuclidesInNeutron
249+
203250
if mergeGammaLibs:
204-
dummyNuclides = [
205-
nuc
206-
for nuc in neutronLibrary.nuclides
207-
if isinstance(nuc._base, nuclideBases.DummyNuclideBase)
208-
]
209-
210-
gamisoLibraryPath = nuclearDataIO.getExpectedGAMISOFileName(
211-
suffix=xsLibrarySuffix, xsID=xsID
251+
gamisoLibraryPath = os.path.join(
252+
baseDir,
253+
nuclearDataIO.getExpectedGAMISOFileName(
254+
suffix=xsLibrarySuffix, xsID=xsID
255+
),
212256
)
213-
pmatrxLibraryPath = nuclearDataIO.getExpectedPMATRXFileName(
214-
suffix=xsLibrarySuffix, xsID=xsID
257+
pmatrxLibraryPath = os.path.join(
258+
baseDir,
259+
nuclearDataIO.getExpectedPMATRXFileName(
260+
suffix=xsLibrarySuffix, xsID=xsID
261+
),
215262
)
216263

217264
# Check if the gamiso and pmatrx data paths exist with the xs library suffix so that
@@ -226,18 +273,20 @@ def mergeXSLibrariesInWorkingDirectory(lib, xsLibrarySuffix="", mergeGammaLibs=F
226273
f"Attempting to find GAMISO/PMATRX data with "
227274
f"only XS ID {xsID} instead."
228275
)
229-
gamisoLibraryPath = nuclearDataIO.getExpectedGAMISOFileName(xsID=xsID)
230-
pmatrxLibraryPath = nuclearDataIO.getExpectedPMATRXFileName(xsID=xsID)
276+
gamisoLibraryPath = os.path.join(
277+
baseDir, nuclearDataIO.getExpectedGAMISOFileName(xsID=xsID)
278+
)
279+
pmatrxLibraryPath = os.path.join(
280+
baseDir, nuclearDataIO.getExpectedPMATRXFileName(xsID=xsID)
281+
)
231282

232283
# GAMISO data
233284
gammaLibrary = gamiso.readBinary(gamisoLibraryPath)
234285
addedDummyData = gamiso.addDummyNuclidesToLibrary(
235-
gammaLibrary, dummyNuclides
286+
gammaLibrary, dummyNuclidesInNeutron
236287
) # Add DUMMY nuclide data not produced by MC2-3
237288
if addedDummyData:
238-
gamisoDummyPath = os.path.abspath(
239-
os.path.join(os.getcwd(), gamisoLibraryPath)
240-
)
289+
gamisoDummyPath = gamisoLibraryPath
241290
gamiso.writeBinary(gammaLibrary, gamisoDummyPath)
242291
gammaLibraryDummyData = gamiso.readBinary(gamisoDummyPath)
243292
librariesToMerge.append(gammaLibraryDummyData)
@@ -247,12 +296,10 @@ def mergeXSLibrariesInWorkingDirectory(lib, xsLibrarySuffix="", mergeGammaLibs=F
247296
# PMATRX data
248297
pmatrxLibrary = pmatrx.readBinary(pmatrxLibraryPath)
249298
addedDummyData = pmatrx.addDummyNuclidesToLibrary(
250-
pmatrxLibrary, dummyNuclides
299+
pmatrxLibrary, dummyNuclidesInNeutron
251300
) # Add DUMMY nuclide data not produced by MC2-3
252301
if addedDummyData:
253-
pmatrxDummyPath = os.path.abspath(
254-
os.path.join(os.getcwd(), pmatrxLibraryPath)
255-
)
302+
pmatrxDummyPath = pmatrxLibraryPath
256303
pmatrx.writeBinary(pmatrxLibrary, pmatrxDummyPath)
257304
pmatrxLibraryDummyData = pmatrx.readBinary(pmatrxDummyPath)
258305
librariesToMerge.append(pmatrxLibraryDummyData)

0 commit comments

Comments
 (0)