def __init__(self): _XSLibrary.__init__(self) self.pmatrxMetadata = NuclideXSMetadata() self.isotxsMetadata = NuclideXSMetadata() self.gamisoMetadata = NuclideXSMetadata() # keys are nuclide labels such as U235AA # vals are XSNuclide objects self._nuclides = {} self._scatterWeights = {}
class IsotxsLibrary(_XSLibrary): """ IsotxsLibrary objects are a collection of cross sections (XS) for both neutron and gamma reactions. IsotxsLibrary objects must be initialized with data through one of the read methods within this package See Also -------- :py:func:`armi.nuclearDataIO.isotxs.readBinary` :py:func:`armi.nuclearDataIO.gamiso.readBinary` :py:func:`armi.nuclearDataIO.pmatrx.readBinary` :py:class:`CompxsLibrary` Examples -------- >>> lib = xsLibraries.IsotxsLibrary() >>> # this doesn't have any information yet, we can read ISOTXS information >>> libIsotxs = isotxs.readBinary('ISOAA') >>> # any number of XSLibraries can be merged >>> lib.merge(libIsotxs) # now the `lib` contains the ISOAA information. """ def __init__(self): _XSLibrary.__init__(self) self.pmatrxMetadata = NuclideXSMetadata() self.isotxsMetadata = NuclideXSMetadata() self.gamisoMetadata = NuclideXSMetadata() # keys are nuclide labels such as U235AA # vals are XSNuclide objects self._nuclides = {} self._scatterWeights = {} gammaEnergyUpperBounds = properties.createImmutableProperty( "gammaEnergyUpperBounds", "a PMATRX or GAMISO", "Get or set the gamma energy groups.", ) neutronDoseConversionFactors = properties.createImmutableProperty( "neutronDoseConversionFactors", "a PMATRX", "Get or set the neutron dose conversion factors.", ) gammaDoseConversionFactors = properties.createImmutableProperty( "gammaDoseConversionFactors", "a PMATRX", "Get or set the gamma does conversion factors.", ) @property def numGroups(self): """Get the number of neutron energy groups""" return len(self.neutronEnergyUpperBounds) @property def numGroupsGamma(self): """get the number of gamma energy groups""" return len(self.gammaEnergyUpperBounds) @property def xsIDs(self): """ Get the XS ID's present in this library. Assumes the suffixes are the last 2 letters in the nucNames """ return list( set( getSuffixFromNuclideLabel(name) for name in self.nuclideLabels)) def __repr__(self): files = (self.isotxsMetadata.fileNames + self.pmatrxMetadata.fileNames + self.gamisoMetadata.fileNames) if not any(files): return "<IsotxsLibrary empty>" return "<IsotxsLibrary id:{} containing {} nuclides from {}>".format( id(self), len(self), ", ".join(files)) def __setitem__(self, key, value): _XSLibrary.__setitem__(self, key, value) self._nuclides[key] = value def __getitem__(self, key): return self._nuclides[key] def get(self, nuclideLabel, default): return self._nuclides.get(nuclideLabel, default) def getNuclide(self, nucName, suffix): """ Get a nuclide object from the XS library or None. Parameters ---------- nucName : str ARMI nuclide name, e.g. 'U235', 'PU239' suffix : str Restrict to a specific nuclide lib suffix e.g. 'AA' Returns ------- nuclide : Nuclide object A nuclide from the library or None """ libLabel = nuclideBases.byName[nucName].label + suffix try: return self[libLabel] except KeyError: runLog.error("Error in {}.\nSee stderr.".format(self)) raise def __delitem__(self, key): _XSLibrary.__delitem__(self, key) del self._nuclides[key] @property def nuclideLabels(self): """Get the nuclide Names.""" # need to create a new list so the _orderedNuclideLabels does not get modified. return list(self._orderedNuclideLabels) @property def nuclides(self): return [self[name] for name in self._orderedNuclideLabels] def getNuclides(self, suffix): """Returns a list of the nuclide objects in the library""" nucs = [] # nucName is U235IA, etc.. nuc.name is U235, etc for nucLabel, nuc in self.items(): # `in` used below for support of >26 xs groups if not suffix or suffix in getSuffixFromNuclideLabel(nucLabel): # accept things with the suffix if one is given if nuc not in nucs: nucs.append(nuc) return nucs def merge(self, other): """Merge two XSLibraries""" runLog.debug("Merging XS library {} into XS library {}".format( other, self)) self._mergeProperties(other) # merging meta data may raise an exception before knowing anything about the contained nuclides # if it raises an exception, nothing has been modified in two objects isotxsMeta, pmatrxMeta, gamisoMeta = self._mergeMetadata(other) self._mergeNuclides(other) # only vampire the __dict__ if successful other.__dict__ = {} # only reassign metadata if successful self.isotxsMetadata = isotxsMeta self.pmatrxMetadata = pmatrxMeta self.gamisoMetadata = gamisoMeta def _mergeProperties(self, other): properties.unlockImmutableProperties(other) try: self.neutronDoseConversionFactors = other.neutronDoseConversionFactors self._mergeNeutronEnergies(other) self.gammaEnergyUpperBounds = other.gammaEnergyUpperBounds self.gammaDoseConversionFactors = other.gammaDoseConversionFactors finally: properties.lockImmutableProperties(other) def _mergeMetadata(self, other): isotxsMeta = self.isotxsMetadata.merge(other.isotxsMetadata, self, other, "ISOTXS", exceptions.IsotxsError) pmatrxMeta = self.pmatrxMetadata.merge(other.pmatrxMetadata, self, other, "PMATRX", exceptions.PmatrxError) gamisoMeta = self.gamisoMetadata.merge(other.gamisoMetadata, self, other, "GAMISO", exceptions.GamisoError) return isotxsMeta, pmatrxMeta, gamisoMeta def _mergeNuclides(self, other): # these must be different for nuclideKey, nuclide in other.items(): if nuclideKey in self: self[nuclideKey].merge(nuclide) else: self[nuclideKey] = nuclide def resetScatterWeights(self): self._scatterWeights = {} def getScatterWeights(self, scatterMatrixKey="elasticScatter"): """ Build or retrieve pre-built scatter weight data This acts like a cache for _buildScatterWeights See Also -------- _buildScatterWeights """ if not self._scatterWeights.get(scatterMatrixKey): self._scatterWeights[scatterMatrixKey] = self._buildScatterWeights( scatterMatrixKey) return self._scatterWeights[scatterMatrixKey] def _buildScatterWeights(self, scatterMatrixKey): r""" Build a scatter-weight lookup table for the scatter matrix. Scatter "weights" are needed for sensitivity studies when deriviatives wrt the scatter XS are required. They are defined like: .. math:: w_{g^{\prime} \leftarrow g} = \frac{\sigma_{s,g^{\prime} \leftarrow g}} {\sum_{g^{\prime\prime}=1}^G \sigma_{s, g^{\prime\prime} \leftarrow g}} Returns ------- scatterWeights : dict (xsID, fromGroup) : weight column (sparse Gx1). See Also -------- terrapower.physics.neutronics.uq.sensitivities.MeshMatrix.derivativeM """ runLog.info("Building {0} weights on cross section library".format( scatterMatrixKey)) scatterWeights = {} for nucName, nuc in self.items(): nucScatterWeights = nuc.buildNormalizedScatterColumns( scatterMatrixKey) for fromG, scatterColumn in nucScatterWeights.items(): scatterWeights[nucName, fromG] = scatterColumn return scatterWeights def plotNucXs(self, nucNames, xsNames, fName=None, label=None, noShow=False, title=None): """ generates a XS plot for a nuclide on the ISOTXS library nucName : str or list The nuclides to plot xsName : str or list the XS to plot e.g. n,g, n,f, nalph, etc. see xsCollections for actual names. fName : str, optional if fName is given, the file will be written rather than plotting to screen label : str, optional is an optional label for image legends, useful in ipython sessions. noShow : bool, optional Won't finalize plot. Useful for using this to make custom plots. Examples -------- >>> l = ISOTXS() >>> l.plotNucXs('U238NA','fission') Plot n,g for all xenon and krypton isotopes >>> f = lambda name: 'XE' in name or 'KR' in name >>> l.plotNucXs(sorted(filter(f,l.nuclides.keys())),itertools.repeat('nGamma')) See Also -------- armi.nucDirectory.nuclide.plotScatterMatrix """ # convert all input to lists if isinstance(nucNames, str): nucNames = [nucNames] if isinstance(xsNames, str): xsNames = [xsNames] for nucName, xsName in zip(nucNames, xsNames): nuc = self[nucName] thisLabel = label or "{0} {1}".format(nucName, xsName) x = self.neutronEnergyUpperBounds / 1e6 y = nuc.micros[xsName] pyplot.plot(x, y, "-", label=thisLabel, drawstyle="steps-post") ax = pyplot.gca() ax.set_xscale("log") ax.set_yscale("log") pyplot.grid(color="0.70") pyplot.title(title or " microscopic XS from {0}".format(self)) pyplot.xlabel("Energy (MeV)") pyplot.ylabel("microscopic XS (barns)") pyplot.legend() if fName: pyplot.savefig(fName) elif not noShow: pyplot.show() def purgeFissionProducts(self, r): """ Purge the fission products based on the active nuclides within the reactor. Parameters ---------- r : py:class:`armi.reactors.reactor.Reactor` a reactor, or None .. warning:: Sometimes worker nodes do not have a reactor, fission products will not be purged. """ runLog.info("Purging detailed fission products from {}".format(self)) modeledNucs = r.blueprints.allNuclidesInProblem for key, nuc in list(self.items()): if nuc.name not in modeledNucs: del self[key]