pyslha.py

Sat, 21 Aug 2010 19:01:12 +0100

author
Andy Buckley <andy@insectnation.org>
date
Sat, 21 Aug 2010 19:01:12 +0100
changeset 33
80cd82d24675
parent 32
34fa1801ce34
child 34
9f96ba4e000b
permissions
-rw-r--r--

Improving!

andy@1 1 #! /usr/bin/env python
andy@1 2
andy@8 3 """\
andy@8 4 A simple but flexible parser of SUSY Les Houches Accord (SLHA) model and decay files.
andy@25 5
andy@33 6 TODO: Provide convenience methods for populating block dictionary hierarchies (take from readSLHA)
andy@33 7 TODO: Split writeSLHA into writeSLHA{Blocks,Decays}
andy@8 8 """
andy@8 9
andy@8 10 from __future__ import with_statement
andy@26 11
andy@8 12 __author__ = "Andy Buckley <andy.buckley@cern.ch"
andy@30 13 __version__ = "0.2.0"
andy@8 14
andy@1 15 import re
andy@1 16
andy@4 17 def _autotype(var):
andy@30 18 """Automatically convert strings to numerical types if possible."""
andy@30 19 if type(var) is not str:
andy@4 20 return var
andy@4 21 if var.isdigit():
andy@4 22 return int(var)
andy@4 23 try:
andy@4 24 f = float(var)
andy@4 25 return f
andy@4 26 except ValueError:
andy@4 27 return var
andy@4 28
andy@30 29 def _autostr(var):
andy@30 30 """Automatically numerical types to the right sort of string."""
andy@30 31 if type(var) is float:
andy@30 32 return "%e" % var
andy@30 33 return str(var)
andy@30 34
andy@30 35
andy@4 36
andy@12 37 class Block(object):
andy@8 38 """
andy@8 39 Object representation of any BLOCK elements read from the SLHA file. Blocks
andy@8 40 have a name, may have an associated Q value, and then a collection of data
andy@8 41 entries, stored as a recursive dictionary. Types in the dictionary are
andy@8 42 numeric (int or float) when a cast from the string in the file has been
andy@8 43 possible.
andy@8 44 """
andy@5 45 def __init__(self, name, q=None):
andy@1 46 self.name = name
andy@1 47 self.entries = {}
andy@5 48 self.q = _autotype(q)
andy@1 49
andy@1 50 def add_entry(self, entry):
andy@1 51 #print entry
andy@1 52 nextparent = self.entries
andy@1 53 if len(entry) < 2:
andy@1 54 raise Exception("Block entries must be at least a 2-tuple")
andy@4 55 #print "in", entry
andy@4 56 entry = map(_autotype, entry)
andy@4 57 #print "out", entry
andy@1 58 for e in entry[:-2]:
andy@1 59 if e is not entry[-1]:
andy@1 60 nextparent = nextparent.setdefault(e, {})
andy@1 61 nextparent[entry[-2]] = entry[-1]
andy@1 62 #print self.entries
andy@1 63
andy@1 64 def __cmp__(self, other):
andy@31 65 return cmp(self.name, other.name)
andy@1 66
andy@1 67 def __str__(self):
andy@1 68 s = self.name
andy@5 69 if self.q is not None:
andy@5 70 s += " (Q=%s)" % self.q
andy@1 71 s += "\n"
andy@1 72 s += str(self.entries)
andy@1 73 return s
andy@1 74
andy@1 75
andy@12 76 class Decay(object):
andy@8 77 """
andy@8 78 Object representing a decay entry on a particle decribed by the SLHA file.
andy@8 79 'Decay' objects are not a direct representation of a DECAY block in an SLHA
andy@8 80 file... that role, somewhat confusingly, is taken by the Particle class.
andy@8 81
andy@8 82 Decay objects have three properties: a branching ratio, br, an nda number
andy@12 83 (number of daughters == len(ids)), and a tuple of PDG PIDs to which the
andy@12 84 decay occurs. The PDG ID of the particle whose decay this represents may
andy@12 85 also be stored, but this is normally known via the Particle in which the
andy@12 86 decay is stored.
andy@8 87 """
andy@8 88 def __init__(self, br, nda, ids, parentid=None):
andy@8 89 self.parentid = parentid
andy@6 90 self.br = br
andy@6 91 self.nda = nda
andy@6 92 self.ids = ids
andy@29 93 assert(self.nda == len(self.ids))
andy@6 94
andy@6 95 def __cmp__(self, other):
andy@31 96 return cmp(other.br, self.br)
andy@6 97
andy@6 98 def __str__(self):
andy@12 99 return "%e %s" % (self.br, self.ids)
andy@6 100
andy@6 101
andy@12 102 class Particle(object):
andy@8 103 """
andy@8 104 Representation of a single, specific particle, decay block from an SLHA
andy@8 105 file. These objects are not themselves called 'Decay', since that concept
andy@8 106 applies more naturally to the various decays found inside this
andy@8 107 object. Particle classes store the PDG ID (pid) of the particle being
andy@8 108 represented, and optionally the mass (mass) and total decay width
andy@8 109 (totalwidth) of that particle in the SLHA scenario. Masses may also be found
andy@8 110 via the MASS block, from which the Particle.mass property is filled, if at
andy@8 111 all. They also store a list of Decay objects (decays) which are probably the
andy@8 112 item of most interest.
andy@8 113 """
andy@6 114 def __init__(self, pid, totalwidth=None, mass=None):
andy@6 115 self.pid = pid
andy@6 116 self.totalwidth = totalwidth
andy@6 117 self.mass = mass
andy@6 118 self.decays = []
andy@6 119
andy@6 120 def add_decay(self, br, nda, ids):
andy@6 121 self.decays.append(Decay(br, nda, ids))
andy@6 122 self.decays.sort()
andy@6 123
andy@6 124 def __cmp__(self, other):
andy@6 125 if abs(self.pid) == abs(other.pid):
andy@31 126 return cmp(self.pid, other.pid)
andy@31 127 return cmp(abs(self.pid), abs(other.pid))
andy@6 128
andy@6 129 def __str__(self):
andy@6 130 s = str(self.pid)
andy@7 131 if self.mass is not None:
andy@7 132 s += " : mass = %e GeV" % self.mass
andy@6 133 if self.totalwidth is not None:
andy@7 134 s += " : total width = %e GeV" % self.totalwidth
andy@6 135 for d in self.decays:
andy@12 136 if d.br > 0.0:
andy@12 137 s += "\n %s" % d
andy@6 138 return s
andy@1 139
andy@1 140
andy@31 141 def readSLHAFile(spcfilename, **kwargs):
andy@21 142 """
andy@21 143 Read an SLHA file, returning dictionaries of blocks and decays.
andy@31 144
andy@31 145 Other keyword parameters are passed to readSLHA.
andy@21 146 """
andy@21 147 with open(spcfilename, "r") as f:
andy@31 148 return readSLHA(f.read(), kwargs)
andy@21 149
andy@21 150
andy@31 151 def readSLHA(spcstr, ignorenobr=False):
andy@21 152 """
andy@31 153 Read an SLHA definition from a string, returning dictionaries of blocks and
andy@31 154 decays.
andy@31 155
andy@31 156 If the ignorenobr parameter is True, do not store decay entries with a
andy@31 157 branching ratio of zero.
andy@21 158 """
andy@1 159 blocks = {}
andy@1 160 decays = {}
andy@21 161 #
andy@21 162 currentblock = None
andy@21 163 currentdecay = None
andy@21 164 for line in spcstr.splitlines():
andy@21 165 ## Handle (ignore) comment lines
andy@21 166 if line.startswith("#"):
andy@21 167 continue
andy@21 168 if "#" in line:
andy@21 169 line = line[:line.index("#")]
andy@21 170
andy@21 171 ## Handle BLOCK/DECAY start lines
andy@21 172 if line.upper().startswith("BLOCK"):
andy@21 173 match = re.match(r"BLOCK\s+(\w+)\s+(Q=\s*.+)?", line.upper())
andy@21 174 if not match:
andy@8 175 continue
andy@21 176 blockname = match.group(1)
andy@21 177 qstr = match.group(2)
andy@21 178 if qstr is not None:
andy@21 179 qstr = qstr[2:].strip()
andy@21 180 currentblock = blockname
andy@21 181 currentdecay = None
andy@21 182 blocks[blockname] = Block(blockname, q=qstr)
andy@21 183 elif line.upper().startswith("DECAY"):
andy@21 184 match = re.match(r"DECAY\s+(\d+)\s+([\d\.E+-]+).*", line.upper())
andy@21 185 if not match:
andy@21 186 continue
andy@21 187 pdgid = int(match.group(1))
andy@21 188 width = float(match.group(2))
andy@21 189 currentblock = "DECAY"
andy@21 190 currentdecay = pdgid
andy@21 191 decays[pdgid] = Particle(pdgid, width)
andy@21 192 else:
andy@21 193 ## In-block line
andy@21 194 if currentblock is not None:
andy@21 195 items = line.split()
andy@21 196 if len(items) < 1:
andy@6 197 continue
andy@21 198 if currentblock != "DECAY":
andy@21 199 if len(items) < 2:
andy@21 200 ## Treat the ALPHA block differently
andy@21 201 blocks[currentblock].value = _autotype(items[0])
andy@33 202 blocks[currentblock].entries = _autotype(items[0])
andy@8 203 else:
andy@21 204 blocks[currentblock].add_entry(items)
andy@21 205 else:
andy@21 206 br = float(items[0])
andy@21 207 nda = int(items[1])
andy@21 208 ids = map(int, items[2:])
andy@31 209 if br > 0.0 or not ignorenobr:
andy@31 210 decays[currentdecay].add_decay(br, nda, ids)
andy@1 211
andy@8 212 ## Try to populate Particle masses from the MASS block
andy@8 213 for pid in blocks["MASS"].entries.keys():
andy@8 214 if decays.has_key(pid):
andy@8 215 decays[pid].mass = blocks["MASS"].entries[pid]
andy@8 216
andy@1 217 return blocks, decays
andy@1 218
andy@1 219
andy@33 220 def readISAWIGFile(isafilename, **kwargs):
andy@33 221 """
andy@33 222 Read a spectrum definition from a file in the ISAWIG format, returning
andy@33 223 dictionaries of blocks and decays. While this is not an SLHA format, it is
andy@33 224 informally supported as a useful mechanism for converting ISAWIG spectra to
andy@33 225 SLHA.
andy@33 226
andy@33 227 Other keyword parameters are passed to readSLHA.
andy@33 228 """
andy@33 229 with open(isafilename, "r") as f:
andy@33 230 return readISAWIG(f.read(), kwargs)
andy@33 231
andy@33 232
andy@33 233 def readISAWIG(isastr, ignorenobr=False):
andy@33 234 """
andy@33 235 Read a spectrum definition from a string in the ISAWIG format, returning
andy@33 236 dictionaries of blocks and decays. While this is not an SLHA format, it is
andy@33 237 informally supported as a useful mechanism for converting ISAWIG spectra to
andy@33 238 SLHA.
andy@33 239
andy@33 240 ISAWIG parsing based on the HERWIG SUSY specification format, from
andy@33 241 http://www.hep.phy.cam.ac.uk/~richardn/HERWIG/ISAWIG/file.html
andy@33 242
andy@33 243 If the ignorenobr parameter is True, do not store decay entries with a
andy@33 244 branching ratio of zero.
andy@33 245 """
andy@33 246
andy@33 247 ## PDG MC ID codes mapped to HERWIG SUSY ID codes, based on
andy@33 248 ## http://www.hep.phy.cam.ac.uk/~richardn/HERWIG/ISAWIG/susycodes.html
andy@33 249 HERWIGID2PDGID = {}
andy@33 250 HERWIGID2PDGID[203] = 25 ## HIGGSL0
andy@33 251 HERWIGID2PDGID[204] = 35 ## HIGGSH0
andy@33 252 HERWIGID2PDGID[205] = 36 ## HIGGSA0
andy@33 253 HERWIGID2PDGID[206] = 37 ## HIGGS+
andy@33 254 HERWIGID2PDGID[207] = -37 ## HIGGS-
andy@33 255 HERWIGID2PDGID[401] = 1000001 ## SSDLBR
andy@33 256 HERWIGID2PDGID[407] = -1000001 ## SSDLBR
andy@33 257 HERWIGID2PDGID[402] = 1000002 ## SSULBR
andy@33 258 HERWIGID2PDGID[408] = -1000002 ## SSUL
andy@33 259 HERWIGID2PDGID[403] = 1000003 ## SSSLBR
andy@33 260 HERWIGID2PDGID[409] = -1000003 ## SSSL
andy@33 261 HERWIGID2PDGID[404] = 1000004 ## SSCLBR
andy@33 262 HERWIGID2PDGID[410] = -1000004 ## SSCL
andy@33 263 HERWIGID2PDGID[405] = 1000005 ## SSB1BR
andy@33 264 HERWIGID2PDGID[411] = -1000005 ## SSB1
andy@33 265 HERWIGID2PDGID[406] = 1000006 ## SST1BR
andy@33 266 HERWIGID2PDGID[412] = -1000006 ## SST1
andy@33 267 HERWIGID2PDGID[413] = 2000001 ## SSDR
andy@33 268 HERWIGID2PDGID[419] = -2000001 ## SSDRBR
andy@33 269 HERWIGID2PDGID[414] = 2000002 ## SSUR
andy@33 270 HERWIGID2PDGID[420] = -2000002 ## SSURBR
andy@33 271 HERWIGID2PDGID[415] = 2000003 ## SSSR
andy@33 272 HERWIGID2PDGID[421] = -2000003 ## SSSRBR
andy@33 273 HERWIGID2PDGID[416] = 2000004 ## SSCR
andy@33 274 HERWIGID2PDGID[422] = -2000004 ## SSCRBR
andy@33 275 HERWIGID2PDGID[417] = 2000005 ## SSB2
andy@33 276 HERWIGID2PDGID[423] = -2000005 ## SSB2BR
andy@33 277 HERWIGID2PDGID[418] = 2000006 ## SST2
andy@33 278 HERWIGID2PDGID[424] = -2000006 ## SST2BR
andy@33 279 HERWIGID2PDGID[425] = 1000011 ## SSEL-
andy@33 280 HERWIGID2PDGID[431] = -1000011 ## SSEL+
andy@33 281 HERWIGID2PDGID[426] = 1000012 ## SSNUEL
andy@33 282 HERWIGID2PDGID[432] = -1000012 ## SSNUELBR
andy@33 283 HERWIGID2PDGID[427] = 1000013 ## SSMUL-
andy@33 284 HERWIGID2PDGID[433] = -1000013 ## SSMUL+
andy@33 285 HERWIGID2PDGID[428] = 1000014 ## SSNUMUL
andy@33 286 HERWIGID2PDGID[434] = -1000014 ## SSNUMLBR
andy@33 287 HERWIGID2PDGID[429] = 1000015 ## SSTAU1-
andy@33 288 HERWIGID2PDGID[435] = -1000015 ## SSTAU1+
andy@33 289 HERWIGID2PDGID[430] = 1000016 ## SSNUTL
andy@33 290 HERWIGID2PDGID[436] = -1000016 ## SSNUTLBR
andy@33 291 HERWIGID2PDGID[437] = 2000011 ## SSEL-
andy@33 292 HERWIGID2PDGID[443] = -2000011 ## SSEL+
andy@33 293 HERWIGID2PDGID[438] = 2000012 ## SSNUEL
andy@33 294 HERWIGID2PDGID[444] = -2000012 ## SSNUELBR
andy@33 295 HERWIGID2PDGID[439] = 2000013 ## SSMUL-
andy@33 296 HERWIGID2PDGID[445] = -2000013 ## SSMUL+
andy@33 297 HERWIGID2PDGID[440] = 2000014 ## SSNUMUL
andy@33 298 HERWIGID2PDGID[446] = -2000014 ## SSNUMLBR
andy@33 299 HERWIGID2PDGID[441] = 2000015 ## SSTAU1-
andy@33 300 HERWIGID2PDGID[447] = -2000015 ## SSTAU1+
andy@33 301 HERWIGID2PDGID[442] = 2000016 ## SSNUTL
andy@33 302 HERWIGID2PDGID[448] = -2000016 ## SSNUTLBR
andy@33 303 HERWIGID2PDGID[449] = 1000021 ## GLUINO
andy@33 304 HERWIGID2PDGID[450] = 1000022 ## NTLINO1
andy@33 305 HERWIGID2PDGID[451] = 1000023 ## NTLINO2
andy@33 306 HERWIGID2PDGID[452] = 1000025 ## NTLINO3
andy@33 307 HERWIGID2PDGID[453] = 1000035 ## NTLINO4
andy@33 308 HERWIGID2PDGID[454] = 1000024 ## CHGINO1+
andy@33 309 HERWIGID2PDGID[456] = -1000024 ## CHGINO1-
andy@33 310 HERWIGID2PDGID[455] = 1000037 ## CHGINO2+
andy@33 311 HERWIGID2PDGID[457] = -1000037 ## CHGINO2-
andy@33 312 HERWIGID2PDGID[458] = 1000039 ## GRAVTINO
andy@33 313
andy@33 314 blocks = {}
andy@33 315 decays = {}
andy@33 316 lines = isastr.splitlines()
andy@33 317
andy@33 318 def getnextvalidline():
andy@33 319 global lines
andy@33 320 while lines:
andy@33 321 s = lines.pop(0)
andy@33 322 ## Return None if EOF reached
andy@33 323 if len(s) == 0:
andy@33 324 continue
andy@33 325 ## Strip trailing newline and surrounding whitespace
andy@33 326 s = s[:-1].strip()
andy@33 327 ## Strip comments
andy@33 328 if "#" in s:
andy@33 329 s = s[:s.index("#")].strip()
andy@33 330 ## Return if non-empty
andy@33 331 if len(s) > 0:
andy@33 332 return s
andy@33 333
andy@33 334 ## Populate MASS block
andy@33 335 masses = pyslha.Block("MASS")
andy@33 336 numentries = int(getnextvalidline())
andy@33 337 for i in xrange(numentries):
andy@33 338 hwid, mass, lifetime = map(pyslha._autotype, getnextvalidline(f).split())
andy@33 339 print hwid, HERWIGID2PDGID.get(hwid, hwid), mass, lifetime
andy@33 340
andy@33 341 # ## First write out masses section:
andy@33 342 # ## Number of SUSY + top particles
andy@33 343 # ## IDHW, RMASS(IDHW), RLTIM(IDHW)
andy@33 344 # ## repeated for each particle
andy@33 345 # ## IDHW is the HERWIG identity code.
andy@33 346 # ## RMASS and RTLIM are the mass in GeV, and lifetime in seconds respectively.
andy@33 347 # massout = ""
andy@33 348 # for pid in PIDS:
andy@33 349 # if pid < 6:
andy@33 350 # continue
andy@33 351 # if MASSES.has_key(pid) and DECAYS.has_key(pid):
andy@33 352 # width = DECAYS[pid].totalwidth
andy@33 353 # lifetime = -1
andy@33 354 # if width > 0:
andy@33 355 # lifetime = 1.0/(width * 1.51926778e24) ## == hbar/E in seconds
andy@33 356 # massout += "%d %e %e\n" % (HERWIGID2PDGID.get(pid, pid), MASSES[pid], lifetime)
andy@33 357 # else:
andy@33 358 # print "PID %d not found!" % pid
andy@33 359 # out += "%d\n" % massout.count("\n")
andy@33 360 # out += massout
andy@33 361
andy@33 362
andy@33 363 # ## Next each particles decay modes together with their branching ratios and matrix element codes
andy@33 364 # ## Number of decay modes for a given particle (IDK)
andy@33 365 # ## IDK(*), BRFRAC(*), NME(*) & IDKPRD(1-5,*)
andy@33 366 # ## repeated for each mode.
andy@33 367 # ## Repeated for each particle.
andy@33 368 # ## IDK is the HERWIG code for the decaying particle, BRFRAC is the branching ratio of
andy@33 369 # ## the decay mode. NME is a code for the matrix element to be used, either from the
andy@33 370 # ## SUSY elements or the main HERWIG MEs. IDKPRD are the HERWIG identity codes of the decay products.
andy@33 371 # for pid in PIDS:
andy@33 372 # if DECAYS.has_key(pid):
andy@33 373 # decayout = "%d\n" % len(DECAYS[pid].decays)
andy@33 374 # for d in DECAYS[pid].decays:
andy@33 375 # ## TODO: Identify decay matrix element to use
andy@33 376 # decayout += "%d %e 0 " % (HERWIGID2PDGID.get(pid, pid), d.br)
andy@33 377 # ## TODO: Order decay products as required
andy@33 378 # ids = [0,0,0,0,0]
andy@33 379 # for i, pid in enumerate(d.ids):
andy@33 380 # ids[i] = pid
andy@33 381 # ids = map(str, ids)
andy@33 382 # decayout += " ".join(ids) + "\n"
andy@33 383 # out += decayout
andy@33 384
andy@33 385
andy@33 386 # ## Now the SUSY parameters
andy@33 387 # ## TANB, ALPHAH:
andy@33 388 # out += "%e %e\n" % (BLOCKS["MINPAR"].entries[3], BLOCKS["ALPHA"].entries[0])
andy@33 389 # ## Neutralino mixing matrix
andy@33 390 # nmix = BLOCKS["NMIX"].entries
andy@33 391 # for i in xrange(1, 5):
andy@33 392 # out += "%e %e %e %e\n" % (nmix[i][1], nmix[i][2], nmix[i][3], nmix[i][4])
andy@33 393 # ## Chargino mixing matrices V and U
andy@33 394 # vmix = BLOCKS["VMIX"].entries
andy@33 395 # out += "%e %e %e %e\n" % (vmix[1][1], vmix[1][2], vmix[2][1], vmix[2][2])
andy@33 396 # umix = BLOCKS["UMIX"].entries
andy@33 397 # out += "%e %e %e %e\n" % (umix[1][1], umix[1][2], umix[2][1], umix[2][2])
andy@33 398 # # THETAT,THETAB,THETAL
andy@33 399 # import math
andy@33 400 # out += "%e %e %e\n" % (math.acos(BLOCKS["STOPMIX"].entries[1][1]),
andy@33 401 # math.acos(BLOCKS["SBOTMIX"].entries[1][1]),
andy@33 402 # math.acos(BLOCKS["STAUMIX"].entries[1][1]))
andy@33 403 # # ATSS,ABSS,ALSS
andy@33 404 # out += "%e %e %e\n" % (BLOCKS["AU"].entries[3][3],
andy@33 405 # BLOCKS["AD"].entries[3][3],
andy@33 406 # BLOCKS["AE"].entries[3][3])
andy@33 407 # # MUSS == sign(mu)
andy@33 408 # out += "%f\n" % BLOCKS["MINPAR"].entries[4]
andy@33 409
andy@33 410
andy@33 411
andy@21 412
andy@31 413 def writeSLHAFile(spcfilename, blocks, decays, **kwargs):
andy@29 414 """
andy@29 415 Write an SLHA file from the supplied blocks and decays dicts.
andy@31 416
andy@31 417 Other keyword parameters are passed to writeSLHA.
andy@29 418 """
andy@29 419 with open(spcfilename, "w") as f:
andy@31 420 f.write(writeSLHA(blocks, decays, kwargs))
andy@29 421
andy@29 422
andy@33 423 ## TODO: Split writeSLHA into writeSLHA{Blocks,Decays}
andy@33 424
andy@31 425 def writeSLHA(blocks, decays, ignorenobr=False):
andy@29 426 """
andy@29 427 Return an SLHA definition as a string, from the supplied blocks and decays dicts.
andy@29 428 """
andy@31 429 sep = " "
andy@29 430 out = ""
andy@30 431 def dict_hier_strs(d, s=""):
andy@30 432 if type(d) is dict:
andy@30 433 for k, v in sorted(d.iteritems()):
andy@31 434 for s2 in dict_hier_strs(v, s + sep + _autostr(k)):
andy@30 435 yield s2
andy@30 436 else:
andy@31 437 yield s + sep + _autostr(d)
andy@30 438 ## Blocks
andy@30 439 for bname, b in sorted(blocks.iteritems()):
andy@29 440 namestr = b.name
andy@29 441 if b.q is not None:
andy@29 442 namestr += " Q= %e" % b.q
andy@29 443 out += "BLOCK %s\n" % namestr
andy@30 444 for s in dict_hier_strs(b.entries):
andy@31 445 out += sep + s + "\n"
andy@29 446 out += "\n"
andy@30 447 ## Decays
andy@30 448 for pid, particle in sorted(decays.iteritems()):
andy@29 449 out += "DECAY %d %e\n" % (particle.pid, particle.totalwidth)
andy@30 450 for d in sorted(particle.decays):
andy@31 451 if d.br > 0.0 or not ignorenobr:
andy@31 452 products_str = " ".join(map(str, d.ids))
andy@31 453 out += sep + "%e" % d.br + sep + "%d" % len(d.ids) + sep + products_str + "\n"
andy@29 454 out += "\n"
andy@29 455 return out
andy@29 456
andy@29 457
andy@29 458
andy@1 459 if __name__ == "__main__":
andy@1 460 import sys
andy@1 461 for a in sys.argv[1:]:
andy@29 462 blocks, decays = readSLHAFile(a)
andy@3 463
andy@5 464 for bname, b in sorted(blocks.iteritems()):
andy@5 465 print b
andy@5 466 print
andy@3 467
andy@4 468 print blocks["MASS"].entries[25]
andy@6 469 print
andy@6 470
andy@6 471 for p in sorted(decays.values()):
andy@6 472 print p
andy@6 473 print
andy@29 474
andy@31 475 print writeSLHA(blocks, decays, ignorenobr=True)

mercurial