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  }