go-hep.org/x/hep@v0.38.1/lhef/reader.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 lhef
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/xml"
    10  	"errors"
    11  	"fmt"
    12  	"io"
    13  )
    14  
    15  // Decoder represents an LHEF parser reading a particular input stream.
    16  //
    17  // A Decoder is initialized with an input io.Reader from which to read a version 1.0
    18  // Les Houches Accord event file.
    19  type Decoder struct {
    20  	r       io.Reader
    21  	dec     *xml.Decoder
    22  	evt     xml.StartElement // the current xml.Token holding a HEPEUP
    23  	Version int              // LHEF file version
    24  	Run     HEPRUP           // User process run common block
    25  }
    26  
    27  func NewDecoder(r io.Reader) (*Decoder, error) {
    28  	var err error
    29  	dec := xml.NewDecoder(r)
    30  	d := &Decoder{
    31  		r:       r,
    32  		dec:     dec,
    33  		Version: -42,
    34  		Run:     HEPRUP{},
    35  	}
    36  	// err := dec.dec.Decode(&dec.lhevt)
    37  	// if err != nil {
    38  	// 	return nil
    39  	// }
    40  	// fmt.Printf(">>> version=%v\n", dec.lhevt.Version)
    41  
    42  	tok, err := dec.Token()
    43  	if err != nil || tok == nil {
    44  		return nil, err
    45  	}
    46  
    47  	// make sure we are reading a LHEF file
    48  	start, ok := tok.(xml.StartElement)
    49  	if !ok || start.Name.Local != "LesHouchesEvents" {
    50  		return nil, errors.New("lhef.Decoder: missing LesHouchesEvent start-tag")
    51  	}
    52  
    53  	//fmt.Printf(">>> %v\n", start)
    54  	version := start.Attr[0].Value
    55  	//fmt.Printf("    version=[%s]\n", version)
    56  	switch version {
    57  	default:
    58  		d.Version = -42
    59  	case "1.0":
    60  		d.Version = 1
    61  	case "2.0":
    62  		d.Version = 2
    63  	}
    64  
    65  	var (
    66  		init xml.StartElement
    67  		// header xml.StartElement // FIXME(sbinet)
    68  	)
    69  
    70  Loop:
    71  	for {
    72  		tok, err = dec.Token()
    73  		if err != nil || tok == nil {
    74  			return nil, err
    75  		}
    76  		switch tok := tok.(type) {
    77  		case xml.Comment:
    78  			// skip
    79  		case xml.CharData:
    80  			// skip
    81  		case xml.StartElement:
    82  			switch tok.Name.Local {
    83  			case "init":
    84  				init = tok
    85  				break Loop
    86  			case "header":
    87  				// FIXME(sbinet): do something about header's content.
    88  				//		header = tok //FIXME
    89  				//panic(fmt.Errorf("header not implemented: %v", header))
    90  			}
    91  		}
    92  	}
    93  
    94  	if init.Name.Local != "init" {
    95  		return nil, errors.New("lhef.Decoder: missing init start-tag")
    96  	}
    97  
    98  	// extract compulsory initialization information
    99  	tok, err = dec.Token()
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	data, ok := tok.(xml.CharData)
   104  	if !ok || len(data) == 0 {
   105  		return nil, errors.New("lhef.Decoder: missing init payload")
   106  	}
   107  	buf := bytes.NewBuffer(data)
   108  	_, err = fmt.Fscanf(
   109  		buf,
   110  		"\n%d %d %f %f %d %d %d %d %d %d\n",
   111  		&d.Run.IDBMUP[0],
   112  		&d.Run.IDBMUP[1],
   113  		&d.Run.EBMUP[0],
   114  		&d.Run.EBMUP[1],
   115  		&d.Run.PDFGUP[0],
   116  		&d.Run.PDFGUP[1],
   117  		&d.Run.PDFSUP[0],
   118  		&d.Run.PDFSUP[1],
   119  		&d.Run.IDWTUP,
   120  		&d.Run.NPRUP,
   121  	)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	n := int(d.Run.NPRUP)
   127  	if n < 0 {
   128  		return nil, fmt.Errorf("lhef.Decoder: invalid NPRUP (%d)", d.Run.NPRUP)
   129  	}
   130  	f64 := make([]float64, 3*n)
   131  	d.Run.XSECUP = f64[:n:n]
   132  	d.Run.XERRUP = f64[n : 2*n : 2*n]
   133  	d.Run.XMAXUP = f64[2*n:]
   134  	d.Run.LPRUP = make([]int32, n)
   135  
   136  	for i := range n {
   137  		_, err = fmt.Fscanf(
   138  			buf,
   139  			"%f %f %f %d\n",
   140  			&d.Run.XSECUP[i],
   141  			&d.Run.XERRUP[i],
   142  			&d.Run.XMAXUP[i],
   143  			&d.Run.LPRUP[i],
   144  		)
   145  		if err != nil {
   146  			return nil, fmt.Errorf("lhef: failed to decode NPRUP %d: %w", i, err)
   147  		}
   148  	}
   149  
   150  	// FIXME(sbinet): implement v2 specific stuff
   151  	// if d.Version >= 2 {
   152  	// 	// do version-2 specific stuff
   153  	// }
   154  
   155  	err = d.seek(init.End())
   156  	if err != nil {
   157  		return nil, fmt.Errorf("lhef: could not find 'init' end tag: %w", err)
   158  	}
   159  
   160  	return d, nil
   161  }
   162  
   163  // advance to next event
   164  func (d *Decoder) next() error {
   165  LoopEvt:
   166  	for {
   167  		tok, err := d.dec.Token()
   168  		if err != nil {
   169  			return err
   170  		}
   171  		switch tt := tok.(type) {
   172  		case xml.Comment:
   173  			// skip
   174  		case xml.CharData:
   175  			// skip
   176  		case xml.StartElement:
   177  			switch tt.Name.Local {
   178  			case "event":
   179  				d.evt = tt
   180  				break LoopEvt
   181  			}
   182  		}
   183  	}
   184  
   185  	return nil
   186  }
   187  
   188  func (d *Decoder) seek(tok xml.Token) error {
   189  seek:
   190  	for {
   191  		tk, err := d.dec.Token()
   192  		if err != nil {
   193  			return err
   194  		}
   195  		if tk == tok {
   196  			break seek
   197  		}
   198  	}
   199  
   200  	return nil
   201  }
   202  
   203  // Read an event from the file
   204  func (d *Decoder) Decode() (*HEPEUP, error) {
   205  
   206  	// check whether the initialization was successful
   207  	if d.Run.NPRUP < 0 {
   208  		return nil, errors.New("lhef.Decode: initialization failed (no particle entries)")
   209  	}
   210  
   211  	err := d.next()
   212  	if err != nil {
   213  		return nil, err
   214  	}
   215  
   216  	// extract payload data
   217  	tok, err := d.dec.Token()
   218  	if err != nil {
   219  		return nil, err
   220  	}
   221  	data, ok := tok.(xml.CharData)
   222  	if !ok {
   223  		return nil, fmt.Errorf("lhef.Decode: invalid token (%T: %v)", tok, tok)
   224  	}
   225  	if len(data) <= 0 {
   226  		return nil, errors.New("lhef.Decode: empty event")
   227  	}
   228  	buf := bytes.NewBuffer(data)
   229  
   230  	evt := &HEPEUP{
   231  		NUP: 0,
   232  	}
   233  
   234  	_, err = fmt.Fscanf(
   235  		buf,
   236  		"\n%d %d %f %f %f %f\n",
   237  		&evt.NUP,
   238  		&evt.IDPRUP,
   239  		&evt.XWGTUP,
   240  		&evt.SCALUP,
   241  		&evt.AQEDUP,
   242  		&evt.AQCDUP,
   243  	)
   244  	if err != nil {
   245  		fmt.Printf("--> 2 err: %v\n", err)
   246  		fmt.Printf("  data:    %v\n", string(data))
   247  		fmt.Printf("  token:   (%T: %v)\n", tok, tok)
   248  		return nil, err
   249  	}
   250  
   251  	n := int(evt.NUP)
   252  	evt.IDUP = make([]int64, n)
   253  	evt.ISTUP = make([]int32, n)
   254  	n2 := make([][2]int32, 2*n)
   255  	evt.MOTHUP = n2[:n:n]
   256  	evt.ICOLUP = n2[n:]
   257  	evt.PUP = make([][5]float64, n)
   258  	f64 := make([]float64, 2*n)
   259  	evt.VTIMUP = f64[:n:n]
   260  	evt.SPINUP = f64[n:]
   261  	for i := range n {
   262  		_, err = fmt.Fscanf(
   263  			buf,
   264  			"%d %d %d %d %d %d %f %f %f %f %f %f %f\n",
   265  			&evt.IDUP[i],
   266  			&evt.ISTUP[i],
   267  			&evt.MOTHUP[i][0],
   268  			&evt.MOTHUP[i][1],
   269  			&evt.ICOLUP[i][0],
   270  			&evt.ICOLUP[i][1],
   271  			&evt.PUP[i][0], &evt.PUP[i][1], &evt.PUP[i][2],
   272  			&evt.PUP[i][3], &evt.PUP[i][4],
   273  			&evt.VTIMUP[i],
   274  			&evt.SPINUP[i],
   275  		)
   276  		if err != nil {
   277  			fmt.Printf("--> 3-%d err: %v\n", i, err)
   278  			return nil, err
   279  		}
   280  	}
   281  
   282  	// read any additional comments...
   283  	_ /*evtComments*/ = buf.Bytes()
   284  
   285  	// do
   286  
   287  	// put "cursor" to next event...
   288  	err = d.seek(d.evt.End())
   289  	if err != nil {
   290  		return nil, fmt.Errorf("lhef: could not find 'event' end tag: %w", err)
   291  	}
   292  
   293  	return evt, nil
   294  }