theta and deltaangle lose precision for small angles

Aperta
#759 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

@robinbishtt ci sta già lavorando.

Dal 4/11/2026.

  • #760 di @robinbishtt — aperta

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
25/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Ferma
Stack tecnologico
python
Ambito
backend, data

Direzione di ricerca

Read the theta and deltaangle implementations, then inspect the existing tests and the SymPy tests that pin the acos expressions. Reproduce the small-angle precision loss with the examples in the issue and review the proposed atan2 approach and its zero-vector behavior changes. Done means small angles retain precision, equivalent vector representations yield zero separation, and the tests reflect the agreed edge-case behavior.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

bug (unverified)
Vector Version

1.9.1.dev4+gcaf34cddf

Python Version

Python 3.13.16

OS / Environment

Linux

Describe the bug

theta and deltaangle lose precision for small angles. theta is computed as arccos(z / mag) and deltaangle as arccos(dot / (|v1| |v2|)). For a small angle the argument rounds to 1, so most digits are gone, and below about 1e-8 rad the result is exactly 0.

Reproducer:

import math
import vector

print("vector", vector.__version__)

for small in (1e-4, 1e-6, 1e-8, 1e-10):
    theta = vector.obj(x=small, y=0.0, z=1.0).theta
    print(f"theta({small:g}) = {theta!r:24} exact {math.atan(small)!r:24}")

pt, pz = 0.01, 6800.0
p = vector.obj(pt=pt, phi=0.3, pz=pz, E=math.hypot(pt, pz))
print("forward theta", p.theta, "exact", math.atan2(pt, pz))

for delta in (1e-4, 1e-6, 1e-8, 1e-10):
    a = vector.obj(x=1.0, y=0.0, z=0.0)
    b = vector.obj(x=1.0, y=delta, z=0.0)
    print(f"deltaangle({delta:g}) = {a.deltaangle(b)!r:24} exact {math.atan(delta)!r}")

v = vector.obj(x=1.0, y=1.0, z=1.0)
print("same vector, xytheta vs rhophiz:", v.to_xytheta().deltaangle(v.to_rhophiz()))

Output on main:

vector 1.9.1.dev4+gcaf34cddf
theta(0.0001) = np.float64(9.999999973779312e-05) exact 9.999999966666667e-05
theta(1e-06) = np.float64(1.000044449303342e-06) exact 9.999999999996666e-07
theta(1e-08) = np.float64(0.0)          exact 1e-08
theta(1e-10) = np.float64(0.0)          exact 1e-10
forward theta 1.4706170310349988e-06 exact 1.4705882352930577e-06
deltaangle(0.0001) = np.float64(9.999999973779312e-05) exact 9.999999966666667e-05
deltaangle(1e-06) = np.float64(1.000044449303342e-06) exact 9.999999999996666e-07
deltaangle(1e-08) = np.float64(0.0)          exact 1e-08
deltaangle(1e-10) = np.float64(0.0)          exact 1e-10
same vector, xytheta vs rhophiz: 1.4901161193847656e-08

theta(1e-6) is off by about 4e-5 relative and theta(1e-8) is 0.0. The forward proton (pt = 0.01 GeV, pz = 6800 GeV) has theta wrong by about 2e-5 relative which would matter for forward proton or elastic scattering analyses. The last line shows the same vector in xytheta and in rhophiz having a deltaangle of 1.49e-8 instead of 0.

arctan2 fixes both: theta = arctan2(rho, z) and deltaangle = arctan2(|v1 x v2|, v1 . v2). ROOT's TVector3::Theta also uses atan2(Perp(), z).

I have a patch for both and can open a PR if you are fine with this. deltaangle.py changes a lot but only because it gets shorter the other coordinate combinations are built from the Cartesian one the way cross.py does it 710 lines down to 146. ran the existing test suite on it 4960 passed 17 skipped including 49 new tests that fail on current main. Nine SymPy tests that pinned the acos expressions needed new expected values. In benchmark on 1e6 vectors theta got faster 12 ms to 7 ms and deltaangle slower 31 ms to 38 ms because of the cross product.

Two behaviour changes I would like your view on:

  • deltaangle with a zero length vector returns 0.0 instead of nan. ROOT's TVector3::Angle returns 0 there too.
  • theta of (0, 0, -0.0) returns pi instead of 0. ROOT returns 0 for any zero vector.

the same root cause as #463 where deltaangle between identical vectors gave nan because the arccos argument rounded above 1. #465 fixed that by clamping the argument which removes the nan but the angle is still only accurate to about 1.5e-8 rad the square root of the double precision epsilon.

Any additional but relevant log output

No response

Lingua principale
Python
Stelle
102
Fork
47
Merge medio
7g 3h
PR unite (30g)
2

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di scikit-hep/vector

Tutte le issue di scikit-hep/vector

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.