# <<BEGIN-copyright>>
# <<END-copyright>>
from __future__ import print_function
epsilonExponent = -10
energyUnit = 'eV'
import sys
import math
from pqu import PQU as PQUModule
from fudge.core.math import linearAlgebra as linearAlgebraModule
import xData.standards as standardsModule
import xData.axes as axesModule
import xData.constant as constantModule
import xData.values as valuesModule
import xData.XYs as XYsModule
import xData.regions as regionsModule
import xData.link as linkModule
import xData.multiD_XYs as multiD_XYsModule
import xData.array as arrayModule
import xData.gridded as griddedModule
import xData.uncertainties as uncertaintiesModule
from PoPs import IDs as IDsPoPsModule
from PoPs import alias as PoPsAliasModule
from PoPs.groups import misc as chemicalElementMiscPoPsModule
from fudge.gnds import physicalQuantity as physicalQuantityModule
from fudge.gnds import warning as warningModule
from fudge.gnds import externalFile as externalFileModule
import fudge.gnds.tokens as tokensModule
import fudge.gnds.resonances as resonancesModule
import fudge.gnds.sums as sumsModule
from fudge.gnds.reactionData.doubleDifferentialCrossSection.chargedParticleElastic import CoulombPlusNuclearElastic as CoulombPlusNuclearElasticModule
from fudge.gnds.reactionData.doubleDifferentialCrossSection.chargedParticleElastic import nuclearPlusInterference as nuclearPlusInterferenceModule
from fudge.gnds.reactionData.doubleDifferentialCrossSection.chargedParticleElastic import nuclearAmplitudeExpansion as nuclearAmplitudeExpansionModule
import fudge.gnds.covariances.base as covarianceBaseModule
import fudge.gnds.covariances.covarianceSuite as covarianceSuiteModule
import fudge.gnds.covariances.section as covarianceSectionModule
import fudge.gnds.covariances.summed as covarianceSummedModule
import fudge.gnds.covariances.shortRangeSelfScalingVariance as shortRangeSelfScalingVarianceModule
import fudge.gnds.covariances.mixed as covarianceMixedModule
import fudge.gnds.covariances.modelParameters as covarianceModelParametersModule
import fudge.gnds.covariances.tokens as covarianceTokensModule
import fudge.gnds.channels as channelsModule
import fudge.gnds.channelData.fissionEnergyReleased as fissionEnergyReleasedModule
import fudge.gnds.reactions.reaction as reactionModule
import fudge.gnds.reactions.production as productionModule
import fudge.gnds.reactionData.crossSection as crossSectionModule
import fudge.gnds.productData.multiplicity as multiplicityModule
from fudge.gnds.productData import energyDeposition as energyDepositionModule
import fudge.gnds.productData.distributions.unspecified as unspecifiedModule
import fudge.gnds.productData.distributions.angular as angularModule
import fudge.gnds.productData.distributions.energy as energyModule
import fudge.gnds.productData.distributions.uncorrelated as uncorrelatedModule
import fudge.gnds.productData.distributions.angularEnergy as angularEnergyModule
import fudge.gnds.productData.distributions.energyAngular as energyAngularModule
import fudge.gnds.productData.distributions.KalbachMann as KalbachMannModule
import fudge.gnds.productData.distributions.reference as referenceModule
from fudge.legacy.converting import endf_endl as endf_endlModule
from fudge.legacy.converting import toGNDSMisc as toGNDSMiscModule
from . import endfFileToGNDSMisc as endfFileToGNDSMiscModule
from site_packages.legacy.toENDF6 import ENDFconversionFlags as ENDFconversionFlagsModule
MTWithOnlyNeutonProducts = [ 2 ]
for MT in endf_endlModule.endfMTtoC_ProductLists :
if( ( endf_endlModule.endfMTtoC_ProductLists[MT]['n'] > 0 ) or endf_endlModule.endfMTtoC_ProductLists[MT].isFission ) :
MTWithOnlyNeutonProducts.append( MT )
frames = { 1 : standardsModule.frames.labToken, 2 : standardsModule.frames.centerOfMassToken }
FUDGE_EPS = endfFileToGNDSMiscModule.FUDGE_EPS
productNameToZA = { 'n' : 1, 'H1' : 1001, 'H2' : 1002, 'H3' : 1003, 'He3' : 2003, 'He4' : 2004, IDsPoPsModule.photon : 0 }
lightIsotopeNames = [ 'n', 'H1', 'H2', 'H3', 'He3', 'He4' ]
# The following is a kludge for ENDF/B-VII.1 files that are missing some MF 8 data. Namely,
# n-020_Ca_040, n-020_Ca_042, n-020_Ca_043, n-020_Ca_044, n-020_Ca_046, n-020_Ca_048,
# n-082_Pb_204, n-082_Pb_206, n-082_Pb_207 and n-082_Pb_208.
# Data for the following meta-stables are bogus as I could not find values:
# Re182_m1, Ir186_m1, Au185_m1, Hg187_m1, Hg189_m1, Hg191_m1, Tl186_m1, Tl188_m1, Tl190_m1, Tl191_m1, Tl193_m1, Tl194_m1, Pb193_m1 and Pb199_m1.
# Meta-stable energies in eV. Data as ( levelIndex, levelEnergy )
metaStableData = {
"Al26_m1" : ( 1, 228305. ), "Cl34_m1" : ( 1, 146360. ), "W179_m1" : ( 2, 221926. ), "W183_m1" : ( 7, 309493. ),
"W185_m1" : ( 6, 197383. ), "Re182_m1" : ( 1, 1000. ), "Re184_m1" : ( 5, 188010. ), "Re186_m1" : ( 4, 149000. ),
"Re188_m1" : ( 7, 172069. ), "Re190_m1" : ( 3, 210000. ), "Os181_m1" : ( 1, 49200. ), "Os183_m1" : ( 2, 170710. ),
"Os189_m1" : ( 1, 30812. ), "Os191_m1" : ( 1, 74382. ), "Ir186_m1" : ( 1, 1000. ), "Ir190_m1" : ( 2, 26100. ),
"Ir190_m2" : ( 37, 376400. ) , "Ir191_m1" : ( 3, 171240. ), "Ir192_m1" : ( 3, 56720. ), "Ir192_m2" : ( 16, 168140. ),
"Ir193_m1" : ( 2, 80239. ), "Ir194_m1" : ( 7, 147072. ), "Ir195_m1" : ( 2, 1e5 ), "Ir196_m1" : ( 4, 410000. ),
"Ir197_m1" : ( 2, 115000. ), "Pt183_m1" : ( 1, 34500. ), "Pt185_m1" : ( 2, 103410. ), "Pt193_m1" : ( 5, 149780. ),
"Pt195_m1" : ( 7, 259300. ), "Pt197_m1" : ( 9, 399590. ), "Pt199_m1" : ( 8, 424000. ), "Au185_m1" : ( 1, 1000. ),
"Au187_m1" : ( 2, 120510. ), "Au189_m1" : ( 3, 247230. ), "Au193_m1" : ( 4, 290190. ), "Au195_m1" : ( 4, 318580. ),
"Au196_m1" : ( 3, 84656. ), "Au197_m1" : ( 4, 409150. ), "Au200_m1" : ( 11, 962000. ), "Hg185_m1" : ( 4, 99300. ),
"Hg187_m1" : ( 1, 1000. ), "Hg189_m1" : ( 2, 1000. ), "Hg191_m1" : ( 1, 1000. ), "Hg193_m1" : ( 3, 140760. ),
"Hg195_m1" : ( 3, 176070. ), "Hg197_m1" : ( 4, 298930. ), "Hg199_m1" : ( 7, 532480. ), "Tl186_m1" : ( 1, 1000. ),
"Tl187_m1" : ( 2, 335009. ), "Tl188_m1" : ( 1, 1000. ), "Tl189_m1" : ( 1, 257600. ), "Tl190_m1" : ( 1, 1000. ),
"Tl191_m1" : ( 1, 1000. ), "Tl192_m1" : ( 1, 156000. ), "Tl193_m1" : ( 1, 1000. ), "Tl194_m1" : ( 1, 1000. ),
"Tl195_m1" : ( 2, 482630. ), "Tl196_m1" : ( 6, 394200. ), "Tl198_m1" : ( 7, 543500. ), "Pb187_m1" : ( 1, 81000. ),
"Pb191_m1" : ( 1, 138000. ), "Pb193_m1" : ( 1, 1000. ), "Pb195_m1" : ( 2, 202900. ), "Pb197_m1" : ( 2, 319310. ),
"Pb199_m1" : ( 1, 1000. ), "Pb201_m1" : ( 4, 629100. ), "Pb202_m1" : ( 13, 2169830. ), "Pb203_m1" : ( 6, 825200. ),
"Sc42_m1" : ( 2, 616300. ), "Sc44_m1" : ( 1, 271240. ), "Sc46_m1" : ( 1, 142528. ),
"Mn50_m1" : ( 1, 225280. ), "Mn52_m1" : ( 1, 377749. ),
"Se73_m1" : ( 1, 25710. ), "Se77_m1" : ( 1, 161922.3 ), "Se79_m1" : ( 1, 95770. ), "Se81_m1" : ( 1, 103000. ),
"Br74_m1" : ( 1, 13580. ), "Br76_m1" : ( 1, 102580. ), "Br77_m1" : ( 1, 105860. ), "Br79_m1" : ( 1, 207610. ),
"Br80_m1" : ( 1, 85843. ), "Br82_m1" : ( 1, 45949.2 ), "Br84_m1" : ( 1, 320000. ),
"Kr79_m1" : ( 1, 129770. ), "Kr81_m1" : ( 1, 190640. ), "Kr83_m1" : ( 1, 41557.5 ), "Kr85_m1" : ( 1, 304871. ),
"Rb81_m1" : ( 1, 86317.1 ), "Rb82_m1" : ( 1, 69000. ), "Rb84_m1" : ( 1, 463591. ), "Rb86_m1" : ( 1, 556051. ),
"Rb90_m1" : ( 1, 106901. ),
"Sr83_m1" : ( 1, 259151. ), "Sr85_m1" : ( 1, 238791. ), "Sr87_m1" : ( 1, 388533. ),
"Y83_m1" : ( 1, 62047.1 ), "Y85_m1" : ( 1, 196800. ), "Y86_m1" : ( 1, 218211. ), "Y87_m1" : ( 1, 380821. ),
"Y89_m1" : ( 1, 908971. ), "Y90_m1" : ( 1, 681671. ), "Y91_m1" : ( 1, 555580. ),
"Zr85_m1" : ( 1, 292281. ), "Zr87_m1" : ( 1, 335841. ), "Zr89_m1" : ( 1, 587821. ),
"Nb90_m1" : ( 1, 124670. ), "Nb91_m1" : ( 1, 104601. ), "Nb92_m1" : ( 1, 135501. ), "Nb93_m1" : ( 1, 30770.1 ),
"Mo91_m1" : ( 1, 653011. ),
"Tc90_m1" : ( 1, 100000. ), "Tc91_m1" : ( 1, 139300. ), "Tc93_m1" : ( 1, 391840. ), "Tc94_m1" : ( 1, 76000. ),
"Tc95_m1" : ( 1, 38900. ), "Tc96_m1" : ( 1, 34230. ),
"Bi192_m1" : ( 1, 147000. ), "Bi193_m1" : ( 1, 308000. ), "Bi194_m1" : ( 1, 109000. ), "Bi194_m2" : ( 2, 200000. ),
"Bi195_m1" : ( 1, 401000. ), "Bi196_m1" : ( 1, 271000. ), "Bi197_m1" : ( 1, 500000. ), "Bi198_m1" : ( 1, 100000. ),
"Bi198_m2" : ( 2, 248500. ), "Bi199_m1" : ( 1, 667000. ), "Bi200_m1" : ( 1, 428200. ), "Bi201_m1" : ( 1, 846350. ) }
crossSectionAxes = crossSectionModule.defaultAxes( energyUnit )
multiplicityAxes = multiplicityModule.defaultAxes( energyUnit )
energyDepositionAxes = energyDepositionModule.defaultAxes( energyUnit )
angularAxes = angularModule.defaultAxes( energyUnit )
energyAxes = energyModule.defaultAxes( energyUnit )
energyAngularAxes = energyAngularModule.defaultAxes( energyUnit )
angularEnergyAxes = angularEnergyModule.defaultAxes( energyUnit )
KalbachMann_f_Axes = KalbachMannModule.fSubform.defaultAxes( energyUnit )
KalbachMann_r_Axes = KalbachMannModule.rSubform.defaultAxes( energyUnit )
KalbachMann_a_Axes = KalbachMannModule.aSubform.defaultAxes( energyUnit )
fissionEnergyReleasedAxes = fissionEnergyReleasedModule.defaultAxes( energyUnit )
[docs]def particleZA( info, particleID ) :
particle = info.reactionSuite.PoPs[particleID]
return( chemicalElementMiscPoPsModule.ZA( particle ) )
[docs]class myIter:
"""Iterator that keeps track of line number."""
def __init__( self, iterable ):
self.index = 0
self.iterable = iter( iterable )
self.length = len( iterable )
[docs] def next( self ) :
next_ = self.iterable.next()
self.index += 1
return next_
# Two useful shortcuts for reading ENDF data.
funkyF = endfFileToGNDSMiscModule.sixFunkyFloatStringsToFloats
[docs]def funkyFI( a, logFile = sys.stderr ) : # read ENDF line with 2 floats and 4 ints
return( endfFileToGNDSMiscModule.sixFunkyFloatStringsToIntsAndFloats( a, [ 2, 3, 4, 5 ], logFile = logFile ) )
# create some custom Exceptions:
[docs]class BadResonances( Exception ) : pass
[docs]class BadCovariance( Exception ) : pass
[docs]class dummyCrossSection :
def __init__( self, domainMin, domainMax, unit ) :
self.__domainMin = domainMin
self.__domainMax = domainMax
self.__unit = unit
@property
def domainMin( self ) : return( self.__domainMin )
@property
def domainMax( self ) : return( self.__domainMax )
@property
def domainUnit( self ) : return( self.__unit )
[docs]def calculateZA( ZACompound, ZAOther, minus = True ) :
"""This function handles the removal (or addition) of ZAOther to ZACompound include natural compound (but not a natural other)."""
if( ( ZACompound % 1000 ) == 0 ) : ZAOther = 1000 * ( ZAOther // 1000 )
if( minus ) : return( ZACompound - ZAOther )
return( ZACompound + ZAOther )
[docs]def printAWR_mode( info, MT, MF, ZA, AWR ) :
if( info.AWR_mode is not None ) : info.AWR_mode.write( "AWR_mode:: MT: %s: MF: %s: ZA: %s: AWR: %s::\n" % ( MT, MF, ZA, AWR ) )
[docs]def nudgeValue( value, sign ) :
if( value == 0 ) : raise ValueError( 'FIXME' )
valueEpsilon = 10**( math.floor( math.log10( abs( value ) ) ) + epsilonExponent )
return( value + sign * valueEpsilon )
[docs]def getMultiplicity( multiplicity, EPrior, Ein ) :
if( isinstance( multiplicity, XYsModule.XYs1d ) ) :
return( multiplicity.evaluate( Ein ) )
elif( isinstance( multiplicity, regionsModule.regions1d ) ) :
for region in multiplicity :
if( Ein <= region.domainMax ) :
if( region.domainMax == EPrior == Ein ) : continue # Next region is the one we want.
return( region.evaluate( Ein ) )
return( 0 )
raise Exception( 'unsupported multiplicity form "%s"' % multiplicity.moniker )
[docs]def getMultiplicityPointwiseOrPieceWise( info, data, warningList ) :
regions = []
for region in data :
if( len( region ) > 1 ) : regions.append( region )
if( len( regions ) == 1 ) :
multiplicity = multiplicityModule.XYs1d( data = regions[0], label = info.style, axes = multiplicityAxes,
interpolation = regions[0].interpolation )
# BRB : fix me.
# elif( ( len( regions ) == 2 ) and ( regions[0][-1] == regions[1][0] ) and
# ( regions[0].axes[0].interpolation == regions[1].axes[0].interpolation ) ) :
# xys = regions[1].copyDataToXYs( ) # This is a XYs1d data masquerading as regions1d, convert to XYs1d.
# xys[0][0] *= ( 1 + FUDGE_EPS )
# xys = regions[0].copyDataToXYs( ) + xys
# multiplicity = multiplicityModule.XYs1d( regions = xys, axes = axea )
else :
multiplicity = multiplicityModule.regions1d( label = info.style, axes = multiplicityAxes )
for region in regions :
_region = region.copy( )
_region.axes = multiplicityAxes
multiplicity.append( _region )
return( multiplicity )
[docs]def getTotalOrPromptFission( info, MT456Data, totalOrPrompt, warningList ) :
ZA, AWR, dummy, LNU, dummy, dummy = endfFileToGNDSMiscModule.sixFunkyFloatStringsToFloats( MT456Data[0], logFile = info.logs )
ZA = int( ZA )
info.addMassAWR( ZA, AWR )
LNU = int( LNU )
info.logs.write( ' %s fission neutron data: LNU = %d\n' % ( totalOrPrompt, LNU ) )
if( LNU == 1 ) :
dataLine, polynomial = endfFileToGNDSMiscModule.getList( 1, MT456Data, logFile = info.logs )
domainMin, domainMax = 1e-5, 20e6 # BRB, these need to be set from data
fissionMultiplicity = multiplicityModule.polynomial( coefficients = polynomial['data'], label = info.style,
axes = multiplicityAxes, domainMin = domainMin, domainMax = domainMax )
else :
dataLine, TAB1, multiplicityRegions = endfFileToGNDSMiscModule.getTAB1Regions( 1, MT456Data, axes = multiplicityAxes, logFile = info.logs )
fissionMultiplicity = getMultiplicityPointwiseOrPieceWise( info, multiplicityRegions, warningList )
return( fissionMultiplicity )
[docs]def getDelayedFission( info, MT455Data, warningList ) :
info.logs.write( ' Delayed fission neutron data (MT=455)' )
MT455DataMF1 = MT455Data[1]
ZA, AWR, LDG, LNU, dummy, dummy = endfFileToGNDSMiscModule.sixFunkyFloatStringsToFloats( MT455DataMF1[0], logFile = info.logs )
ZA = int( ZA )
info.addMassAWR( ZA, AWR )
LDG, LNU = int( LDG ), int( LNU )
info.logs.write( ' LDG=%s LNU=%s' % ( LDG, LNU ) )
if( LDG != 0 ) : raise Exception( "Only energy-independent delayed fission neutrons are supported" )
if( LNU != 2 ) : raise Exception( "Only tables of delayed fission neutrons are supported" )
dataLine, decayRateData = endfFileToGNDSMiscModule.getList( 1, MT455DataMF1, logFile = info.logs )
NNF = int( decayRateData['NPL'] )
decayRates = decayRateData['data']
dataLine, TAB1, multiplicityRegions = endfFileToGNDSMiscModule.getTAB1Regions( dataLine, MT455DataMF1, logFile = info.logs, axes = multiplicityAxes )
info.totalDelayedMultiplicity = getMultiplicityPointwiseOrPieceWise( info, multiplicityRegions, warningList )
interps = [region.interpolation for region in multiplicityRegions]
if len(set(interps)) > 1:
raise Exception("Currently only one interpolation flag is supported")
nubarInterpolation = multiplicityRegions[0].interpolation
if( 5 in MT455Data ) :
delayedNeutronEnergies, weights = readMF5( info, 455, MT455Data[5], warningList, delayNeutrons = True )
weightsSum = XYsModule.XYs1d( [], axes = weights[0].axes, interpolation = weights[0].interpolation ) # Renormalize weights to sum to 1.
for weight in weights : weightsSum = weightsSum + weight
if( weightsSum.rangeMin < 0.999999 or weightsSum.rangeMax > 1.000001 ): # don't renormalize weights if they are already normalized to ENDF precision limit
for weight in weights :
for i1, xy in enumerate( weight ) : XYsModule.pointwiseXY.__setitem__( weight, i1, xy[1] / weightsSum.evaluate( xy[0] ) )
else :
delayedNeutronEnergies = len( decayRates ) * [ None ]
totalDelayedMultiplicity_ = [ region / len( decayRates ) for region in multiplicityRegions ]
nuBar = getMultiplicityPointwiseOrPieceWise( info, totalDelayedMultiplicity_, warningList )
if( len( decayRates ) > 1 ) : warningList.append( 'More than one delayed fission neutron decay time but no MF = 5 data' )
if( len( decayRates ) != len( delayedNeutronEnergies ) ) :
warningList.append( "MF1 MT455 claims %d delayed neutron groups, but MF5 MT455 claims %d groups" % \
( len( decayRates ), len( delayedNeutronEnergies ) ) )
info.doRaise.append( warningList[-1] )
decayRates = []
delayedNeutrons = []
for i1, decayRate in enumerate( decayRates ) :
energySubform = delayedNeutronEnergies[i1]
if( energySubform is not None ) :
weight = weights[i1]
weightsInterpolation = weight.interpolation
if( weightsInterpolation == standardsModule.interpolation.flatToken ) :
if( ( len( weight ) == 2 ) and ( nubarInterpolation == standardsModule.interpolation.linlinToken ) ) :
weightsInterpolation = standardsModule.interpolation.linlinToken
weight = XYsModule.XYs1d( data = [ xy for xy in weight ], axes = weight.axes )
if( weightsInterpolation != nubarInterpolation ) :
raise Exception( 'For total nubar and energy interpolation differ which is currently not supported' )
if( weightsInterpolation != standardsModule.interpolation.linlinToken ) :
raise Exception( 'For energy only "lin-lin" interpolation is supported: %s' % weightsInterpolation )
totalDelayedM = info.totalDelayedMultiplicity
if( info.totalDelayedMultiplicity.domainMax > weight.domainMax ) :
totalDelayedM = info.totalDelayedMultiplicity.domainSlice( domainMax = weight.domainMax )
if( weight.domainMax > totalDelayedM.domainMax ) : weight = weight.domainSlice( domainMax = totalDelayedM.domainMax )
if( weight.domainMin < totalDelayedM.domainMin ) :
if( len( weight ) == 2 ) :
if( weight[0][1] == weight[1][1] ) : weight = weight.domainSlice( domainMin = totalDelayedM.domainMin )
multiplicity = totalDelayedM * weight
nuBar = getMultiplicityPointwiseOrPieceWise( info, [ multiplicity ], warningList )
particle = toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameGamma( info, 1 ), nuBar, multiplicity = nuBar )
particle.addAttribute( 'emissionMode', tokensModule.delayedToken )
particle.addAttribute( 'decayRate', PQUModule.PQU( PQUModule.pqu_float.surmiseSignificantDigits( decayRate ), "1/s" ) )
if( energySubform is not None ) :
angularSubform = angularModule.isotropic2d( )
form = uncorrelated( info.style, frames[1], angularSubform, energySubform )
particle.distribution.add( form )
delayedNeutrons.append( particle )
info.logs.write( '\n' )
return( delayedNeutrons )
[docs]def getFissionEnergies( info, domainMin, domainMax, warningList ) :
"""
For NPLY = 0 this data consists of pairs ( energy, standard deviation ). The energies are:
EFR: kinetic energy of all fission fragments
ENP: energy of prompt fission neutrons
END: energy of delayed fission neutrons
EGP: energy of prompt fission gammas
EGD: energy of delayed fission gammas
EB: energy of delayed fission betas
ENU: energy of fission neutrinos
ER: EFR + ENP + END + EGP + EGD + EB, fission Q minus the neutrinos
ET: ER + ENU, total fission Q
For NPLY > 0 the fission energies are polynomials of degree NPLY in the incident energy,
and the structure of the above table is repeated, once for each polynomial coefficient.
"""
MF1Data = info.fissionEnergyReleaseData[1]
dataLine = 0
ZA, AWR, dummy, LFC, dummy, NFC = endfFileToGNDSMiscModule.sixFunkyFloatStringsToIntsAndFloats( MF1Data[dataLine], intIndices = [ 0, 5 ], logFile = info.logs )
ZA = int( ZA )
info.addMassAWR( ZA, AWR )
dataLine += 1
dummy, dummy, dummy, NPLY, N1, N2 = endfFileToGNDSMiscModule.sixFunkyFloatStringsToFloats( MF1Data[ dataLine ], logFile = info.logs )
if (N2 != (NPLY+1)*9) or (N1 != N2*2):
warningList.append( "Inconsistent N1/N2/NPLY in section MF=1 MT=458!" )
nCoeffs = int( N2 ) # total number of coefficients for all energy release components (each also has an uncertainty)
dataLine += 1
energies = endfFileToGNDSMiscModule.nFunkyFloatStringsToFloats( nCoeffs, dataLine, MF1Data, dimension = 2, logFile = info.logs )
dataLine += int( math.ceil(nCoeffs * 2 / 6.) )
FERterms = {}
monikers = ( 'promptProductKE','promptNeutronKE','delayedNeutronKE','promptGammaEnergy','delayedGammaEnergy',
'delayedBetaEnergy','neutrinoEnergy','nonNeutrinoEnergy','totalEnergy' )
for idx, moniker in enumerate( monikers ) :
coeffs, uncerts = zip( *energies[idx::9] )
poly1d = fissionEnergyReleasedModule.polynomial1d( coefficients=coeffs,
domainMin=domainMin, domainMax=domainMax, axes = fissionEnergyReleasedAxes,
coefficientUncertainties=uncerts )
Class = getattr( fissionEnergyReleasedModule, moniker )
FERterms[ moniker ] = Class( data=poly1d )
if LFC == 1: # also have tabulated distributions for some or all energy release terms
for NDCindex in range(NFC):
dataLine, TAB1, regions = endfFileToGNDSMiscModule.getTAB1Regions(dataLine, MF1Data,
allowInterpolation6=True,
logFile=info.logs, axes=fissionEnergyReleasedAxes, cls=fissionEnergyReleasedModule.XYs1d)
if len(regions) != 1:
warningList.append("Tabular fission energy release with multiple regions not yet supported!")
info.doRaise.append( warningList[-1] )
moniker = monikers[int(TAB1['L2'])-1]
Class = getattr(fissionEnergyReleasedModule, moniker)
FERterms[ moniker ] = Class( regions[0] )
return fissionEnergyReleasedModule.fissionEnergyReleased( label = info.style, **FERterms )
[docs]def angularLegendrePiecewiseToPointwiseIfPossible( piecewiseForm ) :
if( len( piecewiseForm ) != 1 ) : return( piecewiseForm )
pointwise = angularModule.XYs2d( axes = angularAxes )
for series in piecewiseForm[0] : pointwise.append( series )
return( pointwise )
[docs]def angularLegendreToPointwiseOrPiecewiseLegendre( MT, angularData, warningList, MF, msg, subformPointwise = None ) :
regions = [] # list of regions.
i1 = 0
priorEnergy = -1
lists = angularData['Lists']
try :
for i2, interpolationFlag in angularData['interpolationInfo'] :
if( interpolationFlag > 5 ) : raise Exception( 'Unsupported interpolation = %s for MF=%s, MT=%s' % ( interpolationFlag, MF, MT ) )
interpolationQualifier, interpolationEin = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS2plusd( interpolationFlag )
region = [ interpolationQualifier, interpolationEin, [] ]
if( i1 > 0 ) :
if( lists[i1]['C2'] != lastRegion[0] ) : region[2].append( lastRegion )
for i3 in range( i1, i2 ) :
energy, coefficients = lists[i3]['C2'], [ 1.0 ] + lists[i3]['data']
if( energy == priorEnergy ) :
if( coefficients == lastRegion[-1] ):
continue
if len(region[2]) > 1: regions.append( region )
region = [ interpolationQualifier, interpolationEin, [] ]
lastRegion = ( energy, coefficients )
region[2].append( lastRegion )
priorEnergy = energy
if len(region[2]) > 1: regions.append( region )
i1 = i2
except ValueError as err :
warningList.append( 'ValueError occurred when constructing LegendreSeries: %s' % err )
raise
if( ( len( regions ) == 1 ) and ( subformPointwise is None ) ) :
interpolationQualifier, interpolationEin, region = regions[0]
subformLegendre = angularModule.XYs2d( axes = angularAxes, interpolation = interpolationEin,
interpolationQualifier = interpolationQualifier )
for i1, ( energy, coefficients ) in enumerate( region ) :
subformLegendre.append( angularModule.Legendre( axes = angularAxes, coefficients = coefficients, value = energy ) )
else :
subformLegendre = angularModule.regions2d( axes = angularAxes )
for i1, regionInfo in enumerate( regions ) :
interpolationQualifier, interpolationEin, region = regionInfo
LegendreRegion = angularModule.XYs2d( axes = angularAxes, interpolation = interpolationEin,
interpolationQualifier = interpolationQualifier )
for i2, ( energy, coefficients ) in enumerate( region ) :
LegendreRegion.append( angularModule.Legendre( axes = angularAxes, coefficients = coefficients, value = energy ) )
subformLegendre.append( LegendreRegion )
if( subformPointwise is not None ) :
if( isinstance( subformPointwise, angularModule.regions2d ) ) :
raise NotImplementedError( 'hell - need to implement this' )
else :
region = angularModule.XYs2d( interpolation = subformPointwise.interpolation,
interpolationQualifier = subformPointwise.interpolationQualifier, axes = angularAxes )
for data in subformPointwise : region.append( data )
subformLegendre.append( region )
return( subformLegendre )
[docs]def convertNuclearPlusInterferenceDataToPiecewise( MT, angularData, warningList, MF, msg, identicalParticles ) :
"""
Return three terms (nuclear + real/imaginary interference). These in turn contain
Legendre expansions at various incident energies.
"""
axes = angularAxes
nuclear = angularModule.regions2d( axes = axes )
interferenceReal = angularModule.regions2d( axes = axes )
interferenceImaginary = angularModule.regions2d( axes = axes )
index, start, lastRegion = 0, 0, None
lists = angularData['Lists']
for end, interpolationFlag in angularData['interpolationInfo'] :
interpolationQualifier, interpolationE_in = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS2plusd( interpolationFlag )
if( interpolationFlag > 6 ) : raise Exception( 'Unsupported interpolation = %s for MF=%s, MT=%s' % ( interpolationFlag, MF, MT ) )
#interpolationE_in, interpolationCl, interpolationQualifier = endfFileToGNDSMiscModule.ENDFInterpolationToGNDSAxes3plusd( interpolationFlag )
region_Nuc = angularModule.XYs2d( interpolation = interpolationE_in, axes = axes )
region_IntReal = angularModule.XYs2d( interpolation = interpolationE_in, axes = axes )
region_IntImaginary = angularModule.XYs2d( interpolation = interpolationE_in, axes = axes )
priorEnergy = -1
if( lastRegion is not None ) :
if( lists[start]['C2'] != lastRegion ) : # ensure no gaps between regions
region_Nuc.append( angularModule.Legendre( coefficients = nuclear_term, value = lastRegion, axes = axes ) )
region_IntReal.append( angularModule.Legendre( coefficients = interference_termReal, value = lastRegion, axes = axes ) )
region_IntImaginary.append( angularModule.Legendre( coefficients = interference_termImaginary, value = lastRegion, axes = axes ) )
for idx in range( start, end ) :
list = lists[idx]
energy = list['C2']
if( energy == priorEnergy ) : # This fixes a problem with some data having two same energy values.
energy += FUDGE_EPS * energy
warningList.append( 'same energies, second one being incremented for MT = %d, MF = %d, %s' % ( MT, MF, msg ) )
priorEnergy = energy
if( identicalParticles ) :
splitPoint = list['N2'] + 1
else :
splitPoint = list['N2'] * 2 + 1
nuclear_term = list['data'][:splitPoint]
if( identicalParticles ) : # nuclear_term only stores even-L coefficients. Add extra zeros for odd-L:
newList = [nuclear_term[0]]
for coef in nuclear_term[1:]: newList.extend([0,coef])
nuclear_term = newList
interference_term, interference_termReal, interference_termImaginary = list['data'][splitPoint:], [], []
for jdx in range( 0, len( interference_term ), 2 ) :
interference_termReal.append( interference_term[jdx] )
interference_termImaginary.append( interference_term[jdx+1] )
region_Nuc.append( angularModule.Legendre( coefficients = nuclear_term, value = energy, axes = axes ) )
region_IntReal.append( angularModule.Legendre( coefficients = interference_termReal, value = energy, axes = axes ) )
region_IntImaginary.append( angularModule.Legendre( coefficients = interference_termImaginary, value = energy, axes = axes ) )
lastRegion = energy
nuclear[index] = region_Nuc
interferenceReal[index] = region_IntReal
interferenceImaginary[index] = region_IntImaginary
index += 1
start = end
nuclear = nuclearAmplitudeExpansionModule.nuclearTerm( angularLegendrePiecewiseToPointwiseIfPossible( nuclear ) )
interferenceReal = nuclearAmplitudeExpansionModule.realInterferenceTerm(
angularLegendrePiecewiseToPointwiseIfPossible( interferenceReal ) )
interferenceImaginary = nuclearAmplitudeExpansionModule.imaginaryInterferenceTerm(
angularLegendrePiecewiseToPointwiseIfPossible( interferenceImaginary ) )
return( nuclear, interferenceReal, interferenceImaginary )
[docs]def convertAngularToPointwiseOrPiecewiseFromTAB2_TAB1( MT, angularTAB1, warningList ) :
angularData = angularTAB1['TAB2s']
if( len( angularData ) == 1 ) :
interplation, angularData = angularData[0] # BRB: need to check interpolation?
subform = angularModule.XYs2d( axes = angularAxes )
for xys in angularData :
if( len( xys ) > 1 ) : raise NotImplementedError( 'hell - need to support this' )
xys = xys[0]
xys = angularModule.XYs1d( data = xys, axes = angularAxes, interpolation = xys.interpolation, value = xys.value )
subform.append( xys )
else :
raise NotImplementedError( 'hell - regions2d tabulated angular not currently supported' )
return( subform )
[docs]def convertAngularToPointwiseOrPiecewiseFromTAB2_List( MT, LANG, angularList, warningList ) :
"""
Like convertAngularToPointwiseOrPiecewiseFromTAB2_TAB1 except mu,P given as LISTs instead of TAB1s.
"""
angularData = angularList['Lists']
try :
interpolation = { 12 : 2, 14 : 4 }[LANG]
except :
print( 'interpolation = LANG %d' % LANG )
raise NotImplementedError( 'hell - what is this and how does it differ from 12' )
interpolation = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS1d( interpolation )
subform = angularModule.XYs2d( axes = angularAxes )
e_in_Prior = -1
for i1, list in enumerate( angularData ) :
LANG_e_in = int( list['L1'] )
if( LANG_e_in != LANG_e_in ) : raise NotImplementedError( 'hell - need to implement this' )
e_in = list['C2']
if( e_in == e_in_Prior ) : raise NotImplementedError( 'hell - need to implement this' )
data = list['data']
if( MT == 526 ) : # Some MT 526 have data like '0.999998+0 2.046010+5 0.999998+0 2.870580+5' which this fixes.
j1, j2 = None, None
for j3 in range( 0, len( data ), 2 ) :
if( j2 is not None ) :
if( data[j2] == data[j3] ) : data[j2] -= 0.5 * ( data[j2] - data[j1] )
j1, j2 = j2, j3
xys = angularModule.XYs1d( data = list['data'], dataForm = 'list', axes = angularAxes,
interpolation = interpolation, value = e_in )
subform.append( xys )
e_in_Prior = e_in
return( subform )
[docs]def toPointwiseOrPiecewiseEnergy( MT, TAB2 ) :
def getEpP( energyPrior, data ) :
EpP = data[0]
energy = float( EpP.value )
if( len( data ) == 1 ) :
EpP = energyModule.XYs1d( data = EpP, interpolation = EpP.interpolation, value = energy, axes = energyAxes )
else :
EpP = energyModule.regions1d( value = energy, axes = energyAxes )
for datum in data :
EpP.append( energyModule.XYs1d( data = datum, interpolation = datum.interpolation, axes = energyAxes ) )
return( energy, EpP )
axes = energyAxes
if( TAB2['NR'] == 1 ) :
interpolation, data = TAB2['TAB2s'][0]
interpolationQualifier, interpolation = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS2plusd( interpolation )
subform = energyModule.regions2d( axes = axes )
subformRegion = energyModule.XYs2d( axes = axes, interpolation = interpolation,
interpolationQualifier = interpolationQualifier )
energyPrior = -1
for EpP in data :
EIn = float( EpP[0].value )
if( EIn == energyPrior ) :
if( len( subformRegion ) > 1 ) : subform.append( subformRegion )
subformRegion = energyModule.XYs2d( axes = axes, interpolation = interpolation, interpolationQualifier = interpolationQualifier )
energyPrior = -1
energyPrior, EpPp = getEpP( energyPrior, EpP )
subformRegion.append( EpPp )
if( len( subform ) == 0 ) :
subform = subformRegion
else :
subform.append( subformRegion )
else :
subform = energyModule.regions2d( axes = axes )
TAB2s = TAB2['TAB2s']
for i1, ( interpolation, TAB1s ) in enumerate( TAB2s ) :
interpolationQualifier, interpolation = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS2plusd( interpolation )
region = energyModule.XYs2d( axes = axes, interpolation = interpolation, interpolationQualifier = interpolationQualifier )
energyPrior = -1
for EpP in TAB1s :
energyPrior, EpPp = getEpP( energyPrior, EpP )
region.append( EpPp )
subform.append( region )
return( subform )
[docs]def discreteOrPrimaryGamma( cls, energy, domainMin, domainMax ) :
energySubform = cls( energy, domainMin, domainMax, axes = energyAxes )
return( energySubform )
[docs]def translateENDFJpi( I, P ):
# endf uses weird convention for Jpi. Translate to simpler version:
spin = abs(I)
if I: parity = abs(I) / I
else: parity = P or 1 # if (I,P)=(0,0) treat as '0+'
return resonancesModule.spin(spin), resonancesModule.parity(parity)
[docs]def readMF2( info, MF2, warningList ) :
"""
parse MF2 into resonances class (and sub-classes)
"""
from xData import table as tableModule
# store MT #s for all reactions that need to include resonance data:
resonanceMTs = set()
# check for inconsistent spins
targetSpins = set()
scatteringRadiusAxes = axesModule.axes( labelsUnits={ 1: ('energy_in','eV'), 0: ('radius','fm') } )
def readResonanceSection( LRU, LRF, NRO, NAPS ):
"""Helper function, read in resonance info for one energy range."""
scatRadius = None
if NRO!=0: # energy-dependent scattering radius
if NAPS==2: raise BadResonances("NAPS=2 option not yet supported!")
line1 = mf2.next()
dum, dum, dum, dum, NR, NP = funkyFI( line1, logFile = info.logs )
nLines = NR//3 + bool(NR%3) + NP//3 + bool(NP%3)
data = [line1] + [mf2.next() for i in range(nLines)]
dataLine, TAB1, regions = endfFileToGNDSMiscModule.getTAB1Regions( 0, data,
axes = axesModule.axes( labelsUnits={ 1: ('energy_in','eV'), 0: ('radius','10*fm') } ),
logFile = info.logs )
if TAB1['NR']!=1:
raise NotImplementedError("multi-region scattering radius")
data = regions[0]
data = data.convertAxisToUnit(0,'fm')
scatRadius = resonancesModule.scatteringRadius( data )
if LRU==0: # scattering radius only. Note AP given in 10*fm
SPI, AP, dum, dum, NLS, dum = funkyFI( mf2.next(), logFile = info.logs )
targetSpins.add( SPI )
info.particleSpins['target'] = ( resonancesModule.spin(SPI), 0 ) # no parity information
return AP*10, None
elif LRU==1 and LRF in (1,2): #SLBW or MLBW form
SPI, AP, dum, dum, NLS, dum = funkyFI( mf2.next(), logFile = info.logs )
targetSpins.add( SPI )
info.particleSpins['target'] = ( resonancesModule.spin(SPI), 0 )
resList = []
negativeJs = False
for lidx in range(NLS):
AWRI, QX, L, LRX, tmp, NRS = funkyFI( mf2.next(), logFile = info.logs )
if tmp!=6*NRS:
raise BadResonances( "incorrect values in resonance section line %d" % mf2.index )
for line in range(NRS):
e,j,gtot,gn,gg,gf = funkyF( mf2.next(), logFile = info.logs )
if j<0: negativeJs = True
resList.append( [e,L,j,gtot,gn,gg,gf] )
if negativeJs: raise BadResonances("Encountered negative J-values for SLBW/MLBW")
table = tableModule.table(
columns = [
tableModule.columnHeader( 0, name="energy", unit="eV" ),
tableModule.columnHeader( 1, name="L", unit="" ),
tableModule.columnHeader( 2, name="J", unit="" ),
tableModule.columnHeader( 3, name="totalWidth", unit="eV" ),
tableModule.columnHeader( 4, name="neutronWidth", unit="eV" ),
tableModule.columnHeader( 5, name="captureWidth", unit="eV" ),
tableModule.columnHeader( 6, name="fissionWidth", unit="eV" ), ],
data = sorted(resList, key=lambda(res): res[0]) ) # sort by energy only
for column in ("totalWidth","fissionWidth"):
if not any( table.getColumn(column) ):
table.removeColumn(column)
if LRF==1: approximation = resonancesModule.BreitWigner.singleLevel
else: approximation = resonancesModule.BreitWigner.multiLevel
return AP*10, resonancesModule.BreitWigner( info.style, approximation, resonancesModule.resonanceParameters(table),
scatteringRadius=scatRadius, calculateChannelRadius=not(NAPS) )
elif LRU==1 and LRF==3: # Reich-Moore form, convert it to look like LRF=7
from fudge.processing.resonances.reconstructResonances import getAllowedTotalSpins
ENDFconversionFlags = ['LRF3']
SPI, AP, LAD, dum, NLS, NLSC = funkyFI( mf2.next(), logFile = info.logs )
if NLSC:
ENDFconversionFlags.append('LvaluesNeededForConvergence=%d' % NLSC)
targetSpins.add( SPI )
info.particleSpins['target'] = ( resonancesModule.spin(SPI), 0 ) # store spin in GNDS particle list
assert NRO==0
resDict = {}
LdependentAP = {}
haveFission = False
for lidx in range(NLS):
AWRI, APL, L, dum, tmp, NRS = funkyFI( mf2.next(), logFile = info.logs )
if tmp!=6*NRS:
raise BadResonances("incorrect values in resonance section line %d" % mf2.index)
if APL:
LdependentAP[L] = APL
for line in range(NRS):
e,j,gn,gg,gf1,gf2 = funkyF( mf2.next(), logFile = info.logs )
if (gf1 or gf2): haveFission = True
channelSpin = SPI + math.copysign(0.5, j)
if j==0:
if SPI-L==0.5:
channelSpin = SPI-0.5
elif SPI-L==-0.5:
channelSpin = SPI+0.5
else:
raise ValueError( "Can't couple L=%s and S=%s to J=%s!" % (L,channelSpin,j) )
resDict.setdefault(L,{}).setdefault(abs(j),{}).setdefault(channelSpin,[]).append(
[e,gg,gn,gf1,gf2] )
for J in resDict[L]:
for channelSpin in resDict[L][J]:
if J not in getAllowedTotalSpins( L, channelSpin, useFactor2Trick=False ):
# some evaluations don't indicate anything about channel spin, need to determine manually:
if J in getAllowedTotalSpins( L, SPI-0.5, useFactor2Trick=False ):
newChannelSpin = SPI-0.5
resDict[L][J][newChannelSpin] = resDict[L][J][channelSpin]
del resDict[L][J][channelSpin]
if 'ignoreChannelSpin' not in ENDFconversionFlags:
ENDFconversionFlags.append('ignoreChannelSpin')
else:
raise ValueError( "Can't couple L=%s and S=%s to J=%s!" % (L,channelSpin,j) )
for L in range(max(NLS,NLSC)):
if L not in resDict: resDict[L] = {}
gsum = 0
targetGSum = (2*L+1) * (2 * (2*SPI+1))
for J in resDict[L]:
for S in resDict[L][J]:
gsum += (2*J+1)
if gsum < targetGSum: # add extra spin groups (with no resonances) for potential scattering:
for S in (SPI-0.5, SPI+0.5):
if S < 0: continue
J = abs(L - S)
jmax = L + S
while True:
jdict = resDict[L].setdefault(J,{})
if S not in jdict:
jdict[S] = []
gsum += (2*J+1)
J += 1
if J > jmax: break
if gsum != targetGSum:
raise ValueError( "Method to fix missing gfactor failed! gsum should be %f, is %f" %
(2*L+1,gsum / (2 * (2*SPI+1) ) ) )
if LdependentAP:
ENDFconversionFlags.append('explicitAPL')
if AP==0:
ENDFconversionFlags.append('AP=0')
AP = LdependentAP[0]
resonanceReactions = resonancesModule.resonanceReactions()
mts = [102,2]
if haveFission: mts.append( 18 )
for MT in mts:
gndsChannel, = [chan for chan in info.reactionSuite.reactions if chan.ENDF_MT == MT]
eliminated = (MT==102)
if MT==2: ejectile = 'n'
elif MT==102: ejectile = 'photon'
else: ejectile = None
reactionLink = linkModule.link(gndsChannel)
resonanceReactions.add(
resonancesModule.resonanceReaction( label=gndsChannel.label, reactionLink=reactionLink,
ejectile=ejectile, computeShiftFactor=False, eliminated=eliminated,
scatteringRadius=None )
)
columnHeaders = [
tableModule.columnHeader(0, name="energy", unit="eV"),
tableModule.columnHeader(1, name="capture width", unit="eV"),
tableModule.columnHeader(2, name="elastic width", unit="eV"),
tableModule.columnHeader(3, name="fission width_1", unit="eV"),
tableModule.columnHeader(4, name="fission width_2", unit="eV"),
]
targetParity = 1 # parity is not usually stored in ENDF-6 (exception: LRF=7). For now assume it's positive
if len(info.PoPs[info.target].nucleus.parity) > 0:
targetParity = info.PoPs[info.target].nucleus.parity[0].value
jdx = 0
spinGroups = resonancesModule.spinGroups()
for L in sorted(resDict.keys()):
for J in sorted(resDict[L].keys(), key=lambda val: abs(val)):
for channelSpin in sorted(resDict[L][J].keys()):
table = tableModule.table(columns=columnHeaders[:], data=resDict[L][J][channelSpin])
channels = resonancesModule.channels()
channels.add( resonancesModule.channel("0", resonanceReactions[0].label, columnIndex=1,
L=int(L), channelSpin=resonancesModule.spin(1)) ) # capture
channels.add( resonancesModule.channel("1", resonanceReactions[1].label, columnIndex=2,
L=int(L), channelSpin=resonancesModule.spin(channelSpin)) )
if L in LdependentAP and LdependentAP[L] != AP:
APL = constantModule.constant1d( LdependentAP[L] * 10, domainMin=EL, domainMax=EH,
axes=scatteringRadiusAxes )
channels[-1].scatteringRadius = resonancesModule.scatteringRadius( APL )
channels[-1].hardSphereRadius = resonancesModule.hardSphereRadius( APL )
if haveFission:
channels.add( resonancesModule.channel("2", resonanceReactions[2].label,
columnIndex=3, L=0, channelSpin=resonancesModule.spin(0)) )
if any( table.getColumn('fission width_2') ):
channels.add( resonancesModule.channel("3", resonanceReactions[2].label,
columnIndex=4, L=0, channelSpin=resonancesModule.spin(0)) )
else:
table.removeColumn('fission width_2')
else:
table.removeColumn('fission width_2')
table.removeColumn('fission width_1')
parity = targetParity * (-1)**L
spinGroups.add( resonancesModule.spinGroup(str(jdx), resonancesModule.spin(abs(J)),
resonancesModule.parity(parity), channels, resonancesModule.resonanceParameters(table)) )
jdx += 1
rmatrix_ = resonancesModule.RMatrix( info.style, resonanceReactions, spinGroups,
approximation="Reich_Moore",
calculateChannelRadius=not(NAPS), supportsAngularReconstruction=bool(LAD),
LvaluesNeededForConvergence=NLSC, relativisticKinematics=False,
reducedWidthAmplitudes=False, boundaryCondition="S" )
if ENDFconversionFlags:
info.ENDFconversionFlags.add( rmatrix_, ",".join(ENDFconversionFlags) )
return AP*10, rmatrix_
elif LRU==1 and LRF==4: # Adler-Adler, not currently supported
raise BadResonances( "Adler-Adler resonance formalism not yet supported!" )
elif LRU==1 and LRF==7: # R-Matrix Limited
dum,dum,IFG,KRM,NJS,KRL = funkyFI( mf2.next(), logFile = info.logs )
if KRM==3:
approximation = 'Reich_Moore'
elif KRM==4:
approximation = 'Full R-Matrix'
else:
raise BadResonances( "R-Matrix with KRM=%d not yet implemented!\n" % KRM )
dum,dum,NPP,dum,tmp1,tmp2 = funkyFI( mf2.next(), logFile = info.logs )
if tmp1!=12*NPP or tmp2!=2*NPP:
raise BadResonances( "incorrect LRF7 header!" )
# some helper functions:
def getOutgoingParticles( MT, targZA, projZA ):
reacStr = endf_endlModule.ENDF_MTZAEquation(projZA,targZA, MT)[1]
outgoing = reacStr.split('->')[1].strip()
pA, pB = outgoing.split()[::2]
return pA, pB
# ENDF R-Matrix starts by listing outgoing particle pairs
# these are referred back to later on:
resonanceReactions = resonancesModule.resonanceReactions()
PNTs, SHFs = [], []
for idx in range(NPP):
MA, MB, ZA, ZB, IA, IB = funkyF( mf2.next(), logFile = info.logs )
Q, PNT, SHF, MT, PA, PB = funkyF( mf2.next(), logFile = info.logs )
MT = int(MT)
resonanceMTs.add(MT)
PNTs.append( PNT )
if SHF==-1: SHF=0 # format changed between ENDF-5 and -6, some evaluations still have old version
SHFs.append( SHF )
# identify the channel using ZA and MT:
pA,pB = getOutgoingParticles( MT, int( ZAM ), info.projectileZA )
# get target spin. In future, this should already be present in particle list
info.particleSpins[pA] = translateENDFJpi(IA,PA)
if MT != 102: # spin/parity of 2nd particle are always 0 for capture in ENDF
info.particleSpins[pB] = translateENDFJpi(IB,PB)
# note: ZA and ZB in ENDF are charges, not ZA numbers. Compute ZA and add to particle mass dictionary:
ZA_A, ZA_B = endf_endlModule.ENDF_MTZAEquation(int(ZAM),info.projectileZA, MT)[0]
# ZA_A and ZA_B may not be in the same order as MA and MB, need to figure which ones go together
if ZA != ZB:
if (ZA_A // 1000) == ZB: ZA_A, ZA_B = ZA_B, ZA_A
else: # two isotopes, so higher A goes with larger mass
if ZA_A > ZA_B: ZA_A, ZA_B = ZA_B, ZA_A
if MA > MB: MA, MB = MB, MA
info.addMassAWR(ZA_A, MA)
info.addMassAWR(ZA_B, MB)
channelName = "%s + %s" % (pA,pB)
gndsChannel, = [chan for chan in info.reactionSuite.reactions if chan.ENDF_MT == MT]
Qval = None
eliminated = (KRM==3 and MT==102)
if Q==0 and gndsChannel.outputChannel.Q.evaluated.constant >= 0: pass
elif gndsChannel.outputChannel.Q.evaluated.constant != Q:
warningList.append("Resonance region Q-value doesn't match the rest of the evaluation")
originalQ = gndsChannel.outputChannel.Q.evaluated
newQ = channelsModule.QModule.constant1d( Q, domainMin=originalQ.domainMin,
domainMax=originalQ.domainMax, axes=originalQ.axes.copy(), label=info.style )
Qval = channelsModule.QModule.component()
Qval.add( newQ )
reactionLink = linkModule.link(gndsChannel)
resonanceReactions.add(
resonancesModule.resonanceReaction( label=channelName, reactionLink=reactionLink,
ejectile=pA, computeShiftFactor=bool(SHF), Q=Qval, eliminated=eliminated ) )
# next we have NJS spin groups, each containing channels and resonances
spinGroups = resonancesModule.spinGroups()
radii = {}
boundaryConditions = []
for spinGroupIndex in range(NJS):
# read scattering radius, binding, etc:
AJ, PJ, KBK, KPS, tmp, NCH = funkyFI( mf2.next(), logFile = info.logs )
if KBK != 0:
raise NotImplementedError("KBK != 0 in resonances LRF=7")
if KPS != 0:
raise NotImplementedError("KPS != 0 in resonances LRF=7")
if tmp!=6*NCH:
raise BadResonances("incorrect LRF7 header, line %d" % mf2.index)
channels = resonancesModule.channels()
columnHeaders = [ tableModule.columnHeader(0, name="energy", unit="eV") ]
channelNames = []
for idx in range(NCH):
IPP, L, SCH, BND, APE, APT = funkyF( mf2.next(), logFile = info.logs )
thisChannel = resonanceReactions[int(IPP)-1]
BC = None
if BND not in (0, -L):
BC = BND
channels.add( resonancesModule.channel(str(idx), thisChannel.label, columnIndex=idx+1, L=int(L),
channelSpin=resonancesModule.spin(SCH), boundaryConditionOverride = BC) )
channelName = "%s width" % thisChannel.label
jdx = 2
while True:
if channelName not in channelNames:
channelNames.append( channelName ); break
channelName = '%s width_%d' % (thisChannel.label, jdx)
jdx += 1
radii.setdefault(thisChannel, []).append( (channels[-1], APT*10, APE*10) )
boundaryConditions.append( (L,BND) )
columnHeaders.append( tableModule.columnHeader(idx+1, name=channelName, unit="eV") )
# resonances for this J:
dum,dum,dum,NRS,tmp,NX = funkyFI( mf2.next(), logFile = info.logs )
if tmp!=6*NX:
raise BadResonances("incorrect LRF7 header, line %d" % mf2.index)
if NRS==0: mf2.next() # skip empty line
resonances = []
for i in range(NRS):
nlines = int(math.ceil( (NCH+1)/6.0 )) # Extra "1" is for the Eres column
vals = []
for j in range(nlines):
vals += funkyF( mf2.next(), logFile = info.logs )
resonances.append( vals[:NCH+1] )
table = tableModule.table( columns=columnHeaders, data=resonances )
# done with this spin group:
J, pi = translateENDFJpi(AJ,PJ)
spinGroups.add( resonancesModule.spinGroup(str(spinGroupIndex), J, pi, channels,
resonancesModule.resonanceParameters(table) ) )
# Use elastic scattering radius as 'default' value for entire resonance section
from collections import Counter
elastic, = [reac for reac in resonanceReactions if reac.reactionLink.link.ENDF_MT == 2]
dum, trueRad, dum = zip(*radii[elastic])
AP = Counter(trueRad).most_common(1)[0][0]
# for each resonanceReaction, store default value for true radius and effective radius.
# Only include them in specific channels if we need to override the default value.
for resonanceReac in resonanceReactions:
channel, trueRad, effRad = zip(*radii[resonanceReac])
if not any(trueRad) and not any(effRad): continue # ignore radii for (n,gamma)
APTmostCommon = Counter(trueRad).most_common(1)[0][0]
if APTmostCommon != AP:
resonanceReac.scatteringRadius = resonancesModule.scatteringRadius(
constantModule.constant1d(APTmostCommon, domainMin=EL, domainMax=EH, axes=scatteringRadiusAxes)
)
APEmostCommon = Counter(effRad).most_common(1)[0][0]
if APEmostCommon != APTmostCommon:
resonanceReac.hardSphereRadius = resonancesModule.hardSphereRadius(
constantModule.constant1d(APEmostCommon, domainMin=EL, domainMax=EH, axes=scatteringRadiusAxes)
)
for (channel,val1,val2) in radii[resonanceReac]:
if val1 != APTmostCommon:
channel.scatteringRadius = resonancesModule.scatteringRadius(
constantModule.constant1d(val1, domainMin=EL, domainMax=EH, axes=scatteringRadiusAxes)
)
if val2 != APEmostCommon:
channel.hardSphereRadius = resonancesModule.hardSphereRadius(
constantModule.constant1d(val2, domainMin=EL, domainMax=EH, axes=scatteringRadiusAxes)
)
# determine boundary condition. Most common: all == 0 or -L
irregular = [bc for bc in boundaryConditions if bc[1] not in (0,-bc[0])]
for tmp in irregular: boundaryConditions.remove(tmp)
Ls, BCs = zip(*boundaryConditions)
BCset = set(BCs)
BCset_irregular = set()
if len(irregular) > 0:
Ls_irregular, BCs_irregular = zip(*irregular)
BCset_irregular = set(BCs_irregular)
if BCset == {0}: # BND = SHF, SAMMY convention
boundaryCondition = 'S'
elif all([shf==2 for shf in SHFs]):
raise NotImplementedError("Brune transform (SHF=2) proposed but not yet implemented")
elif all( [L==-BC for L,BC in boundaryConditions] ):
boundaryCondition = '-L'
elif len(BCset) == 0 and len(BCset_irregular) == 1: # non-zero constant boundary condition for all channels
boundaryCondition = BCset_irregular.pop()
for sg in spinGroups:
for chan in sg.channels:
chan.boundaryConditionOverride = None
else:
raise Exception("Can't decipher boundary condition!")
calculatePenetrability=any(PNTs)
# end of spin groups. write RMatrix class:
return AP, resonancesModule.RMatrix(info.style, resonanceReactions, spinGroups, approximation=approximation,
relativisticKinematics=bool(KRL), reducedWidthAmplitudes=bool(IFG),
calculateChannelRadius=not(NAPS), boundaryCondition=boundaryCondition,
calculatePenetrability=calculatePenetrability,
supportsAngularReconstruction=True)
elif LRU==2: # unresolved
levelSpacingAxes = axesModule.axes(labelsUnits={1:('energy_in','eV'), 0:('levelSpacing','eV')})
widthAxes = axesModule.axes(labelsUnits={1:('energy_in','eV'), 0:('average width','eV')})
resonanceReactions = resonancesModule.resonanceReactions()
resonanceReactionLabels = {}
for MT in (2, 102, 18): # ENDF-6 also supports a 'competitive' channel, but it is not associated with any reaction
gndsChannel = [reac for reac in info.reactionSuite.reactions if reac.ENDF_MT == MT]
if not gndsChannel: continue
gndsChannel, = gndsChannel
resonanceReactionLabels[MT] = gndsChannel.label
reactionLink = linkModule.link(gndsChannel)
resonanceReactions.add(
resonancesModule.resonanceReaction(label=gndsChannel.label, reactionLink=reactionLink,
ejectile=None))
L_list = resonancesModule.URR_Lsections()
LRF_LFW = "LRF%d,LFW%d" % (LRF, LFW)
SPI,AP,LSSF,dum,NE,NLS = funkyFI( mf2.next(), logFile = info.logs )
info.LSSF = bool(LSSF)
targetSpins.add( SPI )
if info.target not in info.particleSpins:
info.particleSpins[info.target] = ( resonancesModule.spin(SPI), 0 )
if NRO==0:
scatRadius = resonancesModule.scatteringRadius(
constantModule.constant1d(AP*10, domainMin=EL, domainMax=EH, axes=scatteringRadiusAxes) )
if LFW==0 and LRF==1: # 'Case A', see ENDF 2017 manual page 76
NLS = NE
for lidx in range(NLS):
J_list = resonancesModule.URR_Jsections()
AWRI, dum, L, dum, tmp, NJS = funkyFI( mf2.next(), logFile = info.logs )
if tmp!=6*NJS:
raise BadResonances("bad unresolved flag, line %d" % mf2.index)
for jidx in range(NJS):
D,AJ,AMUN,GNO,GG,dum = funkyF( mf2.next(), logFile = info.logs )
levelSpacing = resonancesModule.levelSpacing(
XYsModule.XYs1d([[EL,D],[EH,D]], axes=levelSpacingAxes) )
widths = resonancesModule.URR_widths()
widths.add(
resonancesModule.URR_width(
resonanceReactionLabels.get(2),
data = XYsModule.XYs1d([[EL,GNO],[EH,GNO]], axes=widthAxes),
degreesOfFreedom = AMUN )
)
widths.add(
resonancesModule.URR_width(
resonanceReactionLabels.get(102),
data = XYsModule.XYs1d([[EL,GG],[EH,GG]], axes=widthAxes) )
)
J_list.add( resonancesModule.URR_Jsection( str(jidx), resonancesModule.spin(AJ), levelSpacing, widths ) )
L_list.add( resonancesModule.URR_Lsection( str(lidx), L, J_list ) )
elif LFW==1 and LRF==1: # 'Case B', only fission width is energy-dependent
nlines = int(math.ceil(NE/6.0))
energyList = []
for i in range(nlines):
energyList += funkyF(mf2.next(), logFile = info.logs)
energyList = energyList[:NE]
for lidx in range(NLS):
J_list = resonancesModule.URR_Jsections()
AWRI,dum,L,dum,NJS,dum = funkyFI( mf2.next(), logFile = info.logs )
for jidx in range(NJS):
dum,dum,L,MUF,tmp,dum = funkyFI( mf2.next(), logFile = info.logs )
if tmp!=NE+6:
raise BadResonances("Bad unresolved flag, line %d" % mf2.index)
D,AJ,AMUN,GNO,GG,dum = funkyF( mf2.next(), logFile = info.logs )
fissionWidth = []
for i in range(nlines):
fissionWidth += funkyF( mf2.next(), logFile = info.logs )
fissionWidth = fissionWidth[:NE]
levelSpacing = resonancesModule.levelSpacing(
XYsModule.XYs1d([[EL,D],[EH,D]], axes=levelSpacingAxes) )
widths = resonancesModule.URR_widths()
widths.add(
resonancesModule.URR_width(
resonanceReactionLabels.get(2),
data = XYsModule.XYs1d([[EL,GNO],[EH,GNO]], axes=widthAxes),
degreesOfFreedom = AMUN )
)
widths.add(
resonancesModule.URR_width(
resonanceReactionLabels.get(102),
data = XYsModule.XYs1d([[EL,GG],[EH,GG]], axes=widthAxes) )
)
widths.add(
resonancesModule.URR_width(
resonanceReactionLabels.get(18),
data = XYsModule.XYs1d( zip(energyList,fissionWidth), axes=widthAxes),
degreesOfFreedom = MUF )
)
J_list.add( resonancesModule.URR_Jsection( str(jidx), resonancesModule.spin(AJ), levelSpacing, widths ) )
L_list.add( resonancesModule.URR_Lsection( str(lidx), L, J_list ) )
elif LRF==2: # 'Case C', most common in ENDF-VII.1
NLS = NE
for Lidx in range(NLS):
J_list = resonancesModule.URR_Jsections()
AWRI,dum,L,dum,NJS,dum = funkyFI( mf2.next(), logFile = info.logs )
for jidx in range(NJS):
resList = []
AJ,dum,INT,dum,tmp,NE = funkyFI( mf2.next(), logFile = info.logs )
interpolation = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS1d(INT)
if tmp!=6*NE+6:
raise BadResonances("bad unresolved flag, line %d" % mf2.index)
dum,dum,AMUX,AMUN,AMUG,AMUF = funkyF( mf2.next(), logFile = info.logs )
for i in range(NE):
resList.append( funkyF( mf2.next(), logFile = info.logs ) )
# temporarily store in a table for convenience:
table = tableModule.table( columns= [
tableModule.columnHeader( 0, name="energy", unit="eV" ),
tableModule.columnHeader( 1, name="levelSpacing", unit="eV" ),
tableModule.columnHeader( 2, name="competitive", unit="eV" ),
tableModule.columnHeader( 3, name="elastic", unit="eV" ),
tableModule.columnHeader( 4, name="capture", unit="eV" ),
tableModule.columnHeader( 5, name="fission", unit="eV" ), ],
data = resList )
elist = table.getColumn('energy')
if len(elist) != len(set(elist)): # duplicates detected!
import collections
for energy, count in collections.Counter(elist).most_common():
if count == 1: break
rows = [row for row in table.data if row[0]==energy]
firstMatch = table.data.index(rows[0])
for row in rows[1:]:
if row != rows[0]:
raise NotImplementedError("Discontinuity in unresolved widths")
index = table.data.index(rows[0], firstMatch+1)
table.data.pop(index)
warningList.append("removing duplicate energy from unresolved parameters")
elist = table.getColumn('energy')
levelSpacing = resonancesModule.levelSpacing(
XYsModule.XYs1d(zip(elist,table.getColumn('levelSpacing')),
axes=levelSpacingAxes, interpolation = interpolation) )
widths = resonancesModule.URR_widths()
for MT,width,DOF in ((2,'elastic',AMUN),(102,'capture',AMUG),
(18,'fission',AMUF),(-1,'competitive',AMUX)):
column = table.getColumn(width)
if any(column) or DOF: # keep all channels with DOF > 0 (even if widths are all 0)
if 0 in column and interpolation in (
standardsModule.interpolation.loglinToken,
standardsModule.interpolation.loglogToken):
zidx = len(column) - column[::-1].index(0) + 1 # index of first non-zero value
if zidx -1 != column.count(0):
raise BadResonances("In URR: L=%d, J=%s, channel=%s widths fluctuate 0 to nonzero and back"
% (L,AJ,width) )
if zidx == len(column) or not any(column):
data = XYsModule.XYs1d( zip(elist, column),
axes=widthAxes, interpolation = standardsModule.interpolation.linlinToken )
else: # break up into regions
data = regionsModule.regions1d( axes=widthAxes )
data.append(
XYsModule.XYs1d( zip(elist[:zidx],column[:zidx]),
interpolation = standardsModule.interpolation.linlinToken,
axes = widthAxes ) )
data.append(
XYsModule.XYs1d( zip(elist[zidx-1:],column[zidx-1:]),
interpolation = interpolation, axes = widthAxes ) )
else:
data = XYsModule.XYs1d( zip(elist, column),
axes=widthAxes, interpolation = interpolation )
reactionLabel = resonanceReactionLabels.get(MT, width)
widths.add( resonancesModule.URR_width(reactionLabel, data, DOF) )
J_list.add( resonancesModule.URR_Jsection( str(jidx), resonancesModule.spin(AJ), levelSpacing, widths ) )
L_list.add( resonancesModule.URR_Lsection( str(Lidx), L, J_list ) )
urr_ = resonancesModule.unresolvedTabulatedWidths( info.style, 'SingleLevelBreitWigner',
resonanceReactions, L_list, scatteringRadius = scatRadius,
useForSelfShieldingOnly=info.LSSF )
info.ENDFconversionFlags.add( urr_, LRF_LFW )
return AP * 10, urr_
else:
info.logs.write( "Unexpected LRU=%d, LRF=%d encountered\n" % ( LRU, LRF ) )
# end of helper functions.
# now read MF2 data:
mf2 = myIter(MF2) # mf2.next() to get each line
scatteringRadii = {}
energyBounds = set()
resolvedList = []
unresolvedList = []
# read MF2 header:
ZAM, AWR, dum, dum, NIS, dum = funkyFI( mf2.next(), logFile = info.logs )
ZAM = int( ZAM )
printAWR_mode( info, -1, 2, ZAM, AWR )
info.addMassAWR( ZAM, AWR )
if NIS!=1: info.logs.write( "careful, more than one isotope in MF2!" )
ZAI, ABN, dum, LFW, NER, dum = funkyFI( mf2.next(), logFile = info.logs )
for erange in range(NER):
# each energy range
EL, EH, LRU, LRF, NRO, NAPS = funkyFI( mf2.next(), logFile = info.logs )
radius, resonanceSection = readResonanceSection( LRU, LRF, NRO, NAPS )
scatteringRadii[LRU] = radius
energyBounds.update([EL,EH])
if resonanceSection is not None:
resonanceMTs.update( [1,2,3,18,19,102] )
if LRU==1:
resolvedList.append( (resonanceSection,EL,EH) )
elif LRU==2:
unresolvedList.append( (resonanceSection,EL,EH) )
if not resolvedList: resolved = None
elif len(resolvedList)==1:
form, domainMin, domainMax = resolvedList[0]
resolved = resonancesModule.resolved( domainMin, domainMax, domainUnit='eV' )
resolved.add( form )
else:
warningList.append( "multiple resolved energy intervals are deprecated!" )
form = resonancesModule.energyIntervals(info.style)
idx = 0
for resonanceSection, EL, EH in resolvedList:
interval = resonancesModule.energyInterval(idx,resonanceSection,EL,EH,domainUnit='eV')
form.append(interval)
idx += 1
resolved = resonancesModule.resolved( domainMin=resolvedList[0][1], domainMax=resolvedList[-1][2], domainUnit='eV' )
resolved.add( form )
if not unresolvedList: unresolved = None
elif len(unresolvedList)==1:
form, domainMin, domainMax = unresolvedList[0]
unresolved = resonancesModule.unresolved( domainMin, domainMax, domainUnit='eV' )
unresolved.add( form )
# reconstructCrossSection=not info.LSSF
else:
raise BadResonances( "multiple unresolved regions not supported" )
if mf2.index != mf2.length:
warningList.append("Not all resonance data converted!")
info.doRaise.append( warningList[-1] )
if len( targetSpins ) > 1: warningList.append("multiple values for nuclear spin encountered: %s" % targetSpins)
for LRU in range(3):
if LRU in scatteringRadii:
AP = scatteringRadii[LRU]
break
scatteringRadius = resonancesModule.scatteringRadius(
constantModule.constant1d(AP, domainMin=min(energyBounds), domainMax=max(energyBounds), axes=axesModule.axes(
labelsUnits = { 1: ( 'energy_in', 'eV' ), 0: ( 'radius', 'fm' ) } ), label=info.style ) )
if 2 in scatteringRadii: # unresolved radius may be redundant
if (1 not in scatteringRadii) or (scatteringRadii[2] == scatteringRadii[1]):
if not isinstance( unresolved.evaluated.scatteringRadius.form, XYsModule.XYs1d ):
unresolved.evaluated.scatteringRadius = None
resonances = resonancesModule.resonances( scatteringRadius, resolved, unresolved )
return resonances, sorted(resonanceMTs)
[docs]def readMF3( info, MT, MF3Data, warningList ) :
dataLine, TAB1, crossSectionRegions = endfFileToGNDSMiscModule.getTAB1Regions( 1, MF3Data, allowInterpolation6 = True,
logFile = info.logs, axes = crossSectionAxes, cls = crossSectionModule.XYs1d )
QM, QI, LR = TAB1['C1'], TAB1['C2'], int( TAB1['L2'] )
breakupProducts = None
if( LR == 0 ) :
pass
elif( LR in [ 22, 23, 24, 25, 28, 29, 30, 32, 33, 34, 35, 36 ] ) :
info.logs.write( ' : MF=3, LR=%s' % LR )
breakupProducts, productCounts = {}, endf_endlModule.endfMTtoC_ProductLists[LR].productCounts
for product in productCounts :
if( productCounts[product] != 0 ) : breakupProducts[product] = productCounts[product]
breakupProducts[info.projectile] -= 1
if( breakupProducts[info.projectile] == 0 ) : del breakupProducts[info.projectile]
elif( LR == 31 ) :
warningList.append( 'Invalid LR = %s for MT = %s is being ignored' % ( LR, MT ) )
elif( LR == 1 ) :
info.logs.write( ' : MF=3, LR=1' )
pass
elif( LR in [ 39, 40 ] ) :
if( LR == 40 ) :
warningList.append( 'LR = %s for MT = %s is being ignored' % ( LR, MT ) )
else :
if( MT != 5 ) :
warningList.append( "Breakup LR = %s is not supported: MT = %s" % ( LR, MT ) )
raise NotImplementedError( "Breakup LR = %s is not supported: MT = %s" % ( LR, MT ) )
else :
raise Exception( "Invalid breakup flag LR %s: MT = %d" % ( LR, MT ) )
crossSection = getCrossSectionForm( info, crossSectionRegions )
return( QM, QI, crossSection, LR, breakupProducts )
[docs]def readMF4( info, product, MT, MF4Data, formClass, warningList ) :
if( MT not in MTWithOnlyNeutonProducts ) : info.MF4ForNonNeutrons.append( MT )
ZA, AWR, LVT, LTT, dummy, dummy = endfFileToGNDSMiscModule.sixFunkyFloatStringsToFloats( MF4Data[0], logFile = info.logs )
ZA = int( ZA )
printAWR_mode( info, MT, 4, ZA, AWR )
info.addMassAWR( ZA, AWR )
LVT = int( LVT ) # 1: transformation matrix given. Must be 0 for endf/b6 format but not older formats.
LTT = int( LTT ) # 0: isotropic, 1: Legendre, 2: table, 3: Legendre for low E and table for high E.
dummy, AWR_, LI, LCT, NK, NM = endfFileToGNDSMiscModule.sixFunkyFloatStringsToFloats( MF4Data[1], logFile = info.logs )
if( AWR != AWR_ ) : printAWR_mode( info, MT, -4, ZA, AWR )
LI = int( LI ) # if 1, gammas isotropic
LCT = int( LCT ) # 1 for lab frame, 2 for center of mass
NK = int( NK ) # number of entries in transformation matrix
NM = int( NM ) # maximum Legendre order
if( ( LCT != 2 ) and ( formClass == angularModule.twoBodyForm ) ):
raise ValueError( "Discrete two-body must be in the center-of-mass frame: LCT = %d MT = %d." % ( LCT, MT ) )
firstDataLine = 2
if( LVT != 0 ) :
warningList.append( 'MF = 4, MT = 2 contains obsolete matrix used to transform Legendre coefficients between frames.' )
firstDataLine += ( NK + 5 ) / 6
info.logs.write( ' : MF=4, LTT = %s' % LTT )
if( LTT == 0 ) : # Purely isotropic angular distribution.
subform = angularModule.isotropic2d( )
elif( LTT == 1 ) : # Legendre polynomial coefficient
nextDataLine, angularData = endfFileToGNDSMiscModule.getTAB2_Lists( firstDataLine, MF4Data, logFile = info.logs )
subform = angularLegendreToPointwiseOrPiecewiseLegendre( MT, angularData, warningList, 4, 'LTT = 1' )
elif( LTT == 2 ) : # Tabulated probability distribution
nextDataLine, angularTable = endfFileToGNDSMiscModule.getTAB2_TAB1s( firstDataLine, MF4Data, logFile = info.logs )
subform = convertAngularToPointwiseOrPiecewiseFromTAB2_TAB1( MT, angularTable, warningList )
elif( LTT == 3 ) : # Mixed Legendre and Tabulated probability distribution
nextDataLine, angularData = endfFileToGNDSMiscModule.getTAB2_Lists( firstDataLine, MF4Data, logFile = info.logs )
nextDataLine, angularTable = endfFileToGNDSMiscModule.getTAB2_TAB1s( nextDataLine, MF4Data, logFile = info.logs )
subformPointwise = convertAngularToPointwiseOrPiecewiseFromTAB2_TAB1( MT, angularTable, warningList )
subform = angularLegendreToPointwiseOrPiecewiseLegendre( MT, angularData, warningList, 4, 'LTT = 3', subformPointwise )
else:
raise ValueError("Encountered unknown LTT=%d in MF4" % LTT)
if( formClass is None ) : return( subform )
form = formClass( info.style, frames[LCT], subform )
product.distribution.add( form )
return( form )
[docs]def readMF5( info, MT, MF5Data, warningList, delayNeutrons = False, product = None ) :
ZA, AWR, dummy, dummy, NK, dummy = endfFileToGNDSMiscModule.sixFunkyFloatStringsToFloats( MF5Data[0], logFile = info.logs )
ZA = int( ZA )
printAWR_mode( info, MT, 5, ZA, AWR )
info.addMassAWR( ZA, AWR )
NK = int( NK ) # number of partial energy distributions.
dataLine = 1
energySubforms, weights = [], []
for k in range( NK ) :
dataLine, productData = endfFileToGNDSMiscModule.getTAB1( dataLine, MF5Data, logFile = info.logs )
if( productData['NR'] > 1 ) :
oldInterpolations = productData['interpolationInfo']
if( oldInterpolations == [ [ 3, 1 ], [ 4, 2 ], [ 5, 1 ] ] ) : # This is a kludge for about 5 data sets, but does a good job.
productData['NR'] = 1
productData['data'].insert( 1, [ ( 1. - FUDGE_EPS ) * productData['data'][1][0], productData['data'][0][1] ] )
productData['interpolationInfo'] = [ [ len( productData['data'] ), 2 ] ]
else :
raise ValueError( "Currently only one interpolation flag is supported" )
LF = int( productData['L2'] ) # breakup flag
xPrior, addWarning = None, True
if( productData['data'][0][0] == productData['data'][1][0] ) : del productData['data'][0]
weight = None
if( ( NK > 1 ) and not( delayNeutrons ) ) :
if( productData['NR'] != 1 ) : raise ValueError( "Currently only one interpolation flag is supported for weight for MF=5, MT=%s" % MT )
x1, y1 = productData['data'][0]
discontinuities = []
if( productData['interpolationInfo'][0][1] != 1 ) :
for i1, xy in enumerate( productData['data'][1:] ) : # Check if data can be treated as flat interpolation.
x2, y2 = xy
if( x1 != x2 ) :
if( y1 != y2 ) : raise ValueError( 'Weight data must be convertible to flat interpolation' )
else :
discontinuities.insert( 0, i1 )
x1, y1 = x2, y2
for discontinuity in discontinuities : del productData['data'][discontinuity]
interpolation = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS1d( 1 ) # Flat interpolation.
axes = axesModule.axes( labelsUnits = { 1 : ( 'energy_in' , 'eV' ), 0 : ( 'weight' , '' ) } )
weight = XYsModule.XYs1d( data = productData['data'], axes = axes, interpolation = interpolation )
else :
for xy in productData['data'] :
if( xPrior is not None ) :
if( xy[0] < xPrior ) : raise ValueError( 'xy[0] = %s < xPrior = %s for MT=%d, MF=5' % ( xy[0], xPrior, MT ) )
if( xy[0] == xPrior ) :
xy[0] *= ( 1 + FUDGE_EPS )
if( addWarning ) : warningList.append( 'weights have same energies, second one being incremented for MT=%d, MF=5' % MT )
addWarning = False
xPrior = xy[0]
interpolation = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS1d( productData['interpolationInfo'][0][1] )
axes = multiplicityAxes.copy( )
axes[0].label = ''
weights.append( XYsModule.XYs1d( data = productData['data'], axes = axes, interpolation = interpolation ) ) # weights is only used for delayed nu_bar data
info.logs.write( ' : MF=5, LF=%s' % LF )
U = physicalQuantityModule.U( PQUModule.pqu_float.surmiseSignificantDigits( productData['C1'] ), 'eV' ) # Upper energy limit.
if( LF == 1 ) :
dataLine, EEpETable = endfFileToGNDSMiscModule.getTAB2_TAB1s( dataLine, MF5Data, logFile = info.logs, axes = energyAxes )
subform = toPointwiseOrPiecewiseEnergy( MT, EEpETable )
elif( LF == 5 ) :
dataLine, TAB1, thetas = endfFileToGNDSMiscModule.toEnergyFunctionalData( info, dataLine, MF5Data, 5, 'theta', 'eV' )
dataLine, TAB1, gs = endfFileToGNDSMiscModule.toEnergyFunctionalData( info, dataLine, MF5Data, 5, 'g', '',
xLabel = 'energy_out / theta( energy_in )', xUnit = '' )
subform = energyModule.generalEvaporationSpectrum( U, thetas, gs )
elif( LF == 7 ) :
dataLine, TAB1, thetas = endfFileToGNDSMiscModule.toEnergyFunctionalData( info, dataLine, MF5Data, 7, 'theta', 'eV' )
subform = energyModule.simpleMaxwellianFissionSpectrum( U, thetas )
elif( LF == 9 ) :
dataLine, TAB1, thetas = endfFileToGNDSMiscModule.toEnergyFunctionalData( info, dataLine, MF5Data, 9, 'theta', 'eV' )
subform = energyModule.evaporationSpectrum( U, thetas )
elif( LF == 11 ) :
dataLine, TAB1, a = endfFileToGNDSMiscModule.toEnergyFunctionalData( info, dataLine, MF5Data, 11, 'a', 'eV' )
dataLine, TAB1, b = endfFileToGNDSMiscModule.toEnergyFunctionalData( info, dataLine, MF5Data, 11, 'b', '1/eV' )
subform = energyModule.WattSpectrum( U, a, b )
elif( LF == 12 ) :
dataLine, TAB1, Ts = endfFileToGNDSMiscModule.toEnergyFunctionalData( info, dataLine, MF5Data, 12, 'T_M', 'eV' )
EFL = physicalQuantityModule.EFL( PQUModule.pqu_float.surmiseSignificantDigits( TAB1['C1'] ), 'eV' )
EFH = physicalQuantityModule.EFH( PQUModule.pqu_float.surmiseSignificantDigits( TAB1['C2'] ), 'eV' )
subform = energyModule.MadlandNix( EFL, EFH, Ts )
else :
raise ValueError( "Unsupported LF = %d" % LF )
if( not( delayNeutrons ) and ( NK > 1 ) ) : subform.weight = weight
energySubforms.append( subform )
if( not( delayNeutrons ) ) :
if( NK > 1 ) :
info.logs.write( ' -- using energy.weightedFunctionals subform --' )
weightedSubform = energyModule.weightedFunctionals( )
for functional in energySubforms :
weight = energyModule.weighted( functional.weight, functional )
weightedSubform.addWeight( weight )
del functional.weight
energySubforms = weightedSubform
else :
energySubforms = energySubforms[0]
return( energySubforms, weights )
[docs]def readMF6( MT, info, MF6Data, productList, warningList, undefinedLevelInfo, isTwoBody, crossSection ) :
ZA, AWR, JP, LCT, NK, dummy = endfFileToGNDSMiscModule.sixFunkyFloatStringsToFloats( MF6Data[0], logFile = info.logs )
ZA = int( ZA )
printAWR_mode( info, MT, 6, ZA, AWR )
info.addMassAWR( ZA, AWR )
JPP=int(JP)//10
JPN=int(JP)%10
if JP > 0:
warningList.append(warningModule.NotImplemented("Multiplicity dependent fission data, P(nu)"))
LCT = int( LCT )
if( LCT == 0 ) : # Happens for electro-atomic data.
LCT = 1
if( MT in (525, 526) ) : LCT = 2 # Not sure this is right. Maybe it should be 1.
LCTLight, LCTWeight = LCT, LCT
if( LCT in (3,4) ) : LCTLight, LCTWeight = 2, 1
NK = int( NK ) # number of outgoing particle data sets
dataLine, discreteGammas, discretePrimaryGammas = 1, {}, []
info.logs.write( ' : MF=6' )
for outGoing in range( NK ) :
isLegendreConvertedToEnergy = False
dataLine, productData, multiplicityRegions = endfFileToGNDSMiscModule.getTAB1Regions( dataLine, MF6Data, logFile = info.logs,
axes = multiplicityAxes )
# ZAP is ZA for outgoing particle; AWP is its atomic mass, LIP: 0 for residual in ground state, 1 for first excited state, etc
ZAP, AWP, LIP, LAW, NP = int( productData['C1'] ), productData['C2'], productData['L1'], productData['L2'], productData['NR']
if( ZAP < 2005 ) : LIP = 0 # LIP has multiple meanings. For light products, signifies different products with the same ZAP.
if( ZAP == 11 ) : # 11 is the ZAP for and electron, however, ENDF/B-VII.1 mislabels the photo as 11 also.
ZAP = 0
if( ( LAW == 8 ) or ( MT in [ 525, 526, 528 ] ) or ( MT >= 534 ) ) : ZAP = 9
if( ZAP == 0 ) : warningList.append( 'photon most likely labelled as an electron (ZAP = 11), converting to ZAP = 0' )
printAWR_mode( info, MT, 6, ZAP, AWP )
info.addMassAWR( ZAP, AWP, asTarget=False )
LCTp = LCTLight
if( ZAP % 1000 > 4 ) : LCTp = LCTWeight
if LCT==4:
if outGoing == 0:
LCTp = 2
ZA_recoilPartner = info.projectileZA + info.targetZA - ZAP
elif outGoing == 1: # check whether this is the recoil partner or a break-up product
if ZAP == ZA_recoilPartner:
LCTp = 2
else:
LCTp = 1
else:
LCTp = 1 # lab frame for all remaining break-up products.
LAW = int( LAW )
frame = frames[LCTp]
info.logs.write( ' : ZAP=%s, LAW=%s' % ( ZAP, LAW ) )
form = None
energyDeposition = None
if( LAW == 0 ) :
form = unspecifiedModule.form( info.style, frame )
elif( LAW == 1 ) : # Continuum Energy-Angle distributions
dummy, dummy, LANG, LEP, NR, NE = endfFileToGNDSMiscModule.sixFunkyFloatStringsToFloats( MF6Data[ dataLine ], logFile = info.logs )
LANG = int( LANG ) # identifies the type of data
info.logs.write( ', LANG=%s' % LANG )
LEP = int( LEP ) # interpolation type for outgoing energy
interpolationLEP = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS1d( LEP )
if( LANG == 1 ) : # Legendre expansion
NR = int( NR ) # number of interpolation regions for incident energy
if( NR != 1 ) : raise Exception( "Currently only one interpolation region is supported for MF = 6, LAW = 1, LANG = 2; MT = %s" % MT )
NE = int( NE ) # number of incident energies
dataLine += 1
EinInterpolationTypes = endfFileToGNDSMiscModule.nStringsToInts( NR, dataLine, MF6Data, dimension = 2 )
interpolationQualifier, EinInterpolation = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS2plusd( EinInterpolationTypes[0][1] )
dataLine += 1 + ( NR - 1 ) / 3 # the next data is energy-angle distributions
massRatio = AWR / ( 1. + AWR )
maxLegendre = 0
EEpClsData = []
for EinCount in range( NE ) :
dummy, Ein, ND, NA, NW, NEP = endfFileToGNDSMiscModule.sixFunkyFloatStringsToFloats( MF6Data[dataLine], logFile = info.logs )
ND = int( ND ) # number of discrete gammas (nonzero only for gammas)
NA = int( NA ) # number of angular parameters (i.e., lMax).
NW = int( NW ) # number of data values for this incident energy
NEP = int( NEP ) # number of outgoing energy values
maxLegendre = max( maxLegendre, NA )
dataLine += 1
if( ND != 0 ) :
if( NA > 0 ) : raise Exception( "Logic here currently only supports isotropic scattering." )
discreteGammasAtE, EoutData = endfFileToGNDSMiscModule.readDiscreteAndLegendre( ND, NEP - ND, dataLine, MF6Data,
dimension = 2 + NA, logFile = info.logs )
discretePrimaryGammasAtE = []
EgPrior = -1
for Eg, P in discreteGammasAtE : # Divide gammas into primary and discrete.
if( Eg == EgPrior ) : Eg -= float( "%0.e" % ( 1e-7 * Eg ) )
EgPrior = Eg
if( Eg < 0 ) : # Primary gamma.
Epg = -Eg
if( Ein > 1e-2 ) : Epg -= massRatio * Ein # Only include projectile correction for Ein > 1e-2 as typically Eg ~ 1e6.
discretePrimaryGammasAtE.append( [ Epg, [ Ein, P ] ] )
else : # Discrete gamma.
if( Eg not in discreteGammas ) : discreteGammas[Eg] = []
discreteGammas[Eg].append( [ Ein, P ] )
if( len( discretePrimaryGammasAtE ) > 0 ) :
if( len( discretePrimaryGammas ) == 0 ) :
discretePrimaryGammas = discretePrimaryGammasAtE
else : # Now we need to match level energies (aka binding energies) from prior with Ein's with current Ein.
# This is needed since for different Ein's, the calculation of Epg will vary slightly (hopefully less than 1e-4).
if( len( discretePrimaryGammas ) != len( discretePrimaryGammasAtE ) ) :
raise Exception( 'number of primary gammas at Ein = %s is different then first incident energy' % Ein )
for index, Eg in enumerate( discretePrimaryGammas ) :
if( abs( Eg[0] - discretePrimaryGammasAtE[index][0] ) > 1e-4 * Eg[0] ) :
raise Exception( 'primary energy of %s is not close to primary energy %s' % ( Eg[0], discretePrimaryGammasAtE[index][0] ) )
Eg.append( discretePrimaryGammasAtE[index][1] )
else :
EoutData = endfFileToGNDSMiscModule.nFunkyFloatStringsToFloats( NEP, dataLine, MF6Data, dimension = 2 + NA, logFile = info.logs )
if( len( EoutData ) > 0 ) :
# Test for some common problems.
# 1: all outgoing energies == 0 for continuum gammas.
# This usually only affects one incident energy, so just replace that energy with empty outgoing distribution:
energy_out_list = [ e[0] for e in EoutData ]
if( sum( energy_out_list ) == 0 ) :
warningList.append("At Ein=%s eV, continuum gamma outgoing energies are all 0.0 (MT=%d, ZAP=%d)!"
% ( Ein, MT, ZAP ) )
EoutData = [ [ 0.0, 0.0 ], [ 1.0, 0.0 ] ]
# 2: trouble with duplicate outgoing energies:
elif( ( max( [ energy_out_list.count( a ) for a in energy_out_list ] ) > 2 ) or ( energy_out_list.count( 0.0 ) > 1 ) ) :
warningList.append( "Too many duplicate outgoing energies for Ein=%s eV (MT=%d, ZAP=%d)!"
% ( Ein, MT, ZAP ) )
tmp = []
i1 = 0
if( energy_out_list.count( 0.0 ) > 1 ) :
finalZeroIndex = energy_out_list.count( 0.0 ) - 1
energy_out_list = energy_out_list[finalZeroIndex:]
EoutData = EoutData[finalZeroIndex:]
while( i1 < len( energy_out_list ) ) :
eout = energy_out_list[i1]
eoutCount = energy_out_list.count( eout )
if( eoutCount > 2 ) :
tmp.extend( [ EoutData[i1], EoutData[i1+eoutCount-1] ] )
i1 += eoutCount
else :
tmp.append( EoutData[i1] )
i1 += 1
EoutData = tmp # End of TENDL-specific tests.
EpClsDatas, EpPrior, ClsPrior = [], -1, []
if( LEP == 2 ) : # Remove some data that are not needed and complicates things.
if( len( EoutData ) > 2 ) :
if( EoutData[-1][0] == EoutData[-2][0] ) :
if( EoutData[-1][1] == EoutData[-2][1] ) :
EoutData.pop()
elif (EoutData[-1][1] == 0): # Discontinuity used to make final point == 0. Bump previous energy back slightly
EoutData[-2][0] = nudgeValue( EoutData[-2][0], -1 )
regions = []
skippedLast = False
for i1, EpCs in enumerate( EoutData ) :
e_out, Cls = EpCs[0], EpCs[1:]
if( e_out == EpPrior ) :
if( Cls == ClsPrior ) :
if( skippedLast ) : raise ValueError( 'hell - need to fix' )
warningList.append( 'skipping duplicate e_out = %s, i1 = %s %s %s' % ( e_out, i1, EinCount, Ein ) )
skippedLast = True
continue
else: # create new region:
regions.append( EpClsDatas )
EpClsDatas = []
skippedLast = False
EpClsData = [ e_out, Cls ]
EpClsDatas.append( EpClsData )
EpPrior, ClsPrior = e_out, Cls
if regions:
regions.append( EpClsDatas )
EEpClsData.append( [ Ein, regions, True ] )
else:
EEpClsData.append( [ Ein, EpClsDatas, False ] )
dataLine += 1 + ( NW - 1 ) / 6 # Offset for the next incident energy
if( maxLegendre == 0 ) : # Only have l=0 for each outgoing energy. Convert this to
# uncorrelated with P(E_out|E_in) and isotropic angular distribution.
if( len( EEpClsData ) != 0 ) : # length == 0 happens when there are only discrete gammas and no continuum gamma data.
isLegendreConvertedToEnergy = True
angularSubform = angularModule.isotropic2d( )
EPrior = -1
energySubform = energyModule.regions2d( axes = energyAxes )
energySubformRegion = energyModule.XYs2d( axes = energyAxes, interpolation = EinInterpolation,
interpolationQualifier = interpolationQualifier )
for index, ( Ein, EpCls, multiRegion ) in enumerate( EEpClsData ) :
if multiRegion:
xData = energyModule.regions1d( value = Ein, axes = energyAxes )
for region in EpCls:
EpP = [ [ Ep, P[0] ] for Ep, P in region ]
xData.append( energyModule.XYs1d( data = EpP, axes = energyAxes, interpolation = interpolationLEP ) )
else:
EpP = [ [ Ep, P[0] ] for Ep, P in EpCls ]
xData = energyModule.XYs1d( data = EpP, interpolation = interpolationLEP,
value = Ein, axes = energyAxes )
if( Ein == EPrior ) :
energySubform.append( energySubformRegion )
energySubformRegion = energyModule.XYs2d( axes = energyAxes, interpolation = EinInterpolation,
interpolationQualifier = interpolationQualifier )
energySubformRegion.append( xData )
EPrior = Ein
if( len( energySubform ) > 0 ) :
if( len( energySubformRegion ) > 1 ) : energySubform.append( energySubformRegion )
else :
energySubform = energySubformRegion
form = uncorrelated( info.style, frame, angularSubform, energySubform )
else :
EPrior = -1
energyAngularSubform = energyAngularModule.regions3d( axes = energyAngularAxes )
energyAngularSubformRegion = energyAngularModule.XYs3d( axes = energyAngularAxes, interpolation = EinInterpolation,
interpolationQualifier = interpolationQualifier )
for i1, ( e_in, EpCls, multiRegion ) in enumerate( EEpClsData ) :
if( multiRegion ) : raise NotImplemented
multiD_2d = energyAngularModule.XYs2d( value = e_in, interpolation = interpolationLEP, axes = energyAngularAxes )
for i2, ( e_out, Cls ) in enumerate( EpCls ) :
multiD_2d.append( energyAngularModule.Legendre( coefficients = Cls, value = e_out, axes = energyAngularAxes ) )
if( e_in == EPrior ) :
energyAngularSubform.append( energyAngularSubformRegion )
energyAngularSubformRegion = energyAngularModule.XYs3d( axes = energyAngularAxes, interpolation = EinInterpolation,
interpolationQualifier = interpolationQualifier )
energyAngularSubformRegion.append( multiD_2d )
EPrior = e_in
if( len( energyAngularSubform ) > 0 ) :
energyAngularSubform.append( energyAngularSubformRegion )
else :
energyAngularSubform = energyAngularSubformRegion
form = energyAngularModule.form( info.style, frame, energyAngularSubformRegion )
elif( LANG == 2 ) : # Kalbach-Mann data
if( LCTp != 2 ) : raise Exception( 'LCT = %s != 2 as required for Kalbach-Mann data for MF=6, MT=%s' % ( LCTp, MT ) )
dataLine, KalbachMannData = endfFileToGNDSMiscModule.getTAB2_Lists( dataLine, MF6Data, logFile = info.logs )
if( KalbachMannData['NR'] != 1 ) :
raise Exception( "Currently only one interpolation flag is supported for MF = 6, LAW = 1, LANG = 2; MT = %s" % MT )
interpolationQualifier, interpolation = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS2plusd( KalbachMannData['interpolationInfo'][0][1] )
NA = int( KalbachMannData['Lists'][0]['L2'] )
dataPerPoint = NA + 2
if( interpolationQualifier == standardsModule.interpolation.noneQualifierToken ) :
interpolationQualifier = standardsModule.interpolation.unitBaseToken
fData = multiD_XYsModule.XYs2d( axes = KalbachMann_f_Axes, interpolation = interpolation,
interpolationQualifier = interpolationQualifier )
if( interpolationQualifier == standardsModule.interpolation.unitBaseToken ) :
interpolationQualifier = standardsModule.interpolation.unitBaseUnscaledToken
else :
interpolationQualifier = standardsModule.interpolation.correspondingPointsUnscaledToken
rData = multiD_XYsModule.XYs2d( axes = KalbachMann_r_Axes, interpolation = interpolation,
interpolationQualifier = interpolationQualifier )
aData = None
if( NA == 2 ) :
aData = multiD_XYsModule.XYs2d( axes = KalbachMann_a_Axes, interpolation = interpolation,
interpolationQualifier = interpolationQualifier )
priorE, priorEp_f_r_ = -1, [ -1, -1, -1 ]
for i1, data in enumerate( KalbachMannData['Lists'] ) :
value = data['C2']
Ep_ = data['data'][::dataPerPoint]
f_ = data['data'][1::dataPerPoint]
r_ = data['data'][2::dataPerPoint]
priorEp_f_r__ = [ Ep_, f_, r_ ]
if( value == priorE ) :
if( i1 == 1 ) :
fData.pop( 0 )
rData.pop( 0 )
if( aData is not None ) : aData.pop( 0 )
else :
if( priorEp_f_r_ == priorEp_f_r__ ) : continue # For TENDL files with duplicate data.
print('\nMT=%d' % MT)
print(value, priorEp_f_r_)
print(priorE, priorEp_f_r__)
raise NotImplementedError( 'hell - need to support regions' )
priorE, priorEp_f_r_ = value, priorEp_f_r__
fData.append( XYsModule.XYs1d( data = ( Ep_, f_ ), dataForm = 'xsandys', axes = KalbachMann_f_Axes,
value = value, interpolation = interpolationLEP ) )
rData.append( XYsModule.XYs1d( data = ( Ep_, r_ ), dataForm = 'xsandys', axes = KalbachMann_r_Axes,
value = value, interpolation = interpolationLEP ) )
if( aData is not None ) :
a_ = data['data'][3::dataPerPoint]
aData.append( XYsModule.XYs1d( data = ( Ep_, a_ ), dataForm = 'xsandys', axes = KalbachMann_a_Axes,
value = value, interpolation = interpolationLEP ) )
fSubform = KalbachMannModule.fSubform( fData )
rSubform = KalbachMannModule.rSubform( rData )
aSubform = KalbachMannModule.aSubform( aData )
form = KalbachMannModule.form( info.style, frame, fSubform, rSubform, aSubform )
elif( LANG in [ 12, 13, 14, 15 ] ) : # P(E',mu|E)
NR = int( NR ) # number of interpolation regions for incident energy
if( NR != 1 ) : raise Exception( "Currently only one interpolation region is supported for MF = 6, LAW = 1, LANG = 2; MT = %s" % MT )
NE = int( NE ) # number of incident energies
dataLine += 1
EinInterpolationTypes = endfFileToGNDSMiscModule.nStringsToInts( NR, dataLine, MF6Data, dimension = 2 )
interpolationQualifier, EinInterpolation = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS2plusd( EinInterpolationTypes[0][1] )
dataLine += 1 + ( NR - 1 ) / 3 # the next data is energy-angle distributions
EPrior = -1
energyAngularSubformRegion = energyAngularModule.XYs3d( axes = energyAngularAxes, interpolation = EinInterpolation,
interpolationQualifier = interpolationQualifier )
muInterpolationQualifier, muInterpolation = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS2plusd( LANG - 10 )
for EinCount in range( NE ) :
dummy, Ein, ND, NA, NW, NEP = endfFileToGNDSMiscModule.sixFunkyFloatStringsToFloats( MF6Data[dataLine], logFile = info.logs )
ND = int( ND ) # number of discrete gammas (nonzero only for gammas)
NA = int( NA ) # number of angular parameters (i.e., the number of mu values).
NW = int( NW ) # number of data values for this incident energy
NEP = int( NEP ) # number of outgoing energy values
dataLine += 1
if( ND != 0 ) : raise Exception( 'Discrete gammas not support for MF=6, LAW=%d, LANG=%d; MT=%d' %
( LAW, LANG, MT ) )
if( Ein == EPrior ) : raise Exception( 'regions not implemented for MF=6, LAW=%d, LANG=%d; MT=%d; Ein = %s' %
( LAW, LANG, MT, Ein ) )
EPrior = Ein
EpF0_fOfMu = endfFileToGNDSMiscModule.nFunkyFloatStringsToFloats( NW / ( NA + 2 ), dataLine, MF6Data,
logFile = info.logs, dimension = NA + 2 )
dataLine += 1 + ( NW - 1 ) / 6 # Offset for the next incident energy
fOfMu_givenEp = energyAngularModule.XYs2d( value = Ein, interpolation = interpolationLEP )
for data in EpF0_fOfMu :
Ep = data.pop( 0 )
f0 = data.pop( 0 )
fOfMu = f0 * XYsModule.XYs1d( data, dataForm = 'list' )
fOfMu = energyAngularModule.XYs1d( fOfMu, value = Ep, interpolation = muInterpolation )
fOfMu_givenEp.append( fOfMu )
energyAngularSubformRegion.append( fOfMu_givenEp )
form = energyAngularModule.form( info.style, frame, energyAngularSubformRegion )
else :
raise Exception( "Unsupported LANG = %d for continuum energy-angle distribution MF = 6: ZAP = %d, LAW = %d: MT = %d" % \
( LANG, ZAP, LAW, MT ) )
elif( LAW == 2 ) :
if( LCT not in (2,4) ): raise Exception( "Discrete two-body must be in the center-of-mass frame: LCT = %d MT = %d." % ( LCT, MT ) )
isTwoBody = True
dataLine, angularData = endfFileToGNDSMiscModule.getTAB2_Lists( dataLine, MF6Data, logFile = info.logs )
LANG = int( angularData['Lists'][0]['L1'] )
info.logs.write( ', LANG=%s' % LANG )
if( angularData['NR'] != 1 ) :
raise Exception( "Currently only one interpolation flag is supported for MF = 6, LAW = 2, LANG = %s; MT = %s" % ( LANG, MT ) )
interpolationQualifier, interpolationE_in = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS2plusd( angularData['interpolationInfo'][0][1] )
if( LANG == 0 ) :
angularSubform = angularLegendreToPointwiseOrPiecewiseLegendre( MT, angularData, warningList, 6, 'LAW = 2, LANG = 0' )
form = angularModule.twoBodyForm( info.style, frame, angularSubform )
elif( LANG in [ 12, 14 ] ) :
angularSubform = convertAngularToPointwiseOrPiecewiseFromTAB2_List( MT, LANG, angularData, warningList )
form = angularModule.twoBodyForm( info.style, frame, angularSubform )
else :
raise Exception( "LANG = %d for LAW = %d not supported: MT = %d" % ( LANG, LAW, MT ) )
if( ( ZAP == 0 ) and ( AWP != 0 ) ) :
form = angularModule.twoBodyForm( info.style, frame, angularSubform )
elif( LAW == 3 ) :
subform = angularModule.isotropic2d( )
form = angularModule.twoBodyForm( info.style, frame, subform )
elif( LAW == 4 ) :
subform = angularModule.recoil( product.distribution[info.style], relative=True )
form = angularModule.twoBodyForm( info.style, frame, subform )
elif( LAW == 5 ) : # charged-particle elastic scattering
assert LCT == 2, "Charged-particle elastic must be in the center-of-mass frame: LCT = %d MT = %d." % ( LCT, MT )
dataLine, angularData = endfFileToGNDSMiscModule.getTAB2_Lists( dataLine, MF6Data, logFile = info.logs )
SPI = angularData['C1']
LIDP = angularData['L1'] # identical particles?
info.particleSpins[info.projectile] = ( resonancesModule.spin( SPI ), 0 ) # no parity information
LTP = int( angularData['Lists'][0]['L1'] )
info.logs.write( ', LTP=%s' % LTP )
interpolationQualifier, interpolationE_in = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS2plusd( angularData['interpolationInfo'][0][1] )
# LTP flag changes interpretation of the data:
if( LTP == 1 ) :
(nuclear, real, imaginary) = convertNuclearPlusInterferenceDataToPiecewise( MT, angularData, warningList, 6, 'LAW = 5, LTP = %d'%LTP, LIDP )
dSigma_subform = nuclearAmplitudeExpansionModule.nuclearAmplitudeExpansion(
nuclearTerm=nuclear, realInterference=real, imaginaryInterference=imaginary )
elif( LTP == 2 ) :
raise NotImplemented( "MF=6 LAW=5 LTP=2 not yet implemented (MT%d)!" % MT )
elif( LTP in ( 12, 14, 15 ) ) :
subform = convertAngularToPointwiseOrPiecewiseFromTAB2_List( MT, LTP, angularData, warningList )
assert len( set( [tmp.domainMax for tmp in subform] ) ) == 1, "mu cutoff should not depend on energy!"
muCutoff = subform[0].domainMax
crossSection = crossSectionModule.XYs1d( data = 2*math.pi*crossSection, axes = crossSection.axes )
dSigma_subform = nuclearPlusInterferenceModule.nuclearPlusInterference(
muCutoff = muCutoff,
crossSection = nuclearPlusInterferenceModule.crossSection( crossSection ),
distribution = nuclearPlusInterferenceModule.distribution( subform)
)
else:
raise Exception( "unknown LTP encountered for MF=6, LAW=5, MT=%s" % MT )
dSigma_form = CoulombPlusNuclearElasticModule.form( info.style, info.projectile, dSigma_subform, identicalParticles = (LIDP == 1))
info.dSigma_form = dSigma_form
# also make a link from 'normal' distribution to differential part:
form = referenceModule.CoulombPlusNuclearElastic( link=dSigma_form, label=info.style, relative=True )
elif( LAW == 6 ) :
APSX, dummy, dummy, dummy, dummy, NPSX = endfFileToGNDSMiscModule.sixFunkyFloatStringsToFloats( MF6Data[ dataLine ], logFile = info.logs )
dataLine += 1
APSX *= info.massTracker.neutronMass
angularSubform = angularModule.isotropic2d( )
mass = physicalQuantityModule.mass( PQUModule.pqu_float.surmiseSignificantDigits( APSX ), 'amu' )
energySubform = energyModule.NBodyPhaseSpace( int( NPSX ), mass )
# Some data has the wrong frame, should always be com hence frames[2].
form = uncorrelated( info.style, frames[2], angularSubform, energySubform )
elif( LAW == 7 ) :
dataLine, NEData = endfFileToGNDSMiscModule.getTAB2Header( dataLine, MF6Data, logFile = info.logs )
NR = int( NEData['NR'] ) # number of interpolation regions for this incident energy
if( NR != 1 ) : raise Exception( "Currently only one interpolation flag is supported for MF = 6, LAW = 7; MT = %s" % MT )
interpolationQualifier, interpolation = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS2plusd( NEData['interpolationInfo'][0][1] )
angularEnergySubform = angularEnergyModule.XYs3d( axes = angularEnergyAxes, interpolation = interpolation,
interpolationQualifier = interpolationQualifier )
for i1 in range( int( NEData['NZ'] ) ) : # Loop over incident energies
dataLine, muEpPTable = endfFileToGNDSMiscModule.getTAB2_TAB1s( dataLine, MF6Data, logFile = info.logs, axes = angularEnergyAxes )
muEpP = muEpPTable['TAB2s']
if( len( muEpP ) != 1 ) : raise ValueError( 'hell - need to fix' )
interpolation, muEpP = muEpP[0]
interpolationQualifier, interpolation = endfFileToGNDSMiscModule.ENDFInterpolationToGNDS2plusd( muEpPTable['interpolationInfo'][0][1] )
muEpP_multiD = angularEnergyModule.XYs2d( value = muEpPTable['C2'],
interpolation = interpolation, interpolationQualifier = interpolationQualifier, axes = angularEnergyAxes )
for i2, EpP in enumerate( muEpP ) :
if( len( EpP ) > 1 ) : raise ValueError( 'hell - need to fix' )
muEpP_multiD.append( angularEnergyModule.XYs1d.returnAsClass( EpP[0], EpP[0] ) )
angularEnergySubform.append( muEpP_multiD )
form = angularEnergyModule.form( info.style, frame, angularEnergySubform )
elif( LAW == 8 ) :
dataLine, TAB1, energyLoss = endfFileToGNDSMiscModule.getTAB1Regions( dataLine, MF6Data, logFile = info.logs )
if( len( energyLoss ) != 1 ) : raise ValueError( 'hell - fix me' )
energyLoss = energyLoss[0]
data = [ [ energyLoss.domainMin, energyLoss.domainMin ], [ energyLoss.domainMax, energyLoss.domainMax ] ]
energyLoss = energyLoss.__class__( data, axes = energyLoss.axes ) - energyLoss
energyDeposition = energyDepositionModule.XYs1d( label = info.style, axes = energyDepositionAxes,
data = energyLoss, interpolation = energyLoss.interpolation )
else :
raise Exception( "LAW = %d not implemented: MT = %d." % ( LAW, MT ) )
multiplicityData = productData['data']
rangeMin, integerMultiplicity = multiplicityData[0][1], False
if( ( ZAP != 0 ) and ( int( rangeMin ) == rangeMin ) ) :
integerMultiplicity = True
for x, y in multiplicityData : integerMultiplicity &= ( rangeMin == y )
if( integerMultiplicity ) :
multiplicity = int( rangeMin )
else :
multiplicity = getMultiplicityPointwiseOrPieceWise( info, multiplicityRegions, warningList )
if( isinstance( multiplicity, multiplicityModule.XYs1d ) and ( multiplicity.rangeMin < 0 ) ) :
warningList.append( "Negative multiplicity encountered for MF6, MT%d %s" %
( MT, toGNDSMiscModule.getTypeNameENDF( info, ZAP, undefinedLevelInfo ) ) )
if( ( ZAP == 0 ) and ( AWP == 0 ) ) : # Gammas. Appear to always be stored using LAW = 1 and LANG = 1.
def addGammaProduct( form, multiplicity ) :
_crossSection = crossSection
if( isinstance( multiplicity, multiplicityModule.regions1d ) ) :
_crossSection = multiplicity
if( len( multiplicity ) == 1 ) :
label = multiplicity.label
multiplicity = multiplicity[0]
multiplicity.label = label
if( isinstance( multiplicity, multiplicityModule.XYs1d ) ) :
if( len( multiplicity ) < 2 ) : return( None )
_crossSection = multiplicity
product = toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameENDF( info, ZAP, None ),
crossSection, multiplicity = multiplicity )
product.distribution.add( form )
productList.append( product )
return( product ) # May be required for LAW = 4 logic.
def addGammaAdjustWeight( angularSubform, energySubform, totalGammaMultiplicity ) :
"""
Have Legendre section with total multiplicity and only l=0 for discrete gammas.
Convert to isotropic angular distributions, plus adjust weights.
"""
def getPointwiseMultiplicity( angularSubform, totalGammaMultiplicity, EPrior, axes ) :
data = []
for energy_in in angularSubform :
multiplicity = getMultiplicity( totalGammaMultiplicity, EPrior, energy_in.value )
data.append( [ energy_in.value, energy_in.coefficients[0] * multiplicity ] )
EPrior = energy_in.value
multiplicity = multiplicityModule.XYs1d( data = data, axes = axes )
return( EPrior, multiplicity )
if( len( angularSubform ) < 2 ) : return( None )
axes = multiplicityAxes
if( isinstance( angularSubform, angularModule.XYs2d ) ) :
EPrior, multiplicity = getPointwiseMultiplicity( angularSubform, totalGammaMultiplicity, angularSubform[0].value, axes )
multiplicity.label = info.style
elif( isinstance( angularSubform, angularModule.regions2d ) ) :
multiplicity = multiplicityModule.regions1d( label = info.style, axes = axes )
EPrior = -1
for region in angularSubform :
EPrior, multiplicityRegion = getPointwiseMultiplicity( region, totalGammaMultiplicity, EPrior, axes )
multiplicity.append( multiplicityRegion )
else :
raise Exception( 'Unsupport angular subform = "%s"' % angularSubform.moniker )
product = toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameENDF( info, ZAP, None ),
multiplicity, multiplicity = multiplicity )
angularSubform = angularModule.isotropic2d( )
form = uncorrelated( info.style, frame, angularSubform, energySubform )
product.distribution.add( form )
productList.append( product )
return( product ) # May be required for LAW = 4 logic.
def addPrimaryOrDiscreteGamma( distinctType, Eg, ELegenres, totalGammaMultiplicity, frame ) :
if( distinctType == 'discrete' ) :
energySubform = discreteOrPrimaryGamma( energyModule.discreteGamma, Eg, crossSection.domainMin, crossSection.domainMax )
else :
energySubform = discreteOrPrimaryGamma( energyModule.primaryGamma, Eg, crossSection.domainMin, crossSection.domainMax )
angularSubform = angularModule.XYs2d( axes = angularAxes )
EPrior = -1
maxLegendre = 0
angularRegion = angularModule.regions2d( axes = angularAxes )
for i1, ( energy, coefficients ) in enumerate( ELegenres ) :
maxLegendre = max( maxLegendre, len( coefficients ) )
if( energy == EPrior ) :
angularRegion.append( angularSubform )
angularSubform = angularModule.XYs2d( axes = angularAxes )
angularSubform.append( angularModule.Legendre( coefficients = coefficients, value = energy, axes = angularAxes ) )
EPrior = energy
if( len( angularRegion ) > 0 ) :
angularRegion.append( angularSubform )
angularSubform = angularRegion
if( maxLegendre == 1 ) : # Only have l=0 for each incident energy. Distribution needs to be normalized.
return( addGammaAdjustWeight( angularSubform, energySubform, totalGammaMultiplicity ) )
form = uncorrelated( info.style, frame, angularSubform, energySubform )
return( addGammaProduct( form, totalGammaMultiplicity ) )
totalGammaMultiplicity = multiplicity # Makes the name more explicit.
if( ( len( discreteGammas ) + len( discretePrimaryGammas ) ) > 0 ) :
info.totalMF6_12_13Gammas[MT] = [ 6, multiplicity ]
if( form is not None ) : # Continuum gamma present
if( discreteGammas or discretePrimaryGammas ) :
def fixContinuumGammaSpectrum( energyDist ) :
EpPrior = 2e-5
energyDist[0] = ( 0, 1e-16 ) # Make distribution with small probability near 0.
energyDist[1] = ( EpPrior, 0 )
for i1 in range( 2, len( energyDist ) ) :
Ep, P1 = energyDist[i1]
if( Ep < EpPrior ) : Ep = 2 * EpPrior
EpPrior = Ep
energyDist[i1] = ( Ep, 0 )
if( isinstance( totalGammaMultiplicity, XYsModule.XYs1d ) ) :
newMultiplicity = multiplicityModule.XYs1d( data = [], axes = totalGammaMultiplicity.axes,
interpolation = totalGammaMultiplicity.interpolation, label = info.style )
elif( isinstance( totalGammaMultiplicity, regionsModule.regions ) ) :
newMultiplicity = multiplicityModule.regions1d( axes = totalGammaMultiplicity.axes, label = info.style )
else :
raise Exception( 'Unsupported multiplicity form "%s"' % totalGammaMultiplicity.moniker )
if( isinstance( energySubform, energyModule.XYs2d ) ) : energySubform = [ energySubform ]
EPrior = energySubform[0][0].value
for i1, region in enumerate( energySubform ) :
for i2, energyDist in enumerate( region ) :
Ein = energyDist.value
integral = energyDist.integrate( )
if( integral == 0 ) :
if( not( info.continuumSpectraFix ) ) :
raise Exception( "Zero norm continuum gamma spectrum energies = %s (MT=%d). Try option 'continuumSpectraFix'" %
( energyDist.value, MT ) )
fixContinuumGammaSpectrum( energyDist )
integral = energyDist.integrate( )
if( isinstance( newMultiplicity, XYsModule.XYs1d ) ) :
newMultiplicity.setValue( Ein, getMultiplicity( totalGammaMultiplicity, EPrior, Ein ) * integral )
elif( isinstance( newMultiplicity, regionsModule.regions ) ) :
if( Ein == EPrior ) :
if( ( i1 + i2 ) > 0 ) : newMultiplicity.append( newRegionMultiplicity )
newRegionMultiplicity = multiplicityModule.XYs1d( axes = totalGammaMultiplicity.axes, data = [] )
newRegionMultiplicity.setValue( Ein, getMultiplicity( totalGammaMultiplicity, EPrior, Ein ) * integral )
region[i2] = region[i2].normalize( )
EPrior = Ein
if( isinstance( energySubform, list ) ) : energySubform = energySubform[0]
form = uncorrelated( info.style, form.productFrame, form.angularSubform.data, energySubform )
if( isinstance( newMultiplicity, multiplicityModule.regions1d ) ) :
newMultiplicity.append( newRegionMultiplicity )
product = addGammaProduct( form, newMultiplicity )
else:
product = addGammaProduct( form, totalGammaMultiplicity )
for Eg in sorted( discreteGammas ) :
product = addPrimaryOrDiscreteGamma( 'discrete', Eg, discreteGammas[Eg], totalGammaMultiplicity, frame )
for EgEinPs in discretePrimaryGammas :
product = addPrimaryOrDiscreteGamma( 'primary', EgEinPs[0], EgEinPs[1:], totalGammaMultiplicity, frame )
else : # Non gamma particle.
if( ( info.targetLevel > 0 ) and ( MT in range( 51, 90 ) ) and ( ZAP == info.targetZA ) ) :
# for isomeric targets, need to adjust the product level: MT51 goes to ground state, etc.
if( ( MT - 50 ) <= info.targetLevel ) : undefinedLevelInfo['levelIndex'] -= 1
thisParticle = toGNDSMiscModule.getTypeNameENDF( info, ZAP, undefinedLevelInfo )
if( LIP > 0 ) :
thisParticleBaseName = thisParticle.id
metaStableName = PoPsAliasModule.metaStable.metaStableNameFromNuclearLevelNameAndMetaStableIndex( thisParticleBaseName, LIP )
if( metaStableName in info.PoPs ) :
levelName = info.PoPs[ metaStableName ].pid
thisParticle = info.reactionSuite.PoPs[levelName]
else :
try :
levelIndex, level = metaStableData[metaStableName]
thisParticle = toGNDSMiscModule.getTypeNameGamma( info, ZAP, level = level, levelIndex = levelIndex )
info.PoPs.add( PoPsAliasModule.metaStable( metaStableName, thisParticle.id, int(LIP) ) )
except :
raise KeyError( 'Meta stable data not available for %s' % metaStableName )
product = toGNDSMiscModule.newGNDSParticle( info, thisParticle, crossSection, multiplicity = multiplicity )
if( form is not None ) : product.distribution.add( form )
if( energyDeposition is not None ) : product.energyDeposition.add( energyDeposition )
productList.append( product )
if( ( len( discreteGammas ) > 0 ) and ( productData['interpolationInfo'][0][1] != 2 ) ) :
info.logs.write( 'interpolation %s is not linear for gamma multiplicity' % productData['interpolationInfo'][0][1] )
for product in productList :
if( product.id == IDsPoPsModule.photon ) :
info.ENDFconversionFlags.add( product, 'MF6' )
elif( info.reactionSuite.projectile in ( 'n', IDsPoPsModule.photon ) ) :
if( isTwoBody or ( product.id == IDsPoPsModule.neutron ) ) :
info.ENDFconversionFlags.add(product, 'MF6')
return( isTwoBody )
[docs]def readMF8( info, MT, MTData, warningList ) :
"Regular decay data."
firstLMF, radioactiveDatas = None, []
if( 8 in MTData ) :
dataLine, MF8Data = 1, MTData[8]
ZA, AWR, LIS, LISO, NS, NO = endfFileToGNDSMiscModule.sixFunkyFloatStringsToIntsAndFloats( MF8Data[0], intIndices = [ 0, 2, 3, 4, 5 ], logFile = info.logs )
info.addMassAWR( ZA, AWR )
printAWR_mode( info, MT, 8, ZA, AWR )
MF9Data = readMF9or10( info, MT, MTData, 9, LIS, warningList )
MF10Data = readMF9or10( info, MT, MTData, 10, LIS, warningList )
metastables = {}
for idx in range( NS ) :
ZAP, ELFS, LMF, LFS, ND6, dummy = endfFileToGNDSMiscModule.sixFunkyFloatStringsToIntsAndFloats( MF8Data[dataLine], intIndices = [ 0, 2, 3, 4 ], logFile = info.logs )
if LMF in (9,10):
if LMF==9: IZAP = MF9Data[idx][0]['L1']
else: IZAP = MF10Data[idx][0]['L1']
if (ZAP != IZAP):
warningList.append("For MT=%d, inconsistent ZAP in MF8 and MF%d: %d vs %d" % (MT, LMF, ZAP, IZAP))
info.doRaise.append(warningList[-1])
return (None, [])
if( MT==18 ) :
if ZAP != -1:
warningList.append("For sub-actinide fission (MT=18 MF=8/10) expected ZAP=-1, got %d" % ZAP)
if not info.acceptBadMF10FissionZAP:
info.doRaise.append(warningList[-1])
radioactiveDatas.append([0, 0, 0, None, MF10Data[0][-1], 0, ELFS])
return (10, radioactiveDatas)
if( ZAP not in metastables ) : metastables[ZAP] = 0
if( LFS == 0 and ELFS != 0 ) :
warningList.append( "MF8 claims non-zero ELFS = %s for the ground state, MT = %s. Converting ELFS to 0" % (ELFS, MT ) )
info.doRaise.append( warningList[-1] )
ELFS = 0
if( ELFS != 0 ) : metastables[ZAP] += 1
if( firstLMF is None ) : firstLMF = LMF
if( LMF != firstLMF ) : raise Exception( 'LMF changing from %s to %s is not allowed' % ( firstLMF, LMF ) )
dataLine += 1
crossSection, multiplicity = None, 1
QM, QI = None, None
if( LMF == 3 ) :
pass
elif( LMF == 6 ) : # multiplicity in MF6, which hasn't been read. Set multiplicity to 'unspecified', to be overridden later.
multiplicity = multiplicityModule.unspecified( 'eval' )
elif( LMF in [ 9, 10 ] ) :
if( ( ( LMF == 9 ) and not( MF9Data ) ) or ( ( LMF == 10 ) and not( MF10Data ) ) ) : # BRB ????? Why are we checking for bad data.
LMF1 = ( 10 if( LMF == 9 ) else 9 )
warningList.append( 'LMF = %d, but no MF%d found for MT%d. Trying LMF=%d instead' % ( LMF, LMF, MT, LMF1 ) )
info.doRaise.append( warningList[-1] )
if( ( ( LMF1 == 9 ) and not( MF9Data ) ) or ( ( LMF1 == 10 ) and not( MF10Data ) ) ) :
# neither MF9 or MF10 exist.
continue
LMF = LMF1
if( LMF == 9 ) :
TAB1, multiplicity = MF9Data[idx]
multiplicity = getMultiplicityPointwiseOrPieceWise( info, multiplicity, warningList )
else :
TAB1, crossSection = MF10Data[idx]
QM, QI, IZAP, LFS9or10 = TAB1['C1'], TAB1['C2'], int( TAB1['L1'] ), int( TAB1['L2'] )
ELFS9or10 = QM - QI
if( abs( ELFS - ELFS9or10 ) > 2e-4 * abs( ELFS ) ) :
warningList.append( "MF8 residual level energy = %s for level %s of ZA = %d not close to MF%s's value = %s for MT = %s"
% ( ELFS, LIS, ZAP, LMF, ELFS9or10, MT ) )
info.doRaise.append( warningList[-1] )
if( LFS != LFS9or10 ):
warningList.append("For MT%d, MF8 claims level index = %d but MF9/10 claim level index = %d"
% (MT, LFS, LFS9or10))
info.doRaise.append( warningList[-1] )
radioactiveDatas.append( [ ZAP, ELFS, LFS, multiplicity, crossSection, LFS, QI ] )
if( metastables[ZAP] and ( ZAP != 0 ) ) :
residual = toGNDSMiscModule.getTypeNameGamma( info, ZAP, level = ELFS, levelIndex = LFS )
isotopeName = residual.isotope.key
aliasName = PoPsAliasModule.metaStable.metaStableNameFromNuclearLevelNameAndMetaStableIndex( isotopeName, metastables[ZAP] )
if( not( aliasName in info.PoPs ) ) :
info.PoPs.add( PoPsAliasModule.metaStable( aliasName, residual.id, metastables[ZAP] ) )
if( NO == 0 ) : dataLine += ( ND6 + 5 ) / 6
return( firstLMF, radioactiveDatas )
[docs]def readMF9or10( info, MT, MTData, MF, targetLIS, warningList ) :
if( MF not in MTData.keys( ) ) : return( None )
dataLine, MFData, MF9or10 = 1, MTData[MF], []
ZA, AWR, LIS, dummy, NS, dummy = endfFileToGNDSMiscModule.sixFunkyFloatStringsToIntsAndFloats( MFData[0], intIndices = [ 0, 2, 4 ], logFile = info.logs )
ZA = int( ZA )
printAWR_mode( info, MT, MF, ZA, AWR )
info.addMassAWR( ZA, AWR )
if( LIS != targetLIS ) :
warningList.append( "residual's LIS = %s does not match target's LIS = %s: MT=%d, MF=%d" % ( LIS, targetLIS, MT, MF ) )
info.doRaise.append( warningList[-1] )
return
if( MF == 10 ) :
axes = crossSectionAxes
XYsclass = crossSectionModule.XYs1d
else:
axes = axesModule.axes( labelsUnits = { 1 : ( 'energy_in' , 'eV' ), 0 : ( 'weight' , '' ) } )
XYsclass = multiplicityModule.XYs1d
for i1 in range( NS ) :
dataLine, TAB1, regions = endfFileToGNDSMiscModule.getTAB1Regions( dataLine, MFData, axes = axes, logFile = info.logs, cls = XYsclass )
if( MF == 10 ) :
XSec = getCrossSectionForm( info, regions )
else :
XSec = regions
MF9or10.append( [ TAB1, XSec ] )
return( MF9or10 )
[docs]def readMF12_13( info, MT, MTData, productList, warningList, crossSection, _dummyCrossSection, gammaBRTolerance = 1e-6 ) :
def addMF12_13GammaToList( gList, EGk, ESk, LP, LF, regions ) :
"""EGk is the gamma's energy and ESk is the gamma's origination level energy."""
if( EGk in gList ) : raise ValueError( 'Gammas with the same energy (%s) are not supported: MT=%s' % ( EGk, MT ) )
gList.append( { 'EGk' : EGk, 'ESk' : ESk, 'LP' : LP, 'LF' : LF, 'yield' : regions, 'angularSubform' : None, 'energySubform' : None } )
def checkAngularData( gamma ) :
angularSubform = gamma['angularSubform']
if( angularSubform is None ) : angularSubform = angularModule.isotropic2d( )
gamma['angularSubform'] = angularSubform
def addGammaProduct( info, MF, gamma, productList, warningList, ESk ) :
yields = gamma['yield']
conversionFlags = []
multiplicity = getMultiplicityPointwiseOrPieceWise( info, yields, warningList )
if( MF == 13 ) :
conversionFlags.append('MF13')
multiplicity._temp_divideByCrossSection = True
if( gamma['ESk'] != 0 ) :
conversionFlags.append( 'ESk=%s' % ESk )
product = toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameENDF( info, 0, None ), multiplicity,
multiplicity = multiplicity )
angularSubform = gamma['angularSubform']
energySubform = gamma['energySubform']
form = uncorrelated( info.style, frames[1], angularSubform, energySubform )
product.distribution.add( form )
if conversionFlags : info.ENDFconversionFlags.add(product, ','.join(conversionFlags))
productList.append( product )
if( 12 in MTData ) :
if( 13 in MTData ) :
raise Exception( 'MF = 12 and 13 present for MT=%s, this is not supported' % MT )
MF = 12
elif( 13 in MTData ) :
MF = 13
elif( ( 14 in MTData ) or ( 15 in MTData ) ) :
warningList.append('MF 14 and/or 15 data and no MF 12 or 13 data: MT=%s MFs=%s' % ( MT, MTData.keys( ) ) )
info.doRaise.append( warningList[-1] )
return
else :
return
MF12_13Data = MTData[MF]
ZA, AWR, LO, LG, NK, dummy = endfFileToGNDSMiscModule.sixFunkyFloatStringsToIntsAndFloats( MF12_13Data[0], intIndices = [ 0, 2, 3, 4 ], logFile = info.logs )
printAWR_mode( info, MT, MF, ZA, AWR )
info.addMassAWR( ZA, AWR )
info.logs.write( ' : MF=%s LO=%s : ZAP=0 ' % ( MF, LO ) )
dataLine, continuousGamma, discreteGammas, primaryGammas, branchingGammas = 1, [], [], [], []
if( ( ( MF == 12 ) and ( LO == 1 ) ) or ( ( MF == 13 ) and ( LO == 0 ) ) ) :
if( MF == 12 ) :
axes = multiplicityAxes
else :
axes = crossSectionAxes
if( NK > 1 ) :
dataLine, TAB1, regions = endfFileToGNDSMiscModule.getTAB1Regions( dataLine, MF12_13Data, axes = axes, logFile = info.logs )
info.totalMF6_12_13Gammas[MT] = [ MF, getMultiplicityPointwiseOrPieceWise( info, regions, warningList ) ]
for i in range( NK ) :
dataLine, TAB1, regions = endfFileToGNDSMiscModule.getTAB1Regions( dataLine, MF12_13Data, axes = axes, logFile = info.logs )
EGk, ESk, LP, LF = TAB1['C1'], TAB1['C2'], int( TAB1['L1'] ), int( TAB1['L2'] )
if( EGk == 0. ) :
if( LP not in [ 0, 1 ] ) : raise Exception( 'LP = %s != 0 for continuous gamma for MT = %s' % ( LP, MT ) )
if( len( continuousGamma ) == 0 ) :
addMF12_13GammaToList( continuousGamma, EGk, ESk, LP, LF, regions )
else :
raise Exception( 'continuous gamma information for MF=%s, MT = %s already exist' % ( MF, MT ) )
elif( LP == 2 ) :
addMF12_13GammaToList( primaryGammas, EGk, ESk, LP, LF, regions )
else :
addMF12_13GammaToList( discreteGammas, EGk, ESk, LP, LF, regions )
elif( ( MF == 12 ) and ( LO == 2 ) ) :
dataLine, LO2 = endfFileToGNDSMiscModule.getList( dataLine, MF12_13Data, logFile = info.logs )
LP = int(LO2['L1'])
if( ( LP == 2 ) and ( MT not in ( 91, 649, 699, 749, 799, 849 ) ) ) :
warningList.append("Incorrect 'primary gamma' flag for MF12 MT%d" % MT)
NT, LGp = LO2['N2'], LG + 1
NK = NT
for idx in range( NT ) :
parentEnergy, finalEnergy = LO2['C1'], LO2['data'][idx*LGp]
if parentEnergy==0:
raise Exception("Gamma decay from ground state in MF12 MT%d" % MT)
if abs((parentEnergy-finalEnergy)/parentEnergy)<0.0001:
raise Exception("Zero-energy gamma from %f eV to %f eV in MF12 MT%d" % (parentEnergy,finalEnergy,MT))
branchingGammas.append( {'ES' : LO2['C1'], 'EGk' : 0, 'ESk' : LO2['data'][idx*LGp], 'angularSubform' : None,
'LG' : LG, 'branching' : LO2['data'][idx*LGp+1:idx*LGp+LGp]} )
gammaBRList = [ g['branching'][0] for g in branchingGammas ]
sumGammaBRList = sum( gammaBRList )
if abs( sumGammaBRList - 1.0 ) > gammaBRTolerance:
warningList.append( "sum of gamma BR's for MT="+str(MT)+" MF=12 is " + str(sumGammaBRList)+' != 1.0' )
info.MF12_LO2[MT] = branchingGammas
else :
raise Exception( 'LO=%s is not valid for MF=%s, MT=%s' % ( LO, MF, MT ) )
readMF14( info, MT, MTData, MF, NK, warningList, discreteGammas, primaryGammas, continuousGamma, branchingGammas )
readMF15( info, MT, MTData, continuousGamma, warningList )
for gamma in branchingGammas :
if( not( gamma['angularSubform'] is None ) ) :
info.logs.write( 'NON-isotropic gamma' )
break
if( 14 in MTData ) : info.logs.write( ': MF=14 ' )
if( 15 in MTData ) : info.logs.write( ': MF=15 ' )
if( len( continuousGamma ) ) :
gamma = continuousGamma[0]
checkAngularData( gamma )
addGammaProduct( info, MF, gamma, productList, warningList, gamma['ESk'] )
if( crossSection is None ) :
crossSection = dummyCrossSection( regions[0].domainMin, regions[-1].domainMax, 'eV' )
_dummyCrossSection.append( crossSection )
for gamma in discreteGammas :
checkAngularData( gamma )
gamma['energySubform'] = discreteOrPrimaryGamma( energyModule.discreteGamma, gamma['EGk'], crossSection.domainMin, crossSection.domainMax )
addGammaProduct( info, MF, gamma, productList, warningList, gamma['ESk'] )
for gamma in primaryGammas :
checkAngularData( gamma )
gamma['energySubform'] = discreteOrPrimaryGamma( energyModule.primaryGamma, gamma['EGk'], crossSection.domainMin, crossSection.domainMax )
addGammaProduct( info, MF, gamma, productList, warningList, gamma['ESk'] )
for gamma in branchingGammas : checkAngularData( gamma )
[docs]def readMF14( info, MT, MTData, MF, NK, warningList, discreteGammas, primaryGammas, continuousGamma, branchingGammas ) :
allGammas = discreteGammas + primaryGammas + continuousGamma + branchingGammas
def addAngularData( EGk, ESk, subform ) :
possibleGammas = []
for gamma in allGammas :
if( ( abs( EGk - gamma['EGk'] ) < 1e-4 ) and ( abs( ESk - gamma['ESk'] ) < 1e-4 ) ) : possibleGammas.append( gamma )
if( len( possibleGammas ) == 0 ) :
sys.stderr.write( "MF = 14 gamma data: EGk = %s, ESk = %s\n" % ( EGk, ESk ) )
sys.stderr.write( 'MF = %s gamma list is,\n' % MF )
for gamma in allGammas : sys.stderr.write( " EGk = %s, ESk = %s\n" % ( gamma['EGk'], gamma['ESk'] ) )
raise Exception( 'No matching gamma from MF = %s found for MF = 14 gamma: MT=%s: see above' % ( MF, MT ) )
if( len( possibleGammas ) != 1 ) : raise Exception( 'Multiple possible gammas found for MF=14 data: EGk=%s, ESk=%s, MT=%s' % ( EGk, ESk, MT ) )
gamma = possibleGammas[0]
if( gamma['angularSubform'] is None ) :
gamma['angularSubform'] = subform
else :
raise Exception( 'Gamma already has MF=14 angular data: EGk=%s, ESk=%s, MT=%s' % ( EGk, ESk, MT ) )
if( not( 14 in MTData ) ) : return
MF14Data = MTData[14]
ZA, AWR, LI, LTT, NK14, NI = endfFileToGNDSMiscModule.sixFunkyFloatStringsToIntsAndFloats( MF14Data[0], intIndices = [ 0, 2, 3, 4, 5 ], logFile = info.logs )
printAWR_mode( info, MT, 14, ZA, AWR )
info.addMassAWR( ZA, AWR )
if( ( NK14 != NK ) and info.printBadNK14 ) :
warningList.append( 'MF14 NK = %s != MF12/13 NK = %s for MT = %s' % ( NK14, NK, MT ) )
dataLine, frame = NI + 1, standardsModule.frames.labToken
if( LTT == 0 ) : # All distributions are isotropic
pass
elif( LTT == 1 ) :
for i in range( NK14 - NI ) :
dataLine, angularData = endfFileToGNDSMiscModule.getTAB2_Lists( dataLine, MF14Data, logFile = info.logs )
if( angularData['NR'] != 1 ) : raise Exception( 'Currently only one interpolation flag is supported: NR=%s, MT=%s' % ( angularData['NR'], MT ) )
EGk, ESk = angularData['C1'], angularData['C2']
subform = angularLegendreToPointwiseOrPiecewiseLegendre( MT, angularData, warningList, 4, 'LTT = 1' )
addAngularData( EGk, ESk, subform )
else :
raise Exception( 'MF=14, LI=%s not implemented' % LI )
[docs]def readMF15( info, MT, MTData, continuousGamma, warningList ) :
if( 15 not in MTData ) :
if( len( continuousGamma ) ) :
warningList.append( 'Continous gamma with no MF=15 data: MT=%s' % MT )
info.doRaise.append( warningList[-1] )
return
if( len( continuousGamma ) == 0 ) :
warningList.append( 'MF=15 data and no continous gamma MF=12,13 data: MT=%s' % MT )
info.doRaise.append( warningList[-1] )
MF15Data = MTData[15]
ZA, AWR, dummy, dummy, NC, dummy = endfFileToGNDSMiscModule.sixFunkyFloatStringsToIntsAndFloats( MF15Data[0], intIndices = [ 0, 4 ], logFile = info.logs )
printAWR_mode( info, MT, 15, ZA, AWR )
info.addMassAWR( ZA, AWR )
if( NC != 1 ) : raise Exception( 'NC = %s > 1 is not supported: MT=%s' % ( NC, MT ) )
dataLine, weights = endfFileToGNDSMiscModule.getTAB1( 1, MF15Data, logFile = info.logs )
for Ein, weight in weights['data'] :
if( weight != 1 ) : raise Exception( 'For MF15 data weight other than 1 is not currently supportd: MT%d' % MT )
LF = int( weights['L2'] )
if( LF != 1 ) : raise Exception( 'For MF=15 data, only LF=1 is currently supported, not LF=%s : MT%s' % ( LF, MT ) )
dataLine, EEpETable = endfFileToGNDSMiscModule.getTAB2_TAB1s( dataLine, MF15Data, logFile = info.logs, axes = energyAxes )
continuousGamma[0]['energySubform'] = toPointwiseOrPiecewiseEnergy( MT, EEpETable )
[docs]def genID( cov_info, MT, MF, MT2=None, MF2=None, MAT2=None, QI=None, QI2=None, linkType='rowColumn' ):
"""
For covariances we need a unique id for each section, and also need link info.
This is messy: lots of special cases.
"""
evalStyle = cov_info['style']
MTdict = cov_info['MTdict']
def getReaction( MT, MF, QI=None ):
# find the <reaction> corresponding to this covariance info, if any
if MT in (452,455):
for multiplicitySum in cov_info['multiplicitySums']:
if multiplicitySum.ENDF_MT == MT:
return multiplicitySum
if MT == 456:
MT = 18 # redirect prompt nubar to fission
if MT in MTdict:
chThisMT = MTdict[MT]
if len(chThisMT)==1:
return chThisMT[0]
elif MF==40: # MF40 section may contain covariances for multiple excited states of residual
thisChannel = [ch for ch in chThisMT if isinstance(ch, productionModule.production) and ch.getQ('eV')==QI ]
if len(thisChannel)==1: return thisChannel[0]
elif MT in cov_info:
# Q-values disagree between MF10/MF40. Assume 1st covariance is for lowest-energy residual, etc
index = cov_info[MT]
cov_info[MT] += 1
else:
index = 0; cov_info[MT] = 1
return thisChannel[ index ]
elif MF==33:
# residual must be in ground state unless MT in 51-90, etc
thisChannel = [ch for ch in chThisMT if (isinstance(ch, reactionModule.reaction) and
sum( [p.getLevelAsFloat('eV') for p in ch.outputChannel] )==0) or
isinstance(ch, sumsModule.crossSectionSum)]
if len(thisChannel) != 1: raise BadCovariance("MF33 MT%d covariance doesn't correspond to any channel!"
% MT )
return thisChannel[0]
else :
raise BadCovariance( "Can't determine which reaction this covariance (MF%d MT%d) corresponds to!" % ( MF, MT ) )
return
rowReaction = getReaction( MT, MF, QI )
def makeID(MT, reaction):
if reaction is not None:
#Id = str( reaction.outputChannel )
Id = str( reaction )
elif MT in (452,455,456):
Id = { 452 : 'total', 455 : tokensModule.delayedToken, 456 : tokensModule.promptToken }[MT]
elif MT in (1,4,103,104,105,106,107):
Id = {1:'total', 4:'sum(z,n)', 103:'sum(z,p)', 104:'sum(z,d)',
105:'sum(z,t)', 106:'sum(z,He3)', 107:'sum(z,a)'}[MT]
elif 850 < MT < 871:
Id = "lump%d" % (MT-851)
else: Id = "MF%d_MT%d" % (MF,MT)
return Id
rowId = makeID( MT, rowReaction )
otherTarget = None
if MAT2:
# cross-material covariance
try:
otherTarget = endf_endlModule.getParticleNameFromMAT(MAT2)
except KeyError:
raise BadCovariance("Encountered illegal MAT number %d in covariances!" % MAT2)
colReaction = None # must create an 'externalReaction' and link to it below
versus = ' vs. '
colId = "%s MF%d MT%d" % (otherTarget,MF2,MT2)
elif (MT2 and MT2!=MT):
MF2 = MF2 or MF
colReaction = getReaction( MT2, MF2, QI2 )
versus = ' vs. '
colId = makeID( MT2, colReaction )
else:
colId = versus = ''
qualifier = {31:' [nubar]', 33:'', 34:' [angular distribution]', 35:' [spectrum]', 40:''}[MF]
ID = rowId + versus + colId + qualifier
# also create links from covariances to data:
def makeLink( MT, reaction, Id, MAT2, linkClass ):
link_ = linkClass(ENDF_MFMT="%d,%d" % (MF,MT))
link_.root = "$reactions"
if reaction is not None:
if MF in (33,40):
link_.link = reaction.crossSection[evalStyle]
elif MF==31:
if isinstance(reaction, sumsModule.multiplicitySum):
link_.link = reaction.multiplicity[evalStyle]
else:
link_.link = reaction.outputChannel[0].multiplicity[evalStyle]
elif MF==34:
link_.link = reaction.outputChannel[0].distribution[evalStyle].subforms[0]
elif MF==35:
distribution = reaction.outputChannel[0].distribution[evalStyle]
if( isinstance( distribution, uncorrelatedModule.form ) ) :
link_.link = distribution.energySubform
else :
link_.link = distribution
elif MAT2:
# cross-material covariance: link needs to point to an external file
cov_info['externalFiles'].append( otherTarget )
link_.root = "$%s" % otherTarget
link_.path = "/FIXME/path/to/MT%d" % MT2
else:
if 850 < MT < 871: pass
elif MT==4: cov_info['MTL_2'][(MT,MF)] = zip(range(50,92),[33]*41)
elif MT==103: cov_info['MTL_2'][(MT,MF)] = zip(range(600,650),[33]*49)
elif MT==104: cov_info['MTL_2'][(MT,MF)] = zip(range(651,700),[33]*49)
elif MT==105: cov_info['MTL_2'][(MT,MF)] = zip(range(701,750),[33]*49)
elif MT==106: cov_info['MTL_2'][(MT,MF)] = zip(range(751,800),[33]*49)
elif MT==107: cov_info['MTL_2'][(MT,MF)] = zip(range(801,850),[33]*49)
elif MT==1: cov_info['MTL_2'][(MT,MF)] = zip(range(2,1000),[33]*998)
if (MT,MF) not in cov_info['lumpedChannels']:
quant = sumsModule.crossSectionSum(label=Id,ENDF_MT=MT)
cov_info['lumpedChannels'][(MT,MF)] = quant
quant = cov_info['lumpedChannels'][(MT,MF)]
link_.link = quant.crossSection
return link_
linkClass = covarianceSummedModule.summand
if linkType == 'rowColumn':
linkClass = covarianceSectionModule.rowData
rowData = makeLink( MT, rowReaction, rowId, MAT2, linkClass )
colData = None
if (MT2 and MT2!=MT) or MAT2:
if linkType == 'rowColumn':
linkClass = covarianceSectionModule.columnData
colData = makeLink( MT2, colReaction, colId, MAT2, linkClass )
return ID, [rowData, colData]
[docs]def readMatrix( info, LS,LB, NT,NP, dat ):
""" matrix format is very similar for MF31, MF33 and MF35, so we can
generalize parsing the matrix """
if NP in (0,1): # matrix has at most one energy boundary, no data
return None
nlines, remainder = divmod(NT,6)
subsec = []
for line in range(nlines): subsec += funkyF(dat.next(), logFile = info.logs)
if remainder: subsec += funkyF(dat.next(), logFile = info.logs)[:remainder]
# LB flag tells how to interpret this data:
if LB in (0,1,2,8,9): # diagonal
subsec = subsec[:NT]
energyBounds = [subsec[::2]]
data = subsec[1::2]
matrix = arrayModule.diagonal( (len(data),len(data)), data )
elif LB==5:
if LS==1: #symmetric upper-diagonal
energyBounds = [subsec[:NP],]
data = linearAlgebraModule.switchSymmetry( subsec[NP:NT] )
matrix = arrayModule.full( (NP-1,NP-1), data, symmetry=arrayModule.symmetryLowerToken )
else: # asymmetric, but same energy grids for both axes:
energyBounds = [subsec[:NP]]
matrix = subsec[NP:]
matrix = arrayModule.full( (NP-1,NP-1), matrix )
elif LB==6: # asymmetric
NER = NP
NEC = (NT-1)//NER
energyBounds = [subsec[:NER], subsec[NER:NER+NEC]]
matrix = subsec[NER+NEC:NT]
NEC-=1; NER-=1 # matrix dimensions
matrix = arrayModule.full( (NER,NEC), matrix )
else:
return None
# FIXME: covariances need 'flat' interpolation along both independent axes, but gridded doesn't support that yet
axes = axesModule.axes( labelsUnits = { 0 : ( 'matrix_elements', '' ),
1 : ( 'column_energy_bounds', 'eV' ),
2 : ( 'row_energy_bounds', 'eV' ) } )
axes[2] = axesModule.grid( axes[2].label, axes[2].index, axes[2].unit,
style = axesModule.boundariesGridToken, values = valuesModule.values( energyBounds[0] ) )
if len(energyBounds)==2:
axes[1] = axesModule.grid( axes[1].label, axes[1].index, axes[1].unit,
style = axesModule.boundariesGridToken, values = valuesModule.values( energyBounds[1] ) )
else:
axes[1] = axesModule.grid( axes[1].label, axes[1].index, axes[1].unit,
style = axesModule.linkGridToken, values = linkModule.link( link = axes[2].values, relative = True ) )
# BRB FIX ME
return griddedModule.gridded2d( axes, matrix )
[docs]def readMF31_33( info, dat, mf, mt, cov_info, warningList ):
""" nubar and cross section covariances have basically the same form
in ENDF, so we can treat them the same way: """
dat = myIter(dat)
# dat contains one MFMT section, but in gnds each cross-correlation gets its own section:
sectionList, linkData = [], []
ZA, AWR, dum, MTL, dum, NL = funkyFI(dat.next(), logFile = info.logs)
ZA = int( ZA )
info.addMassAWR( ZA, AWR )
if MTL!=0:
# MTL!=0 implies section is a placeholder pointing to a lumped channel
if (MTL,mf) in cov_info['MTL']:
cov_info['MTL'][(MTL,mf)].append((mt,mf))
else: cov_info['MTL'][(MTL,mf)] = [(mt,mf)]
for subsection in range(NL):
XMF1, XLFS1, MAT1, MT1, NC, NI = funkyFI( dat.next(), logFile = info.logs)
if MAT1 == info.MAT:
# Some files explicitly give MAT1==MAT for internal covariance.
# for simplicity, just set MAT1=0 unless it is actually a different material
MAT1 = 0
XMF1,XLFS1 = int(XMF1),int(XLFS1)
covarsThisSection = []
if XMF1!=0: # field is usually 0, but could be 1 for MF31 or 3 for MF33.
if mf==31 and XMF1==1:
pass
elif mf==33 and XMF1==3:
pass
else:
raise BadCovariance( "XMF1=%d for MF=%d in covariances not currently supported!" % (XMF1,mf) )
if XLFS1!=0:
raise BadCovariance( "non-zero XLFS1 in covariances not currently supported!")
for NCdx in range(NC):
dum,dum,dum,LTY,dum,dum = funkyFI(dat.next(), logFile = info.logs)
if LTY==0:
E1,E2,dum,dum,NCI2,NCI = funkyFI(dat.next(), logFile = info.logs)
subsec = []
nlines = int(math.ceil(NCI2/6.0))
for line in range(nlines): subsec += funkyF(dat.next(), logFile = info.logs)
#coefs = subsec[:NCI2][::2]
pointerList = []
for coef,mtnum in zip(subsec[:NCI2][::2],subsec[:NCI2][1::2]):
Id, pointers = genID( cov_info, int(mtnum), mf, linkType='summand' )
link = pointers[0]
link.attributes['coefficient'] = coef
pointerList.append( link )
covarsThisSection.append(covarianceSummedModule.summedCovariance(label=info.style,
domainMin=E1, domainMax=E2, domainUnit='eV', pointerList=pointerList) )
cov_info['NC_data'].append( covarsThisSection[-1] )
else:
warningList.append( 'non-zero LTY in MF33' )
for NIdx in range(NI):
dum,dum,LS,LB,NT,NP = funkyFI(dat.next(), logFile = info.logs)
matrix = readMatrix( info, LS,LB,NT,NP, dat )
if LB not in (0,1,2,5,6,8):
warningList.append( 'skipping LB%d section for MF%d MT%d' % ( LB, mf, mt ) )
continue
if matrix is None:
warningList.append( 'skipping empty matrix for MF%d MT%d' % ( mf, mt ) )
info.doRaise.append( warningList[-1] )
continue
Type='relative'
if LB in (0,8,9):
Type='absolute'
matrix.axes[0].unit = 'b**2'
ENDFconversionFlag = None
if LB in (2,3,4,): ENDFconversionFlag = "LB=%d" % LB
if LB in (8,9):
varianceDependence = {8: shortRangeSelfScalingVarianceModule.inverseToken,
9: shortRangeSelfScalingVarianceModule.directToken}[ LB ]
covmatrix = shortRangeSelfScalingVarianceModule.shortRangeSelfScalingVariance(
label=info.style, type=Type, dependenceOnProcessedGroupWidth=varianceDependence, matrix=matrix )
else:
covmatrix = covarianceBaseModule.covarianceMatrix( label = info.style, type=Type, matrix=matrix )
if ENDFconversionFlag:
info.ENDFconversionFlags.add( covmatrix, ENDFconversionFlag )
covarsThisSection.append( covmatrix )
# create unique id for each section:
idNow, pointers = genID( cov_info, mt, mf, MT2=MT1, MF2=(XMF1 or mf), MAT2=MAT1 )
rowdat, coldat = pointers
section = covarianceSectionModule.section( label=idNow, rowData=rowdat, columnData=coldat )
if len(covarsThisSection)>1:
form = covarianceMixedModule.mixedForm( label = info.style, components=covarsThisSection )
for idx in range( len( form ) ) :
form[idx].label = str(idx)
elif len(covarsThisSection)==1:
form = covarsThisSection[0]
else:
#raise Exception("Encountered empty covariance section!!!")
info.logs.write("Missing covariance data from section!")
continue
section.add( form )
sectionList.append( section )
linkData.append( (mt,mf,MT1,XMF1, idNow) )
# end loop over NL subsections
if dat.index != dat.length: raise BadCovariance("Not all covariance data converted, MF%d MT%d" % (mf,mt))
return sectionList, linkData
[docs]def readMF32( info, dat, mf, mt, cov_info, warningList ) :
# MF=32 resonance parameter covariances. Must be synchronized with MF=2 resonance parameters
try: import numpy
except ImportError:
warningList.append("Skipping MF32 since NumPy is unavailable")
return [],[]
resonances = cov_info['resonances']
def swaprows( matrix, i1, i2, nrows ):
# matrix rows may be out-of-order and need resorting
rows = matrix[i1:i1+nrows].copy()
matrix[i1:i1+nrows] = matrix[i2:i2+nrows]; matrix[i2:i2+nrows] = rows
cols = matrix[:,i1:i1+nrows].copy()
matrix[:,i1:i1+nrows] = matrix[:,i2:i2+nrows]; matrix[:,i2:i2+nrows] = cols
def read_LCOMP1( dim, matrixSize, dat ):
data = []
nLines, rem = divmod(matrixSize, 6)
for i in range(nLines): data += funkyF(dat.next(), logFile=info.logs)
if rem: data += funkyF(dat.next(), logFile=info.logs)[:rem]
matrix = numpy.zeros((dim, dim))
start, length = 0, dim
for i in range(dim):
# data stores upper-diagonal matrix. Symmetrize:
matrix[i, i:] = matrix[i:, i] = data[start:start + length]
start = start + length
length = length - 1
return matrix
def read_LCOMP2_correlation( NNN, NM, NDIGIT, dat ):
"""
:param NNN: matrix dimension
:param NM: number of lines to read from dat
:param NDIGIT: Number of significant digits stored
:param dat: open ENDF MF=32 section
:return: numpy.array with shape (NNN,NNN) storing correlations
"""
matrix = numpy.eye(NNN, dtype="float") * 10**NDIGIT
for idx in range(NM):
row,col,vals = endfFileToGNDSMiscModule.readEndfINTG( dat.next(), NDIGIT )
vals = vals[:row-col]
# go to 0-based index:
row -= 1
col -= 1
if row>=NNN or col>=row:
raise BadCovariance("Matrix indices out of range for MF32 LCOMP=2 matrix")
matrix[row,col:col+len(vals)] = vals
for idx in range(NNN): # symmetrize
matrix[idx,idx:] = matrix[idx:,idx]
matrix /= float(10**NDIGIT)
return matrix
dat = myIter(dat)
ZA, AWR, dum, dum, NIS, dum = funkyFI(dat.next(), logFile = info.logs)
ZA = int( ZA )
info.addMassAWR( ZA, AWR )
if (NIS!=1): raise BadCovariance( "Can't handle multi-isotope file 32!" )
ZAI,ABN,dum,LFW,NER,dum = funkyFI(dat.next(), logFile = info.logs)
sections = []
for subsection in range(NER):
EL,EH,LRU,LRF,NRO,NAPS = funkyFI(dat.next(), logFile = info.logs)
if (NRO!=0): raise BadCovariance( "Can't handle non-zero NRO in MF32!" )
# format is determined mainly by combination of LCOMP and LRU/LRF
if LRU==1: # resolved resonance covariance section
ENDFconversionFlags = []
if LRF in (1,2,3): # Breit-Wigner and simplified Reich-Moore formats are similar
if not hasattr(resonances.resolved,'evaluated'):
warningList.append("Resonance covariance data for non-existant resonance region")
break
if LRF in (1,2):
mf2_elist = zip( resonances.resolved.evaluated.resonanceParameters.table.getColumn('energy'),
resonances.resolved.evaluated.resonanceParameters.table.getColumn('neutronWidth'),
resonances.resolved.evaluated.resonanceParameters.table.getColumn('captureWidth') )
else:
ENDFconversionFlags.append('LRF3')
mf2_elist = [[],[],[]]
for spinGroup in resonances.resolved.evaluated.spinGroups:
mf2_elist[0].extend( spinGroup.resonanceParameters.table.getColumn('energy') )
mf2_elist[1].extend(spinGroup.resonanceParameters.table.getColumn('elastic width') )
mf2_elist[2].extend(spinGroup.resonanceParameters.table.getColumn('capture width') )
mf2_elist = zip( *mf2_elist )
SPI,AP,dum,LCOMP,NLS,ISR = funkyFI(dat.next(), logFile = info.logs)
DAP = []
if ISR>0: # scattering radius uncertainty
if LRF in (1,2):
dum,dap,dum,dum,dum,dum = funkyFI(dat.next(), logFile = info.logs)
DAP = [10*dap]
else: # LRF==3
dum,dum,dum,dum,MLS,one = funkyFI(dat.next(), logFile = info.logs)
for idx in range( int( math.ceil(MLS/6.0) ) ):
DAP.extend( funkyF(dat.next(), logFile = info.logs) )
DAP = [10*dap for dap in DAP[:MLS]] # convert from 10*fm to fm
if LCOMP==0: # internal correlations given for each resonance, no cross-resonance terms
ENDFconversionFlags.append( 'LCOMP=0' )
mf32_resonances, mf32_covars = [],[]
NRS = 0
for Lval in range(NLS):
AWRI, dum, L, dum, tmp, nrs_ = funkyFI(dat.next(), logFile = info.logs)
NRS += nrs_
for i in range(nrs_):
mf32_resonances.append( funkyF(dat.next(), logFile = info.logs) )
mf32_covars.append( funkyF(dat.next(), logFile = info.logs) + funkyF(dat.next(), logFile = info.logs) )
dEsq, dNsq, dNdG, dGsq, dNdF, dGdF, dFsq, dJdN, dJdG, dJdF, dJsq, dum = zip(*mf32_covars)
MPAR = 3
if any(dFsq): MPAR = 4
if any(dJsq): raise BadCovariance("Encountered uncertainty on J in MF32!")
matrix = numpy.zeros((MPAR*NRS,MPAR*NRS))
for ridx in range(NRS):
matrix[ridx*MPAR,ridx*MPAR] = dEsq[ridx]
matrix[ridx*MPAR+1,ridx*MPAR+1] = dNsq[ridx]
matrix[ridx*MPAR+2,ridx*MPAR+1:ridx*MPAR+3] = [dNdG[ridx], dGsq[ridx]]
if MPAR==4:
matrix[ridx*MPAR+3,ridx*MPAR+1:ridx*MPAR+4] = [dNdF[ridx], dGdF[ridx], dFsq[ridx]]
# symmetrize:
for ridx in range( MPAR*NRS ):
matrix[ridx,ridx:] = matrix[ridx:,ridx]
mf32_elist = [(lis[0],lis[3],lis[4]) for lis in mf32_resonances]
nResonances = len(mf32_elist)
Type="absolute"
matrixClass = arrayModule.flattened
elif LCOMP==1:
AWRI,dum,dum,dum,NSRS,NLRS = funkyFI(dat.next(), logFile = info.logs)
dum,dum,MPAR,dum,tmp,NRB = funkyFI(dat.next(), logFile = info.logs)
dim = NRB * MPAR # num. of resonances * num. parameters per resonance
matrixSize = dim * (dim+1) // 2
if matrixSize + 6*NRB != tmp:
raise BadCovariance("Incorrect dimension for the matrix!")
# resonanances are listed again (redundant!):
mf32_resonances = [ funkyF(dat.next(), logFile = info.logs) for i in range(NRB) ]
if LRF in (1,2):
mf32_elist = [(lis[0],lis[3],lis[4]) for lis in mf32_resonances]
else:
mf32_elist = [(lis[0],lis[2],lis[3]) for lis in mf32_resonances]
matrix = read_LCOMP1( dim, matrixSize, dat )
nResonances = len(mf32_elist)
Type="absolute"
matrixClass = arrayModule.full
elif LCOMP==2:
ENDFconversionFlags.append( 'LCOMP=2' )
AWRI, QX, dum, LRX, tmp, NRSA = funkyFI(dat.next(), logFile = info.logs)
# resonance parameters + uncertainties:
mf32_resonances = [funkyF(dat.next(), logFile = info.logs) for i in range(NRSA*2)]
if LRF in (1,2):
mf32_elist = [(lis[0],lis[3],lis[4]) for lis in mf32_resonances[::2]]
else:
mf32_elist = [(lis[0],lis[2],lis[3]) for lis in mf32_resonances[::2]]
# for LCOMP==2, off-diagonal terms are given as correlation matrix:
dum,dum,NDIGIT,NNN,NM,dum = funkyFI(dat.next(), logFile = info.logs)
MPAR = NNN/NRSA
diagonal = []
for idx in range(NRSA):
if LRF in (1,2):
dE,dum,dum,dGammaN,dGammaG,dGammaF = mf32_resonances[2*idx+1]
diagonal.extend( [dE,dGammaN,dGammaG] )
if MPAR==4: diagonal.append( dGammaF )
elif LRF==3:
dE,dum,dGammaN,dGammaG,dGammaF1,dGammaF2 = mf32_resonances[2*idx+1]
diagonal.extend( [dE,dGammaN,dGammaG] )
if MPAR==4: diagonal.extend( [dGammaF1] )
elif MPAR==5: diagonal.extend( [dGammaF1,dGammaF2] )
if len(diagonal)!=NNN: raise BadCovariance( "Incorrect dimensions for LCOMP=2 matrix!" )
# off-diagonal parts of matrix are stored as sparse correlation matrix:
ENDFconversionFlags.append( 'NDIGIT=%d' % NDIGIT )
matrix = read_LCOMP2_correlation( NNN, NM, NDIGIT, dat )
# convert correlation -> relative covariance matrix
rsd = numpy.sqrt( numpy.array( diagonal ) ) # FIXME don't think we need sqrt here!
matrix = matrix * numpy.outer(rsd,rsd)
nResonances = NRSA
Type="absolute"
matrixClass = arrayModule.flattened
if LRF in (1,2):
start = 0
MPAR += 3 # expand matrix with zeros to account for L,J and totalWidth columns
index = []
for ridx in range(nResonances):
index.extend([start+1,start+2,start+3])
start += MPAR
n_b = matrix.shape[0] + len(index)
dim = nResonances * MPAR
assert n_b == dim
not_index = numpy.array([k for k in range(n_b) if k not in index])
matrix2 = numpy.zeros((dim,dim))
matrix2[not_index.reshape(-1,1), not_index] = matrix
matrix = matrix2
matrixClass = arrayModule.flattened # even if originally LCOMP=1
# mf32 may not contain all resonances from mf2:
mf2_elist_sorted = sorted(mf2_elist, key=lambda res: res[0])
mf32_elist_sorted = sorted(mf32_elist, key=lambda res: res[0])
if mf32_elist != mf32_elist_sorted or LCOMP==0:
ENDFconversionFlags.append( 'sortByL' )
if len(mf2_elist) != len(mf32_elist):
if not set(mf32_elist).issubset(mf2_elist):
onlyInMF32 = set(mf32_elist).difference(mf2_elist)
ndiffs = len(onlyInMF32)
warningList.append("MF32 resonance parameters differ for %d resonances. For example:" % ndiffs)
for mf32res in sorted(onlyInMF32):
# find closest match (by resonance energy) in MF=2
eres = mf32res[0]
for idx,mf2res in enumerate(mf2_elist_sorted):
if mf2res[0] > eres: break
if abs(mf2_elist_sorted[idx-1][0] - eres) < abs(mf2res[0] - eres):
idx -= 1
mf2res = mf2_elist_sorted[idx-1]
warningList.append( " resonance #%d: MF2 = %s, MF32 = %s" % (idx, mf2res, mf32res) )
if not info.verboseWarnings: break
raise BadCovariance("MF32 resonance parameters don't match MF2 parameters!")
else:
dim = len(mf2_elist) * MPAR
matrix2 = numpy.zeros((dim,dim))
matrix2[:len(matrix),:len(matrix)] = matrix
matrix = matrix2
for mf2res in mf2_elist:
if mf2res not in mf32_elist:
mf32_elist.append(mf2res)
matrixClass = arrayModule.flattened # since some rows will be all 0
if mf32_elist != mf2_elist or LCOMP==0: # rearrange order of MF32 resonances to match GNDS storage order
mf32_elist_extended = mf32_elist + [v for v in mf2_elist if v not in mf32_elist]
for i1 in range(len(mf2_elist)):
i2 = mf32_elist_extended.index(mf2_elist[i1])
if i2 != i1:
swaprows(matrix, MPAR * i1, MPAR * i2, MPAR)
# also need to swap values in elist2:
val = mf32_elist_extended[i1]
mf32_elist_extended[i1] = mf32_elist_extended[i2]
mf32_elist_extended[i2] = val
if LRF==3: # also swap elastic and capture widths to follow LRF=7 convention
for i1 in range(len(mf2_elist)):
swaprows(matrix, MPAR * i1 + 1, MPAR * i1 + 2, 1)
if DAP: # scattering radius uncertainty was specified. Expand matrix to include it:
if len(DAP) > 1:
raise BadCovariance("Energy-dependent scat. radius uncertainty not yet handled!")
dim = len(matrix) + len(DAP)
new_matrix = numpy.zeros( (dim,dim) )
for i in range(len(DAP)): new_matrix[i,i] = DAP[i]
new_matrix[ len(DAP):, len(DAP): ] = matrix
matrix = new_matrix
# switch to diagonal matrix if possible (much more compact):
if numpy.all( matrix==( numpy.identity(len(matrix)) * matrix.diagonal() ) ):
GNDSmatrix = arrayModule.diagonal( shape=matrix.shape, data=matrix.diagonal() )
elif matrixClass is arrayModule.flattened:
GNDSmatrix = arrayModule.flattened.fromNumpyArray(matrix, symmetry=arrayModule.symmetryLowerToken)
else:
GNDSmatrix = arrayModule.full( shape=matrix.shape, data=matrix[ numpy.tril_indices(len(matrix)) ],
symmetry=arrayModule.symmetryLowerToken)
# store into GNDS:
parameters = covarianceModelParametersModule.parameters()
if LRF in (1,2):
resData = resonances.resolved.evaluated.resonanceParameters.table
nParams = resData.nColumns * resData.nRows
startIndex = 0
if DAP:
parameters.add( covarianceModelParametersModule.parameterLink(label="scatteringRadius",
root="$reactions", link=resonances.resolved.evaluated.scatteringRadius, matrixStartIndex=0,
nParameters=1) )
startIndex = 1
parameters.add( covarianceModelParametersModule.parameterLink( label="resonanceParameters",
root="$reactions", link=resData, matrixStartIndex=startIndex, nParameters=nParams ) )
else:
# for RMatrix need links to each spinGroup
startIndex = 0
if DAP:
parameters.add( covarianceModelParametersModule.parameterLink(label="scatteringRadius",
root="$reactions", link=resonances.scatteringRadius, matrixStartIndex=0, nParameters=1) )
startIndex += 1
for spinGroup in resonances.resolved.evaluated:
nParams = spinGroup.resonanceParameters.table.nColumns * spinGroup.resonanceParameters.table.nRows
if nParams == 0: continue
parameters.add(covarianceModelParametersModule.parameterLink(
label=spinGroup.label, link=spinGroup.resonanceParameters.table, root="$reactions",
matrixStartIndex=startIndex, nParameters=nParams
))
startIndex += nParams
covmatrix = covarianceModelParametersModule.parameterCovarianceMatrix(info.style, GNDSmatrix,
parameters, type=Type)
if ENDFconversionFlags:
info.ENDFconversionFlags.add(covmatrix, ','.join(ENDFconversionFlags))
elif LRF==7:
dum,dum,IFG,LCOMP,NJS,ISR = funkyFI(dat.next(), logFile = info.logs)
if ISR>0:
raise NotImplementedError("scattering radius uncertainty in MF32 LRF7")
if LCOMP==1:
AWRI, dum, dum, dum, NSRS, NLRS = funkyFI(dat.next(), logFile=info.logs)
dum, dum, NJSX, dum, dum, dum = funkyFI(dat.next(), logFile=info.logs)
for jdx in range(NJSX):
spinGroup = resonances.resolved.evaluated[jdx]
dum, dum, NCH, NRB, sixNX, NX = funkyFI(dat.next(), logFile=info.logs)
assert sixNX == 6*NX
resonanceParams = []
nlines = int(math.ceil((NCH + 1) / 6.0)) # Extra "1" is for the Eres column
for i in range(NRB):
vals = []
for j in range(nlines):
vals += funkyF(dat.next(), logFile=info.logs)
resonanceParams.append(vals[:NCH + 1])
# test for consistency with MF2
if spinGroup.resonanceParameters.table.data != resonanceParams:
raise BadCovariance("MF32 resonance parameters don't match MF2 parameters for spin group %d!"
% jdx )
# rest of matrix:
dum, dum, dum, dum, N, NPARB = funkyFI(dat.next(), logFile=info.logs)
assert N == (NPARB*(NPARB+1))/2
matrix = read_LCOMP1( NPARB, N, dat )
Type="absoluteCovariance"
ENDFconversionFlags.append( "LCOMP=1" )
elif LCOMP==2:
dum,dum,NPP,NJSX,twelveNPP,twoNPP = funkyFI(dat.next(), logFile = info.logs)
assert (twoNPP == 2*NPP) and (twelveNPP == 12*NPP)
for idx in range(NPP):
# FIXME should check these against MF2 values:
MA, MB, ZA, ZB, IA, IB = funkyF( dat.next(), logFile = info.logs )
Q, PNT, SHF, MT, PA, PB = funkyF( dat.next(), logFile = info.logs )
if NJSX not in (NJS, 0):
warningList.append( "WARNING in MF=32: NJSX not consistent with NJS: %d vs %d!" % (NJSX, NJS) )
allUncerts = []
for jdx in range(NJS):
spinGroup = resonances.resolved.evaluated[jdx]
AJ, PJ, dum, dum, sixNCH, NCH = funkyFI(dat.next(), logFile = info.logs)
for cidx in range(NCH):
# FIXME should also check these against MF2:
PPI, L, SCH, BND, APE, APT = funkyFI(dat.next(), logFile = info.logs)
dum,dum,dum,NRSA,twelveNX,NX = funkyFI( dat.next(), logFile = info.logs )
if twelveNX!=12*NX:
warningList.append("WARNING: incorrect LRF7 header, line %d" % dat.index)
if NRSA==0: dat.next() # skip empty line
resonanceParams = []
resonanceUncerts = []
nlines = int(math.ceil( (NCH+1)/6.0 )) # Extra "1" is for the Eres column
for i in range(NRSA):
vals = []
uncerts = []
for j in range(nlines):
vals += funkyF( dat.next(), logFile = info.logs )
for j in range(nlines):
uncerts += funkyF( dat.next(), logFile = info.logs )
resonanceParams.append( vals[:NCH+1] )
resonanceUncerts.append( uncerts[:NCH+1] )
allUncerts += uncerts[:NCH+1]
# now test for consistency with MF2
if spinGroup.resonanceParameters.table.data != resonanceParams:
raise BadCovariance("MF32 resonance parameters don't match MF2 parameters for spin group %d!"
% jdx )
J, pi = translateENDFJpi(AJ,PJ)
if not J == spinGroup.spin and pi == spinGroup.parity:
raise BadCovariance("Inconsistent J/pi for MF2 / MF32 spin group %d" % jdx)
# correlations:
dum,dum, NDIGIT, NNN, NM, dum = funkyFI( dat.next(), logFile = info.logs )
matrix = read_LCOMP2_correlation(NNN,NM,NDIGIT,dat)
# now we can either add uncertainty columns to the parameter tables (and store correlation matrix),
# or convert to covariance matrix. For now do the latter
rsd = numpy.array( allUncerts )
matrix = matrix * numpy.outer(rsd,rsd)
Type="absoluteCovariance"
ENDFconversionFlags.append( "LCOMP=2" )
ENDFconversionFlags.append( "NDIGIT=%d" % NDIGIT )
else:
raise NotImplementedError("MF32 LRF=7 LCOMP=%d" % LCOMP)
# switch to diagonal matrix if possible (much more compact):
if numpy.all( matrix==( numpy.identity(len(matrix)) * matrix.diagonal() ) ):
GNDSmatrix = arrayModule.diagonal( shape = matrix.shape, data = matrix.diagonal() )
else:
GNDSmatrix = arrayModule.flattened.fromNumpyArray(matrix, symmetry=arrayModule.symmetryLowerToken)
# store into GNDS (need links to each spinGroup)
parameters = covarianceModelParametersModule.parameters()
startIndex = 0
for spinGroup in resonances.resolved.evaluated:
nParams = spinGroup.resonanceParameters.table.nColumns * spinGroup.resonanceParameters.table.nRows
if nParams == 0: continue
parameters.add( covarianceModelParametersModule.parameterLink(
label = spinGroup.label, link = spinGroup.resonanceParameters.table, root="$reactions",
matrixStartIndex=startIndex, nParameters=nParams
))
startIndex += nParams
covmatrix = covarianceModelParametersModule.parameterCovarianceMatrix(info.style, GNDSmatrix,
parameters, type=Type )
if ENDFconversionFlags:
info.ENDFconversionFlags.add(covmatrix, ','.join(ENDFconversionFlags))
else:
raise KeyError("Unknown LRF %d encountered in MF32" % LRF)
rowData = covarianceSectionModule.rowData(info.reactionSuite.resonances.resolved.evaluated,
root='$reactions')
parameterSection = covarianceModelParametersModule.parameterCovariance("resolved resonances", rowData)
parameterSection.add(covmatrix)
sections.append(parameterSection)
else:
# unresolved resonance parameters
def makeURRcovariance( uncert, energyBounds, conversionFlag = None ):
matrix = arrayModule.full(shape=(1, 1), data=[uncert])
axes = axesModule.axes(labelsUnits={0: ('matrix_elements', ''),
1: ('column_energy_bounds', 'eV'),
2: ('row_energy_bounds', 'eV')})
axes[2] = axesModule.grid(axes[2].label, axes[2].index, axes[2].unit,
style=axesModule.boundariesGridToken, values=valuesModule.values(energyBounds[0]))
if len(energyBounds) == 2:
axes[1] = axesModule.grid(axes[1].label, axes[1].index, axes[1].unit,
style=axesModule.boundariesGridToken, values=valuesModule.values(energyBounds[1]))
else:
axes[1] = axesModule.grid(axes[1].label, axes[1].index, axes[1].unit,
style=axesModule.linkGridToken, values=linkModule.link(link=axes[2].values, relative=True))
covmatrix = covarianceBaseModule.covarianceMatrix( info.style, type=covarianceTokensModule.relativeToken,
matrix = griddedModule.gridded2d(axes, matrix) )
if conversionFlag:
info.ENDFconversionFlags.add( covmatrix, conversionFlag )
return covmatrix
URR = resonances.unresolved.evaluated
LJs = []
SPI,AP,dum,dum,NLS,dum = funkyFI( dat.next(), logFile = info.logs )
for lval in range(NLS):
AWRI,dum,L,dum,tmp,NJS = funkyFI( dat.next(), logFile = info.logs )
if tmp!=6*NJS: raise BadCovariance( "Incorrect header in MF32 unresolved section!" )
for jval in range(NJS):
D,AJ,GNO,GG,GF,GX = funkyF( dat.next(), logFile = info.logs )
if AJ.is_integer(): AJ = int(AJ)
LJs.append( (L,AJ,{'D':D,'GNO':GNO,'GG':GG,'GF':GF,'GX':GX}) )
# matrix:
dum,dum,MPAR,dum,tmp,NPAR = funkyFI( dat.next(), logFile = info.logs )
if tmp != (NPAR*(NPAR+1))/2: raise BadCovariance( "Incorrect header in MF32 unresolved section!" )
nlines = int(math.ceil(tmp/6.0))
data = []
for line in range(nlines): data += funkyF(dat.next(), logFile = info.logs)
matrix = numpy.zeros((NPAR,NPAR))
start, length = 0, NPAR
for i1 in range(NPAR):
matrix[i1,i1:] = matrix[i1:,i1] = data[start:start+length]
start = start+length; length = length-1
if numpy.all( matrix==0 ):
warningList.append("ignoring empty unresolved covariance matrix!")
continue
# find URR section corresponding to each row in the matrix:
matrixSections = []
for L,J,averageParams in LJs:
conversionFlag = []
for key,value in averageParams.items():
if value: conversionFlag.append( '%s=%s' % (key,value) )
conversionFlag = ','.join(conversionFlag)
lsection, = [lsec for lsec in URR.Ls if lsec.L == L]
jsection, = [jsec for jsec in lsection.Js if jsec.J == J]
for idx in range(MPAR):
matrixSections.append( [lsection.L, jsection.J, jsection.widths[idx], conversionFlag] )
assert len(matrixSections) == len(matrix)
crossTermCounter = 0
for sidx,(L,J,width,conversionFlag) in enumerate(matrixSections):
uncert = matrix[sidx,sidx]
rowData = covarianceSectionModule.rowData(width, root='$reactions')
label = "%s URR: L=%s J=%s" % (width.label, L, float(J))
covarianceSection = covarianceModelParametersModule.averageParameterCovariance(
label, rowData=rowData )
covarianceSection.add( makeURRcovariance(uncert, [width.data.domain()], conversionFlag) )
width.data.uncertainty = uncertaintiesModule.uncertainty(
functional=uncertaintiesModule.covariance(link=covarianceSection[info.style],
root="$covariances" ) )
sections.append( covarianceSection )
if numpy.any(matrix[sidx,sidx+1:]): # cross terms present
for ctidx, crossTerm in enumerate(matrix[sidx,sidx+1:]):
if crossTerm != 0:
otherWidth = matrixSections[sidx+ctidx+1][2]
columnData = covarianceSectionModule.columnData( otherWidth )
label = "URR cross term %d" % crossTermCounter
covarianceSection = covarianceModelParametersModule.averageParameterCovariance(
label, rowData=rowData, columnData=columnData )
covarianceSection.add( makeURRcovariance(crossTerm, [width.data.domain()]) )
sections.append( covarianceSection )
crossTermCounter += 1
return sections, []
[docs]def readMF34( info, dat, mf, mt, cov_info, warningList ):
""" angular distribution covariances: """
# dat contains one MFMT section
dat = myIter(dat)
sectionList, linkData = [], []
ZA, AWR, dum, LTT, dum, NMT = funkyFI(dat.next(), logFile = info.logs)
ZA = int( ZA )
info.addMassAWR( ZA, AWR )
for subsection in range(NMT):
dum,dum,MAT1,MT1,NL,NL1 = funkyFI(dat.next(), logFile = info.logs)
if MT1 == mt:
NSS = NL*(NL+1)/2
else:
NSS=NL*NL1
if MAT1 != 0: raise BadCovariance( "Cross material angular distribution covariance is not allowed in ENDF format. Found MAT1 =",str(MAT1) )
if MT1 != mt: raise NotImplementedError( "Cross reaction covariances in angular distribution covariance data not supported" )
for iNSS in range(NSS):
dum, dum, L, L1, LCT, NI = funkyFI(dat.next(), logFile = info.logs)
frame = [ "frameOfMF4", standardsModule.frames.labToken, standardsModule.frames.centerOfMassToken][LCT]
covarsThisL = []
for NIdx in range(NI):
dum,dum,LS,LB,NT,NE = funkyFI(dat.next(), logFile = info.logs)
if( ( LS not in [ 1, 0 ] ) and ( LB < 7 ) ) :
raise BadCovariance( "Unexpected LS%d LB%d in MF34" % (LS, LB) )
# pretend it's MF33 file:
matrix = readMatrix( info, LS,LB,NT,NE, dat )
if LB==0: raise Exception("LB=0 in Legendre covariances")
covarsThisL.append( covarianceBaseModule.covarianceMatrix(
label = info.style, type='relative', matrix=matrix, productFrame=frame ) )
if len(covarsThisL)>1:
sectionForm = covarianceMixedModule.mixedForm( label = info.style, components=covarsThisL )
for idx in range(len(sectionForm)): sectionForm[idx].label = str(idx)
elif len(covarsThisL)==1:
sectionForm = covarsThisL[0]
# add unique id to the section:
idNow, pointers = genID(cov_info, mt, mf)
rowdat, coldat = pointers
rowdat['L'] = L
if L1 != L:
coldat = covarianceSectionModule.columnData(rowdat.link, root=rowdat.root, ENDF_MFMT="34,2", L=L1)
idNow += " L%d vs. L%d" % (L, L1)
section = covarianceSectionModule.section(label=idNow, rowData=rowdat, columnData=coldat)
section.add(sectionForm)
sectionList.append(section)
linkData.append((mt, mf, mt, mf, idNow))
if frame == 'frameOfMF4':
info.ENDFconversionFlags.add( sectionForm, "LCT=0" )
cov_info.setdefault( 'MF34_missingFrames', {} ).setdefault( mt, [] ).append( section )
if dat.index != dat.length: raise BadCovariance("Not all covariance data converted, MF%d MT%d" % (mf,mt))
return sectionList, linkData
[docs]def readMF35( info, dat, mf, mt, cov_info, warningList ):
""" spectra covariances are fairly simple: """
# dat contains one MFMT section
dat = myIter(dat)
sectionList, linkData = [], []
ZA, AWR, dum, dum, NK, dum = funkyFI(dat.next(), logFile = info.logs)
ZA = int( ZA )
info.addMassAWR( ZA, AWR )
for subsection in range(NK):
# each subsection contains matrix for a different incident energy interval.
E1,E2,LS,LB,NT,NE = funkyFI(dat.next(), logFile = info.logs)
if not (LS==1 and LB==7):
raise BadCovariance( "Unexpected LS%d LB%d in MF35" % (LS, LB) )
# pretend it's MF33 file:
LS=1; LB=5
matrix = readMatrix( info, LS, LB, NT, NE, dat )
matrix.axes[0].unit = '1/eV**2'
form = covarianceBaseModule.covarianceMatrix( label = info.style, type='absolute', matrix=matrix )
# add unique id to the section:
idNow, pointers = genID( cov_info, mt, mf )
idNow += " energy range %d" % subsection
rowdat, coldat = pointers
rowdat.attributes['domainMin'] = E1
rowdat.attributes['domainMax'] = E2
rowdat.attributes['domainUnit'] = 'eV'
section = covarianceSectionModule.section( label=idNow, rowData=rowdat, columnData=coldat)
section.add( form )
sectionList.append( section )
linkData.append( (mt,mf,mt,mf, idNow) )
# end loop over NK subsections
if dat.index != dat.length: raise BadCovariance("Not all covariance data converted, MF%d MT%d" % (mf,mt))
return sectionList, linkData
[docs]def readMF40(info,dat,mf,mt,cov_info,warningList):
""" production of radioactive isotopes. Also very similar to MF33 """
dat = myIter(dat)
sectionList, linkData = [],[]
ZA, AWR, LIS, dum, NS, dum = funkyFI(dat.next(), logFile = info.logs)
ZA = int( ZA )
info.addMassAWR( ZA, AWR )
# each subsection represents different excited state of residual
for subsection in range(NS):
try:
QM,QI,IZAP,LFS,dum,NL = funkyFI(dat.next(), logFile = info.logs)
except StopIteration:
warningList.append('MF40 MT%d lists incorrect number of subsections!' % mt )
info.doRaise.append( warningList[-1] )
break
if mt == 18 and IZAP != -1:
warningList.append("For MT=18 MF=40, expected IZAP=-1 but got %d" % IZAP)
info.doRaise.append(warningList[-1])
return ([], [])
for subsubsection in range(NL):
# each subsubsection is a single matrix
XMF1,XLFS1,MAT1,MT1,NC,NI = funkyFI(dat.next(), logFile = info.logs)
XMF1,XLFS1 = int(XMF1),int(XLFS1) # XLFS1: level index
covarsThisSection = []
if XMF1 not in (0,10):
raise BadCovariance( "non-zero XMF1/XLFS1 in covariances not currently handled!" )
if MAT1!=0:
warningList.append( "cross-material covariance with MAT=%d" % MAT1 )
for NCdx in range(NC):
dum,dum,dum,LTY,dum,dum = funkyFI(dat.next(), logFile = info.logs)
if LTY==0:
E1,E2,dum,dum,NCI2,NCI = funkyFI(dat.next(), logFile = info.logs)
subsec = []
nlines = int(math.ceil(NCI2/6.0))
for line in range(nlines): subsec += funkyF(dat.next(), logFile = info.logs)
#coefs = subsec[:NCI2][::2]
pointerList = [
linkModule.link( 'summand', genID( cov_info, int(mtnum), mf )[0],
attributes={'ENDF_MFMT':"%d,%d"%(mf,mtnum), 'coefficient':coef})
for coef,mtnum in zip(subsec[:NCI2][::2],subsec[:NCI2][1::2])
]
covarsThisSection.append(covarianceSummedModule.summedCovariance(label=info.style,
domainMin=E1, domainMax=E2, domainUnit='eV', pointerList=pointerList))
else:
warningList.append( 'non-zero LTY in MF40' )
for NIdx in range(NI):
dum,dum,LS,LB,NT,NP = funkyFI(dat.next(), logFile = info.logs)
matrix = readMatrix( info, LS,LB,NT,NP, dat )
if LB not in (0,1,5,6):
warningList.append( 'skipping LB%d section for MF%d MT%d' % ( LB, mf, mt ) )
continue
Type='relative'
if LB==0:
Type='absolute'
matrix.axes[0].unit = 'b**2'
covarsThisSection.append( covarianceBaseModule.covarianceMatrix( label = info.style, type=Type, matrix=matrix) )
if MAT1!=0:
continue
# create unique id for each section:
idNow, pointers = genID( cov_info, mt, mf, MT2=MT1, MF2=(XMF1 or mf), MAT2=MAT1, QI=QI )
rowdat, coldat = pointers
section = covarianceSectionModule.section( label=idNow, rowData=rowdat, columnData=coldat )
if len(covarsThisSection)>1:
form = covarianceMixedModule.mixedForm( label = info.style, components=covarsThisSection )
for idx in range(len(form)): form[idx].label = str(idx)
elif len(covarsThisSection)==1:
form = covarsThisSection[0]
else:
#raise Exception("Encountered empty covariance section!!!")
info.logs.write("Missing covariance data from section!")
continue
section.add( form )
sectionList.append( section )
linkData.append( (mt,mf,MT1,XMF1, idNow) )
# end loop over NL subsections
if dat.index != dat.length:
warningList.append( "Not all covariance data converted for MF%d MT%d" % (mf,mt) )
info.doRaise.append( warningList[-1] )
return sectionList, linkData
[docs]def parseMF6FissionData( info, MF6Data, fissionNeutronsAndGammasDataFromMF6, warningList ) :
print( " WARNING: parseMF6FissionData function not complete." )
dataLine = 0
ZA, AWR, JP, LCT, NK, dummy = endfFileToGNDSMiscModule.sixFunkyFloatStringsToIntsAndFloats( MF6Data[dataLine], intIndices = [ 0, 2, 3, 4 ],
logFile = info.logs )
dataLine += 1
JPP = JP / 10
JPN = JP - 10 * JPP
for particleIndex in range( NK ) :
dataLine = parseMF6FissionParticle( info, dataLine, MF6Data, JPN, JPP, fissionNeutronsAndGammasDataFromMF6, warningList )
[docs]def parseMF6FissionParticle( info, dataLine, MF6Data, JPN, JPP, fissionNeutronsAndGammasDataFromMF6, warningList ) :
# The work on this is incomplete.
dataLine, productData, multiplicityRegions = endfFileToGNDSMiscModule.getTAB1Regions( dataLine, MF6Data, logFile = info.logs,
axes = multiplicityAxes )
ZAP, AWP, LIP, LAW, NP = int( productData['C1'] ), productData['C2'], productData['L1'], productData['L2'], productData['NR']
energyDistribution = None
JP = JPP
if( ZAP == 1 ) : JP = JPN
if( JP != 1 ) : raise ValueError( 'JP = %s not suppported' % JP )
fissionNeutronsAndGammasDataFromMF6[ZAP].append( [ multiplicityRegions, energyDistribution ] )
return( dataLine )
[docs]def fillRemainingProductsResidualForBreakup( info, decayChannel, lightIsotopeNames, breakupProducts, residualZA, crossSection ) :
residualZA2 = residualZA
for productName in lightIsotopeNames :
if( productName in breakupProducts ) :
multiplicity = breakupProducts[productName]
product = toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameGamma( info, productNameToZA[productName] ),
crossSection, multiplicity = multiplicity )
decayChannel.products.add( decayChannel.products.uniqueLabel( product ) )
if( ( residualZA % 1000 ) > 0 ) :
residualZA2 -= multiplicity * productNameToZA[productName]
else :
residualZA2 -= multiplicity * ( 1000 * ( productNameToZA[productName] / 1000 ) )
if( residualZA2 != 0 ) : decayChannel.products.add( decayChannel.products.uniqueLabel(
toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameGamma( info, residualZA2 ), crossSection ) ) )
[docs]def parseReaction( info, target, projectileZA, targetZA, MT, MTData, warningList, parseCrossSectionOnly = False, channelProcess = None ) :
"""
Translate all available data for the reaction with this MT.
:return: tuple(crossSection, outputChannel, MFKeys) where MFKeys contains MF numbers that remain untranslated (should be empty)
"""
productList = []
MFKeys = MTData.keys( )
info.logs.write( ' %3d %s' % ( MT, sorted( MFKeys ) ) )
for MF in [ 8, 9, 10, 31, 32, 33, 34, 35, 40, 45 ] :
if( MF in MFKeys ) : MFKeys.remove( MF )
if( ( MT == 3 ) and ( 3 not in MFKeys ) ) : # Kludge, for ENDF files that for MT 3 have MF 12 and 13 but not MF 3 data.
QM, QI, crossSection, LR, breakupProducts = 0, 0, None, 0, None
else :
QM, QI, crossSection, LR, breakupProducts = readMF3( info, MT, MTData[3], warningList )
MFKeys.remove( 3 )
if( parseCrossSectionOnly ) :
channel = channelsModule.NBodyOutputChannel( process = channelProcess )
channel.Q.add( toGNDSMiscModule.returnConstantQ( info.style, QM, crossSection ) )
return( crossSection, channel, MFKeys )
fissionGenre = { 18 : channelsModule.fissionGenreTotal,
19 : channelsModule.fissionGenreFirstChance,
20 : channelsModule.fissionGenreSecondChance,
21 : channelsModule.fissionGenreThirdChance,
38 : channelsModule.fissionGenreFourthChance }.get(MT, None)
neutronMFs = []
fissionNeutronsAndGammasDataFromMF6 = { 0 : [], 1 : [] } # Keys are ZAP (i.e., 0 for gammas and 1 for neutrons).
for MF in [ 4, 5 ] :
if( MF in MFKeys ) : neutronMFs.append( MF )
if( ( neutronMFs != [] ) and ( 6 in MFKeys ) ) :
if( MT == 18 ) :
parseMF6FissionData( info, MTData[6], fissionNeutronsAndGammasDataFromMF6, warningList )
MFKeys.remove( 6 )
else :
raise Exception( "MF 6 present and MF 4 and/or 5 present: not allowed" ) # This should never happen!
endfMTProductList = endf_endlModule.endfMTtoC_ProductLists[MT]
compoundZA = calculateZA( targetZA, projectileZA, minus = False )
lightIsotopeZAs = sorted( [ productNameToZA[product] for product in lightIsotopeNames ] )
lightIsotopeZAsMultiplicity = {}
for product in lightIsotopeNames : lightIsotopeZAsMultiplicity[productNameToZA[product]] = endfMTProductList.productCounts[product]
if( ( 4 in neutronMFs ) or ( ( MT == 18 ) and ( neutronMFs == [ 5 ] ) ) ) : # MT == 18 and neutronMFs == [ 5 ] is a special case for bad data (g + Am241).
ZAP = 1
if( MT not in [ 2, 5, 18, 19, 20, 21, 38 ] ) : # Not elastic, fission or sumOfRemainingReactions.
for product in lightIsotopeNames :
if( endfMTProductList.productCounts[product] > 0 ) : break
ZAP = productNameToZA[product]
levelIndex, decayChannel, twoBodyResidualZA = None, None, None
if( 50 <= MT < 91 ) :
levelIndex = MT - 50
elif( 600 <= MT < 649 ) :
levelIndex = MT - 600
elif( 650 <= MT < 699 ) :
levelIndex = MT - 650
elif( 700 <= MT < 749 ) :
levelIndex = MT - 700
elif( 750 <= MT < 799 ) :
levelIndex = MT - 750
elif( 800 <= MT < 849 ) :
levelIndex = MT - 800
elif( 875 <= MT < 891 ) :
levelIndex = MT - 875
level = QM - QI # If level > 0., residual is in an excited state.
if( breakupProducts is not None ) :
if( 50 <= MT < 91 ) :
level = -QI
elif( MT == 91 ) :
pass
else :
print(breakupProducts)
raise NotImplementedError( 'breakup for MT %s is not supported' % MT )
isUndefinedTwoBody = ( MT == 91 ) or ( 102 < MT <= 107 ) or ( MT in [ 649, 699, 749, 799, 849 ] )
isTwoBody = ( MT == 2 ) or ( 50 <= MT < 91 ) or ( ( 600 <= MT < 849 ) and not( isUndefinedTwoBody ) )
if( isTwoBody or isUndefinedTwoBody ) :
if( MT == 2 ) :
ZAP = projectileZA
else :
for productName in endfMTProductList.productCounts :
if( endfMTProductList.productCounts[productName] != 0 ) : break
if( productName == IDsPoPsModule.photon ) :
ZAP = 0
else :
ZAP = productNameToZA[productName]
twoBodyResidualZA = calculateZA( compoundZA, ZAP )
undefinedLevelInfo = { 'ZA' : twoBodyResidualZA, 'level' : level, 'levelIndex' : levelIndex, 'count' : 0 }
if( neutronMFs == [ 4 ] ) : # This is a two-body reaction with only angular data.
if( not( isTwoBody ) ) : raise ValueError( 'With only MF = 4 data present, reaction is assumed to be two-body and it is not for MT = %s' % MT )
product = toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameGamma( info, ZAP ), crossSection )
form = readMF4( info, product, MT, MTData[4], angularModule.twoBodyForm, warningList )
MFKeys.remove( 4 )
productList.append( product )
elif( ( neutronMFs == [ 4, 5 ] ) or ( ( neutronMFs == [ 5 ] ) and ZAP == 1 ) ) :
# Don't check ZAP if MT=5. Currently this combination, MT=5, MF=4/5 appears only for incident gammas
if( MT != 5 and ZAP != 1 ) : raise ValueError( 'ZAP = %d != 1 for MFs = [ 4, 5 ] for MT = %d' % ( ZAP, MT ) )
multiplicity = 1
if( MT not in [ 2, 5, 18, 19, 20, 21, 38 ] ) : # Not elastic or fission.
for product in lightIsotopeNames :
if( endfMTProductList.productCounts[product] > 0 ) : break
ZAP = productNameToZA[product]
multiplicity = endfMTProductList.productCounts[product]
else :
if( MT not in [ 2, 5 ] ) : multiplicity = -1 # MT 5 is special case where (g,n') put into MT 5 instead of one of 50-91.
product = toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameENDF( info, ZAP, undefinedLevelInfo ),
crossSection, multiplicity = multiplicity )
if( neutronMFs == [ 5 ] ) :
warningList.append("MF=5 found with no accompanying MF=4, assuming angular distribution for MT=%i is isotropic"%MT)
angularSubform = angularModule.isotropic2d( ) # MF = 5 data is always in lab frame.
else :
angularSubform = readMF4( info, product, MT, MTData[4], None, warningList )
MFKeys.remove( 4 )
energySubform , weights = readMF5( info, MT, MTData[5], warningList, product = product )
MFKeys.remove( 5 )
form = uncorrelated( info.style, frames[1], angularSubform, energySubform ) # BRB: is frame right.
product.distribution.add( form )
productList.append( product )
elif( 6 in MFKeys ) :
isTwoBody = readMF6( MT, info, MTData[6], productList, warningList, undefinedLevelInfo, isTwoBody, crossSection )
MFKeys.remove( 6 )
elif( neutronMFs == [] ) :
if( isTwoBody and False ) : # ????????? Why False
raise Exception( 'How did we get here.' )
product = toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameGamma( info, ZAP ), crossSection )
residualZA = calculateZA( compoundZA, ZAP )
if( levelIndex is not None ) :
if( ( levelIndex <= info.targetLevel ) and ( info.targetZA == residualZA ) ) : levelIndex -= 1
if( QI != QM ) : # Residual is in an excited state.
decayChannel = channelsModule.NBodyOutputChannel( )
decayChannel.products.add( decayChannel.products.uniqueLabel(
toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameGamma( info, residualZA ), crossSection ) ) )
residual = toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameGamma( info, residualZA, level = level ),
crossSection, outputChannel = decayChannel )
productList.append( product )
productList.append( residual )
else :
pass
_dummyCrossSection = []
readMF12_13( info, MT, MTData, productList, warningList, crossSection, _dummyCrossSection )
_crossSection = crossSection
if( _crossSection is None ) : _crossSection = _dummyCrossSection[0] # Should only happen for MT=3 with no MF=3.
for MF in [ 12, 13, 14, 15 ] :
if( MF in MFKeys ) : MFKeys.remove( MF )
""" # FIXME: doesn't appear to be used anymore
specialBe9n2nExcited, specialBe9n2nExcitedLevel = False, 0
if( 875 <= MT < 892 ) : # Special case for (z,2n[?])
if( targetZA == 4009 ) : # Special case for Be9(n,2n[?]He4)He4
specialBe9n2nExcited = True
specialBe9n2nExcitedLevel = ( QM - QI ) / 1e6
"""
if( MT == 5 ) :
if( QM != QI ) : info.logs.write( ' --QM %s != QI = %s\n' % ( QM, QI ) )
outputChannel = channelsModule.sumOfRemainingOutputChannels( )
outputChannel.Q.add( toGNDSMiscModule.returnConstantQ( info.style, QM, _crossSection ) )
elif( ( MT == 102 ) and not( isTwoBody ) ) :
residualIndex, gammaMissing = -1, False
for index, product in enumerate( productList ) :
if( product.id != IDsPoPsModule.photon ) : residualIndex = index
gammaMissing = ( product.id == IDsPoPsModule.photon ) or gammaMissing
if( residualIndex == -1 ) :
productList.insert( 0, toGNDSMiscModule.newGNDSParticle( info,
toGNDSMiscModule.getTypeNameENDF( info, calculateZA( compoundZA, 0 ), undefinedLevelInfo ), crossSection ) )
if( residualIndex > 0 ) : productList.insert( 0, productList.pop( residualIndex ) )
if( not( gammaMissing ) ) : productList.append( toGNDSMiscModule.newGNDSParticle( info,
toGNDSMiscModule.getTypeNameENDF( info, 0, undefinedLevelInfo ), crossSection ) )
outputChannel = channelsModule.NBodyOutputChannel( )
outputChannel.Q.add( toGNDSMiscModule.returnConstantQ( info.style, QM, _crossSection ) ) # Q????? What about QI?
elif( isTwoBody ) :
if( ( QI == 0 ) and ( QM != 0 ) ) : raise Exception("QI = 0, QM = %f for MT=%d" % (QM,MT))
outputChannel = channelsModule.twoBodyOutputChannel( )
outputChannel.Q.add( toGNDSMiscModule.returnConstantQ( info.style, QI, _crossSection ) )
if( len( productList ) == 0 ) :
for ZA in lightIsotopeZAs :
if( lightIsotopeZAsMultiplicity[ZA] != 0 ) :
productList.append( toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameENDF( info, ZA, undefinedLevelInfo ),
crossSection ) )
break
if( len( productList ) == 0 ) :
if( MT != 2 ) : raise Exception( "product data for reaction MT = %s needs to be implemented" % MT )
productList.append( toGNDSMiscModule.newGNDSParticle( info,
toGNDSMiscModule.getTypeNameENDF( info, projectileZA, undefinedLevelInfo ), crossSection ) )
decayProductList = productList[1:]
productList = productList[:1] # Assume first product is "b" in "a + A -> b + B" where B is the larger product.
ZA = particleZA( info, productList[0].id )
residualZA = calculateZA( compoundZA, ZA )
levelIndex = undefinedLevelInfo['levelIndex']
if( levelIndex is not None ) :
if( ( levelIndex <= info.targetLevel ) and ( targetZA == residualZA ) ) : levelIndex -= 1
undefinedLevelInfo['levelIndex'] = levelIndex
for index, product in enumerate( decayProductList ) :
ZA = particleZA( info, product.id )
if( residualZA == ZA ) :
productList.append( decayProductList.pop( index ) )
break
if( len( productList ) < 2 ) :
if( MT == 2 ) :
productList.append( toGNDSMiscModule.newGNDSParticle( info, target, crossSection ) )
else :
if( ZA == undefinedLevelInfo['ZA'] ) : undefinedLevelInfo['ZA'] = None
productList.append( toGNDSMiscModule.newGNDSParticle( info,
toGNDSMiscModule.getTypeNameENDF( info, residualZA, undefinedLevelInfo ), crossSection ) )
if 4 not in MTData.keys():
info.ENDFconversionFlags.add( productList[-1], 'implicitProduct' )
if( info.style in productList[0].distribution ) :
recoilForm = angularModule.twoBodyForm( info.style, standardsModule.frames.centerOfMassToken,
angularSubform = angularModule.recoil( productList[0].distribution[info.style], relative=True ) )
productList[-1].distribution.add( recoilForm )
decayZAs, decayGammaList, decayNonGammaList = 0, [], []
for decayProduct in decayProductList :
if( decayProduct.id == IDsPoPsModule.photon ) :
decayGammaList.append( decayProduct )
mult = 1
else :
decayNonGammaList.append( decayProduct )
mult = decayProduct.multiplicity.getConstant()
decayZAs += particleZA(info, decayProduct.id) * mult
if( LR == 1 ) :
if( decayZAs != residualZA ) : raise Exception( "decayZAs = %d != residualZA = %d" % ( decayZAs, residualZA ) )
elif( decayZAs == 0 ) :
if( len( decayGammaList ) != 0 ) :
if( len( decayNonGammaList ) == 0 ) :
decayNonGammaList.append( toGNDSMiscModule.newGNDSParticle( info,
toGNDSMiscModule.getTypeNameENDF( info, residualZA, None ), crossSection ) )
elif( len( decayNonGammaList ) != 0 ) :
if( len( decayGammaList ) == 0 ) : decayGammaList.append( toGNDSMiscModule.newGNDSParticle( info,
toGNDSMiscModule.getTypeNameENDF( info, 0, None ), crossSection ) )
decayProductList = decayNonGammaList + decayGammaList
else :
raise Exception( "decayZAs = %d != 0" % decayZAs )
if( breakupProducts is not None ) :
if( decayChannel is not None ) : raise Exception( 'breakupProducts and decayChannel both not None' )
decayChannel = channelsModule.NBodyOutputChannel( )
decayChannel.Q.add( toGNDSMiscModule.returnConstantQ( info.style, QM - QI, _crossSection ) )
fillRemainingProductsResidualForBreakup( info, decayChannel, lightIsotopeNames, breakupProducts,
particleZA( info, productList[1].id ), crossSection )
productList[1].addOutputChannel( decayChannel )
elif( len( decayProductList ) > 0 ) : # At this point, both two bodies are in productList and second one is redisual.
if( QI > QM ) : raise Exception( "Negative decay Q-value for MT%d, QI = %s, QM = %s" % ( MT, QI, QM ) )
decayChannel = channelsModule.NBodyOutputChannel( )
decayChannel.Q.add( toGNDSMiscModule.returnConstantQ( info.style, QM - QI, _crossSection ) ) # Q????? Not right?
for decayProduct in decayProductList : decayChannel.products.add( decayChannel.products.uniqueLabel( decayProduct ) )
productList[1].addOutputChannel( decayChannel )
elif( endfMTProductList.isFission ) :
outputChannel = channelsModule.fissionChannel( fissionGenre = fissionGenre )
if hasattr( info, 'fissionEnergyReleaseData' ):
FER = getFissionEnergies( info, crossSection.domainMin, crossSection.domainMax, warningList )
# also check for consistency between polynomial expansion and approximate constant Q:
useThisQM = FER.nonNeutrinoEnergy.data.coefficients[ 0 ]
if abs( QM - useThisQM ) > 1e-7 * abs(QM):
warningList.append( "Fission QM inconsistent with energy release data for MT = " + str( MT ) )
outputChannel.Q.add( FER )
else:
useThisQM = QM
outputChannel.Q.add( toGNDSMiscModule.returnConstantQ( info.style, useThisQM, _crossSection ) )
if( MT == 18 ) :
if( len( productList ) > 0 ) : outputChannel.products.add( outputChannel.products.uniqueLabel( productList.pop( 0 ) ) )
if( len( outputChannel ) == 0 ) :
multiplicity = multiplicityModule.unspecified( info.style )
product = toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameGamma( info, 1 ), crossSection,
multiplicity = multiplicity )
outputChannel.products.add( outputChannel.products.uniqueLabel( product ) )
else :
for product in outputChannel :
if( product.id == IDsPoPsModule.neutron ) : break
info.firstFissionNeutron = product
if( tokensModule.promptToken in info.totalOrPromptFissionNeutrons ) :
product.multiplicity.remove( info.style )
product.multiplicity.add( info.totalOrPromptFissionNeutrons[tokensModule.promptToken] )
product.multiplicity.remove( 'constant' )
product.addAttribute( 'emissionMode', tokensModule.promptToken )
# BRB uncomment if( 'total' in info.totalOrPromptFissionNeutrons ) :
# ditto warningList.append( 'have prompt fission nu_bar so not including total' )
elif( 'total' in info.totalOrPromptFissionNeutrons ) :
product.multiplicity.remove( info.style )
product.multiplicity.add( info.totalOrPromptFissionNeutrons['total'] )
product.multiplicity.remove( 'constant' )
product.addAttribute( 'emissionMode', 'total' )
if( hasattr( info, 'delayedFissionDecayChannel' ) ) :
for delayedNeutron in info.delayedFissionDecayChannel :
outputChannel.products.add( outputChannel.products.uniqueLabel( delayedNeutron ) )
else :
if( neutronMFs == [] ) :
pass # we used to add a reference to total fission nubar and PFNS, but that's not physically correct
"""
if( hasattr( info, 'firstFissionNeutron' ) ) :
multiplicity = multiplicityModule.reference( link=info.firstFissionNeutron.multiplicity, label = info.style )
else : # When singleMTOnly is fission MT != 18.
multiplicity = multiplicityModule.unspecified( label = info.style )
product = toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameGamma( info, 1 ),
crossSection, multiplicity = multiplicity )
if( hasattr( info, 'firstFissionNeutron' ) ) :
form = referenceModule.form( link = info.firstFissionNeutron.distribution, label = info.style )
product.distribution.add( form )
outputChannel.products.add( outputChannel.products.uniqueLabel( product ) )
"""
# July 2011: some files have distributions for 1stChanceFission etc, but should still link to total nubar:
for product in productList:
multiplicity = product.multiplicity[info.style]
if( ( isinstance( multiplicity, multiplicityModule.constant1d ) ) and ( product.multiplicity[info.style].evaluate( 0 ) == -1 ) ) :
if hasattr( info, 'firstFissionNeutron' ):
product.multiplicity.remove( info.style )
multiplicity = multiplicityModule.reference( info.firstFissionNeutron.multiplicity, label = info.style )
product.multiplicity.add( multiplicity )
while( len( productList ) > 0 ) : outputChannel.products.add( outputChannel.products.uniqueLabel( productList.pop( 0 ) ) )
else :
outputChannel = channelsModule.NBodyOutputChannel( process = channelProcess )
outputChannel.Q.add( toGNDSMiscModule.returnConstantQ( info.style, QI, _crossSection ) ) # Q?????
if( MT not in [ 1, 18, 19, 20, 21, 38 ] ) :
residualZA, ZAsMultiplicities, productAsResidual, biggestProduct = compoundZA, {}, None, 0
for index, product in enumerate( productList ) :
if( product.id == IDsPoPsModule.photon ) : continue
ZA = particleZA( info, product.id )
multiplicity = product.multiplicity[info.style]
if( isinstance( multiplicity, multiplicityModule.constant1d ) ) :
mult = int( multiplicity.constant )
else :
info.logs.write( '\n\nIncorrect multiplicity in ENDF file! MT = %s\n' % MT )
info.logs.write( 'Multiplicity should be constant but is "%s".\n' % multiplicity.moniker )
raise ValueError( 'Multiplicity should be a constant and it is not.' )
if( ZA in lightIsotopeZAs ) :
residualZA = calculateZA( residualZA, mult * ZA, minus = True )
# If we have different distributions for both neutrons in (n,2n), n shows up twice in the productList.
if( ZA in ZAsMultiplicities ) :
ZAsMultiplicities[ZA] += mult
else :
ZAsMultiplicities[ZA] = mult
else :
if( productAsResidual is not None ) :
raise Exception( 'multiple residuals for MT = %d, %s %s' % ( MT, productAsResidual.id, product.id ) )
productAsResidual = product
_residualZA = compoundZA
for ZA in lightIsotopeZAsMultiplicity : _residualZA = calculateZA( _residualZA, lightIsotopeZAsMultiplicity[ZA] * ZA, minus = True )
if( residualZA != 0 ) :
for ZA in lightIsotopeZAs :
if( ZA not in ZAsMultiplicities ) : ZAsMultiplicities[ZA] = 0
if( ZAsMultiplicities[ZA] == lightIsotopeZAsMultiplicity[ZA] ) : continue # All this ZA accounted for.
if( ZAsMultiplicities[ZA] > lightIsotopeZAsMultiplicity[ZA] ) :
raise Exception( 'negative multiplicity for ZA = %s for MT = %s' % ( ZA, MT ) )
multiplicity = lightIsotopeZAsMultiplicity[ZA] - ZAsMultiplicities[ZA]
productList.append( toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameENDF( info, ZA, None ),
crossSection, multiplicity = multiplicity ) )
residualZA = calculateZA( residualZA, multiplicity * ZA, minus = True )
if( productAsResidual is None ) :
if( residualZA > 0 ) : productList.append( toGNDSMiscModule.newGNDSParticle( info,
toGNDSMiscModule.getTypeNameENDF( info, residualZA, undefinedLevelInfo ), _crossSection ) )
if( MT in [ 103, 104, 105, 106, 107, 91, 649, 699, 749, 799, 849, 891 ] ) :
gammaIndices = []
for index, product in enumerate( productList ) :
if( product.id == IDsPoPsModule.photon ) : gammaIndices.append( index )
if( len( gammaIndices ) > 0 ) :
decayChannel = channelsModule.NBodyOutputChannel( )
decayChannel.Q.add( toGNDSMiscModule.returnConstantQ( info.style, QM - QI, _crossSection ) )
finalResidual = toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getTypeNameENDF( info, residualZA, None ),
crossSection )
decayChannel.products.add( decayChannel.products.uniqueLabel( finalResidual ) )
if( productList[-1].toXLink() in info.ENDFconversionFlags.flags ) :
productFlag = info.ENDFconversionFlags.flags[ productList[-1].toXLink() ].flag
info.ENDFconversionFlags.add( finalResidual, productFlag )
for index in gammaIndices : decayChannel.products.add( decayChannel.products.uniqueLabel( productList[index] ) )
gammaIndices.reverse( )
for index in gammaIndices : del productList[index]
productList[-1].addOutputChannel( decayChannel )
if( productList[-1].distribution.hasData( ) ) : # BRB One must be careful here as this assumes that distributions
forms1 = []
for form in productList[-1].distribution :
forms1.append( form )
productList[-1].distribution.remove( form.label )
forms2 = []
for form in finalResidual.distribution :
forms2.append( form )
finalResidual.distribution.remove( form.label )
for form in forms1 : finalResidual.distribution.add( form )
for form in forms2 : productList[-1].distribution.add( form )
if( breakupProducts is not None ) :
if( MT == 91 ) :
if( decayChannel is not None ) : raise Exception( 'breakupProducts and decayChannel both not None' )
decayChannel = channelsModule.NBodyOutputChannel( )
decayChannel.Q.add( toGNDSMiscModule.returnConstantQ( info.style, QM - QI, _crossSection ) )
fillRemainingProductsResidualForBreakup( info, decayChannel, lightIsotopeNames, breakupProducts,
particleZA( info, productList[1].id ), crossSection )
productList[1].addOutputChannel( decayChannel )
else :
raise Exception( 'breakup not supported for MT %d' % MT )
if( isUndefinedTwoBody ) :
residual = productList[1]
particle = info.PoPs[residual.id]
if( ( residual.outputChannel is None ) and ( QM != QI ) ) :
ZA = chemicalElementMiscPoPsModule.ZA( particle )
residual.addOutputChannel( channelsModule.NBodyOutputChannel( ) )
residual.outputChannel.Q.add( toGNDSMiscModule.returnConstantQ( info.style, QM - QI, _crossSection ) )
product = toGNDSMiscModule.newGNDSParticle( info, toGNDSMiscModule.getPoPsParticle( info, ZA, residual.id ),
crossSection, multiplicity = residual.multiplicity[0].copy( ) )
for form in residual.distribution : product.distribution.add( residual.distribution.pop( form.label ) )
residual.outputChannel.products.add( product )
for product in productList :
if( len( product.distribution ) == 0 ) :
frame = standardsModule.frames.labToken
if( isTwoBody ) : frame = standardsModule.frames.centerOfMassToken
form = unspecifiedModule.form( info.style, productFrame = frame )
product.distribution.add( form )
info.ENDFconversionFlags.add( product, 'implicitProduct' )
outputChannel.products.add( outputChannel.products.uniqueLabel( product ) )
if( isinstance( outputChannel, channelsModule.twoBodyOutputChannel ) ) :
productID = outputChannel[0].id
if( productID != info.projectile ) :
if( productID not in info.missingTwoBodyMasses ) : info.missingTwoBodyMasses[productID] = []
info.missingTwoBodyMasses[productID].append( [ outputChannel[1].id, QM ] )
return( crossSection, outputChannel, MFKeys )
[docs]def parseCovariances( info, MTDatas, MTdict, singleMTOnly=None, resonances=None ):
evaluation = "%s-%d.%d" % (info.evaluation, info.NVER, info.LREL)
covarianceSuite = covarianceSuiteModule.covarianceSuite( info.projectile, info.target, evaluation )
linkData = [] # which mf/mts need to be linked for each covariance?
if( singleMTOnly ) : return( covarianceSuite, linkData )
# make list of available covariance information:
warningList = []
cov_info = {'MTL':{}, 'MTL_2':{}, 'lumpedChannels':{}, 'externalFiles':[], 'mfmts':[], 'MTdict':MTdict,
'resonances':resonances, 'NC_data':[], 'style' : info.style, 'projectile' : info.projectile,
'multiplicitySums': info.reactionSuite.sums.multiplicities}
for mt in MTDatas.keys():
if (singleMTOnly is not None) and (mt!=singleMTOnly): continue
for mf in MTDatas[mt].keys():
if mf >= 30: # all covariance-type data
cov_info['mfmts'].append((mf,mt))
cov_info['mfmts'].sort() # sorting first by MF, then by MT
for mf,mt in cov_info['mfmts']:
try:
if mf in (31,33):
covars, tmp = readMF31_33( info, MTDatas[mt][mf], mf, mt, cov_info, warningList )
elif mf == 32:
covars, tmp = readMF32( info, MTDatas[151][32], mf, mt, cov_info, warningList )
elif mf == 34:
covars, tmp = readMF34( info, MTDatas[mt][mf], mf, mt, cov_info, warningList )
elif mf == 35:
covars, tmp = readMF35( info, MTDatas[mt][mf], mf, mt, cov_info, warningList )
elif mf == 40:
covars, tmp = readMF40( info, MTDatas[mt][mf], mf, mt, cov_info, warningList )
else:
warningList.append( 'MF%d not yet supported' % mf)
continue
for cov in covars:
if mf == 32: covarianceSuite.parameterCovariances.add(cov)
else:
covarianceSuite.covarianceSections.add(cov)
if cov.columnData is None:
covarianceLink = uncertaintiesModule.covariance(link=cov[info.style], root="$covariances")
centralValue = cov.rowData.link
if mt in range(851,872):
continue # lumped channel covariances are handled below
if( mf == 35 ) : centralValue = centralValue.data
if not hasattr(centralValue, 'uncertainty'):
continue # kludge for ENDF-VIII Ni58 and Ni60 (they have MF33 MT3 but no MF3 MT3)
if centralValue.uncertainty is not None:
if isinstance( centralValue.uncertainty.data, uncertaintiesModule.covariance ):
listOfCovars = uncertaintiesModule.listOfCovariances()
listOfCovars.add( centralValue.uncertainty.data )
centralValue.uncertainty = uncertaintiesModule.uncertainty( functional=listOfCovars )
centralValue.uncertainty.data.add( covarianceLink )
else:
centralValue.uncertainty = uncertaintiesModule.uncertainty( functional=covarianceLink )
linkData += tmp
except BadCovariance as e:
warningList.append('MF%d MT%d covariance conversion failed with message "%s"' % (mf,mt,e) )
info.doRaise.append( warningList[-1] )
# fix links for summed matrices:
for summedMatrix in cov_info['NC_data']:
for pointer in summedMatrix.pointerList:
pointed_to = [sec for sec in covarianceSuite.covarianceSections if sec.columnData is None
and sec.rowData['ENDF_MFMT'] == pointer['ENDF_MFMT']]
if len(pointed_to) != 1:
thisMFMT = summedMatrix.ancestor.rowData['ENDF_MFMT']
warningList.append( "Covariance for MF,MT=%s attempts to sum over non-existant covariance %s"
% (thisMFMT, pointer['ENDF_MFMT']) )
info.doRaise.append( warningList[-1] )
continue
pointer.link = pointed_to[0]
pointer.root = None # internal link
# fix lumped channel covariances (MT851-871) and summed channels (MT1,4,103-107)
summedReactions = cov_info['MTL'].copy(); summedReactions.update( cov_info['MTL_2'] )
for (mt,mf) in sorted(summedReactions):
try:
lumpedChannels = cov_info['lumpedChannels'][(mt,mf)]
except KeyError as e:
warningList.append("Cannot find lumped channel %s" %str(e) )
continue
summandList = []
Qs = []
for (mt2,mf2) in summedReactions[(mt,mf)]:
if mt not in range(851,872) and mt2 not in cov_info['MTdict']: continue
reac, = [r1 for r1 in info.reactionSuite.reactions if r1.ENDF_MT == mt2]
xsc = reac.crossSection
summandList.append( sumsModule.add( link=xsc ) )
Qs.append( reac.thresholdQAs( 'eV' ) )
lumpedChannels.summands = sumsModule.listOfSummands( summandList )
if len(lumpedChannels.summands) == 0:
warningList.append("MT%d: trying to sum over empty list (may be caused by earlier errors)" % mt)
info.doRaise.append( warningList[-1] )
else:
newXsc = lumpedChannels.sumSummands()
newXsc.label = info.style
covSec, = [sec for sec in covarianceSuite.covarianceSections if sec.columnData is None and
sec.rowData.attributes['ENDF_MFMT'] == '33,%d' % mt]
newXsc.uncertainty = uncertaintiesModule.uncertainty( functional=uncertaintiesModule.covariance(
link = covSec[info.style], root='$covariance' ) )
lumpedChannels.crossSection.add( newXsc )
lumpedChannels.Q.add( channelsModule.QModule.constant1d( max(Qs), newXsc.domainMin, newXsc.domainMax,
axes = channelsModule.QModule.defaultAxes('eV'), label=info.style ) )
info.reactionSuite.sums.crossSections.add( lumpedChannels )
covarianceSuite.externalFiles.add( externalFileModule.externalFile("reactions","test.endf6.xml") )
for exReac in sorted(set(cov_info['externalFiles'])):
covarianceSuite.externalFiles.add( externalFileModule.externalFile(exReac,'FIXME/need/path/to/file') )
if cov_info.get('MF34_missingFrames'):
for (mt, LegendreLVals) in cov_info['MF34_missingFrames'].items():
matchingreactions=[tmp for tmp in info.reactionSuite.reactions if tmp.ENDF_MT==mt]
if matchingreactions:
reaction = matchingreactions[0]
# MF=34 is only for neutrons, so only need to look at neutron product:
frame = reaction.outputChannel.getProductWithName('n').distribution[ info.style ].productFrame
for lval in LegendreLVals:
evaluated = lval[info.style]
if isinstance(evaluated, covarianceBaseModule.covarianceMatrix):
evaluated.productFrame = frame
else:
for subsec in evaluated:
subsec.productFrame = frame
sys.stdout.flush( )
for warning in warningList : info.logs.write( " WARNING: %s\n" % warning, stderrWriting = True )
return covarianceSuite, linkData