def test_getAllFissionProductNuclideBases(self): """Test to ensure the fission product nuclide bases are present""" clideBases = self.lfps.getAllFissionProductNuclideBases() xe135 = nuclideBases.fromName("XE135") kr85 = nuclideBases.fromName("KR85") self.assertIn(xe135, clideBases) self.assertIn(kr85, clideBases)
def test_createReferenceLFPs(self): """Test of the reference fission product model creation""" with open(REFERENCE_LUMPED_FISSION_PRODUCT_FILE, "r") as LFP_FILE: LFP_TEXT = LFP_FILE.read() fpd = lumpedFissionProduct.FissionProductDefinitionFile( io.StringIO(LFP_TEXT)) fpd.fName = REFERENCE_LUMPED_FISSION_PRODUCT_FILE lfps = fpd.createLFPsFromFile() self.assertEqual(len(lfps), 5) LFP_IDS = [ "LFP35", "LFP38", "LFP39", "LFP40", "LFP41", ] for lfp_id in LFP_IDS: self.assertIn(lfp_id, lfps) mo99 = nuclideBases.fromName("MO99") ref_mo99_yields = [0.00091, 0.00112, 0.00099, 0.00108, 0.00101] for ref_fp_yield, lfp_id in zip(ref_mo99_yields, LFP_IDS): lfp = lfps[lfp_id] self.assertIn(mo99, lfp) error = math.fabs(ref_fp_yield - lfp[mo99]) / ref_fp_yield self.assertLess(error, 1e-6)
def test_setGasRemovedFrac(self): """Test of the set gas removal fraction""" lfp = self.fpd.createSingleLFPFromFile("LFP38") xe135 = nuclideBases.fromName("XE135") gas1 = lfp[xe135] lfp.setGasRemovedFrac(0.25) gas2 = lfp[xe135] self.assertAlmostEqual(gas1 * 0.75, gas2)
def test_createLFPs(self): """Test of the fission product model creation""" lfps = self.fpd.createLFPsFromFile() xe135 = nuclideBases.fromName("XE135") self.assertEqual(len(lfps), 3) self.assertIn("LFP35", lfps) for lfp in lfps.values(): self.assertIn(xe135, lfp)
def test_getYield(self): """Test of the yield of a fission product""" xe135 = nuclideBases.fromName("XE135") lfp = self.fpd.createSingleLFPFromFile("LFP39") lfp[xe135] = 3 val3 = lfp[xe135] self.assertEqual(val3, 3) self.assertIsNone(lfp[5])
def test_duplicate(self): """Test to ensure that when we duplicate, we don't adjust the original file""" newLfps = self.lfps.duplicate() ba = nuclideBases.fromName("XE135") lfp1 = self.lfps["LFP39"] lfp2 = newLfps["LFP39"] v1 = lfp1[ba] lfp1[ba] += 5.0 # make sure copy doesn't change w/ first. v2 = lfp2[ba] self.assertEqual(v1, v2)
def _getDetailedFPDensities(self): """ Expands the nuclides in the LFP based on their yields. Returns -------- dfpDensities : dict Detailed Fission Product Densities. keys are FP names, values are block number densities in atoms/bn-cm. Raises ------ IndexError The lumped fission products were not initialized on the blocks. """ dfpDensities = {} if not self.modelFissionProducts: return dfpDensities lfpCollection = self.block.getLumpedFissionProductCollection() if self.diluteFissionProducts: # set all densities to near zero. try: _, dfp = list(lfpCollection.items())[0] except IndexError: raise IndexError( "Lumped fission products are not initialized. Did interactAll BOL run?" ) for individualFpBase in dfp.keys(): dfpDensities[individualFpBase] = self.minimumNuclideDensity else: # expand densities and sum dfpDensitiesByName = lfpCollection.getNumberDensities(self.block) # now, go through the list and make sure that there aren't any values less than the # minimumNuclideDensity; we need to keep trace amounts of nuclides in the problem for fpName, fpDens in dfpDensitiesByName.items(): fp = nuclideBases.fromName(fpName) dfpDensities[fp] = max(fpDens, self.minimumNuclideDensity) return dfpDensities
def test_printDensities(self): _ = nuclideBases.fromName("XE135") lfp = self.fpd.createSingleLFPFromFile("LFP38") lfp.printDensities(10.0)
def test_getExpandedMass(self): xe135 = nuclideBases.fromName("XE135") lfp = self.fpd.createSingleLFPFromFile("LFP38") massVector = lfp.getExpandedMass(mass=0.99) self.assertEqual(massVector.get(xe135), 0.99)
def test_getNumberFracs(self): xe135 = nuclideBases.fromName("XE135") lfp = self.fpd.createSingleLFPFromFile("LFP38") numberFracs = lfp.getNumberFracs() self.assertEqual(numberFracs.get(xe135), 1.0)
def plotAll(xlim, ylim): """Plot all nuclides and transformations.""" # load the burn chain input that comes with ARMI with open(os.path.join(RES, "burn-chain.yaml")) as burnChainStream: nuclideBases.imposeBurnChain(burnChainStream) nbs = nuclideBases.instances fig, ax = plt.subplots(figsize=(15, 10)) patches = [] for nb in nbs: if not nb.trans and not nb.decays: # skip nuclides without any transmutations defined pass patch = plotNuc(nb, ax) patches.append(patch) # loop over all possible transmutations and decays and draw arrows for ti, trans in enumerate(nb.trans + nb.decays): product = nuclideBases.fromName(trans.productNuclides[0]) if product.z == 0: # skip lumped fission products and DUMP nuclides continue # add index-based y-offset to minimize overlaps x, y, xp, yp = ( nb.a - nb.z, nb.z + ti * 0.05, product.a - product.z, product.z + ti * 0.05, ) if trans in nb.trans: color = "deeppink" else: color = "orangered" ax.annotate( "", (xp, yp), (x, y), arrowprops=dict(width=2 * trans.branch, shrink=0.1, alpha=0.4, color=color), ) # add reaction label towards the middle of the arrow xlabel = xp - (xp - x) * 0.5 ylabel = yp - (yp - y) * 0.5 # pretty up the labels a bit with some LaTeX and rotations rxnType = (trans.type.replace("nGamma", r"n,$\gamma$").replace( "nalph", r"n,$\alpha$").replace("ad", r"$\alpha$").replace( "bmd", r"$\beta^-$").replace("bpd", r"$\beta^+$")) if xp != x: # rotate the nuclide type label to sit right on the arrow rotation = math.atan((yp - y) / (xp - x)) * 180 / math.pi else: rotation = 0 ax.text(xlabel, ylabel, rxnType, color="grey", ha="center", rotation=rotation) pc = PatchCollection(patches, facecolor="mistyrose", alpha=0.2, edgecolor="black") ax.add_collection(pc) ax.set_xlim(xlim) ax.set_ylim(ylim) ax.set_aspect("equal") ax.set_xlabel("Neutrons (N)") ax.set_ylabel("Protons (Z)") ax.set_title("Transmutations and Decays (with branching)") plt.show()