go-hep.org/x/hep@v0.38.1/fmom/ops_test.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 "reflect" 9 "testing" 10 11 "gonum.org/v1/gonum/floats/scalar" 12 "gonum.org/v1/gonum/spatial/r3" 13 ) 14 15 func p3equal(p1, p2 r3.Vec, epsilon float64) bool { 16 if cmpeq(p1.X, p2.X, epsilon) && 17 cmpeq(p1.Y, p2.Y, epsilon) && 18 cmpeq(p1.Z, p2.Z, epsilon) { 19 return true 20 } 21 return false 22 } 23 24 func newPxPyPzE(p4 PxPyPzE) P4 { 25 return &p4 26 } 27 28 func newEEtaPhiM(p4 PxPyPzE) P4 { 29 var pp EEtaPhiM 30 pp.Set(&p4) 31 return &pp 32 } 33 34 func newEtEtaPhiM(p4 PxPyPzE) P4 { 35 var pp EtEtaPhiM 36 pp.Set(&p4) 37 return &pp 38 } 39 40 func newPtEtaPhiM(p4 PxPyPzE) P4 { 41 var pp PtEtaPhiM 42 pp.Set(&p4) 43 return &pp 44 } 45 46 func newIPtCotThPhiM(p4 PxPyPzE) P4 { 47 var pp IPtCotThPhiM 48 pp.Set(&p4) 49 return &pp 50 } 51 52 func deepEqual(p1, p2 P4) bool { 53 return Equal(p1, p2) 54 } 55 56 func TestAdd(t *testing.T) { 57 for _, tc := range []struct { 58 p1 P4 59 p2 P4 60 want P4 61 }{ 62 { 63 p1: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 64 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 65 want: newPxPyPzE(NewPxPyPzE(20, 20, 20, 40)), 66 }, 67 { 68 p1: newEEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 69 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 70 want: newEEtaPhiM(NewPxPyPzE(20, 20, 20, 40)), 71 }, 72 { 73 p1: newEtEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 74 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 75 want: newEtEtaPhiM(NewPxPyPzE(20, 20, 20, 40)), 76 }, 77 { 78 p1: newPtEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 79 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 80 want: newPtEtaPhiM(NewPxPyPzE(20, 20, 20, 40)), 81 }, 82 { 83 p1: newIPtCotThPhiM(NewPxPyPzE(10, 10, 10, 20)), 84 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 85 want: newIPtCotThPhiM(NewPxPyPzE(20, 20, 20, 40)), 86 }, 87 } { 88 p1 := tc.p1.Clone() 89 p2 := tc.p2.Clone() 90 91 got := Add(p1, p2) 92 93 if !deepEqual(got, tc.want) { 94 t.Fatalf("got= %#v\nwant=%#v", got, tc.want) 95 } 96 if !reflect.DeepEqual(p1, tc.p1) { 97 t.Fatalf("add modified p1:\ngot= %#v\nwant=%#v", p1, tc.p1) 98 } 99 if !reflect.DeepEqual(p2, tc.p2) { 100 t.Fatalf("add modified p2:\ngot= %#v\nwant=%#v", p2, tc.p2) 101 } 102 } 103 } 104 105 func TestIAdd(t *testing.T) { 106 for _, tc := range []struct { 107 p1 P4 108 p2 P4 109 want P4 110 }{ 111 { 112 p1: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 113 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 114 want: newPxPyPzE(NewPxPyPzE(20, 20, 20, 40)), 115 }, 116 { 117 p1: newEEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 118 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 119 want: newEEtaPhiM(NewPxPyPzE(20, 20, 20, 40)), 120 }, 121 { 122 p1: newEtEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 123 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 124 want: newEtEtaPhiM(NewPxPyPzE(20, 20, 20, 40)), 125 }, 126 { 127 p1: newPtEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 128 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 129 want: newPtEtaPhiM(NewPxPyPzE(20, 20, 20, 40)), 130 }, 131 { 132 p1: newIPtCotThPhiM(NewPxPyPzE(10, 10, 10, 20)), 133 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 134 want: newIPtCotThPhiM(NewPxPyPzE(20, 20, 20, 40)), 135 }, 136 } { 137 p1 := tc.p1.Clone() 138 p2 := tc.p2.Clone() 139 140 got := IAdd(p1, p2) 141 142 if !deepEqual(got, tc.want) { 143 t.Fatalf("got= %#v\nwant=%#v", got, tc.want) 144 } 145 146 if !reflect.DeepEqual(got, p1) { 147 t.Fatalf("fmom.IAdd did not modify p1 in-place:\ngot= %#v\nwant=%#v", got, p1) 148 } 149 if !reflect.DeepEqual(p2, tc.p2) { 150 t.Fatalf("fmom.IAdd modified p2:\ngot= %#v\nwant=%#v", p2, tc.p2) 151 } 152 } 153 } 154 155 func TestEqual(t *testing.T) { 156 for _, tc := range []struct { 157 p1 P4 158 p2 P4 159 want bool 160 }{ 161 { 162 p1: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 163 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 164 want: true, 165 }, 166 { 167 p1: newEEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 168 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 169 want: true, 170 }, 171 { 172 p1: newEtEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 173 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 174 want: true, 175 }, 176 { 177 p1: newPtEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 178 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 179 want: true, 180 }, 181 { 182 p1: newIPtCotThPhiM(NewPxPyPzE(10, 10, 10, 20)), 183 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 184 want: true, 185 }, 186 187 { 188 p1: newPxPyPzE(NewPxPyPzE(10+1e-14, 10, 10, 20)), 189 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 190 want: false, 191 }, 192 { 193 p1: newPxPyPzE(NewPxPyPzE(10, 10+1e-14, 10, 20)), 194 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 195 want: false, 196 }, 197 { 198 p1: newPxPyPzE(NewPxPyPzE(10, 10, 10+1e-14, 20)), 199 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 200 want: false, 201 }, 202 { 203 p1: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20+1e-14)), 204 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 205 want: false, 206 }, 207 } { 208 { 209 got := deepEqual(tc.p1, tc.p2) 210 if got != tc.want { 211 t.Fatalf("got= %#v\nwant=%#v\np1=%#v\np2=%#v\n", got, tc.want, tc.p1, tc.p2) 212 } 213 } 214 got := Equal(tc.p1, tc.p2) 215 if got != tc.want { 216 t.Fatalf("got= %#v\nwant=%#v\np1=%#v\np2=%#v\n", got, tc.want, tc.p1, tc.p2) 217 } 218 } 219 } 220 221 func TestScale(t *testing.T) { 222 for _, tc := range []struct { 223 p P4 224 a float64 225 want P4 226 }{ 227 { 228 p: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 229 a: 1, 230 want: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 231 }, 232 233 { 234 p: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 235 a: 0, 236 want: newPxPyPzE(NewPxPyPzE(0, 0, 0, 0)), 237 }, 238 239 { 240 p: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 241 a: -1, 242 want: newPxPyPzE(NewPxPyPzE(-10, -10, -10, -20)), 243 }, 244 245 { 246 p: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 247 a: 2, 248 want: newPxPyPzE(NewPxPyPzE(20, 20, 20, 40)), 249 }, 250 251 { 252 p: newEEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 253 a: 2, 254 want: newEEtaPhiM(NewPxPyPzE(20, 20, 20, 40)), 255 }, 256 { 257 p: newEtEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 258 a: 2, 259 want: newEtEtaPhiM(NewPxPyPzE(20, 20, 20, 40)), 260 }, 261 { 262 p: newPtEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 263 a: 2, 264 want: newPtEtaPhiM(NewPxPyPzE(20, 20, 20, 40)), 265 }, 266 { 267 p: newIPtCotThPhiM(NewPxPyPzE(10, 10, 10, 20)), 268 a: 2, 269 want: newIPtCotThPhiM(NewPxPyPzE(20, 20, 20, 40)), 270 }, 271 } { 272 p := tc.p.Clone() 273 274 got := Scale(tc.a, p) 275 276 if !deepEqual(got, tc.want) { 277 t.Fatalf("got= %#v\nwant=%#v", got, tc.want) 278 } 279 if !reflect.DeepEqual(p, tc.p) { 280 t.Fatalf("add modified p:\np=%#v (ref)\np=%#v (new)", tc.p, p) 281 } 282 } 283 } 284 285 func TestInvMass(t *testing.T) { 286 for _, tc := range []struct { 287 p1 P4 288 p2 P4 289 want float64 290 }{ 291 { 292 p1: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 293 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 294 want: newPxPyPzE(NewPxPyPzE(20, 20, 20, 40)).M(), 295 }, 296 { 297 p1: newEEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 298 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 299 want: newEEtaPhiM(NewPxPyPzE(20, 20, 20, 40)).M(), 300 }, 301 { 302 p1: newEtEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 303 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 304 want: newEtEtaPhiM(NewPxPyPzE(20, 20, 20, 40)).M(), 305 }, 306 { 307 p1: newPtEtaPhiM(NewPxPyPzE(10, 10, 10, 20)), 308 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 309 want: newPtEtaPhiM(NewPxPyPzE(20, 20, 20, 40)).M(), 310 }, 311 { 312 p1: newIPtCotThPhiM(NewPxPyPzE(10, 10, 10, 20)), 313 p2: newPxPyPzE(NewPxPyPzE(10, 10, 10, 20)), 314 want: newIPtCotThPhiM(NewPxPyPzE(20, 20, 20, 40)).M(), 315 }, 316 } { 317 p1 := tc.p1.Clone() 318 p2 := tc.p2.Clone() 319 320 got := InvMass(p1, p2) 321 322 if !scalar.EqualWithinULP(got, tc.want, 2) { 323 t.Fatalf("got= %#v\nwant=%#v", got, tc.want) 324 } 325 326 if !reflect.DeepEqual(tc.p1, p1) { 327 t.Fatalf("fmom.InvMass modified p1 in-place:\ngot: %#v\nwant:%#v", p1, tc.p1) 328 } 329 if !reflect.DeepEqual(tc.p2, p2) { 330 t.Fatalf("fmom.InvMass modified p2 in-place:\ngot: %#v\nwant:%#v", p2, tc.p2) 331 } 332 } 333 } 334 335 func TestBoost(t *testing.T) { 336 var ( 337 p1 = NewPxPyPzE(1, 2, 3, 4) 338 boost = BoostOf(&p1) 339 p1RF = Boost(&p1, r3.Vec{X: -boost.X, Y: -boost.Y, Z: -boost.Z}) 340 boostRF = BoostOf(p1RF) 341 zero r3.Vec 342 ) 343 344 if !p3equal(boostRF, zero, 1e-14) { 345 t.Fatalf("invalid boost: got=%v, want=%v", boostRF, zero) 346 } 347 348 if got, want := Boost(&p1, r3.Vec{}), &p1; !reflect.DeepEqual(got, want) { 349 t.Fatalf("invalid zero-boost: got=%v, want=%v", got, want) 350 } 351 } 352 353 func TestBoostOf(t *testing.T) { 354 for _, tc := range []struct { 355 p P4 356 v r3.Vec 357 panics string 358 }{ 359 { 360 p: newPxPyPzE(NewPxPyPzE(1, 2, 4, 10)), 361 v: r3.Vec{X: 0.1, Y: 0.2, Z: 0.4}, 362 }, 363 { 364 p: newPxPyPzE(NewPxPyPzE(1, 2, 4, -10)), 365 v: r3.Vec{X: -0.1, Y: -0.2, Z: -0.4}, 366 }, 367 { 368 p: newPxPyPzE(NewPxPyPzE(1, 2, 3, 1)), 369 v: r3.Vec{}, 370 panics: "fmom: non-timelike four-vector", 371 }, 372 { 373 p: newPxPyPzE(NewPxPyPzE(1, 2, 3, 0)), 374 v: r3.Vec{}, 375 panics: "fmom: zero-energy four-vector", 376 }, 377 { 378 p: newPxPyPzE(NewPxPyPzE(0, 0, 0, 0)), 379 v: r3.Vec{}, 380 }, 381 } { 382 t.Run("", func(t *testing.T) { 383 if tc.panics != "" { 384 defer func() { 385 e := recover() 386 if e == nil { 387 t.Fatalf("expected a panic: got=%v, want=%v", e, tc.panics) 388 } 389 if got, want := e.(string), tc.panics; got != want { 390 t.Fatalf("invalid panic message:\ngot= %v\nwant=%v", got, want) 391 } 392 }() 393 } 394 395 got := BoostOf(tc.p) 396 if got, want := got, tc.v; got != want { 397 t.Fatalf("invalid boost vector:\ngot= %v\nwant=%v", got, want) 398 } 399 }) 400 } 401 } 402 403 func TestVecOf(t *testing.T) { 404 for _, tc := range []struct { 405 p P4 406 want r3.Vec 407 }{ 408 { 409 p: newPxPyPzE(NewPxPyPzE(0, 10, 20, 30)), 410 want: r3.Vec{X: 0, Y: 10, Z: 20}, 411 }, 412 413 { 414 p: newPxPyPzE(NewPxPyPzE(10, 0, 20, 30)), 415 want: r3.Vec{X: 10, Y: 0, Z: 20}, 416 }, 417 418 { 419 p: newPxPyPzE(NewPxPyPzE(10, 20, 0, 30)), 420 want: r3.Vec{X: 10, Y: 20, Z: 0}, 421 }, 422 } { 423 got := VecOf(tc.p) 424 425 if got != tc.want { 426 t.Fatalf("invalid spatial components for %#v: got= %#v\nwant=%#v", 427 tc.p, got, tc.want) 428 } 429 } 430 }