go-hep.org/x/hep@v0.38.1/fmom/ops.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 fmom 6 7 import ( 8 "fmt" 9 "math" 10 11 "gonum.org/v1/gonum/spatial/r3" 12 ) 13 14 // Equal returns true if p1==p2 15 func Equal(p1, p2 P4) bool { 16 return p4equal(p1, p2, 1e-14) 17 } 18 19 func p4equal(p1, p2 P4, epsilon float64) bool { 20 if cmpeq(p1.E(), p2.E(), epsilon) && 21 cmpeq(p1.Px(), p2.Px(), epsilon) && 22 cmpeq(p1.Py(), p2.Py(), epsilon) && 23 cmpeq(p1.Pz(), p2.Pz(), epsilon) { 24 return true 25 } 26 return false 27 } 28 29 func cmpeq(x, y, epsilon float64) bool { 30 if x == y { 31 return true 32 } 33 34 return math.Abs(x-y) < epsilon 35 } 36 37 // Add returns the sum p1+p2. 38 func Add(p1, p2 P4) P4 { 39 // FIXME(sbinet): 40 // dispatch most efficient/less-lossy addition 41 // based on type(dst) (and, optionally, type(src)) 42 var sum P4 43 switch p1 := p1.(type) { 44 45 case *PxPyPzE: 46 p := NewPxPyPzE(p1.Px()+p2.Px(), p1.Py()+p2.Py(), p1.Pz()+p2.Pz(), p1.E()+p2.E()) 47 sum = &p 48 49 case *EEtaPhiM: 50 p := NewPxPyPzE(p1.Px()+p2.Px(), p1.Py()+p2.Py(), p1.Pz()+p2.Pz(), p1.E()+p2.E()) 51 var pp EEtaPhiM 52 pp.Set(&p) 53 sum = &pp 54 55 case *EtEtaPhiM: 56 p := NewPxPyPzE(p1.Px()+p2.Px(), p1.Py()+p2.Py(), p1.Pz()+p2.Pz(), p1.E()+p2.E()) 57 var pp EtEtaPhiM 58 pp.Set(&p) 59 sum = &pp 60 61 case *PtEtaPhiM: 62 p := NewPxPyPzE(p1.Px()+p2.Px(), p1.Py()+p2.Py(), p1.Pz()+p2.Pz(), p1.E()+p2.E()) 63 var pp PtEtaPhiM 64 pp.Set(&p) 65 sum = &pp 66 67 case *IPtCotThPhiM: 68 p := NewPxPyPzE(p1.Px()+p2.Px(), p1.Py()+p2.Py(), p1.Pz()+p2.Pz(), p1.E()+p2.E()) 69 var pp IPtCotThPhiM 70 pp.Set(&p) 71 sum = &pp 72 73 default: 74 panic(fmt.Errorf("fmom: invalid P4 concrete value: %#v", p1)) 75 } 76 return sum 77 } 78 79 // IAdd adds src into dst, and returns dst 80 func IAdd(dst, src P4) P4 { 81 // FIXME(sbinet): 82 // dispatch most efficient/less-lossy addition 83 // based on type(dst) (and, optionally, type(src)) 84 var sum P4 85 var p4 *PxPyPzE = nil 86 switch p1 := dst.(type) { 87 88 case *PxPyPzE: 89 p4 = p1 90 sum = dst 91 92 case *EEtaPhiM: 93 p := NewPxPyPzE(p1.Px(), p1.Py(), p1.Pz(), p1.E()) 94 p4 = &p 95 sum = dst 96 97 case *EtEtaPhiM: 98 p := NewPxPyPzE(p1.Px(), p1.Py(), p1.Pz(), p1.E()) 99 p4 = &p 100 sum = dst 101 102 case *PtEtaPhiM: 103 p := NewPxPyPzE(p1.Px(), p1.Py(), p1.Pz(), p1.E()) 104 p4 = &p 105 sum = dst 106 107 case *IPtCotThPhiM: 108 p := NewPxPyPzE(p1.Px(), p1.Py(), p1.Pz(), p1.E()) 109 p4 = &p 110 sum = dst 111 112 default: 113 panic(fmt.Errorf("fmom: invalid P4 concrete value: %#v", dst)) 114 } 115 p4.P4.X += src.Px() 116 p4.P4.Y += src.Py() 117 p4.P4.Z += src.Pz() 118 p4.P4.T += src.E() 119 sum.Set(p4) 120 return sum 121 } 122 123 // Scale returns a*p 124 func Scale(a float64, p P4) P4 { 125 // FIXME(sbinet): 126 // dispatch most efficient/less-lossy operation 127 // based on type(dst) (and, optionally, type(src)) 128 out := p.Clone() 129 dst := NewPxPyPzE(a*p.Px(), a*p.Py(), a*p.Pz(), a*p.E()) 130 out.Set(&dst) 131 return out 132 } 133 134 // InvMass computes the invariant mass of two incoming 4-vectors p1 and p2. 135 func InvMass(p1, p2 P4) float64 { 136 p := Add(p1, p2) 137 return p.M() 138 } 139 140 // BoostOf returns the 3d boost vector of the provided four-vector p. 141 // It panics if p has zero energy and a non-zero |p|^2. 142 // It panics if p isn't a timelike four-vector. 143 func BoostOf(p P4) r3.Vec { 144 e := p.E() 145 if e == 0 { 146 if p.P2() == 0 { 147 return r3.Vec{} 148 } 149 panic("fmom: zero-energy four-vector") 150 } 151 if p.M2() <= 0 { 152 panic("fmom: non-timelike four-vector") 153 } 154 155 inv := 1 / e 156 return r3.Vec{X: inv * p.Px(), Y: inv * p.Py(), Z: inv * p.Pz()} 157 } 158 159 // Boost returns a copy of the provided four-vector 160 // boosted by the provided three-vector. 161 func Boost(p P4, vec r3.Vec) P4 { 162 o := p.Clone() 163 if vec == (r3.Vec{}) { 164 return o 165 } 166 167 var ( 168 px = p.Px() 169 py = p.Py() 170 pz = p.Pz() 171 ee = p.E() 172 173 p3 = r3.Vec{X: px, Y: py, Z: pz} 174 v2 = r3.Dot(vec, vec) 175 bp = r3.Dot(vec, p3) 176 177 gamma = 1 / math.Sqrt(1-v2) 178 beta = (gamma - 1) / v2 179 180 alpha = beta*bp + gamma*ee 181 ) 182 183 pp := NewPxPyPzE( 184 px+alpha*vec.X, 185 py+alpha*vec.Y, 186 pz+alpha*vec.Z, 187 gamma*(ee+bp), 188 ) 189 190 o.Set(&pp) 191 192 return o 193 } 194 195 // VecOf returns the 3-vector of fhe four-momentum 196 func VecOf(p P4) r3.Vec { 197 return r3.Vec{ 198 X: p.Px(), 199 Y: p.Py(), 200 Z: p.Pz(), 201 } 202 }