Source code for fudge.core.utilities.reactionStrings

# <<BEGIN-copyright>>
# <<END-copyright>>

"""
Containers for a particle and a reaction, plus utility to parse in string
representations to containers:
>>> parseReaction("n + Fe56 -> n[multiplicity:'2'] + (Fe55_s -> gamma)")
"""

from pyparsing import *

__metaclass__ = type

[docs]class particleString: optionList = ('multiplicity','emissionMode','decayRate') specialNames = ( 'gamma', 'e' ) # treat differently def __init__(self, symbol, A, excitation=0, opts=None, decaysTo=None): self.symbol = symbol self.A = A self.excitation = excitation self.opts = opts or {} self.decaysTo = decaysTo or [] def __str__(self): ret = '' if self.decaysTo: ret += '(' if self.symbol in particleString.specialNames: ret += self.symbol else: ret += '%s%i' % (self.symbol, self.A) if self.excitation == 's': ret += '_s' elif self.excitation: ret += '_e%i' % self.excitation opts = ["%s:'%s'" % (key,self.opts[key]) for key in particleString.optionList if self.opts.get(key) is not None] if opts: ret += "[" + ', '.join(opts) + "]" if self.decaysTo: ret += ' -> ' + ' + '.join([str(a) for a in self.decaysTo]) + ')' return ret
[docs]class reactionString: def __init__(self, projectile, target, products, info=None): self.projectile = projectile self.target = target self.products = products self.info = info def __str__(self): ret = '%s + %s -> ' % (self.projectile,self.target) ret += ' + '.join( [str(p) for p in self.products] ) if self.info: ret += ' [%s]' % self.info return ret
[docs]def particleParser(): """Parse string of form "Pu239_e2[option1:'value', option2:'value' ... ]" into particle class.""" integer = Word(nums).setParseAction( lambda t: int(t[0]) ) optionDict = (Suppress('[') + delimitedList( Word(alphas)+Suppress(':') + Suppress("'")+Word(alphanums+'+-.')+Suppress("'") , delim=",") + Suppress(']') ) optionDict.setParseAction( lambda t: dict(zip( t[::2],t[1::2] )) ) # now define particle: name, excitation, [list of options] particle = ( Word(alphas)+integer + Optional( Suppress('_') + ((Suppress('e')+integer) | Word('s')), default=0 ) + Optional( optionDict, default={} ) ) # special cases: gamma and electron have no A or excitation: specialParticle = ( (Literal('gamma')|Literal('e'))+Optional(optionDict, default={}) ).setParseAction( lambda t: [t[0],0,0,t[1]] ) particleParser = particle | specialParticle #particleParser.setParseAction( lambda t: particleString(*t) ) return particleParser
[docs]def reactionParser(): """ Parse reaction of form "n + Fe56 -> n[options...] + (Fe55_u -> gamma)" into reaction class.""" # reaction string may include one or more decays, # of form (Th232 -> He4 + (Ra228 -> He4 + Rd224)). # decays may contain subsequent decays, so they are defined recursively: decay = Forward() particle = particleParser() atom = Group(particle) | Group( Suppress('(') + decay + Suppress(')') ) decay << Group(particle) + Suppress('->') + Group(delimitedList(atom,delim='+')) inputChannel = Group(particle)+Suppress('+')+Group(particle) outputChannel = delimitedList(atom, delim='+') # extra channel information, "[total fission]" for example: info = Optional(Suppress('[') + Word(alphas+' ') + Suppress(']'), default='') return inputChannel+Literal('->').suppress() + Group(outputChannel) + info
[docs]def parseReaction( str ): reaction = reactionParser() proj, targ, outgoing, info = reaction.parseString(str) proj, targ = [particleString(*a) for a in (proj,targ)] products = [] def readProduct(element): if len(element)==4: return particleString( *element ) elif len(element)==2: # decay parent = particleString(*element[0]) for daughter in element[1]: parent.decaysTo.append( readProduct( daughter ) ) return parent else: raise Exception, "parsing problem!" for prod in outgoing: products.append( readProduct(prod) ) return reactionString(proj, targ, products, info)