go-hep.org/x/hep@v0.38.1/lcio/mc.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 lcio
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"strings"
    11  
    12  	"go-hep.org/x/hep/sio"
    13  )
    14  
    15  // McParticleContainer is a collection of monte-carlo particles.
    16  type McParticleContainer struct {
    17  	Flags     Flags
    18  	Params    Params
    19  	Particles []McParticle
    20  }
    21  
    22  func (mcs McParticleContainer) String() string {
    23  	o := new(strings.Builder)
    24  	fmt.Fprintf(o, "%[1]s print out of MCParticle collection %[1]s\n\n", strings.Repeat("-", 15))
    25  	fmt.Fprintf(o, "  flag:  0x%x\n%v", mcs.Flags, mcs.Params)
    26  
    27  	fmt.Fprintf(o,
    28  		"simulator status bits: [sbvtcls] "+
    29  			"s: created in simulation "+
    30  			"b: backscatter "+
    31  			"v: vertex is not endpoint of parent "+
    32  			"t: decayed in tracker "+
    33  			"c: decayed in calorimeter "+
    34  			"l: has left detector "+
    35  			"s: stopped o: overlay\n",
    36  	)
    37  
    38  	p2i := make(map[*McParticle]int, len(mcs.Particles))
    39  	for i := range mcs.Particles {
    40  		p := &mcs.Particles[i]
    41  		p2i[p] = i
    42  	}
    43  
    44  	fmt.Fprintf(o,
    45  		"[   id    ]"+
    46  			"index|      PDG |    px,     py,        pz    | "+
    47  			"px_ep,   py_ep , pz_ep      | "+
    48  			"energy  |gen|[simstat ]| "+
    49  			"vertex x,     y   ,   z     | "+
    50  			"endpoint x,    y  ,   z     |    mass |  charge |            spin             | "+
    51  			"colorflow | [parents] - [daughters]\n\n",
    52  	)
    53  	pfmt := "[%8.8d]%5d|%10d|% 1.2e,% 1.2e,% 1.2e|" +
    54  		"% 1.2e,% 1.2e,% 1.2e|" +
    55  		"% 1.2e|" +
    56  		" %1d |" +
    57  		"%s|" +
    58  		"% 1.2e,% 1.2e,% 1.2e|" +
    59  		"% 1.2e,% 1.2e,% 1.2e|" +
    60  		"% 1.2e|" +
    61  		"% 1.2e|" +
    62  		"% 1.2e,% 1.2e,% 1.2e|" +
    63  		"  (%d, %d)   |" +
    64  		" ["
    65  
    66  	for i := range mcs.Particles {
    67  		p := &mcs.Particles[i]
    68  		ep := p.EndPoint()
    69  		fmt.Fprintf(o, pfmt,
    70  			ID(p),
    71  			i, p.PDG,
    72  			p.P[0], p.P[1], p.P[2],
    73  			p.PEndPoint[0], p.PEndPoint[1], p.PEndPoint[2],
    74  			p.Energy(),
    75  			p.GenStatus,
    76  			p.SimStatusString(),
    77  			p.Vertex[0], p.Vertex[1], p.Vertex[2],
    78  			ep[0], ep[1], ep[2],
    79  			p.Mass,
    80  			p.Charge,
    81  			p.Spin[0], p.Spin[1], p.Spin[2],
    82  			p.ColorFlow[0], p.ColorFlow[1],
    83  		)
    84  		for ii := range p.Parents {
    85  			if ii > 0 {
    86  				fmt.Fprintf(o, ",")
    87  			}
    88  			fmt.Fprintf(o, "%d", p2i[p.Parents[ii]])
    89  		}
    90  		fmt.Fprintf(o, "] - [")
    91  		for ii := range p.Children {
    92  			if ii > 0 {
    93  				fmt.Fprintf(o, ",")
    94  			}
    95  			fmt.Fprintf(o, "%d", p2i[p.Children[ii]])
    96  		}
    97  		fmt.Fprintf(o, "]\n")
    98  	}
    99  
   100  	fmt.Fprintf(o, "\n-------------------------------------------------------------------------------- \n")
   101  	return o.String()
   102  }
   103  
   104  func (*McParticleContainer) VersionSio() uint32 {
   105  	return Version
   106  }
   107  
   108  func (mc *McParticleContainer) MarshalSio(w sio.Writer) error {
   109  	enc := sio.NewEncoder(w)
   110  	enc.Encode(&mc.Flags)
   111  	enc.Encode(&mc.Params)
   112  	enc.Encode(&mc.Particles)
   113  	return enc.Err()
   114  }
   115  
   116  func (mc *McParticleContainer) UnmarshalSio(r sio.Reader) error {
   117  	dec := sio.NewDecoder(r)
   118  	dec.Decode(&mc.Flags)
   119  	dec.Decode(&mc.Params)
   120  	dec.Decode(&mc.Particles)
   121  	return dec.Err()
   122  }
   123  
   124  func (mc *McParticleContainer) LinkSio(vers uint32) error {
   125  	var err error
   126  	switch {
   127  	case vers <= 8:
   128  		for i := range mc.Particles {
   129  			p := &mc.Particles[i]
   130  			for _, c := range p.Children {
   131  				if c != nil {
   132  					c.Parents = append(c.Parents, p)
   133  				}
   134  			}
   135  		}
   136  
   137  	default:
   138  		for i := range mc.Particles {
   139  			p := &mc.Particles[i]
   140  			for i := range p.Parents {
   141  				mom := p.Parents[i]
   142  				if mom != nil {
   143  					mom.Children = append(mom.Children, p)
   144  				}
   145  			}
   146  		}
   147  	}
   148  
   149  	return err
   150  }
   151  
   152  type McParticle struct {
   153  	Parents   []*McParticle
   154  	Children  []*McParticle
   155  	PDG       int32
   156  	GenStatus int32
   157  	SimStatus uint32
   158  	Vertex    [3]float64
   159  	Time      float32    // creation time of the particle in ns
   160  	P         [3]float64 // Momentum at production vertex
   161  	Mass      float64
   162  	Charge    float32
   163  	endPoint  [3]float64
   164  	PEndPoint [3]float64 // momentum at end-point
   165  	Spin      [3]float32
   166  	ColorFlow [2]int32
   167  }
   168  
   169  func (mc *McParticle) Energy() float64 {
   170  	px := mc.P[0]
   171  	py := mc.P[1]
   172  	pz := mc.P[2]
   173  	return math.Sqrt(px*px + py*py + pz*pz + mc.Mass*mc.Mass)
   174  }
   175  
   176  func (mc *McParticle) EndPoint() [3]float64 {
   177  	if mc.SimStatus&uint32(1<<31) == 0 {
   178  		if len(mc.Children) == 0 {
   179  			return mc.endPoint
   180  		}
   181  		for _, child := range mc.Children {
   182  			if !child.VertexIsNotEnpointOfParent() {
   183  				return child.Vertex
   184  			}
   185  		}
   186  	}
   187  	return mc.endPoint
   188  }
   189  
   190  func (mc *McParticle) SimStatusString() string {
   191  	status := []byte("[    0   ]")
   192  	if mc.SimStatus == 0 {
   193  		return string(status)
   194  	}
   195  	if mc.IsCreatedInSimulation() {
   196  		status[1] = 's'
   197  	}
   198  	if mc.IsBackScatter() {
   199  		status[2] = 'b'
   200  	}
   201  	if mc.VertexIsNotEnpointOfParent() {
   202  		status[3] = 'v'
   203  	}
   204  	if mc.IsDecayedInTracker() {
   205  		status[4] = 't'
   206  	}
   207  	if mc.IsDecayedInCalorimeter() {
   208  		status[5] = 'c'
   209  	} else {
   210  		status[5] = ' '
   211  	}
   212  	if mc.HasLeftDetector() {
   213  		status[6] = 'l'
   214  	}
   215  	if mc.IsStopped() {
   216  		status[7] = 's'
   217  	}
   218  	if mc.IsOverlay() {
   219  		status[8] = 'o'
   220  	}
   221  	return string(status)
   222  }
   223  
   224  func (mc *McParticle) IsCreatedInSimulation() bool {
   225  	return mc.SimStatus&uint32(1<<30) != 0
   226  }
   227  
   228  func (mc *McParticle) IsBackScatter() bool {
   229  	return mc.SimStatus&uint32(1<<29) != 0
   230  }
   231  
   232  func (mc *McParticle) VertexIsNotEnpointOfParent() bool {
   233  	return mc.SimStatus&uint32(1<<28) != 0
   234  }
   235  
   236  func (mc *McParticle) IsDecayedInTracker() bool {
   237  	return mc.SimStatus&uint32(1<<27) != 0
   238  }
   239  
   240  func (mc *McParticle) IsDecayedInCalorimeter() bool {
   241  	return mc.SimStatus&uint32(1<<26) != 0
   242  }
   243  
   244  func (mc *McParticle) HasLeftDetector() bool {
   245  	return mc.SimStatus&uint32(1<<25) != 0
   246  }
   247  
   248  func (mc *McParticle) IsStopped() bool {
   249  	return mc.SimStatus&uint32(1<<24) != 0
   250  }
   251  
   252  func (mc *McParticle) IsOverlay() bool {
   253  	return mc.SimStatus&uint32(1<<23) != 0
   254  }
   255  
   256  func (mc *McParticle) VersionSio() uint32 {
   257  	return Version
   258  }
   259  
   260  func (mc *McParticle) MarshalSio(w sio.Writer) error {
   261  	enc := sio.NewEncoder(w)
   262  	enc.Tag(mc)
   263  	enc.Encode(int32(len(mc.Parents)))
   264  	for ii := range mc.Parents {
   265  		enc.Pointer(&mc.Parents[ii])
   266  	}
   267  	enc.Encode(&mc.PDG)
   268  	enc.Encode(&mc.GenStatus)
   269  	enc.Encode(&mc.SimStatus)
   270  	enc.Encode(&mc.Vertex)
   271  	enc.Encode(&mc.Time)
   272  	mom := [3]float32{float32(mc.P[0]), float32(mc.P[1]), float32(mc.P[2])}
   273  	enc.Encode(&mom)
   274  	mass := float32(mc.Mass)
   275  	enc.Encode(&mass)
   276  	enc.Encode(&mc.Charge)
   277  	if mc.SimStatus&uint32(1<<31) != 0 {
   278  		enc.Encode(&mc.endPoint)
   279  		pend := [3]float32{float32(mc.PEndPoint[0]), float32(mc.PEndPoint[1]), float32(mc.PEndPoint[2])}
   280  		enc.Encode(&pend)
   281  	}
   282  	enc.Encode(&mc.Spin)
   283  	enc.Encode(&mc.ColorFlow)
   284  	return enc.Err()
   285  }
   286  
   287  func (mc *McParticle) UnmarshalSio(r sio.Reader) error {
   288  	dec := sio.NewDecoder(r)
   289  	dec.Tag(mc)
   290  
   291  	var n int32
   292  	dec.Decode(&n)
   293  	if n > 0 {
   294  		mc.Parents = make([]*McParticle, int(n))
   295  		for ii := range mc.Parents {
   296  			dec.Pointer(&mc.Parents[ii])
   297  		}
   298  	}
   299  
   300  	dec.Decode(&mc.PDG)
   301  	dec.Decode(&mc.GenStatus)
   302  	dec.Decode(&mc.SimStatus)
   303  	dec.Decode(&mc.Vertex)
   304  	if r.VersionSio() > 1002 {
   305  		dec.Decode(&mc.Time)
   306  	}
   307  
   308  	var mom [3]float32
   309  	dec.Decode(&mom)
   310  	mc.P[0] = float64(mom[0])
   311  	mc.P[1] = float64(mom[1])
   312  	mc.P[2] = float64(mom[2])
   313  
   314  	var mass float32
   315  	dec.Decode(&mass)
   316  	mc.Mass = float64(mass)
   317  
   318  	dec.Decode(&mc.Charge)
   319  
   320  	if mc.SimStatus&uint32(1<<31) != 0 {
   321  		dec.Decode(&mc.endPoint)
   322  		if r.VersionSio() > 2006 {
   323  			var mom [3]float32
   324  			dec.Decode(&mom)
   325  			mc.PEndPoint[0] = float64(mom[0])
   326  			mc.PEndPoint[1] = float64(mom[1])
   327  			mc.PEndPoint[2] = float64(mom[2])
   328  		}
   329  	}
   330  
   331  	if r.VersionSio() > 1051 {
   332  		dec.Decode(&mc.Spin)
   333  		dec.Decode(&mc.ColorFlow)
   334  	}
   335  	return dec.Err()
   336  }
   337  
   338  var (
   339  	_ sio.Versioner = (*McParticle)(nil)
   340  	_ sio.Codec     = (*McParticle)(nil)
   341  	_ sio.Versioner = (*McParticleContainer)(nil)
   342  	_ sio.Codec     = (*McParticleContainer)(nil)
   343  )