Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F10881032
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
45 KB
Subscribers
None
View Options
diff --git a/Rosetta/internal/SLHA.py b/Rosetta/internal/SLHA.py
index b6b9dad..4bb9f91 100644
--- a/Rosetta/internal/SLHA.py
+++ b/Rosetta/internal/SLHA.py
@@ -1,1182 +1,1203 @@
from collections import OrderedDict, MutableMapping
from operator import itemgetter
import sys
import re
import os
__doc__ = '''
Module for parsing SLHA style input cards and storing BLOCK and DECAY structures
into python dict-like objects that can be indexed and iterated over in a case
insensitive way.
'''
class CaseInsensitiveDict(MutableMapping):
'''
Dict class for string keys that behaves in a case insensitive way.
'''
def __init__(self, data=None, **kwargs):
self._data = {}
if data is None:
data = {}
self.update(data, **kwargs)
def __setitem__(self, key, value):
self._data[key.lower()] = (key, value)
def __getitem__(self, key):
return self._data[key.lower()][1]
def __delitem__(self, key):
del self._data[key.lower()]
def __iter__(self):
return (casedkey for casedkey, mappedvalue in self._data.values())
def __len__(self):
return len(self._data)
def __repr__(self):
return repr([(k,v) for (k,v) in self._data.values()])
class CaseInsensitiveOrderedDict(MutableMapping):
'''
OrderedDict class for string keys that behaves in a case insensitive way.
'''
def __init__(self, data=None, **kwargs):
self._data = OrderedDict()
if data is None:
data = {}
self.update(data, **kwargs)
def __setitem__(self, key, value):
self._data[key.lower()] = (key, value)
def __getitem__(self, key):
return self._data[key.lower()][1]
def __delitem__(self, key):
del self._data[key.lower()]
def __iter__(self):
return (casedkey for casedkey, mappedvalue in self._data.values())
def __len__(self):
return len(self._data)
def __repr__(self):
return repr([(k,v) for (k,v) in self._data.values()])
class Block(MutableMapping):
'''
Container class for SLHA block with a single counter. A subclass of
`collections.OrderedDict`with a restriction on integer keys and a modified
__repr__(). Block can't be initialised with any positional arguments but
rather with the 'data' keyword argument. It can optionally be named using
the 'name' keyword argument. The__str__ function are also defined to output
the contained data in an SLHA formatted block.
'''
def __checkkey__(self, key):
'''Forces key to be of integer type.'''
if type(key) is not self.keytype:
raise TypeError("Key: '{}'. ".format(key) + self.__class__.__name__
+ ' only accepts keys of {}.'.format(self.keytype))
else:
return key
def __cast__(self, val):
'''
Attempts to cast values to type specified in 'vtype' keyword argument
of constructor.
'''
try:
return self.cast(val)
except ValueError:
return val
def __init__(self, name=None, decimal=5, ktype=int, vtype=float,
preamble='', data=None):
''' Intialisation keyword arguments:
name - A name for the block that will appear
in the __str__ and __repr__ methods.
data - A dict type object supporting iteritems()
to initialize Block values.
decimal - Number of decimal points with which
to write out parameter values.
vtype - a function to cast parameter values if
read in as strings i.e. int, float.
preamble - Some text to print before the __str__ output.
'''
self._data = OrderedDict()
self.name = name
self.keytype = ktype
self.cast = vtype # value casting function
self.fmt = ':+.{}e'.format(decimal) # format string
self.preamble = preamble
if data is not None:
self._data.update(data)
def __setitem__(self, key,value):
self._data[self.__checkkey__(key)] = self.__cast__(value)
def __getitem__(self, key):
return self._data[self.__checkkey__(key)]
def __contains__(self, key):
return key in self._data
def __delitem__(self, key):
del self._data[self.__checkkey__(key)]
def __iter__(self):
return iter(self._data)
def __len__(self):
return len(self._data)
def __repr__(self):
return ('<{}: "{}"; {} entries.>'.format(self.__class__,
self.name, len(self)))
def __str__(self):
content = []
sortitems = sorted(self.items())
for k,v in sortitems:
try:
val = float(v)
fmt = self.fmt
except ValueError:
fmt = ''
line = (' {{: <4}} {{{}}}\n'.format(fmt)).format
content.append(line(k,val))
string = self.preamble+'\n'
if content:
string += 'BLOCK {}\n'.format(self.name) + ''.join(content)
return string
def dict(self):
'''Return SHLA Block data as a regular python dict.'''
return self._data
class Matrix(Block):
'''
Container class for SLHA block with multiple counters. A subclass of
`collections.OrderedDict`with a restriction on tuple keys and a modified
__repr__(). Block can't be initialised with any positional arguments but
rather with the 'data' keyword argument. It can optionally be named using
the 'name' keyword argument. The__str__ function are also defined to output
the contained data in an SLHA formatted block. The object is indexed
like a numpy multi dimensional array ( x[i,j,k,...] ).
'''
def __init__(self, *args, **kwargs):
kwargs['ktype'] = tuple
super(Matrix, self).__init__(*args, **kwargs)
def __str__(self):
content = []
sortitems = sorted(self.items(), key=itemgetter(0,0))
for k,v in sortitems:
try:
v = float(v)
fmt = self.fmt
except ValueError:
fmt=''
ind = '{: <4}'*len(k)
line = (' {} {{{}}}\n'.format(ind,fmt)).format
args = list(k)+[v]
content.append(line(*args))
string = self.preamble+'\n'
if content:
string += 'BLOCK {}\n'.format(self.name) + ''.join(content)
return string
def dimension(self):
indx = []
for i,k in enumerate(self.keys()):
if i==0:
indx = [[] for _ in k]
for j, l in enumerate(k):
indx[j].append(l)
isets = [sorted(list(set(x))) for x in indx]
for i,s in enumerate(isets):
smin, smax = min(s), max(s)
if not s == range(smin,smax+1):
strs = [str(x) for x in s]
err = ('subdimension {} of array '.format(i) +
'{}, ({}), is not complete range.'.format(repr(self),
','.join(strs)))
raise SLHAError(err)
return tuple( [len(x) for x in isets] )
def array(self):
array = []
for k,v in self.iteritems():
if isinstance(v,Matrix):
array.append(v.array())
else:
# array.append([v for v in v.values()])
array.append(v)
return array
class NamedBlock(Block):
'''
Class derived from 'Block' with the added functionality of assigning a name
to each key via the 'names' keyword argument. The values can then also be
referenced by name via a lookup in self._numbers.
'''
def __parse__(self, key):
'''
Allows for elements to additionally be referred to by name.
Looks up self._numbers for an assigned name and returns the
associated key. Rasies KeyError if name is not booked.
Used in overloading __setitem__, __getitem__, __contains__
and __delitem__.
'''
if type(key) is str:
try:
return self._numbers[key]
except KeyError:
err = ('Name "{}" has not been assigned to a '.format(key) +
'key in {} {}._names'.format(self.__class__, self.name))
raise KeyError(err)
else:
return key
def __init__(self, name=None, comment='', decimal=5, data = None,
ktype=int, vtype=float, preamble=''):
'''
Same as the SLHA.Block constructor but additionally checks if the data
keyword argument has a "_names" attribute (i.e. if it is an existing
instance of NamedBlock) and stores it. The "comment" keyword argument
prints a comment to the right of the block declaration in __str__().
'''
if data is not None and hasattr(data, '_names'):
self._names = data._names
try:
self._numbers = CaseInsensitiveOrderedDict({v:k for k,v
in self._names.iteritems()})
except AttributeError:
raise ValueError('"names" keyword argument must be a'
'dictionary or support iteritems() method.')
else:
self._names, self._numbers = {}, CaseInsensitiveDict()
self.comment = comment
return super(NamedBlock, self).__init__(name=name, data=data,
ktype=ktype, vtype=vtype,
decimal=decimal,
preamble = preamble)
def __setitem__(self, key, value):
return super(NamedBlock, self).__setitem__(self.__parse__(key), value)
def __getitem__(self, key):
return super(NamedBlock, self).__getitem__(self.__parse__(key))
def __delitem__(self, key):
super(NamedBlock, self).__delitem__(self.__parse__(key))
# Additional cleanup needed for _names and _numbers lookup dicts.
if type(key) is str:
try:
del self._names[self._numbers[key]]
del self._numbers[key]
except KeyError:
pass
else:
try:
del self._numbers[self._names[key]]
del self._names[key]
except KeyError:
pass
def __contains__(self, key):
try:
return super(NamedBlock, self).__contains__(self.__parse__(key))
except KeyError:
return False
def __repr__(self):
return ('< {}: "{}", {} entries ({} named). >'.format(self.__class__,
self.name,
len(self),
len(self._names)))
def __str__(self):
content = []
sortitems = sorted(self.items(), key=itemgetter(0))
for k,v in sortitems:
try:
strval = ('{{{}}}'.format(self.fmt)).format(float(v))
except ValueError:
strval = v
if k in self._names:
content.append(' {: <4} {} # {}\n'.format(k, strval,
self._names[k]))
else:
content.append(' {: <4} {}\n'.format(k,strval))
string = self.preamble+'\n'
if content:
string += ('BLOCK {} # {}\n'.format(self.name, self.comment)
+ ''.join(content))
return string
def get_name(self, key, default=''):
return self._names.get(key, default)
def get_number(self, name, default=None):
return self._numbers.get(name, default)
def new_entry(self, key, value, name=None):
'''
Add a new named block entry. Ensures that the key hasn't already
been set and the name given hasn't already been booked.
'''
if key in self:
err = ("Key '{}' already belongs to {} ".format(key,
self.__class__)
+ "'{}', mapped to name '{}'.".format(self.name,
self.get_name(key)))
raise KeyError(err)
if name in self._numbers:
err = ("Name '{}' already booked in ".format(name) +
"NamedBlock {}, mapped to key '{}'.".format(
self.name, self._numbers[name]))
raise KeyError(err)
else:
if name is not None:
self._names[key] = name
self._numbers[name] = key
self[key]=value
def namedict(self):
'''Return python dict of name:key pairs.'''
return {self._names[k]:v for k,v in self.iteritems()
if k in self._names }
class NamedMatrix(Matrix, NamedBlock):
'''
Class derived from `Matrix` and `NamedBlock` to add the named indexing
functionality to the multi-counter SLHA block structure.
'''
def __setitem__(self, key, value):
return super(NamedMatrix, self).__setitem__(self.__parse__(key), value)
def __getitem__(self, key):
return super(NamedMatrix, self).__getitem__(self.__parse__(key))
def __str__(self):
content = []
sortitems = sorted(self.items(), key=itemgetter(0,0))
for k,v in sortitems:
try:
v = float(v)
fmt = self.fmt
except ValueError:
fmt=''
vname = self._names.get(k,None)
comment = '' if vname is None else '# {}'.format(vname)
ind = '{: <4}'*len(k)
line = (' {} {{{}}} {{}}\n'.format(ind,fmt)).format
args = list(k)+[v, comment]
content.append(line(*args))
string = self.preamble+'\n'
if content:
string += 'BLOCK {}\n'.format(self.name) + ''.join(content)
return string
class CBlock(Block):
container = Block
def __init__(self, *args):
if not args:
re, im = self.container(name='_re'), self.container(name='_im')
self.__init__(re,im)
return
else:
try:
real, imag = args
except ValueError:
err = ('{}.__init__() takes 0 '.format(self.__class__)+
'or 2 arguments ({} given)'.format(len(args)))
raise TypeError(err)
assert type(real) is self.container and type(imag) is self.container, (
' Cblock constructor takes 2 {} '.format(self.container)
+ 'objects as arguments')
name, decimal, preamble = real.name, int(real.fmt[-2]), real.preamble
super(CBlock, self).__init__(name=name, decimal=decimal,
preamble=preamble, vtype=complex)
self.fill(real, imag)
def fill(self, real, imag):
'''
Fill a CBlock from two Block instances containing the
real and imaginary parts
'''
self._re, self._im = real, imag
for k, re in real.iteritems():
try:
im = imag[k]
entry = complex(re,im)
except KeyError:
entry = re
self[k] = entry
def __setitem__(self, key, value):
cval = complex(value)
re, im = value.real, value.imag
self._re[key], self._im[key] = re, im
super(CBlock, self).__setitem__(key, cval)
def __str__(self):
string = self.preamble
if self._re._data:
string += str(self._re)
if self._im._data:
string += str(self._im)
return string
class CMatrix(CBlock, Matrix):
container = Matrix
class CNamedBlock(CBlock, NamedBlock):
container = NamedBlock
def _part(self, key):
if key in self._re:
return self._re
elif key in self._im:
return self._im
else:
raise KeyError('Key "{}" not found in {} "{}"'.format(key,
self.__class__,
self.name))
def fill(self, real, imag):
'''
Fill a CBlock from two Block instances containing the
real and imaginary parts
'''
self._re, self._im = real, imag
for k, re in real.iteritems():
try:
im = imag[k]
entry = complex(re,im)
except KeyError:
entry = re
try:
cname = real._names[k]
cname = 'C'+cname[1:] if cname.startswith('R') else 'C'+cname
except (AttributeError, KeyError):
index = 'x'.join(map(str,k))
cname = 'C{}{}'.format(real.name, index)
self.new_entry(k, entry, name=cname)
for k, im in imag.iteritems():
if k not in real:
try:
cname = imag._names[k]
cname = 'C'+cname[1:] if cname.startswith('I') else 'C'+cname
except (AttributeError, KeyError):
index = 'x'.join(map(str,k))
cname = 'C{}{}'.format(imag.name, index)
self.new_entry(k, entry, name=cname)
def __setitem__(self, key, value):
if type(key) is str and (key in self._re or key in self._im):
part = self._part(key)
key = part.__parse__(key)
part.__setitem__(key, value)
if part is self._re:
self[key] = complex(value, self[key].imag)
elif part is self._im:
self[key] = complex(self[key].real, value)
else:
key = self.__parse__(key)
cval = complex(value)
re, im = value.real, value.imag
self._re[key], self._im[key] = re, im
super(CBlock, self).__setitem__(key, cval)
def __getitem__(self, key):
if type(key) is str and (key in self._re or key in self._im):
part = self._part(key)
return part.__getitem__(key)
else:
return super(CNamedBlock, self).__getitem__(key)
def __delitem__(self, key):
if type(key) is str and (key in self._re or key in self._im):
part = self._part(key)
key = part.__parse__(key)
if part is self._re:
self[key] = complex(0., self[key].imag)
elif part is self._im:
self[key] = complex(self[key].real, 0.)
part.__delitem__(key)
else:
key = self.__parse__(key)
try:
del self._re[key]
except KeyError:
pass
try:
del self._im[key]
except KeyError:
pass
super(CNamedBlock, self).__delitem__(key)
def __contains__(self, key):
if type(key) is str:
return (key in self._re or key in self._im or
super(CNamedBlock, self).__contains__(key))
else:
return super(CNamedBlock, self).__contains__(key)
def get_number(self, name, default=None):
if (name in self._re or name in self._im):
part = self._part(name)
else:
part = self
return part._numbers.get(name, default)
class CNamedMatrix(CNamedBlock, NamedMatrix):
container = NamedMatrix
class Decay(MutableMapping):
'''
Container class for SLHA Decay blocks. A subclass of `collections.OrderedDict`
with a restriction on tuple keys and float values less than 1. A modified
__repr__() function is implemented for easy writing to file. Decay is
initialised with a PID argument to specify the particle to which it refers
as well as its total width. The sum of branching ratios is kept and a
ValueError will be raised if the total exceeds 1. It can optionally be
named using the 'name' keyword argument. Finally a __str__() function is
also defined to output the SLHA formatted block.
'''
def __checkkey__(self, key):
''' Forces key to be a tuple and casts the elements to integers.'''
if type(key) is not tuple:
raise TypeError( self.__class__.__name__ +
' only accepts tuple keys: (PID1, PID2,...).' )
else:
return tuple(map(int,key))
def __checkval__(self, val):
''' Forces values (i.e. branching ratios) to be a float less than 1.'''
try:
fval = float(val)
except ValueError:
raise TypeError( self.__class__.__name__ +
' only accepts floats or values castable via float()' )
if fval > 1.:
raise BRGTOneError("SLHA Decay object for PID = {}. ".format(self.PID)+
"Branching ratio > 1 encountered : {}".format(fval))
return fval
def __init__(self, PID, total,
data=None, comment='', decimal=5, preamble= ''):
''' Positional arguments:
PID - integer to denote particle whose decay is being described
total - total width
Keyword arguments:
data - A dict type object supporting iteritems()
to initialize Decay values.
comment - prints a comment to the right of the block
declaration in __str__().
decimal - Number of decimal points with which
to write out width and BRs.
preamble - Some text to print before the __str__ output.'''
try:
self.PID=int(PID)
except ValueError:
err = ("SLHA Decay object for PID = {}. ".format(PID) +
"'PID' argument must be an integer or be castable via int()")
raise TypeError(err)
try:
self.total=float(total)
except ValueError:
err = ("SLHA Decay object for PID = {}. ".format(PID) +
"'total' argument must be a float or be castable via float()")
raise TypeError(err)
self._BRtot = 0.
self._fmt = ':+.{}e'.format(decimal)
self._comment = comment
self._decimal = decimal
self._comments = {}
self.preamble = preamble
self._data = OrderedDict()
if data is not None:
self._data.update(data)
def __setitem__(self, key, value):
self._data[self.__checkkey__(key)] = self.__checkval__(value)
self._BRtot+=self.__checkval__(value)
# if self._BRtot > 1.:
# raise BRGTOneError("SLHA Decay object for PID = {}. ".format(self.PID)
# + "Sum of branching ratios > 1!")
def __getitem__(self, key):
return self._data[self.__checkkey__(key)]
def __delitem__(self, key):
del self._data[self.__checkkey__( key )]
self._BRtot-=self.__checkval__(self[key])
def __iter__(self):
return iter(self._data)
def __len__(self):
return len(self._data)
def __repr__(self):
return ( '<SHLA Decay: PID={}; {} entries.>'.format(self.PID,
len(self)) )
def __str__(self):
above = '# PDG Width\n'
title = ('DECAY {{:<10}} {{{}}} # {{}}\n'.format(self._fmt)).format
below = '# BR{} NDA ID1 ID2...\n'.format(' '*self._decimal)
if len(self)==0: below=''
content = []
for k,v in self.iteritems():
nparts = len(k)
idfmt = nparts*'{: <10}'
line = ('{{{}}} {{: <10}}{}'.format(self._fmt,idfmt)).format
cmnt = ('# {}'.format(self._comments[k])
if k in self._comments else '')
content.append(line(v, nparts, *k) + cmnt)
string = (self.preamble + '\n' + above
+ title(self.PID, self.total, self._comment)
+ below + '\n'.join(content) )
return string
def new_channel(self, PIDs, BR, comment=None):
'''
Add a new decay channel.
PIDs - tuple of integers.
BR - the branching ratio into that channel.
comment - optional comment to be written to the
right of that channel in __str__().
'''
self[PIDs]=BR
if comment is not None: self._comments[PIDs]=comment
class Card(object):
'''
SLHA card object: a container for storing multiple SLHA.Block,
SLHA.NamedBlock and SLHA.Decay objects. Blocks and decays are stored in
OrderedDicts self.blocks and self.decays respectively.
Index syntax mycard[key] can be used to get or set elements of blocks or
decays possessed by the Card instance. If passed a string key, the card
instance will look up the first block in self.blocks possessing a parameter
with the given name while an int key will return the SLHA.Decay object for
that PID.
'''
def _parent_block(self, key):
'''
Returns the parent of a given string key. First searches for a Matrix
object with that name, then searches in self.matrices for a Matrix
containing that name and finally searches in self.blocks for a block
containing that name. Otherwise raises Key error.
'''
if self.has_matrix(key): return self.matrices
for block in self.matrices.values():
if key in block: return block
try:
if key in block._re:
return block._re
if key in block._im:
return block._im
except AttributeError:
pass
for block in self.blocks.values():
if key in block: return block
return None
def _container(self, key):
'''
Returns the container containing the indexed key. Used in overloading
__setitem__, __getitem__, __contains__ and __delitem__.
'''
if type(key) is int:
return self.decays
elif type(key) is str:
return self._parent_block(key.lower())
else:
err = ('SLHA Card has integer keys for '
'DECAY and string keys for BLOCK.')
raise ValueError(err)
def __init__(self, blocks=None, decays=None, name=None):
''' Keyword arguments:
blocks - a dictionary of items with which to initialise
individual blocks in the card instance i.e.
name:block pairs with block an SLHA.NamedBlock.
decays - a dictionary of SLHA.Decay objects.
matrices - a dictionary of SLHA.NamedMatrix objects.
name - card name'''
self.blocks = CaseInsensitiveOrderedDict()
self.decays = OrderedDict()
self.matrices = CaseInsensitiveOrderedDict()
self.name = name if name is not None else ''
if blocks is not None:
for bname, block in blocks.iteritems():
self.blocks[bname] = NamedBlock(name=bname, data=block)
if decays is not None:
for PID, decay in decays.iteritems():
self.decays[PID]= Decay(PID,decay.total, data=decay)
def __repr__(self):
return ('<SHLA Card "{}": {} blocks, {} decays.>'.format(self.name,
len(self.matrices)+ len(self.blocks), len(self.decays)))
def __contains__(self, key):
container = self._container(key)
return True if container is not None else False
def __getitem__(self, key):
container = self._container(key)
if container is not None:
return container[key.lower()]
else:
err = 'Key/Matrix "{}" not found in {}'.format(key, self)
raise KeyError(err)
def __delitem__(self, key):
container = self._container(key)
if container is not None:
del container[key.lower()]
else:
err = 'Key/Matrix "{}" not found in {}'.format(key, self)
raise KeyError(err)
def __setitem__(self, key, value):
container = self._container(key)
if container is not None:
return container.__setitem__(key.lower(), value)
else:
err = 'Key/Matrix "{}" not found in {}'.format(key, self)
raise KeyError(err)
def add_block(self, block, preamble=''):
'''
Append an SLHA.Block, NamedBlock, Matrix or NamedMatrix to
self.blocks or self.matrices depending on the type.
'''
block.preamble = preamble
if isinstance(block,Matrix):
self.matrices[block.name] = block
else:
self.blocks[block.name] = block
def add_decay(self, decay, preamble=''):
'''Append an SLHA.Decay to self.decays.'''
decay.preamble = preamble
self.decays[decay.PID] = decay
def add_entry(self, blockname, key, value, name=None):
'''
Add a new field in a given block. If the Card instance already
has such a block, a new field is appended. If the Card doesn't, a new
block is created.
'''
if self.has_block(blockname):
self.blocks[blockname].new_entry(key, value, name=name)
elif self.has_matrix(blockname):
self.matrices[blockname].new_entry(key, value, name=name)
else:
if type(key) is tuple:
container = Matrix if name is None else NamedMatrix
cplxcontainer = CMatrix if name is None else NamedMatrix
else:
container = Block if name is None else NamedBlock
cplxcontainer = CBlock if name is None else NamedBlock
if type(value) is complex:
reblock = container(name=blockname)
imblock = container(name='IM'+blockname)
theblock = cplxcontainer(reblock, imblock)
else:
theblock = container(name=blockname)
if name is None:
theblock.new_entry(key, value)
else:
theblock.new_entry(key, value, name=name)
self.add_block(theblock)
def add_channel(self, PID, channel, partial, comment=None):
'''
Add a new channel in a given decay. The Decay for the given PID
must already exist in the Card instance.
'''
assert(self.has_decay(PID)),('Tried adding a decay channel '
'for non existent decay PID')
self.decays[PID].new_channel(channel, partial, comment=comment)
def new_channel(self, PIDs, BR, comment=None):
'''Append a new channel to a given Decay block.'''
self[PIDs]=BR
if comment is not None: self._comments[PIDs]=comment
def has_block(self, name):
return name.lower() in self.blocks
def has_matrix(self, name):
return name.lower() in self.matrices
def has_decay(self, PID):
return PID in self.decays
def write(self, filename, blockorder = [], preamble='', postamble=''):
'''
Write contents of Card in SLHA formatted style to "filename".
Makes use of the __str__ methods written for the SLHA elements.
Keyword arguments:
blockorder - Specify an ordering for printing the block names.
Names given in blockorder will be printed first in the
order specified and others will be printed as ordered
in self.blocks
preamble - Some text to write before the Block and Decay information
postamble - Some text to write after the Block and Decay information
'''
with open(filename,'w') as out:
out.write(preamble)
blockorder = [x.lower() for x in blockorder]
allblocks = self.blocks.keys() + self.matrices.keys()
other_blocks = [b for b in allblocks if b.lower() not in blockorder]
for block in blockorder:
if self.has_block(block):
out.write(str(self.blocks[block]))
elif self.has_matrix(block):
out.write(str(self.matrices[block]))
for block in other_blocks:
if self.has_block(block):
out.write(str(self.blocks[block]))
elif self.has_matrix(block):
out.write(str(self.matrices[block]))
for decay in self.decays.values():
out.write(str(decay))
out.write(postamble)
def set_complex(self):
'''
Processes self.blocks and self.matrices to find real and imaginary
pairs, upgrading them to a single complex version.
'''
cplx = []
for imkey in self.blocks.keys():
if imkey.lower().startswith('im'):
rekey = imkey[2:]
if rekey in self.blocks:
if not isinstance(self.blocks[rekey], CBlock):
cplx.append((rekey,imkey))
for rekey, imkey in cplx:
reblk = self.blocks.get(rekey, None)
imblk = self.blocks.pop(imkey, None)
container = type(reblk)
if container is Block:
ctype = CBlock
elif container is NamedBlock:
ctype = CNamedBlock
cblk = ctype(reblk, imblk)
self.blocks[rekey] = cblk
cplx = []
for imkey in self.matrices.keys():
if imkey.lower().startswith('im'):
rekey = imkey[2:]
if rekey in self.matrices:
if not isinstance(self.matrices[rekey], CBlock):
cplx.append((rekey,imkey))
for rekey, imkey in cplx:
reblk = self.matrices.get(rekey, None)
imblk = self.matrices.pop(imkey, None)
container = type(reblk)
if container is Matrix:
ctype = CMatrix
elif container is NamedMatrix:
ctype = CNamedMatrix
cblk = ctype(reblk, imblk)
self.matrices[rekey] = cblk
def sortblocks(card, ignore = []):
normal_blocks = sorted([k for k in card.blocks.keys()
if k.lower() not in ignore],
key=str.lower)
flav_blocks = sorted([k for k in card.matrices.keys()
if k.lower() not in ignore],
key=str.lower)
flav_cplx = []
for im in [fl for fl in flav_blocks if fl.lower().startswith('im')]:
re = im[2:]
flav_cplx.append(re)
flav_cplx.append(im)
flav_blocks.remove(re)
flav_blocks.remove(im)
return normal_blocks + flav_blocks + flav_cplx
def read(card, set_cplx=True):
'''
SLHA formatted card reader. Blocks and Decay structures are read
into an SLHA.Card object which is returned. Comments are specified by the #
character. Comments to the right of the structures as wel as the individual
fields are stored.
'''
def get_comment(line):
'''
Returns characters following a "#" in line.
returns empty string if match is not found.
'''
match = re.match(r'.*#\s*(.*)\s*', line)
if match: return match.group(1).strip()
else: return ''
thecard = Card()
try:
pcard = open(card,'r')
except IOError:
msg = 'No such file or directory: {}'.format(card)
raise SLHAIOError(msg)
lines = iter(pcard)
counter = 0
try:
while True:
counter+=1 # keep track of line number
stop=False
try: ll=(last_line.strip())
except NameError: ll = (lines.next()).strip()
if not ll: continue
first_chars = re.match(r'\s*(\S+).*',ll).group(1).lower()
if first_chars=='block':
try:
block_details = re.match(r'\s*block\s+([^\n]+)',ll,
re.IGNORECASE).group(1)
except AttributeError:
err = ('Invalid block format encountered ' +
'in line {} of {}.'.format(counter, card) )
raise SLHAError(err)
bname = block_details.split('#')[0].strip()
comment = get_comment(ll)
block_data, last_line, stop = read_until(lines,'block','decay')
elements = []
+ # find first correctly formatted datum and infer matrix
+ # structure (number of keys)
+ for datum in block_data:
+ info = re.match(r'\s*((?:\d+\s+)+)\s*(\S+).*', datum)
+
+ if not info: continue
+
+ key = info.group(1)
+
+ nkeys = len(key.split())
+
+ break
+
+
for datum in block_data:
counter +=1
is_comment = re.match(r'\s*#.*',datum)
if (not datum.strip() or is_comment): continue
-
- info = re.match(r'\s*((?:\d+\s+)+)\s*(\S+).*',
+
+ info = re.match(r'\s*((?:\d+\s+){{{}}})\s*(\S+)(.*)'.format(nkeys),
datum)
if not info:
- print datum
+ # print datum
print ('Ignored datum in block '+
'{},'.format(theblock.name) +
' (line {} of {})'.format(counter, card))
continue
- key, value = info.group(1), info.group(2)
+ key, value, tail = info.group(1), info.group(2), info.group(3).strip()
+ if tail and not(tail.startswith('#')):
+ # print datum
+ print ('Ignored datum with inconsistent formatting in block '+
+ '{},'.format(theblock.name) +
+ ' (line {} of {})'.format(counter, card))
+ continue
+
try:
key = int(key)
except ValueError:
key = tuple( map(int, key.split()) )
dname = get_comment(datum)
try:
entry = float(value)
except ValueError:
entry = value
finally:
elements.append((key,value,dname))
if type(elements[0][0]) is tuple:
theblock = NamedMatrix(name=bname, comment=comment)
else:
theblock = NamedBlock(name=bname, comment=comment)
for ele in elements:
theblock.new_entry(*ele)
thecard.add_block(theblock)
elif first_chars=='decay':
try:
decay_details = re.match(r'\s*decay\s+(.+)',ll,
re.IGNORECASE).group(1)
except AttributeError:
err = ('Invalid decay format encountered' +
'in line {} of {}.'.format(counter, card) )
raise SHLAReadError(err)
info = re.match(r'\s*(\d+)\s+(\S+)\s+.*', decay_details)
PID, total = info.group(1), info.group(2)
comment = get_comment(decay_details)
thedecay = Decay(PID=int(PID), total=float(total),
comment=comment)
decay_data, last_line, stop = read_until(lines,'block','decay')
for datum in decay_data:
counter +=1
is_comment = re.match(r'\s*#.*',datum)
if ((not datum.strip()) or (is_comment)): continue
info = re.match(r'\s*(\S+)\s+(\d+)\s+(.+)',datum)
if not info:
print datum
print ('Ignored above datum in decay '+
'{},'.format(thedecay.PID) +
' (line {} of {})'.format(counter, card))
continue
BR, nout = info.group(1), info.group(2)
PIDinfo = info.group(3).split('#')[0]
PIDs = tuple( map(int, PIDinfo.split()) )
if len(PIDs)!=int(nout):
print ("Number of external particles in column 2 doesn't "
"match number of subsequent columns:")
print datum
print ('Ignored above datum in decay '+
'{},'.format(thedecay.PID) +
' (line {} of {})'.format(counter, card))
continue
comment = get_comment(datum)
thedecay.new_channel(PIDs, float(BR), comment=comment)
thecard.add_decay(thedecay)
if stop: raise StopIteration
except StopIteration:
pcard.close()
if set_cplx:
thecard.set_complex()
return thecard
def read_until(lines, here, *args):
'''
Loops through an iterator of strings by calling next() until
it reaches a line starting with a particular string.
Case insensitive.
Args:
lines - iterator of strings
here - string (plus any further arguments).
Reading will end if the line matches any of these.
Return:
lines_read - list of lines read
line - last line that was read (containing string "here")
'''
end_strings = [here.lower()]+[a.lower() for a in args]
lines_read = []
line = ''
stopiter = False
while not any([line.strip().lower().startswith(x) for x in end_strings]):
try:
line = lines.next()
lines_read.append(line.strip('\n'))
except StopIteration:
stopiter=True
break
try:
if stopiter:
return lines_read, '', stopiter
else:
return lines_read[:-1], lines_read[-1], stopiter
except IndexError:
return [],'',stopiter
# Errors
class SLHAError(Exception):
'''SLHA base exception class. Never raised.'''
pass
class SLHAIOError(SLHAError):
'''IOError'''
pass
class SLHADecayBlockError(SLHAError):
'''SLHA Decay Block Error'''
pass
class BRGTOneError(SLHADecayBlockError):
'''SLHA Decay Block Error'''
pass
if __name__=='__main__':
pass
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, May 3, 5:47 AM (4 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4982817
Default Alt Text
(45 KB)
Attached To
rROSETTAGIT rosettagit
Event Timeline
Log In to Comment