pyslha.py

changeset 192
453a523cba25
parent 189
60c73b489420
child 193
40d024dac179
     1.1 --- a/pyslha.py	Fri Apr 26 01:25:11 2013 +0200
     1.2 +++ b/pyslha.py	Fri Apr 26 20:57:42 2013 +0200
     1.3 @@ -8,25 +8,32 @@
     1.4  use the interface, e.g. for conversion to and from the legacy ISAWIG format, or
     1.5  to plot the mass spectrum and decay chains.
     1.6  
     1.7 -The current release supports SLHA version 1, and as far as we're aware is also
     1.8 +The current release supports SLHA version 1, and as far as I'm aware is also
     1.9  fully compatible with SLHA2: the block structures are read and accessed
    1.10 -completely generically. If you have any problems with SLHA2, please provide an
    1.11 -example input file and we'll investigate.
    1.12 +generically. If you have any problems, please provide an example input file and
    1.13 +I'll investigate.
    1.14  
    1.15  The plotting script provides output in PDF, EPS and PNG via LaTeX and the TikZ
    1.16  graphics package, and as LaTeX/TikZ source for direct embedding into documents or
    1.17  user-tweaking of the generated output.
    1.18  
    1.19  TODOs:
    1.20 - * Store dict entries as tuple keys, e.g. myblock.entries[1,2] rather than recursive dicts => v1.6.0
    1.21 +
    1.22 +For 1.6.0 (or 2.0.0 if changes are really sweeping):
    1.23 + * Convert ISAWIG reader/writer to use new block entries access scheme
    1.24 + * Direct [] access to decay info on Decay
    1.25 + * Block (and Decay) to have __iter__/items() accesssors... or inherit direct from dict?
    1.26   * Preserve comments from read -> write (needs full-line/inline comment separation?)
    1.27 + * Output column alignment cosmetics
    1.28   * Split writeSLHA into writeSLHA{Blocks,Decays}
    1.29 +
    1.30 +Later/maybe:
    1.31   * Identify HERWIG decay matrix element to use in ISAWIG
    1.32   * Handle RPV SUSY in ISAWIG
    1.33  """
    1.34  
    1.35  __author__ = "Andy Buckley <andy.buckley@cern.ch"
    1.36 -__version__ = "1.5.0"
    1.37 +__version__ = "1.6.0a0"
    1.38  
    1.39  
    1.40  def _mkdict():
    1.41 @@ -54,7 +61,7 @@
    1.42          return var
    1.43  
    1.44  def _autostr(var, precision=8):
    1.45 -    """Automatically numerical types to the right sort of string."""
    1.46 +    """Automatically format numerical types as the right sort of string."""
    1.47      if type(var) is float:
    1.48          return ("%." + str(precision) + "e") % var
    1.49      return str(var)
    1.50 @@ -72,8 +79,8 @@
    1.51  class Block(object):
    1.52      """
    1.53      Object representation of any BLOCK elements read from the SLHA file.  Blocks
    1.54 -    have a name, may have an associated Q value, and then a collection of data
    1.55 -    entries, stored as a recursive dictionary. Types in the dictionary are
    1.56 +    have a name, may have an associated Q value, and contain a collection of data
    1.57 +    entries, each indexed by one or more keys. Types in the dictionary are
    1.58      numeric (int or float) when a cast from the string in the file has been
    1.59      possible.
    1.60      """
    1.61 @@ -83,20 +90,18 @@
    1.62          self.q = _autotype(q)
    1.63  
    1.64      def add_entry(self, entry):
    1.65 -        #print entry
    1.66 -        nextparent = self.entries
    1.67          if type(entry) is str:
    1.68              raise Exception("Block entries must be tuples or lists")
    1.69 +        entry = map(_autotype, entry)
    1.70          if len(entry) < 2:
    1.71              raise Exception("Block entry tuples must have at least two entries")
    1.72 -        #print "in", entry
    1.73 -        entry = map(_autotype, entry)
    1.74 -        #print "out", entry
    1.75 -        for e in entry[:-2]:
    1.76 -            if e is not entry[-1]:
    1.77 -                nextparent = nextparent.setdefault(e, _mkdict())
    1.78 -        nextparent[entry[-2]] = entry[-1]
    1.79 -        #print self.entries
    1.80 +        elif len(entry) == 2:
    1.81 +            self.entries[entry[0]] = entry[1]
    1.82 +        else:
    1.83 +            self.entries[tuple(entry[:-1])] = entry[-1]
    1.84 +
    1.85 +    def __getitem__(self, key):
    1.86 +        return self.entries[key]
    1.87  
    1.88      def __cmp__(self, other):
    1.89          return cmp(self.name, other.name)
    1.90 @@ -203,6 +208,7 @@
    1.91      currentdecay = None
    1.92      for line in spcstr.splitlines():
    1.93          ## Handle (ignore) comment lines
    1.94 +        # TODO: Store block/entry comments
    1.95          if line.startswith("#"):
    1.96              continue
    1.97          if "#" in line:
    1.98 @@ -271,35 +277,41 @@
    1.99      """
   1.100      Return an SLHA definition as a string, from the supplied blocks and decays dicts.
   1.101      """
   1.102 +    # TODO: Pay attention to space-padding and minus signs for column alignment
   1.103      fmte = "%." + str(precision) + "e"
   1.104 -
   1.105      sep = "   "
   1.106 -    out = ""
   1.107 -    def dict_hier_strs(d, s=""):
   1.108 -        if isinstance(d, dict):
   1.109 -            for k, v in d.iteritems():
   1.110 -                for s2 in dict_hier_strs(v, s + sep + _autostr(k)):
   1.111 -                    yield s2
   1.112 -        else:
   1.113 -            yield s + sep + _autostr(d)
   1.114 +    blockstrs = []
   1.115      ## Blocks
   1.116      for bname, b in blocks.iteritems():
   1.117          namestr = b.name
   1.118          if b.q is not None:
   1.119              namestr += (" Q= " + fmte) % float(b.q)
   1.120 -        out += "BLOCK %s\n" % namestr
   1.121 -        for s in dict_hier_strs(b.entries):
   1.122 -            out += sep + s + "\n"
   1.123 -        out += "\n"
   1.124 +        blockstr = "BLOCK %s\n" % namestr
   1.125 +        entrystrs = []
   1.126 +        for k, v in b.entries.iteritems():
   1.127 +            entrystr = ""
   1.128 +            if type(k) == tuple:
   1.129 +                entrystr = sep.join(_autostr(i) for i in k)
   1.130 +            else:
   1.131 +                entrystr = _autostr(k)
   1.132 +            entrystr += sep + _autostr(v) # TODO: apply precision formatting for floats
   1.133 +            entrystrs.append(entrystr)
   1.134 +        blockstr += "\n".join(entrystrs)
   1.135 +        blockstrs.append(blockstr)
   1.136 +        ##
   1.137      ## Decays
   1.138      for pid, particle in decays.iteritems():
   1.139 -        out += ("DECAY %d " + fmte + "\n") % (particle.pid, particle.totalwidth or -1)
   1.140 +        blockstr = ("DECAY %d " + fmte + "\n") % (particle.pid, particle.totalwidth or -1)
   1.141 +        decaystrs = []
   1.142          for d in particle.decays:
   1.143              if d.br > 0.0 or not ignorenobr:
   1.144 -                products_str = "   ".join(map(str, d.ids))
   1.145 -                out += sep + fmte % d.br + sep + "%d" % len(d.ids) + sep + products_str + "\n"
   1.146 -        out += "\n"
   1.147 -    return out
   1.148 +                products_str = sep.join(map(str, d.ids))
   1.149 +                decaystr = sep + (fmte % d.br) + sep + ("%d" % len(d.ids)) + sep + products_str
   1.150 +                decaystrs.append(decaystr)
   1.151 +        blockstr += "\n".join(decaystrs)
   1.152 +        blockstrs.append(blockstr)
   1.153 +    ## Total result
   1.154 +    return "\n\n".join(blockstrs)
   1.155  
   1.156  
   1.157  

mercurial