Ejemplo n.º 1
0
def nuclearLevel(Z, A, data):

    symbol = chemicalElementModule.symbolFromZ[Z]
    isotopeID = isotopeModule.isotopeIDFromElementIDAndA(symbol, A)
    keys = random.sample([key for key in data], len(data))
    for index in keys:
        name = nucleusModule.levelNameFromIsotopeNameAndIndex(isotopeID, index)
        nameLower = name[:1].lower() + name[1:]
        nucleus = nucleusModule.particle(nameLower, index)
        level = nuclearLevelModule.particle(name, nucleus)

        atomicMass, nuclearMass, energy, charge, halflife, spin, parity = data[
            index]

        energy = nuclearEnergyLevelModule.double(
            'base', energy, quantityModule.stringToPhysicalUnit('keV'))
        level.energy.add(energy)

        if (atomicMass is not None):
            mass = massModule.double(
                'base', atomicMass, quantityModule.stringToPhysicalUnit('amu'))
            level.mass.add(mass)

        if (nuclearMass is not None):
            mass = massModule.double(
                'base', nuclearMass,
                quantityModule.stringToPhysicalUnit('amu'))
            nucleus.mass.add(mass)

        if (charge is not None):
            charge = chargeModule.integer(
                'base', charge, quantityModule.stringToPhysicalUnit('e'))
            nucleus.charge.add(charge)

        if (halflife is not None):
            if (halflife == 'stable'):
                halflife = halflifeModule.string(
                    'base', halflife, quantityModule.stringToPhysicalUnit('s'))
            else:
                time, unit = halflife.split()
                halflife = halflifeModule.double(
                    'base', float(time),
                    quantityModule.stringToPhysicalUnit(unit))
            nucleus.halflife.add(halflife)

        if (spin is not None):
            spin = spinModule.fraction(
                'base', spinModule.fraction.toValueType(spin),
                quantityModule.stringToPhysicalUnit('hbar'))
            nucleus.spin.add(spin)

        if (parity is not None):
            parity = parityModule.integer(
                'base', parity, quantityModule.stringToPhysicalUnit(''))
            nucleus.parity.add(parity)

        database.add(level)
Ejemplo n.º 2
0
# <<END-copyright>>

from PoPs.quantities import quantity as quantityModule
from PoPs.quantities import mass as massModule
from PoPs.quantities import spin as spinModule
from PoPs.quantities import parity as parityModule
from PoPs.quantities import charge as chargeModule
from PoPs.quantities import halflife as halflifeModule
from PoPs.quantities import nuclearEnergyLevel as nuclearEnergyLevelModule

from PoPs.families import nucleus as nucleusModule
from PoPs.families import nuclearLevel as nuclearLevelModule
from PoPs.groups import isotope as isotopeModule

A = '16'
isotopeID = isotopeModule.isotopeIDFromElementIDAndA('O', A)
isotope = isotopeModule.suite(isotopeID, A)

data = [['0', 15.99491461956, 0, None, None, None, None],
        ['1', None, 6049400, None, None, None, None],
        ['2', None, 6129893, None, None, None, None],
        ['3', None, 6917100, None, None, None, None]]

for index, mass, energy, charge, halflife, spin, parity in data:
    name = nucleusModule.nucleusNameFromNucleusNameAndIndex(isotopeID, index)
    nucleus = nucleusModule.particle(name, index)
    energy = nuclearEnergyLevelModule.double(
        'base', energy, quantityModule.stringToPhysicalUnit('eV'))
    nucleus.energy.add(energy)

    name = nucleusModule.levelNameFromIsotopeNameAndIndex(isotopeID, index)
