Пример #1
0
    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 = {}
Пример #2
0
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]