go-hep.org/x/hep@v0.38.1/slha/decode.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 6 7 import ( 8 "bufio" 9 "bytes" 10 "fmt" 11 "io" 12 "math" 13 "os" 14 "reflect" 15 "regexp" 16 "strconv" 17 "strings" 18 ) 19 20 var ( 21 reBlock = regexp.MustCompile(`BLOCK\s+(\w+)(\s+Q\s*=\s*.+)?`) 22 reDecay = regexp.MustCompile(`DECAY\s+(-?\d+)\s+([\d\.E+-]+|NAN).*`) 23 ) 24 25 // Decode reads SLHA informations from r and returns them as a *slha.SLHA. 26 func Decode(r io.Reader) (*SLHA, error) { 27 var err error 28 type stateType int 29 const ( 30 stBlock stateType = 1 31 stDecay stateType = 2 32 ) 33 var state stateType 34 var blk *Block 35 var part *Particle 36 var data SLHA 37 scan := bufio.NewScanner(r) 38 for scan.Scan() { 39 bline := scan.Bytes() 40 if len(bline) <= 0 { 41 continue 42 } 43 if bline[0] == '#' { 44 // TODO(sbinet) store block/entry comments 45 continue 46 } 47 bup := bytes.ToUpper(bline) 48 switch bup[0] { 49 case 'B': 50 idx := bytes.Index(bup, []byte("#")) 51 comment := "" 52 if idx > 0 { 53 comment = strings.TrimSpace(string(bline[idx+1:])) 54 bup = bytes.TrimSpace(bup[:idx]) 55 } 56 // fmt.Printf("Block> %q (comment=%q)\n", string(bup), comment) 57 state = stBlock 58 all := reBlock.FindStringSubmatch(string(bup)) 59 if all == nil { 60 return nil, fmt.Errorf("slha.decode: invalid block: %q", string(bline)) 61 } 62 groups := all[1:] 63 // for i, v := range groups { 64 // fmt.Printf(" %d/%d: %q\n", i+1, len(groups), v) 65 // } 66 i := len(data.Blocks) 67 data.Blocks = append(data.Blocks, Block{ 68 Name: groups[0], 69 Comment: comment, 70 Q: math.NaN(), 71 Data: make(DataArray, 0), 72 }) 73 blk = &data.Blocks[i] 74 if len(groups) > 1 && groups[1] != "" { 75 qstr := groups[1] 76 idx := strings.Index(qstr, "=") 77 if idx > 0 { 78 qstr = strings.TrimSpace(qstr[idx+1:]) 79 } 80 blk.Q, err = strconv.ParseFloat(qstr, 64) 81 if err != nil { 82 return nil, err 83 } 84 } 85 // fmt.Printf("Block> %v\n", blk) 86 87 case 'D': 88 state = stDecay 89 idx := bytes.Index(bup, []byte("#")) 90 comment := "" 91 if idx > 0 { 92 comment = strings.TrimSpace(string(bline[idx+1:])) 93 bup = bytes.TrimSpace(bup[:idx]) 94 } 95 all := reDecay.FindStringSubmatch(string(bup)) 96 if all == nil { 97 return nil, fmt.Errorf("slha.decode: invalid decay: %q", string(bline)) 98 } 99 groups := all[1:] 100 pdgid, err := strconv.Atoi(groups[0]) 101 if err != nil { 102 return nil, err 103 } 104 width := math.NaN() 105 if len(groups) > 1 && groups[1] != "" { 106 width, err = strconv.ParseFloat(groups[1], 64) 107 if err != nil { 108 return nil, err 109 } 110 } 111 i := len(data.Particles) 112 data.Particles = append(data.Particles, Particle{ 113 PdgID: pdgid, 114 Width: width, 115 Mass: math.NaN(), 116 Comment: comment, 117 Decays: make(Decays, 0, 2), 118 }) 119 part = &data.Particles[i] 120 121 case '\t', ' ': 122 // data line 123 switch state { 124 case stBlock: 125 err = addBlockEntry(bline, blk) 126 if err != nil { 127 return nil, err 128 } 129 case stDecay: 130 err = addDecayEntry(bline, part) 131 if err != nil { 132 return nil, err 133 } 134 } 135 default: 136 137 fmt.Fprintf(os.Stderr, "**WARN** ignoring unknown section [%s]\n", string(bup)) 138 } 139 } 140 err = scan.Err() 141 if err != nil { 142 if err != io.EOF { 143 return nil, err 144 } 145 err = nil 146 } 147 148 // try to populate particles' masses from the MASS block 149 if blk := data.Blocks.Get("MASS"); blk != nil { 150 for i := range data.Particles { 151 part := &data.Particles[i] 152 pdgid := part.PdgID 153 val, err := blk.Get(pdgid) 154 if err == nil { 155 part.Mass = val.Float() 156 } 157 } 158 } 159 return &data, err 160 } 161 162 func addBlockEntry(line []byte, blk *Block) error { 163 var err error 164 var val Value 165 hidx := bytes.Index(line, []byte("#")) 166 if hidx > 0 { 167 val.c = strings.TrimSpace(string(line[hidx+1:])) 168 line = line[:hidx] 169 } 170 line = bytes.TrimSpace(line) 171 tokens := make([][]byte, 0, 3) 172 for _, tok := range bytes.Split(line, []byte(" ")) { 173 if len(tok) <= 0 || bytes.Equal(tok, []byte("")) { 174 continue 175 } 176 tokens = append(tokens, tok) 177 } 178 179 // switch blk.Name { 180 // case "DCINFO": 181 // tokens 182 // } 183 184 ntokens := len(tokens) - 1 185 index := make([]int, ntokens) 186 for i := range index { 187 tok := string(tokens[i]) 188 index[i], err = strconv.Atoi(tok) 189 if err != nil { 190 return fmt.Errorf("slha.decode: invalid index %q. err=%v", tok, err) 191 } 192 } 193 194 sval := string(tokens[len(index)]) 195 switch blk.Name { 196 case "MODSEL": 197 v, err := strconv.Atoi(sval) 198 if err != nil { 199 return err 200 } 201 val.v = reflect.ValueOf(v) 202 203 case "SPINFO", "DCINFO": 204 val.v = reflect.ValueOf(sval) 205 206 default: 207 v, err := anyvalue(sval) 208 if err != nil { 209 return err 210 } 211 val.v = reflect.ValueOf(v) 212 } 213 214 // fmt.Printf("--- %q (comment=%q) len=%d indices=%v val=%#v\n", string(line), val.c, len(tokens), index, val.Interface()) 215 216 blk.Data = append(blk.Data, DataItem{ 217 Index: NewIndex(index...), 218 Value: val, 219 }) 220 return err 221 } 222 223 func anyvalue(str string) (any, error) { 224 var err error 225 var vv any 226 227 vfloat, err := strconv.ParseFloat(str, 64) 228 if err == nil { 229 vv = reflect.ValueOf(vfloat).Interface() 230 return vv, err 231 } 232 233 if strings.Count(str, "D") == 1 { 234 vfloat, err = strconv.ParseFloat(strings.Replace(str, "D", "E", 1), 64) 235 if err == nil { 236 vv = reflect.ValueOf(vfloat).Interface() 237 return vv, err 238 } 239 } 240 241 if strings.Count(str, "d") == 1 { 242 vfloat, err = strconv.ParseFloat(strings.Replace(str, "d", "E", 1), 64) 243 if err == nil { 244 vv = reflect.ValueOf(vfloat).Interface() 245 return vv, err 246 } 247 } 248 249 vint, err := strconv.Atoi(str) 250 if err == nil { 251 vv = reflect.ValueOf(int64(vint)).Interface() 252 return vv, err 253 } 254 255 vv = str 256 return vv, err 257 } 258 259 func addDecayEntry(line []byte, part *Particle) error { 260 var err error 261 comment := "" 262 hidx := bytes.Index(line, []byte("#")) 263 if hidx > 0 { 264 comment = strings.TrimSpace(string(line[hidx+1:])) 265 line = line[:hidx] 266 } 267 line = bytes.TrimSpace(line) 268 tokens := make([][]byte, 0, 3) 269 for _, tok := range bytes.Split(line, []byte(" ")) { 270 if len(tok) <= 0 || bytes.Equal(tok, []byte("")) { 271 continue 272 } 273 tokens = append(tokens, tok) 274 } 275 br, err := strconv.ParseFloat(string(tokens[0]), 64) 276 if err != nil { 277 return fmt.Errorf("slha.decode: invalid decay line %q. err=%v", string(line), err) 278 } 279 nda, err := strconv.Atoi(string(tokens[1])) 280 if err != nil { 281 return fmt.Errorf("slha.decode: invalid decay line %q. err=%v", string(line), err) 282 } 283 ids := make([]int, nda) 284 toks := tokens[2:] 285 for i := range ids { 286 ids[i], err = strconv.Atoi(string(toks[i])) 287 if err != nil { 288 return fmt.Errorf("slha.decode: invalid decay line %q. err=%v", string(line), err) 289 } 290 } 291 part.Decays = append(part.Decays, Decay{ 292 Br: br, 293 IDs: ids, 294 Comment: comment, 295 }) 296 // i := len(part.Decays) - 1 297 // fmt.Printf("--- %q (comment=%q) len=%d decay=%#v\n", string(line), comment, len(tokens), part.Decays[i]) 298 return err 299 }