Ejemplo n.º 3
0
def ITYPE_4(MTDatas, info, verbose=0):
    """Convert ENDF ITYPE 4 data (decay data) into PoPs."""

    errors = []

    # Add ENDF documentation
    info.PoPs.documentation = '\n'.join(MTDatas[451][1][4:-info.NXC])

    # The atom containing the parent nucleus
    parentAtom = toGNDMisc.getPoPsParticle(info,
                                           info.targetZA,
                                           name=None,
                                           levelIndex=info.levelIndex,
                                           level=info.level,
                                           levelUnit=energyUnit)
    decayParticle = parentAtom
    if (miscPoPsModule.hasNucleas(parentAtom)):
        decayParticle = parentAtom.nucleus

    if (457 in MTDatas):
        dataIndex = 0
        MT457MF8Data = MTDatas[457][8]

        decayData = decayParticle.decayData

        # Read parent info block
        ZA, AWR, LIS, LISO, NST, NSP = endfFileToGNDMisc.sixFunkyFloatStringsToIntsAndFloats(
            MT457MF8Data[dataIndex], intIndices=[2, 3, 4, 5])
        dataIndex += printInfo(verbose, dataIndex, MT457MF8Data)

        if (LIS != 0):
            aliasID = "%s_m%s" % (isotopeModule.isotopeIDFromElementIDAndA(
                parentAtom.chemicalElement, parentAtom.A), LISO)
            info.PoPs.add(
                PoPsAliasModule.metaStable(aliasID, parentAtom.id, LISO))

        HL, dHL, dummy, dummy, NC2, dummy = endfFileToGNDMisc.sixFunkyFloatStringsToIntsAndFloats(
            MT457MF8Data[dataIndex], intIndices=[4])
        dataIndex += printInfo(verbose, dataIndex, MT457MF8Data)

        NC = NC2 // 2  # NC: number of decay energies
        if (NC not in [3, 17]):
            raise ValueError(
                "Number of decay energies must be 3 or 17, found %d" % NC)
        nlines = (NC2 + 5) // 6
        aveDecayEnergies = []
        for index in range(nlines):
            aveDecayEnergies.extend(
                endfFileToGNDMisc.sixFunkyFloatStringsToFloats(
                    MT457MF8Data[dataIndex]))
            dataIndex += printInfo(verbose, dataIndex, MT457MF8Data)

        if (len([
                aveDecayEnergy
                for aveDecayEnergy in aveDecayEnergies if (aveDecayEnergy != 0)
        ]) > 0):
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies,
                averageEnergyModule.lightParticles)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies,
                averageEnergyModule.electroMagneticRadiation)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies,
                averageEnergyModule.heavyParticles)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies, averageEnergyModule.betaMinus)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies, averageEnergyModule.betaPlus)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies, averageEnergyModule.AugerElectron)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies,
                averageEnergyModule.conversionElectron)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies, averageEnergyModule.gamma)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies, averageEnergyModule.xRay)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies,
                averageEnergyModule.internalBremsstrahlung)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies, averageEnergyModule.annihilation)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies, averageEnergyModule.alpha)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies, averageEnergyModule.recoil)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies,
                averageEnergyModule.spontaneousFission)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies,
                averageEnergyModule.fissionNeutrons)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies, averageEnergyModule.proton)
            aveDecayEnergies = addAverageDecayEnergyIfPresent(
                decayData, aveDecayEnergies, averageEnergyModule.neutrino)

        SPI, PAR, dum, dum, NDK6, NDK = endfFileToGNDMisc.sixFunkyFloatStringsToIntsAndFloats(
            MT457MF8Data[dataIndex], intIndices=[1, 2, 3, 4, 5])
        dataIndex += printInfo(verbose, dataIndex, MT457MF8Data)
        if (-77.8 < SPI < -77.7):
            SPI = None  # see page 180 of ENDF manual  # FIXME: Need "UNKNOWN" markup

        halflifeValue = None
        if (NST == 1): halflifeValue = 'stable'
        if (PAR == 0): PAR = None  # BRB, Happens for dec-013_Al_040.endf
        toGNDMisc.addParticleData(decayParticle,
                                  info,
                                  massValue=None,
                                  spinValue=SPI,
                                  parityValue=PAR,
                                  chargeValue=None,
                                  halflifeValue=halflifeValue)

        if (NST == 1):  # Nucleus is stable, nothing to do
            pass
        elif (NST == 0):  # Nucleus is unstable
            halflife = halflifeModule.double(
                info.PoPsLabel, HL, halflifeModule.baseUnit
            )  # FIXME: PQU(HL, 's', dHL), can't store uncertainty?
            decayParticle.halflife.add(halflife)

            # Iterate over decay chains
            decayModes = {}
            for i1 in range(NDK):  # iterate over decay modes
                initialDecay, otherDecays, RTYP_key = getRTYP(
                    MT457MF8Data[dataIndex])
                RTYP, RFS, Q, dQ, BR, dBR = endfFileToGNDMisc.sixFunkyFloatStringsToFloats(
                    MT457MF8Data[dataIndex])
                dataIndex += printInfo(verbose, dataIndex, MT457MF8Data)
                if (verbose > 3): print('RTYP = ', RTYP)
                RFS = int(RFS)  # BRB, Isometic state of daughter

                allDecays = [initialDecay] + otherDecays
                decayMode = decayDataModule.decayMode(
                    str(i1), ','.join([decayType[r_id] for r_id in allDecays]))
                decayModes[RTYP_key] = decayMode

                if (dBR):
                    branching = PQU(BR, '', dBR)
                else:
                    branching = PQU(BR, '')
                if (dQ):
                    Qval = PQU(Q, energyUnit, dQ)
                else:
                    Qval = PQU(Q, energyUnit)
                decayMode.Q.add(
                    QModule.double('', Qval.getValue(), Qval.unit)
                )  # FIXME: PQU(Q, 'eV', dQ), can't store uncertainty
                decayMode.probability.add(
                    probabilityModule.double("BR", branching.getValue(), '')
                )  # FIXME: PQU(BR, 's', dBR), can't store uncertainty
                # FIXME: what should we do for really small probabilities, so small ENDF gives 0, like spontaneous fission?
                n1 = len(otherDecays) - 1
                residualZA = addDecayMode(info, decayMode, initialDecay,
                                          info.targetZA, RFS, -1 == n1)
                for i2, otherDecay in enumerate(otherDecays):
                    residualZA = addDecayMode(info, decayMode, otherDecay,
                                              residualZA, RFS, i2 == n1)
                decayData.decayModes.add(decayMode)

                # LCON determines whether continuum spectra given: LCON 0: discrete only, 1: continuous only, 2: both
            for i1 in range(NSP):  # Iterate over spectra
                initialDecay, otherDecays, STYP_key = getRTYP(
                    MT457MF8Data[dataIndex], 11)
                dum, STYP, LCON, zero, six, NER = endfFileToGNDMisc.sixFunkyFloatStringsToIntsAndFloats(
                    MT457MF8Data[dataIndex], intIndices=[2, 3, 4, 5])
                dataIndex += printInfo(verbose, dataIndex, MT457MF8Data)
                STYP = initialDecay
                specType = decayType[STYP]

                FD, dFD, ERave, dERave, FC, dFC = endfFileToGNDMisc.sixFunkyFloatStringsToFloats(
                    MT457MF8Data[dataIndex]
                )  # FD: discrete normalization, FC: continuum norm., ERave: average decay energy
                dataIndex += printInfo(verbose, dataIndex, MT457MF8Data)

                if (LCON != 1):  # Discrete spectra given.
                    for i2 in range(NER):
                        ER, dER, dum, dum, NT, dum = endfFileToGNDMisc.sixFunkyFloatStringsToIntsAndFloats(
                            MT457MF8Data[dataIndex], intIndices=[2, 3, 4, 5])
                        dataIndex += printInfo(verbose, dataIndex,
                                               MT457MF8Data)
                        discreteSpectra = {'ER': ER, 'dER': dER}
                        if (LCON != 1):
                            if (NT not in (6, 8, 12)):
                                raise ValueError(
                                    "Unexpected NT=%d encountered!" % NT)
                            initialDecay, otherDecays, RTYP_key = getRTYP(
                                MT457MF8Data[dataIndex])
                            discreteSpectra[
                                'RTYP_plus'] = endfFileToGNDMisc.sixFunkyFloatStringsToFloats(
                                    MT457MF8Data[dataIndex])
                            dataIndex += printInfo(verbose, dataIndex,
                                                   MT457MF8Data)
                            if (verbose > 3):
                                print('STYP, RTYP = ', STYP, RTYP_key)
                            if (NT > 6):
                                RICC, dRICC, RICK, dRICK, RICL, dRICL = endfFileToGNDMisc.sixFunkyFloatStringsToFloats(
                                    MT457MF8Data[dataIndex])
                                dataIndex += printInfo(verbose, dataIndex,
                                                       MT457MF8Data)
                                discreteSpectra['RICC'], discreteSpectra[
                                    'dRICC'] = RICC, dRICC
                                if (NT > 8):
                                    discreteSpectra['RICK'], discreteSpectra[
                                        'dRICK'] = RICK, dRICK
                                    discreteSpectra['RICL'], discreteSpectra[
                                        'dRICL'] = RICL, dRICL
                        addDiscreteSpectra(decayModes, RTYP_key, STYP,
                                           discreteSpectra)

                if (LCON != 0):  # Continuum spectra given.
                    initialDecay, otherDecays, RTYP_key = getRTYP(
                        MT457MF8Data[dataIndex])
                    dataIndex, TAB1, regions = endfFileToGNDMisc.getTAB1Regions(
                        dataIndex, MT457MF8Data)
                    RTYP = TAB1['C1']
                    if (verbose > 3): print('STYP, RTYP = ', STYP, RTYP)
                    LCOV = int(TAB1['L2'])
                    if (len(regions) != 1):
                        raise Exception('len( regions ) = %s' % len(regions))
                    covariance = None
                    if (LCOV != 0):
                        print("    LCOV != 0")
                        dataIndex, covariance = getList(
                            dataIndex, MT457MF8Data)
                    addContinuumSpectrum(decayModes, RTYP_key, STYP, regions,
                                         covariance)

        else:
            raise ValueError(
                "In decay data (MT=457,MF=8), NST should be 0 or 1. Found %d" %
                NST)

        # Add documentation to PoPs

    return ({'PoPs': info.PoPs, 'errors': errors, 'info': info})
