# <<BEGIN-copyright>>
# <<END-copyright>>
__metaclass__ = type
import math
from . import documentation as documentationModule, suites as suitesModule
from xData import XYs as XYsModule, physicalQuantity as physicalQuantityModule, gridded as griddedModule
from xData import ancestry as ancestryModule
[docs]class thermalScattering( ancestryModule.ancestry ):
moniker = 'thermalScattering'
ancestryMembers = ('mass', 'cutoffEnergy', 'coherentElastic', 'incoherentElastic', 'incoherentInelastic')
def __init__(self, cutoffEnergy, material=None, MAT=None, mass=None, documentation=None, coherentElastic=None,
incoherentElastic=None, incoherentInelastic=None):
ancestryModule.ancestry.__init__( self )
self.material = material
# BRB6 hardwired
self.projectile='n'
self.MAT = MAT
self.mass = mass
self.cutoffEnergy = cutoffEnergy
self.documentation = documentation
# BRB6 need to check for correct class.
self.coherentElastic = coherentElastic
self.incoherentElastic = incoherentElastic
self.incoherentInelastic = incoherentInelastic
[docs] def toXMLList( self, indent = '', **kwargs ) :
indent2 = indent + kwargs.get( 'incrementalIndent', ' ' )
xml = [ indent+'<%s material="%s" MAT="%s">' % (self.moniker,self.material,self.MAT) ]
if self.documentation is not None: xml += self.documentation.toXMLList( indent2, **kwargs )
xml += self.cutoffEnergy.toXMLList( indent2, **kwargs )
xml += self.mass.toXMLList( indent2, **kwargs )
for ts in (coherentElastic.moniker,incoherentElastic.moniker,incoherentInelastic.moniker):
if getattr(self,ts) is not None:
xml += getattr(self,ts).toXMLList( indent2, **kwargs )
xml.append(indent+'</%s>' % self.moniker)
return xml
[docs] def check( self, **kwargs ) :
"""
Check all data in the reactionSuite, returning a list of warnings.
"""
from fudge.gnds import warning
options = { }
for key in kwargs:
if key in options: options[key] = kwargs[key]
else: raise KeyError, "check() received unknown keyword argument '%s'" % key
# assemble some useful info, to be handed down to children's check() functions:
info = { 'reactionSuite': self, }
info.update( options )
warnings = []
result = warning.context('ReactionSuite: %s + %s' % (self.projectile, self.material), warnings)
result.info = info
return result
[docs] def saveToFile( self, filename, **kwargs ):
with open(filename,'w') as fout:
# BRB6 hardwired
fout.write('<?xml version="1.0" encoding="UTF-8"?>\n')
fout.write( '\n'.join( self.toXMLList(**kwargs) ) )
[docs] @staticmethod
def parseXMLNode( element ):
xPath = [ thermalScattering.moniker ]
linkData = {}
try:
kwargs = {
'material': element.get('material'),
'MAT': int( element.get('MAT') )
}
for child in element:
_class = {
documentationModule.documentation.moniker: documentationModule.documentation,
mass.moniker: mass,
cutoffEnergy.moniker: cutoffEnergy,
coherentElastic.moniker: coherentElastic,
incoherentElastic.moniker: incoherentElastic,
incoherentInelastic.moniker: incoherentInelastic
}.get( child.tag, None )
if _class is None:
print("Warning: encountered unexpected element '%s' in thermalScattering!" % child.tag)
kwargs[ child.tag ] = _class.parseXMLNode( child, xPath, linkData )
TS = thermalScattering( **kwargs )
except:
print("Error encountered at xpath = /%s" % '/'.join(xPath))
raise
return TS
[docs]class mass( physicalQuantityModule.physicalQuantity ):
moniker = 'mass'
[docs]class cutoffEnergy( physicalQuantityModule.physicalQuantity ):
moniker = 'cutoffEnergy'
[docs]class coherentElastic( ancestryModule.ancestry ):
moniker = 'coherentElastic'
def __init__(self, S_table):
ancestryModule.ancestry.__init__(self)
self.S_table = S_table
[docs] def toXMLList( self, indent = '', **kwargs ) :
indent2 = indent + kwargs.get( 'incrementalIndent', ' ' )
xml = [indent+'<%s>' % self.moniker]
xml += self.S_table.toXMLList( indent2, **kwargs )
xml[-1] += '</%s>' % self.moniker
return xml
[docs] @staticmethod
def parseXMLNode( element, xPath, linkData ):
xPath.append( element.tag )
Stab = S_table.parseXMLNode( element[0], xPath, linkData )
cohEl = coherentElastic( Stab )
xPath.pop()
return cohEl
[docs]class S_table( ancestryModule.ancestry ):
""" For elastic coherent, cumulative structure factor 'S' is given as function of incident energy and temp. """
moniker = 'S_table'
def __init__(self, gridded2d):
self.gridded2d = gridded2d
[docs] def toXMLList( self, indent = '', **kwargs ) :
indent2 = indent + kwargs.get( 'incrementalIndent', ' ' )
xml = [indent+'<%s>' % self.moniker]
xml += self.gridded2d.toXMLList( indent2, **kwargs )
xml[-1] += '</%s>' % self.moniker
return xml
[docs] @staticmethod
def parseXMLNode( element, xPath, linkData ):
xPath.append( element.tag )
g2d = griddedModule.gridded2d.parseXMLNode( element[0], xPath, linkData )
Stab = S_table( g2d )
xPath.pop()
return Stab
[docs]class incoherentElastic( ancestryModule.ancestry ):
moniker = 'incoherentElastic'
def __init__(self, characteristicCrossSection, DebyeWaller):
ancestryModule.ancestry.__init__(self)
self.characteristicCrossSection = characteristicCrossSection
self.DebyeWaller = DebyeWaller
[docs] def toXMLList( self, indent = '', **kwargs ) :
indent2 = indent + kwargs.get( 'incrementalIndent', ' ' )
xml = [indent+'<%s>' % self.moniker]
xml += self.characteristicCrossSection.toXMLList( indent2, **kwargs )
xml += self.DebyeWaller.toXMLList( indent2, **kwargs )
xml[-1] += '</%s>' % self.moniker
return xml
[docs] @staticmethod
def parseXMLNode( element, xPath, linkData ):
xPath.append( element.tag )
xsc = characteristicCrossSection.parseXMLNode(element.find(characteristicCrossSection.moniker), xPath, linkData)
DW = DebyeWaller.parseXMLNode(element.find(DebyeWaller.moniker), xPath, linkData)
incElastic = incoherentElastic( xsc, DW )
xPath.pop()
return incElastic
[docs]class characteristicCrossSection( physicalQuantityModule.physicalQuantity ):
moniker = 'characteristicCrossSection'
[docs]class DebyeWaller( XYsModule.XYs1d ):
"""For incoherent elastic sections, all we need is a characteristic cross section and a
temperature-dependent list of the Debye-Waller integral """
mutableYUnit = False
moniker = "DebyeWaller"
def __init__(self, *args, **kwargs):
XYsModule.XYs1d.__init__(self, *args, **kwargs)
[docs]class incoherentInelastic( ancestryModule.ancestry ):
moniker = 'incoherentInelastic'
def __init__(self, S_alpha_beta, calculatedAtThermal = False, asymmetric = False, atoms = None):
ancestryModule.ancestry.__init__(self)
self.scatteringAtoms = scatteringAtoms()
if atoms is not None:
for atom in atoms:
self.scatteringAtoms.add( atom )
self.S_alpha_beta = S_alpha_beta
self.calculatedAtThermal = calculatedAtThermal
self.asymmetric = asymmetric
[docs] def toXMLList( self, indent = '', **kwargs ) :
incrementalIndent = kwargs.get( 'incrementalIndent', ' ' )
indent2 = indent + incrementalIndent
attrs = ''
for attr in ('calculatedAtThermal', 'asymmetric'):
if getattr(self,attr): attrs += ' %s="true"' % attr
xml = [indent+'<%s%s>' % (self.moniker, attrs)]
xml += self.scatteringAtoms.toXMLList( indent2 )
xml += self.S_alpha_beta.toXMLList( indent2, **kwargs )
xml[-1] += '</%s>' % self.moniker
return xml
[docs] @staticmethod
def parseXMLNode( element, xPath, linkData ):
xPath.append( incoherentElastic.moniker )
kwargs = {
'calculatedAtThermal': element.get('calculatedAtThermal') == 'true',
'asymmetric': element.get('asymmetric') == 'true'
}
atoms = [scatteringAtom.parseXMLNode( child, xPath, linkData)
for child in element.find('scatteringAtoms')]
Sab = S_alpha_beta.parseXMLNode( element.find( S_alpha_beta.moniker ), xPath, linkData )
incInelastic = incoherentInelastic( Sab, atoms = atoms, **kwargs )
xPath.pop()
return incInelastic
[docs]class scatteringAtoms( suitesModule.suite ):
moniker = 'scatteringAtoms'
def __init__( self ):
suitesModule.suite.__init__( self, [scatteringAtom] )
[docs]class scatteringAtom( ancestryModule.ancestry ):
""" Inelastic incoherent scattering requires a description of each atom that is scattered off """
moniker = 'scatteringAtom'
def __init__(self, label, numberPerMolecule, mass, freeAtomCrossSection, e_critical = None, e_max = None,
functionalForm = None, T_effective = None ):
ancestryModule.ancestry.__init__(self)
self.label = label
self.numberPerMolecule = numberPerMolecule
self.mass = mass
self.freeAtomCrossSection = freeAtomCrossSection
self.e_critical = e_critical
self.e_max = e_max
self.functionalForm = functionalForm
self.T_effective = T_effective
[docs] def boundCrossSection(self):
return self.freeAtomCrossSection.value * ((self.mass.value + 1) / self.mass.value)**2
[docs] def shortCollisionTime( self, alpha, beta, T ):
"""
Equation 7.8 in ENDF manual
:param alpha:
:param beta:
:param T:
:return:
"""
Teff = self.T_effective.evaluate(T)
#num = math.exp( -(alpha-abs(beta))**2 * T / (4*alpha*Teff) - (beta + abs(beta))/2)
# reformulate using T/Teff = 1-f, should be more numerically stable
f = 1 - T/Teff
num = math.exp( (f * (alpha - abs(beta))**2 - (alpha + beta)**2) / (4*alpha) )
den = math.sqrt( 4 * math.pi * alpha * Teff / T )
return num/den
[docs] def toXMLList( self, indent = '', **kwargs ) :
indent2 = indent + kwargs.get( 'incrementalIndent', ' ' )
attrs = ''
if self.functionalForm is not None: attrs = ' functionalForm="%s"' % self.functionalForm
xml = [indent+'<%s label="%s" numberPerMolecule="%i"%s>' % (self.moniker, self.label, self.numberPerMolecule, attrs)]
for attribute in ('mass','freeAtomCrossSection','e_critical','e_max','T_effective'):
if getattr(self, attribute) is not None:
xml += getattr(self,attribute).toXMLList( indent2, **kwargs )
xml[-1] += '</%s>' % self.moniker
return xml
[docs] @staticmethod
def parseXMLNode( element, xPath, linkData ):
xPath.append( element.tag )
kwargs = {
'label': element.get('label'),
'numberPerMolecule': int(element.get('numberPerMolecule')),
'functionalForm': element.get('functionalForm'),
}
for child in element:
_class = {
mass.moniker: mass,
freeAtomCrossSection.moniker: freeAtomCrossSection,
e_critical.moniker: e_critical,
e_max.moniker: e_max,
T_effective.moniker: T_effective
}.get( child.tag, None )
if _class is None:
print("Warning: encountered unexpected element '%s' in scatteringAtom!" % child.tag)
kwargs[ child.tag ] = _class.parseXMLNode( child, xPath, linkData )
SA = scatteringAtom( **kwargs )
xPath.pop()
return SA
[docs]class freeAtomCrossSection( physicalQuantityModule.physicalQuantity ):
moniker = 'freeAtomCrossSection'
[docs]class e_critical( physicalQuantityModule.physicalQuantity ):
moniker = 'e_critical'
[docs]class e_max( physicalQuantityModule.physicalQuantity ):
moniker = 'e_max'
[docs]class T_effective( XYsModule.XYs1d ):
""" In incoherent inelastic sections, each scattering atom using the short collision time (SCT)
approximation needs an effective temperature. """
moniker = 'T_effective'
mutableYUnit = False
def __init__(self, *args, **kwargs):
XYsModule.XYs1d.__init__(self, *args, **kwargs)
[docs]class S_alpha_beta( ancestryModule.ancestry ):
"""
Inelastic incoherent section contains S as a function of (alpha,beta,T).
Currently supports gridded3d, other options may be supported later.
"""
moniker = 'S_alpha_beta'
def __init__(self, gridded3d):
ancestryModule.ancestry.__init__( self )
self.gridded3d = gridded3d
[docs] def toXMLList( self, indent = '', **kwargs ) :
indent2 = indent + kwargs.get( 'incrementalIndent', ' ' )
xml = [indent+'<%s>' % self.moniker]
xml += self.gridded3d.toXMLList( indent2, **kwargs )
xml[-1] += '</%s>' % self.moniker
return xml
[docs] @staticmethod
def parseXMLNode( element, xPath, linkData ):
xPath.append( element.tag )
g3d = griddedModule.gridded3d.parseXMLNode( element[0], xPath, linkData )
Sab = S_alpha_beta( g3d )
xPath.pop()
return Sab
[docs]def readXML( gndsFile ):
"""
Read a GNDS/xml file and create a new reactionSuite instance from the result.
:param gndsFile: path to a GNDS file, as a string.
:return: reactionSuite instance containing all data from the file.
"""
from xml.etree import cElementTree
# wrapper around the xml parser:
from fudge.core.utilities.xmlNode import xmlNode
tsElement = cElementTree.parse( gndsFile ).getroot()
tsElement = xmlNode( tsElement, xmlNode.etree )
return thermalScattering.parseXMLNode( tsElement )