pyslha.py

changeset 192
453a523cba25
parent 189
60c73b489420
child 193
40d024dac179
equal deleted inserted replaced
191:96c2b50d42b5 192:453a523cba25
6 pyslha is a parser/writer module for particle physics SUSY Les Houches Accord 6 pyslha is a parser/writer module for particle physics SUSY Les Houches Accord
7 (SLHA) supersymmetric spectrum/decay files, and a collection of scripts which 7 (SLHA) supersymmetric spectrum/decay files, and a collection of scripts which
8 use the interface, e.g. for conversion to and from the legacy ISAWIG format, or 8 use the interface, e.g. for conversion to and from the legacy ISAWIG format, or
9 to plot the mass spectrum and decay chains. 9 to plot the mass spectrum and decay chains.
10 10
11 The current release supports SLHA version 1, and as far as we're aware is also 11 The current release supports SLHA version 1, and as far as I'm aware is also
12 fully compatible with SLHA2: the block structures are read and accessed 12 fully compatible with SLHA2: the block structures are read and accessed
13 completely generically. If you have any problems with SLHA2, please provide an 13 generically. If you have any problems, please provide an example input file and
14 example input file and we'll investigate. 14 I'll investigate.
15 15
16 The plotting script provides output in PDF, EPS and PNG via LaTeX and the TikZ 16 The plotting script provides output in PDF, EPS and PNG via LaTeX and the TikZ
17 graphics package, and as LaTeX/TikZ source for direct embedding into documents or 17 graphics package, and as LaTeX/TikZ source for direct embedding into documents or
18 user-tweaking of the generated output. 18 user-tweaking of the generated output.
19 19
20 TODOs: 20 TODOs:
21 * Store dict entries as tuple keys, e.g. myblock.entries[1,2] rather than recursive dicts => v1.6.0 21
22 For 1.6.0 (or 2.0.0 if changes are really sweeping):
23 * Convert ISAWIG reader/writer to use new block entries access scheme
24 * Direct [] access to decay info on Decay
25 * Block (and Decay) to have __iter__/items() accesssors... or inherit direct from dict?
22 * Preserve comments from read -> write (needs full-line/inline comment separation?) 26 * Preserve comments from read -> write (needs full-line/inline comment separation?)
27 * Output column alignment cosmetics
23 * Split writeSLHA into writeSLHA{Blocks,Decays} 28 * Split writeSLHA into writeSLHA{Blocks,Decays}
29
30 Later/maybe:
24 * Identify HERWIG decay matrix element to use in ISAWIG 31 * Identify HERWIG decay matrix element to use in ISAWIG
25 * Handle RPV SUSY in ISAWIG 32 * Handle RPV SUSY in ISAWIG
26 """ 33 """
27 34
28 __author__ = "Andy Buckley <andy.buckley@cern.ch" 35 __author__ = "Andy Buckley <andy.buckley@cern.ch"
29 __version__ = "1.5.0" 36 __version__ = "1.6.0a0"
30 37
31 38
32 def _mkdict(): 39 def _mkdict():
33 """Try to return an empty ordered dict, but fall back to normal dict if necessary""" 40 """Try to return an empty ordered dict, but fall back to normal dict if necessary"""
34 try: 41 try:
52 return f 59 return f
53 except ValueError: 60 except ValueError:
54 return var 61 return var
55 62
56 def _autostr(var, precision=8): 63 def _autostr(var, precision=8):
57 """Automatically numerical types to the right sort of string.""" 64 """Automatically format numerical types as the right sort of string."""
58 if type(var) is float: 65 if type(var) is float:
59 return ("%." + str(precision) + "e") % var 66 return ("%." + str(precision) + "e") % var
60 return str(var) 67 return str(var)
61 68
62 69
70 77
71 78
72 class Block(object): 79 class Block(object):
73 """ 80 """
74 Object representation of any BLOCK elements read from the SLHA file. Blocks 81 Object representation of any BLOCK elements read from the SLHA file. Blocks
75 have a name, may have an associated Q value, and then a collection of data 82 have a name, may have an associated Q value, and contain a collection of data
76 entries, stored as a recursive dictionary. Types in the dictionary are 83 entries, each indexed by one or more keys. Types in the dictionary are
77 numeric (int or float) when a cast from the string in the file has been 84 numeric (int or float) when a cast from the string in the file has been
78 possible. 85 possible.
79 """ 86 """
80 def __init__(self, name, q=None): 87 def __init__(self, name, q=None):
81 self.name = name 88 self.name = name
82 self.entries = _mkdict() 89 self.entries = _mkdict()
83 self.q = _autotype(q) 90 self.q = _autotype(q)
84 91
85 def add_entry(self, entry): 92 def add_entry(self, entry):
86 #print entry
87 nextparent = self.entries
88 if type(entry) is str: 93 if type(entry) is str:
89 raise Exception("Block entries must be tuples or lists") 94 raise Exception("Block entries must be tuples or lists")
95 entry = map(_autotype, entry)
90 if len(entry) < 2: 96 if len(entry) < 2:
91 raise Exception("Block entry tuples must have at least two entries") 97 raise Exception("Block entry tuples must have at least two entries")
92 #print "in", entry 98 elif len(entry) == 2:
93 entry = map(_autotype, entry) 99 self.entries[entry[0]] = entry[1]
94 #print "out", entry 100 else:
95 for e in entry[:-2]: 101 self.entries[tuple(entry[:-1])] = entry[-1]
96 if e is not entry[-1]: 102
97 nextparent = nextparent.setdefault(e, _mkdict()) 103 def __getitem__(self, key):
98 nextparent[entry[-2]] = entry[-1] 104 return self.entries[key]
99 #print self.entries
100 105
101 def __cmp__(self, other): 106 def __cmp__(self, other):
102 return cmp(self.name, other.name) 107 return cmp(self.name, other.name)
103 108
104 def __str__(self): 109 def __str__(self):
201 import re 206 import re
202 currentblock = None 207 currentblock = None
203 currentdecay = None 208 currentdecay = None
204 for line in spcstr.splitlines(): 209 for line in spcstr.splitlines():
205 ## Handle (ignore) comment lines 210 ## Handle (ignore) comment lines
211 # TODO: Store block/entry comments
206 if line.startswith("#"): 212 if line.startswith("#"):
207 continue 213 continue
208 if "#" in line: 214 if "#" in line:
209 line = line[:line.index("#")] 215 line = line[:line.index("#")]
210 216
269 275
270 def writeSLHA(blocks, decays, ignorenobr=False, precision=8): 276 def writeSLHA(blocks, decays, ignorenobr=False, precision=8):
271 """ 277 """
272 Return an SLHA definition as a string, from the supplied blocks and decays dicts. 278 Return an SLHA definition as a string, from the supplied blocks and decays dicts.
273 """ 279 """
280 # TODO: Pay attention to space-padding and minus signs for column alignment
274 fmte = "%." + str(precision) + "e" 281 fmte = "%." + str(precision) + "e"
275
276 sep = " " 282 sep = " "
277 out = "" 283 blockstrs = []
278 def dict_hier_strs(d, s=""):
279 if isinstance(d, dict):
280 for k, v in d.iteritems():
281 for s2 in dict_hier_strs(v, s + sep + _autostr(k)):
282 yield s2
283 else:
284 yield s + sep + _autostr(d)
285 ## Blocks 284 ## Blocks
286 for bname, b in blocks.iteritems(): 285 for bname, b in blocks.iteritems():
287 namestr = b.name 286 namestr = b.name
288 if b.q is not None: 287 if b.q is not None:
289 namestr += (" Q= " + fmte) % float(b.q) 288 namestr += (" Q= " + fmte) % float(b.q)
290 out += "BLOCK %s\n" % namestr 289 blockstr = "BLOCK %s\n" % namestr
291 for s in dict_hier_strs(b.entries): 290 entrystrs = []
292 out += sep + s + "\n" 291 for k, v in b.entries.iteritems():
293 out += "\n" 292 entrystr = ""
293 if type(k) == tuple:
294 entrystr = sep.join(_autostr(i) for i in k)
295 else:
296 entrystr = _autostr(k)
297 entrystr += sep + _autostr(v) # TODO: apply precision formatting for floats
298 entrystrs.append(entrystr)
299 blockstr += "\n".join(entrystrs)
300 blockstrs.append(blockstr)
301 ##
294 ## Decays 302 ## Decays
295 for pid, particle in decays.iteritems(): 303 for pid, particle in decays.iteritems():
296 out += ("DECAY %d " + fmte + "\n") % (particle.pid, particle.totalwidth or -1) 304 blockstr = ("DECAY %d " + fmte + "\n") % (particle.pid, particle.totalwidth or -1)
305 decaystrs = []
297 for d in particle.decays: 306 for d in particle.decays:
298 if d.br > 0.0 or not ignorenobr: 307 if d.br > 0.0 or not ignorenobr:
299 products_str = " ".join(map(str, d.ids)) 308 products_str = sep.join(map(str, d.ids))
300 out += sep + fmte % d.br + sep + "%d" % len(d.ids) + sep + products_str + "\n" 309 decaystr = sep + (fmte % d.br) + sep + ("%d" % len(d.ids)) + sep + products_str
301 out += "\n" 310 decaystrs.append(decaystr)
302 return out 311 blockstr += "\n".join(decaystrs)
312 blockstrs.append(blockstr)
313 ## Total result
314 return "\n\n".join(blockstrs)
303 315
304 316
305 317
306 ############################################################################### 318 ###############################################################################
307 ## PDG <-> HERWIG particle ID code translations for ISAWIG handling 319 ## PDG <-> HERWIG particle ID code translations for ISAWIG handling

mercurial