Ejemplo n.º 4
0
from PoPs.groups import isotope as isotopeModule
from PoPs.groups import chemicalElement as chemicalElementModule

database = databaseModule.database('test', '1.2.3')

O16Data = {
    '0': [15.99491461956, 0, None, None, None, None],
    '1': [None, 6049400, None, None, None, None],
    '2': [None, 6129893, None, None, None, None],
    '3': [None, 6917100, None, None, None, None]
}

symbol = chemicalElementModule.symbolFromZ[8]
for A, data in [['17', O16Data], ['16', O16Data]]:
    isotopeID = isotopeModule.isotopeIDFromElementIDAndA(symbol, A)
    keys = random.sample([key for key in data], len(data))
    for index in keys:
        mass, energy, charge, halflife, spin, parity = data[index]

        name = nucleusModule.nucleusNameFromNucleusNameAndIndex(
            isotopeID, index)
        nucleus = nucleusModule.particle(name, index)
        energy = nuclearEnergyLevelModule.double(
            'base', energy, quantityModule.stringToPhysicalUnit('keV'))
        nucleus.energy.add(energy)

        name = nucleusModule.levelNameFromIsotopeNameAndIndex(isotopeID, index)
        level = nuclearLevelModule.particle(name, nucleus)

        if (mass is not None):
