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 )