go-hep.org/x/hep@v0.38.1/slha/slha.go (about)

     1  // Copyright ©2017 The go-hep Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package slha implements encoding and decoding of SUSY Les Houches Accords (SLHA) data format.
     6  package slha // import "go-hep.org/x/hep/slha"
     7  
     8  import (
     9  	"fmt"
    10  	"reflect"
    11  	"strconv"
    12  	"strings"
    13  )
    14  
    15  // SLHA holds informations about a SUSY Les Houches Accords file.
    16  type SLHA struct {
    17  	Blocks    Blocks
    18  	Particles Particles
    19  }
    20  
    21  // Value represents a value (string,int,float64) + comment in a SLHA line.
    22  type Value struct {
    23  	v reflect.Value
    24  	c string // comment attached to value
    25  }
    26  
    27  // Int returns the value as an int64.
    28  // Int panics if the underlying value isn't an int64.
    29  func (v *Value) Int() int64 {
    30  	return v.v.Int()
    31  }
    32  
    33  // Float returns the value as a float64.
    34  // Float panics if the underlying value isn't a float64.
    35  func (v *Value) Float() float64 {
    36  	return v.v.Float()
    37  }
    38  
    39  // Interface returns the value as an empty interface.
    40  func (v *Value) Interface() any {
    41  	return v.v.Interface()
    42  }
    43  
    44  // Kind returns the kind of the value (reflect.String, reflect.Float64, reflect.Int)
    45  func (v *Value) Kind() reflect.Kind {
    46  	return v.v.Kind()
    47  }
    48  
    49  // Comment returns the comment string attached to this value
    50  func (v *Value) Comment() string {
    51  	return v.c
    52  }
    53  
    54  // Block represents a block in a SLHA file.
    55  type Block struct {
    56  	Name    string
    57  	Comment string
    58  	Q       float64
    59  	Data    DataArray
    60  }
    61  
    62  // Get returns the Value at index args.
    63  // Note that args are 1-based indices.
    64  func (b *Block) Get(args ...int) (Value, error) {
    65  	var err error
    66  	var val Value
    67  
    68  	idx := NewIndex(args...)
    69  	val, ok := b.Data.Get(idx)
    70  	if !ok {
    71  		return val, fmt.Errorf("slha: no index (%s) in block %q", strings.Join(strindex(args...), ", "), b.Name)
    72  	}
    73  	return val, err
    74  }
    75  
    76  // Set sets the Value at index args with v.
    77  // Set creates a new empty Value if none exists at args.
    78  // Note that args are 1-based indices.
    79  func (b *Block) Set(v any, args ...int) error {
    80  	var err error
    81  	val, _ := b.Get(args...)
    82  	val.v = reflect.ValueOf(v)
    83  	idx := NewIndex(args...)
    84  	pos := b.Data.pos(idx)
    85  	if pos < 0 {
    86  		pos = len(b.Data)
    87  		b.Data = append(b.Data, DataItem{
    88  			Index: idx,
    89  		})
    90  	}
    91  	b.Data[pos].Value = val
    92  	return err
    93  }
    94  
    95  // DataArray is an ordered list of DataItems.
    96  type DataArray []DataItem
    97  
    98  // DataItem is a pair of (Index,Value).
    99  // Index is a n-dim index (1-based indices)
   100  type DataItem struct {
   101  	Index Index
   102  	Value Value
   103  }
   104  
   105  // Get returns the value at the n-dim index idx.
   106  func (d DataArray) Get(idx Index) (Value, bool) {
   107  	var val Value
   108  	for _, v := range d {
   109  		if v.Index == idx {
   110  			return v.Value, true
   111  		}
   112  	}
   113  	return val, false
   114  }
   115  
   116  func (d DataArray) pos(idx Index) int {
   117  	for i, v := range d {
   118  		if v.Index == idx {
   119  			return i
   120  		}
   121  	}
   122  	return -1
   123  }
   124  
   125  // Index is an n-dimensional index.
   126  // Note that the indices are 1-based.
   127  type Index struct {
   128  	rank   int
   129  	coords string
   130  }
   131  
   132  // NewIndex creates a new n-dim index from args.
   133  // Note that args are 1-based indices.
   134  func NewIndex(args ...int) Index {
   135  	sargs := strindex(args...)
   136  	return Index{
   137  		rank:   len(args),
   138  		coords: strings.Join(sargs, "#"),
   139  	}
   140  }
   141  
   142  // Index returns the n-dim indices.
   143  // Note that the indices are 1-based.
   144  func (idx Index) Index() []int {
   145  	sargs := strings.Split(idx.coords, "#")
   146  	args := make([]int, len(sargs))
   147  	for i, v := range sargs {
   148  		if v == "" {
   149  			continue
   150  		}
   151  		var err error
   152  		args[i], err = strconv.Atoi(v)
   153  		if err != nil {
   154  			panic(fmt.Errorf("slha.index: %v", err))
   155  		}
   156  	}
   157  	return args
   158  }
   159  
   160  func strindex(args ...int) []string {
   161  	sargs := make([]string, len(args))
   162  	for i, v := range args {
   163  		sargs[i] = strconv.Itoa(v)
   164  	}
   165  	return sargs
   166  }
   167  
   168  // Blocks is a list of Blocks.
   169  type Blocks []Block
   170  
   171  // Keys returns the names of the contained blocks.
   172  func (b Blocks) Keys() []string {
   173  	keys := make([]string, len(b))
   174  	for i := range b {
   175  		keys[i] = b[i].Name
   176  	}
   177  	return keys
   178  }
   179  
   180  // Get returns the block named name or nil.
   181  func (b Blocks) Get(name string) *Block {
   182  	for i := range b {
   183  		blk := &b[i]
   184  		if blk.Name == name {
   185  			return blk
   186  		}
   187  	}
   188  	return nil
   189  }
   190  
   191  // Decay is a decay line in an SLHA file.
   192  type Decay struct {
   193  	Br      float64 // Branching Ratio
   194  	IDs     []int   // list of PDG IDs to which the decay occur
   195  	Comment string  // comment attached to this decay line - if any
   196  }
   197  
   198  // Decays is a list of decays in a Decay block.
   199  type Decays []Decay
   200  
   201  // Particle is the representation of a single, specific particle, decay block from a SLHA file.
   202  type Particle struct {
   203  	PdgID   int     // PDG-ID code
   204  	Width   float64 // total width of that particle
   205  	Mass    float64 // mass of that particle
   206  	Comment string
   207  	Decays  Decays
   208  }
   209  
   210  // Particles is a block of particle's decays in an SLHA file.
   211  type Particles []Particle
   212  
   213  func (p Particles) Len() int           { return len(p) }
   214  func (p Particles) Less(i, j int) bool { return p[i].PdgID < p[j].PdgID }
   215  func (p Particles) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
   216  
   217  // Get returns the Particle with matching pdgid or nil.
   218  func (p Particles) Get(pdgid int) *Particle {
   219  	for i := range p {
   220  		part := &p[i]
   221  		if part.PdgID == pdgid {
   222  			return part
   223  		}
   224  	}
   225  	return nil
   226  }