Ejemplo n.º 5
0
    def processMultiGroup(self, style, tempInfo, indent):

        from fudge.processing import group as groupModule
        from fudge.processing.deterministic import transferMatrices as transferMatricesModule

        verbosity = tempInfo['verbosity']
        indent2 = indent + tempInfo['incrementalIndent']
        reactionSuite = tempInfo['reactionSuite']

        product = reactionSuite.PoPs[tempInfo['product'].id]
        productLabel = tempInfo['productLabel']

        energyUnit = tempInfo['incidentEnergyUnit']
        massUnit = energyUnit + '/c**2'
        # BRB6 hardwired
        mass2MeVFactor = PQUModule.PQU(1, energyUnit).getValueAs('MeV')

        if (verbosity > 2): print '%sGrouping %s' % (indent, self.moniker)
        projectileZA = tempInfo['projectileZA']
        targetZA = tempInfo['targetZA']
        if (targetZA == 6000):
            targetZA = 6012
            print '    Kludge for C_natural: changing targetZA from 6000 to %d' % targetZA
        productZA = miscPoPsModule.ZA(product)
        compoundZA = projectileZA + targetZA
        residualZA = compoundZA - productZA
        particlesData = {
            'projectile': {
                'ZA': projectileZA
            },
            'target': {
                'ZA': targetZA
            },
            'product': {
                'ZA': productZA
            },
            'residual': {
                'ZA': residualZA
            },
            'compound': {
                'ZA': compoundZA,
                'mass': tempInfo['projectileMass'] + tempInfo['targetMass']
            }
        }

        residualMass = tempInfo['masses']['Residual']  # Save old value. Why?
        residual = None
        compound = None
        residualSymbol = chemicalElementModule.symbolFromZ[residualZA // 1000]
        residualID = isotopeModule.isotopeIDFromElementIDAndA(
            residualSymbol, str(residualZA % 1000))
        if (residualID in reactionSuite.PoPs):
            residual = reactionSuite.PoPs[residualID]

        compoundSymbol = chemicalElementModule.symbolFromZ[compoundZA // 1000]
        compoundID = isotopeModule.isotopeIDFromElementIDAndA(
            compoundSymbol, str(compoundZA % 1000))
        if (compoundID in reactionSuite.PoPs):
            compound = reactionSuite.PoPs[compoundID]

        try:
            residual.getMass(massUnit)
        except:
            residual = None

        try:
            compound.getMass(massUnit)
        except:
            compound = None

        if (residual is None):
            if (compound is None):
                _residualMass = particlesData['compound'][
                    'mass'] - product.getMass(massUnit)
            else:
                _residualMass = compound.getMass(massUnit) - product.getMass(
                    massUnit)
            tempInfo['masses']['Residual'] = _residualMass
            print 'Could not find residual in particle database: ZA = %d, using mass %s %s' % (
                residualZA, _residualMass, massUnit)
        else:
            tempInfo['masses']['Residual'] = residual.getMass(massUnit)

        masses = tempInfo['masses']
        tempInfo['masses'] = {}
        for particle in masses:
            tempInfo['masses'][particle] = masses[particle] * mass2MeVFactor
        particlesData['compound']['mass'] *= mass2MeVFactor
        try:
            TM_1, TM_E = transferMatricesModule.KalbachMann_TransferMatrix(
                style,
                tempInfo,
                tempInfo['crossSection'],
                particlesData,
                self,
                tempInfo['multiplicity'],
                comment=tempInfo['transferMatrixComment'] +
                ' outgoing data for %s' % tempInfo['productLabel'])
        except:
            tempInfo['masses'] = masses
            raise
        tempInfo['masses'] = masses

        tempInfo['masses']['Residual'] = residualMass
        return (groupModule.TMs2Form(style, tempInfo, TM_1, TM_E))
Ejemplo n.º 6
0
def ITYPE_0( MTDatas, info, reactionSuite, singleMTOnly, MTs2Skip, parseCrossSectionOnly, doCovariances, verbose, reconstructResonances=True ) :

    warningList = []

    info.totalOrPromptFissionNeutrons = {}
    info.totalMF6_12_13Gammas = {}
    if( 452 in MTDatas ) :
        info.totalOrPromptFissionNeutrons['total'] = getTotalOrPromptFission( info, MTDatas[452][1], 'total', warningList )
        #MTDatas.pop( 452 ) # don't remove these yet, still need the covariance info
    if( 455 in MTDatas ) :
        info.delayedFissionDecayChannel = getDelayedFission( info, MTDatas[455], warningList )
        #MTDatas.pop( 455 )
    if( 456 in MTDatas ) :
        info.totalOrPromptFissionNeutrons[tokensModule.promptToken] = getTotalOrPromptFission( info, MTDatas[456][1], tokensModule.promptToken, warningList )
        #MTDatas.pop( 456 )
    if( 458 in MTDatas ) :
        info.fissionEnergyReleaseData = MTDatas[458]
        #MTDatas.pop( 458 )
    if ( 454 in MTDatas ) : 
        info.independentFissionYields = readMF8_454_459( info, 454, MTDatas[454], warningList )
    if ( 459 in MTDatas ) : 
        info.cumulativeFissionYields = readMF8_454_459( info, 459, MTDatas[459], warningList )
    sys.stdout.flush( )
    for warning in warningList : info.logs.write( "       WARNING: %s\n" % warning, stderrWriting = True )

    MTList = endfFileToGNDMiscModule.niceSortOfMTs( MTDatas.keys( ), verbose = False, logFile = info.logs )

    haveTotalFission = (18 in MTList)
    fissionMTs = [mt for mt in MTList if mt in (19,20,21,38)]

    summedReactions = {}
    summedReactionsInfo = { 4 : range( 50, 92 ), 103 : range( 600, 650 ), 104 : range( 650, 700 ), 105 : range( 700, 750 ), 106 : range( 750, 800 ), 107 : range( 800, 850 ) }
    for summedMT, partialReactions in summedReactionsInfo.items( ) :
        if( summedMT not in MTList ) : continue
        for MT in MTList :
            if( MT in partialReactions ) :
                summedReactions[summedMT] = None
                break

    for summedMT in ( 1, 3 ) :
        if( summedMT in MTList ) : summedReactions[summedMT] = None

    MT5Reaction = None
    reactions = []
    fissionComponents = []
    productions = []
    nonElastic = []
    delayInsertingSummedReaction = []
    linksToCheck = []   # links that may need to be updated after reading resonances

    for MT in MTList :
        if( MT in MTs2Skip ) : continue
        if( ( singleMTOnly is not None ) and ( MT != singleMTOnly ) ) : continue

        warningList = []
        MTData = MTDatas[MT]

        # Sometimes excited states are identified in MF8. Read this before reading distributions to make sure info is present.
        LMF, radioactiveDatas = readMF8( info, MT, MTData, warningList )

        doParseReaction = 3 in MTData
        if( not( doParseReaction ) ) :
            if( MT == 3 ) : doParseReaction = ( 12 in MTData ) or ( 13 in MTData )
        if( doParseReaction ) : # normal reaction, with cross section and distributions
            try :
                crossSection, outputChannel, MFKeys = parseReaction( info, info.target, info.projectileZA,
                        info.targetZA, MT, MTData, warningList, parseCrossSectionOnly = parseCrossSectionOnly )
            except KeyboardInterrupt:
                raise
            except:
                import traceback
                info.logs.write( traceback.format_exc( ), stderrWriting = True )
                info.doRaise.append( traceback.format_exc( ) )
                info.logs.write( '\n' )
                sys.stdout.flush( )
                continue

            info.logs.write( '\n' )
            sys.stdout.flush( )
            if( len( MFKeys ) ) :
                warningList.append( 'For reaction MT = %d, the following MFs were not converted: %s\n' % ( MT, MFKeys ) )
            if( outputChannel is None ) : break

            if( MT in summedReactions ) :
                summedReactions[MT] = [ crossSection, outputChannel ]
            else :
                if( MT != 2 ) : nonElastic.append( MT )
                reaction = reactionModule.reaction( outputChannel, ENDF_MT = MT )
                if( hasattr( info, 'dSigma_form' ) ) :
                    reaction.dCrossSection_dOmega.add( info.dSigma_form )
                    del info.dSigma_form
                    crossSection = crossSectionModule.CoulombElasticReference( link = reaction.dCrossSection_dOmega.evaluated,
                            label = info.style, relative = True )
                reaction.crossSection.add( crossSection )
                if( MT == 5 ) :
                    MT5Reaction = reaction
                elif MT in fissionMTs and haveTotalFission: # this is 1st, 2nd, etc fission but total is also present

                    from fudge.gnd.channelData.fissionEnergyReleased import fissionEnergyReleased
                    if isinstance( reaction.outputChannel.Q.evaluated, fissionEnergyReleased ):
                        Qcomponent = reaction.outputChannel.Q
                        qval = toGNDMiscModule.returnConstantQ( info.style,
                            Qcomponent.evaluated.nonNeutrinoEnergy.data.coefficients[0],
                            crossSection )
                        Qcomponent.remove( info.style )
                        Qcomponent.add( qval ) # just put the approximate constant Q-value on 1st-chance, 2nd-chance etc.

                    fissionComponents.append( reaction )
                else :
                    if( MT in summedReactionsInfo ) :
                        delayInsertingSummedReaction.append( reaction )
                    else :
                        reactions.append( [ MT, reaction ] )
        else :
            MFList = []
            for MF in [ 4, 5, 6, 12, 13, 14, 15 ] :
                if( MF in MTData ) : MFList.append( '%d' % MF )
            if( MFList != [] ) : warningList.append( 'MT = %d has MF = %s data and no MF 3 data' % ( MT, ', '.join( MFList ) ) )

        for radioactiveData in radioactiveDatas : # Get radioactive production data (if any) from MF 8-10. Cross section form depends on value of LMF.
            if( LMF in [ 3, 6, 9 ] ) :  # Cross section is reference to MF3.
                productionCrossSection = crossSectionModule.reference( link = reaction.crossSection.evaluated, label = info.style )
                linksToCheck.append( productionCrossSection )
            elif( LMF == 10 ) :         # MF10 data is cross section. Product's multipliticy is 1.
                productionCrossSection = radioactiveData[4]
            else :
                raise Exception( "Unknown LMF=%d encountered in MF=8 for MT=%d" % ( LMF, MT ) )

            ZAP = radioactiveData[0]
            ELFS = radioactiveData[1]
            LFS = radioactiveData[2]

            Q = outputChannel.Q[info.style]
            if( LMF in [ 9, 10 ] ) :
                Q = toGNDMiscModule.returnConstantQ( info.style, radioactiveData[6], crossSection )

            if( LMF == 6 ) :      # Product multiplicity is in MF6, so production channel multiplicity needs to refer to it:
                residual = toGNDMiscModule.getTypeNameGamma( info, ZAP, level = ELFS, levelIndex = LFS )
                MF6prod = outputChannel.getProductsWithName( residual.id )

                if( len( MF6prod ) != 1 ) : # problem appears in JEFF-3.2 Y90 and Y91
                    warningList.append( 'Unique MT%d radioactive product %s not found in product list!' %
                                ( MT, residual.id ) )
                    info.doRaise.append( warningList[-1] )
                    continue

                multiplicity = multiplicityModule.reference( label = info.style, link = MF6prod[0].multiplicity )
            else :
                multiplicity = radioactiveData[3]

            try :
                residual = toGNDMiscModule.newGNDParticle( info, toGNDMiscModule.getTypeNameGamma( info, ZAP, level = ELFS, levelIndex = LFS ),
                        crossSection, multiplicity = multiplicity )
            except :
                info.logs.write( '\nMT = %s\n' % MT )
                raise

            productionOutputChannel = channelsModule.productionChannel( )
            productionOutputChannel.Q.add( Q )
            productionOutputChannel.products.add( productionOutputChannel.products.uniqueLabel( residual ) )
            productionOutputChannel.process = "%s%s" % (reactionSuite.target,
                        endf_endlModule.endfMTtoC_ProductLists[MT].reactionLabel.replace('z,', reactionSuite.projectile+',') )

            production = productionModule.production( productionOutputChannel, ENDF_MT = MT )
            production.crossSection.add( productionCrossSection )
            productions.append( production )

        for warning in warningList : info.logs.write( "       WARNING: %s\n" % warning, stderrWriting = True )

    for MT, reaction in reactions :
        reactionSuite.reactions.add( reaction )

    for reaction in delayInsertingSummedReaction :
        reactionSuite.reactions.add( reaction )

    if( MT5Reaction is not None ) :
        reactionSuite.reactions.add( MT5Reaction )

# BRB, The channelIDs should be in a common area?????
    channelIDs = { 1 : 'total', 3 : 'nonelastic', 4 : '(z,n)', 103 : '(z,p)', 104 : '(z,d)', 105 : '(z,t)', 106 : '(z,He3)', 107 :'(z,alpha)' }
    if( 3 in summedReactions ) : summedReactionsInfo[3] = nonElastic
    if( ( 1 in summedReactions ) and ( 2 in MTList ) ) : summedReactionsInfo[1] = [ 2 ] + nonElastic
    summedReactionMTs = endfFileToGNDMiscModule.niceSortOfMTs( summedReactions.keys( ), verbose = False, logFile = info.logs )
    for MT in ( 4, 3, 1 ) :
        if( MT in summedReactionMTs ) :
            summedReactionMTs.remove( MT )
            summedReactionMTs.insert( 0, MT )
    for i1, MT in enumerate( summedReactionMTs ) :
        if( summedReactions[MT] is None ) : continue
        crossSection, outputChannel = summedReactions[MT]
        if( ( MT == 3 ) and ( crossSection is None ) ) : 
            crossSection = deriveMT3MF3FromMT1_2( info, reactionSuite )
        summands = [ sumsModule.add( link = r.crossSection ) for r in reactionSuite.reactions if r.ENDF_MT in summedReactionsInfo[MT] ]
        summedCrossSection = sumsModule.crossSectionSum( label = channelIDs[MT], ENDF_MT = MT,
                summands = sumsModule.listOfSummands( summandList = summands ) )
        summedCrossSection.Q.add( outputChannel.Q[info.style] )
        summedCrossSection.crossSection.add( crossSection )
        reactionSuite.sums.crossSections.add( summedCrossSection )

        gammas = []
        for product in outputChannel :
            particle = reactionSuite.PoPs[product.id]
            if( isinstance( particle, gaugeBosonModule.particle ) ) :
                gammas.append( product )
            else :
                if( product.outputChannel is not None ) :
                    for product2 in product.outputChannel :
                        particle = reactionSuite.PoPs[product2.id]
                        if( isinstance( particle, gaugeBosonModule.particle ) ) : gammas.append( product2 )
        if( len( gammas ) > 0 ) :
            productChannel = channelsModule.NBodyOutputChannel( )
            for QForm in outputChannel.Q : productChannel.Q.add( QForm )
            for gamma in gammas : productChannel.products.add( productChannel.products.uniqueLabel( gamma ) )
            productionReaction = reactionModule.reaction( productChannel, ENDF_MT = MT, label = str( i1 ) )
            crossSectionLink = crossSectionModule.reference( link = summedCrossSection.crossSection.evaluated, label = info.style )
            linksToCheck.append( crossSectionLink )
            productionReaction.crossSection.add( crossSectionLink )
            reactionSuite.orphanProducts.add( productionReaction )

    for i1, reaction in enumerate( fissionComponents ) :  # 1st-chance, 2nd-chance, etc. Convert them to fissionComponent instances:
        fissionComponent = fissionComponentModule.fissionComponent( reaction.outputChannel, reaction.ENDF_MT )
        for crossSection in reaction.crossSection : fissionComponent.crossSection.add( crossSection )
        reactionSuite.fissionComponents.add( fissionComponent )

    for i1, production in enumerate( productions ) :
        reactionSuite.productions.add( production )

    if hasattr( info, 'totalDelayedMultiplicity' ):
        prompt, delayed = [], []
        for neutron in reactionSuite.getReaction('fission').outputChannel.getProductsWithName( IDsPoPsModule.neutron ):
            link_ = sumsModule.add( link = neutron.multiplicity )
            if neutron.getAttribute('emissionMode') == tokensModule.delayedToken:
                delayed.append( link_ )
            else:
                prompt.append( link_ )

        delayedNubar = sumsModule.multiplicitySum( label = "delayed fission neutron multiplicity",
                ENDF_MT = 455, summands = sumsModule.listOfSummands(delayed) )
        delayedNubar.multiplicity.add( info.totalDelayedMultiplicity )
        reactionSuite.sums.multiplicities.add( delayedNubar )

        total = prompt + [sumsModule.add( link = delayedNubar.multiplicity )]
        totalNubar = sumsModule.multiplicitySum( label = "total fission neutron multiplicity",
                ENDF_MT = 452, summands = sumsModule.listOfSummands(total) )
        totalNubar.multiplicity.add( info.totalOrPromptFissionNeutrons['total'] )
        reactionSuite.sums.multiplicities.add( totalNubar )

    warningList = []
    try :               # Parse resonance section.
        mf2 = None
        if( 151 in MTDatas and not parseCrossSectionOnly ) :
            mf2 = MTDatas.get( 151 ).get( 2 )    # Resonance data available.
        if( mf2 ) :
            info.logs.write( '    Reading resonances (MF=2 MT=151)\n' )
            resonances, resonanceMTs = readMF2( info, mf2, warningList )
            kReconstruct = ( info.LRP == 1 )   # LRP was read in from first line of ENDF file
            if resonances.resolved: resonances.resolved.reconstructCrossSection = kReconstruct
            reactionSuite.addResonances( resonances )

            if resonances.reconstructCrossSection:
                # modify cross sections for relevant channels to indicate resonance contribution is needed:
                resonanceLink = crossSectionModule.resonanceLink( link = resonances )

                for MT in resonanceMTs :
                    MTChannels  = [ r1 for r1 in reactionSuite.reactions         if( r1.getENDL_CS_ENDF_MT()['MT'] == MT )
                                    and isinstance(r1, reactionModule.reaction) ]
                    MTChannels += [ r1 for r1 in reactionSuite.sums.crossSections   if( r1.ENDF_MT == MT ) ]
                    MTChannels += [ r1 for r1 in reactionSuite.fissionComponents if( r1.getENDL_CS_ENDF_MT()['MT'] == MT ) ]
                    if( len( MTChannels ) == 0 ) :
                        if( MT in ( 3, 18, 19 ) ) :
                            continue
                        else :
                            warningList.append( 'Unable to find channel corresponding to resonance data for MT%d' % MT )
                    elif( len( MTChannels ) == 1 ) :
                        crossSectionComponent = MTChannels[0].crossSection
                        backgroundForm = crossSectionComponent[info.style]
                        backgroundForm.label = None
                        crossSectionComponent.remove( backgroundForm.label )
                        crossSectionComponent.add( crossSectionModule.resonancesWithBackground( info.style, backgroundForm, resonanceLink ) )
                        for link in linksToCheck:
                            if link.link is backgroundForm:
                                link.link = crossSectionComponent[ info.style ]
                    else :
                        raise 'hell - FIXME'                # This may not be correct.
                        crossSectionComponent = MTChannels[0].crossSection
                        backgroundComponent = crossSectionComponent[info.style].crossSection
                        backgroundForm = backgroundComponent[info.style]
                        backgroundComponent.remove( backgroundForm.label )
                        referredXSecForm = crossSectionModule.resonancesWithBackground( info.style, backgroundForm, resonanceLink )
                        backgroundComponent.add( referredXSecForm )

    except BadResonances as e:
        warningList.append( '       ERROR: unable to parse resonances! Error message: %s' % e )
        info.doRaise.append( warningList[-1] )

    if( doCovariances ) :
        covarianceMFs = sorted( set( [mf for mt in MTDatas.values() for mf in mt.keys() if mf>30] ) )
        if covarianceMFs:
            info.logs.write( '    Reading covariances (MFs %s)\n' % ','.join(map(str,covarianceMFs) ) )
        try:
            """ parse covariances. This also requires setting up links from data to covariances, so we
            must ensure the links are synchronized """

            MTdict = {}
            for reaction in ( list( reactionSuite.reactions ) + list( reactionSuite.sums.crossSections ) + list( reactionSuite.productions ) 
                    + list( reactionSuite.fissionComponents ) ) :
                MT = reaction.ENDF_MT
                if MT in MTdict:
                    MTdict[MT].append( reaction )
                else:
                    MTdict[MT] = [reaction]
            covarianceSuite, linkData = parseCovariances( info, MTDatas, MTdict, singleMTOnly = singleMTOnly,
                    resonances = getattr( reactionSuite, 'resonances', None ) )
            if( len( covarianceSuite ) > 0 ) :
                covarianceSuite.target = str(info.target)
                covarianceSuite.projectile = str(info.projectile)
                covarianceSuite.styles.add( info.evaluatedStyle )
                #covarianceSuite.removeExtraZeros() # disable for easier comparison to ENDF
            else :
                covarianceSuite = None
        except Exception as e:
            warningList.append( "Couldn't parse covariances! Error message: %s" % e )
            info.doRaise.append( warningList[-1] )
            covarianceSuite = None
            raise
    else :
        covarianceSuite = None

    info.massTracker.useMostCommonAMUmasses()

    if( info.level > 0 ) : # AWR is for isomer mass. Adjust info.ZAMasses to GS mass:
        groundStateMass = info.massTracker.getMassAMU( info.targetZA ) - PQUModule.PQU(
            PQUModule.pqu_float.surmiseSignificantDigits( info.level ),'eV/c**2').getValueAs('amu')
        info.massTracker.addMassAMU( info.targetZA, groundStateMass )  # overwrite excited state mass

    for ZA in info.massTracker.amuMasses :
        if( ZA in [ 1 ] ) : continue
        mass = info.massTracker.amuMasses[ZA]
        elementSymbol = chemicalElementModule.symbolFromZ[ZA/1000]
        A = str( ZA % 1000 )
        name = isotopeModule.isotopeIDFromElementIDAndA( elementSymbol, A )
        name = nucleusModule.levelNameFromIsotopeNameAndIndex( name, '0' )
        mass = massModule.double( info.PoPsLabel, mass, quantityModule.stringToPhysicalUnit( 'amu' ) )
        if( name not in reactionSuite.PoPs ) : toGNDMiscModule.getPoPsParticle( info, ZA, levelIndex = 0 )
        particle = reactionSuite.PoPs[name]
        particle.mass.add( mass )

    MF12BaseMTsAndRange = [ [ 50, 92 ], [ 600, 650 ], [ 650, 700 ], [ 700, 750 ], [ 750, 800 ], [ 800, 850 ] ]

    if( singleMTOnly is None ) :
        branchingData = None
        #if( len( info.MF12_LO2 ) > 0 ) : reactionSuite.gammaBranching = {}
        for MTLO2, MF12_LO2 in sorted(info.MF12_LO2.items()) :  # The logic below assumes MTs are in ascending order per base MT.
            branchingBaseMT = None
            for MTBase, MTEnd in MF12BaseMTsAndRange :             # Determine base MT for this MTLO2
                if( MTBase < MTLO2 < MTEnd ) :
                    branchingBaseMT = MTBase
                    break
            if( branchingBaseMT is not None ) :
                residualZA = endf_endlModule.ENDF_MTZAEquation( info.projectileZA, info.targetZA, branchingBaseMT )[0][-1]
                residual = toGNDMiscModule.getTypeNameENDF( info, residualZA, None )
                residualName = residual.id
                if( isinstance( residual, nuclearLevelModule.particle ) ) : residualName = residual.getAncestor( ).id
                level = MTLO2 - branchingBaseMT
                levelName, levelEnergy = '_e%d' % level, MF12_LO2[0]['ES']
                fullName = residualName + levelName
                    # compare this value to level energy from the particle list (from MF3 Q-value).
                particleLevelEnergy_eV = reactionSuite.PoPs[fullName].energy[0].value
                if( levelEnergy != particleLevelEnergy_eV ) :
                    if( particleLevelEnergy_eV < 1e-12 ) :
                        warningList.append( "MF12 parent level energy (%s) set to zero?" % particleLevelEnergy_eV )
                        info.doRaise.append( warningList[-1] )
                    elif( abs( levelEnergy - particleLevelEnergy_eV ) < 1e-4 * particleLevelEnergy_eV ) :
                        MFLabel = '3'
                                                                                            # Value with most precision wins.
                        str1 = PQUModule.floatToShortestString( levelEnergy * 1e-20 )          # 1e-20 to insure e-form is returned.
                        str2 = PQUModule.floatToShortestString( particleLevelEnergy_eV * 1e-20 )  # Want 1.23e-16 and not 12300 to differ
                        if( len( str1 ) > len( str2 ) ) :                                   # length from 1.2345e-16 and not 12345.
                            reactionSuite.PoPs[fullName].energy[0].value = levelEnergy
                            MFLabel = '12'
                        warningList.append( "MT%d MF12 level energy %s differs from MF3 value %s. Setting to MF%s value." %
                                ( MTLO2, levelEnergy, particleLevelEnergy_eV, MFLabel ) )
                    else :
                        warningList.append( "MT%d MF12 parent level energy (%s) doesn't match known level" % ( MTLO2, particleLevelEnergy_eV ) )
                        info.doRaise.append( warningList[-1] )
                for i1, MF12 in enumerate( MF12_LO2 ) :
                    try :
                        finalLevelEnergy = MF12['ESk']
                        if( finalLevelEnergy > 0. ) :   # Find particle in the particleList with energy = finalLevelEnergy
                            finalParticles = [ lev for lev in reactionSuite.getParticle( residualName )
                                    if lev.energy.float('eV') == finalLevelEnergy ]
                            if( len( finalParticles ) == 1 ) :
                                finalParticle = finalParticles[0]
                            else :                      # No exact match, look for levels within .01% of the exact value.
                                idx = 0
                                while( True ) :
                                    idx += 1
                                    finalParticleName = residualName+'_e%i'%idx
                                    if( not reactionSuite.hasParticle( finalParticleName ) ) :
                                        warningList.append( "MF12 final level energy (%s eV) doesn't match known level when decaying out of level %s " % \
                                                ( finalLevelEnergy, MTLO2 ) )
                                        info.doRaise.append( warningList[-1] )
                                    thisLevelEnergy = reactionSuite.getParticle(finalParticleName).energy.pqu().getValueAs('eV')
                                    if( abs( thisLevelEnergy - finalLevelEnergy ) < 1e-4 * finalLevelEnergy ) :
                                        finalParticle = reactionSuite.getParticle(finalParticleName)
                                        break   # found it
                        else :
                            finalParticle = reactionSuite.getParticle(residualName+'_e0')
                        gammaTransition = 1.
                        if( len( MF12['branching'] ) > 2 ) : gammaTransition = MF12['branching'][1]

                        if( gammaTransition != 1 ) : raise Exception( 'Fix me' )
                        probability = probabilityModule.double( info.PoPsLabel, MF12['branching'][0] )

                        decayMode = decayDataModule.decayMode( str( i1 ), IDsPoPsModule.photon )
                        decayMode.probability.add( probability )
                        _decay = decayDataModule.decay( str( i1 ), decayDataModule.decayModesParticle)
                        _decay.products.add( productModule.product( IDsPoPsModule.photon, IDsPoPsModule.photon ) )
                        _decay.products.add( productModule.product( finalParticle.id, finalParticle.id ) )
                        decayMode.decayPath.add( _decay )
                        reactionSuite.PoPs[fullName].nucleus.decayData.decayModes.add( decayMode )
                    except Exception, err :
                        raise
                        warningList.append( 'raise somewhere in "for MF12 in MF12_LO2" loop: MT%d, %s' % ( MT, str( err ) ) )
                        info.doRaise.append( warningList[-1] )
            else :
                raise Exception( "Could not determine base MT for MF=12's MT=%s" % MTLO2 )