import numpy as np
import time
PI = np.pi
YerhoE2a = 1.52e-4
eVsqkm_to_GeV_over4 = 1e-9 / 1.97327e-7 * 1e3 / 4.0
def probability_vacuum_lbl(s12sq, s13sq, s23sq, delta, Dmsq21, Dmsq31, L, E):
c13sq = 1.0 - s13sq
Ue3sq = s13sq
Ue2sq = c13sq * s12sq
Um3sq = c13sq * s23sq
Ut2sq = s13sq * s12sq * s23sq
Um2sq = (1.0 - s12sq) * (1.0 - s23sq)
Jrr = np.sqrt(Um2sq * Ut2sq)
sind = np.sin(delta)
cosd = np.cos(delta)
Um2sq = Um2sq + Ut2sq - 2.0 * Jrr * cosd
Jvac = 8.0 * Jrr * c13sq * sind
Ue1sq = 1.0 - Ue3sq - Ue2sq
Um1sq = 1.0 - Um3sq - Um2sq
Ut3sq = 1.0 - Um3sq - Ue3sq
Ut2sq = 1.0 - Um2sq - Ue2sq
Ut1sq = 1.0 - Um1sq - Ue1sq
Lover4E = eVsqkm_to_GeV_over4 * L / E
D21 = Dmsq21 * Lover4E
D31 = Dmsq31 * Lover4E
sinD21 = np.sin(D21)
sinD31 = np.sin(D31)
sinD32 = np.sin(D31 - D21)
triple_sin = sinD21 * sinD31 * sinD32
sinsqD21_2 = 2.0 * sinD21 * sinD21
sinsqD31_2 = 2.0 * sinD31 * sinD31
sinsqD32_2 = 2.0 * sinD32 * sinD32
Pme_CPC = ((Ut3sq - Um2sq * Ue1sq - Um1sq * Ue2sq) * sinsqD21_2 +
(Ut2sq - Um3sq * Ue1sq - Um1sq * Ue3sq) * sinsqD31_2 +
(Ut1sq - Um3sq * Ue2sq - Um2sq * Ue3sq) * sinsqD32_2)
Pme_CPV = -Jvac * triple_sin
Pmm = 1.0 - 2.0 * (Um2sq * Um1sq * sinsqD21_2 +
Um3sq * Um1sq * sinsqD31_2 +
Um3sq * Um2sq * sinsqD32_2)
Pee = 1.0 - 2.0 * (Ue2sq * Ue1sq * sinsqD21_2 +
Ue3sq * Ue1sq * sinsqD31_2 +
Ue3sq * Ue2sq * sinsqD32_2)
probs = np.zeros((3, 3))
probs[0, 0] = Pee
probs[0, 1] = Pme_CPC - Pme_CPV
probs[0, 2] = 1.0 - Pee - probs[0, 1]
probs[1, 0] = Pme_CPC + Pme_CPV
probs[1, 1] = Pmm
probs[1, 2] = 1.0 - probs[1, 0] - Pmm
probs[2, 0] = 1.0 - Pee - probs[1, 0]
probs[2, 1] = 1.0 - probs[0, 1] - Pmm
probs[2, 2] = 1.0 - probs[0, 2] - probs[1, 2]
return probs
def probability_matter_lbl(s12sq, s13sq, s23sq, delta, Dmsq21, Dmsq31,
L, E, rho, Ye, N_Newton):
c13sq = 1.0 - s13sq
Ue2sq = c13sq * s12sq
Ue3sq = s13sq
Um3sq = c13sq * s23sq
Ut2sq = s13sq * s12sq * s23sq
Um2sq = (1.0 - s12sq) * (1.0 - s23sq)
Jrr = np.sqrt(Um2sq * Ut2sq)
sind = np.sin(delta)
cosd = np.cos(delta)
Um2sq = Um2sq + Ut2sq - 2.0 * Jrr * cosd
Jmatter = 8.0 * Jrr * c13sq * sind
Amatter = Ye * rho * E * YerhoE2a
Dmsqee = Dmsq31 - s12sq * Dmsq21
A_sum = Dmsq21 + Dmsq31
See = A_sum - Dmsq21 * Ue2sq - Dmsq31 * Ue3sq
Tmm_base = Dmsq21 * Dmsq31
Tee = Tmm_base * (1.0 - Ue3sq - Ue2sq)
C = Amatter * Tee
A = A_sum + Amatter
xmat = Amatter / Dmsqee
tmp = 1.0 - xmat
lambda3 = Dmsq31 + 0.5 * Dmsqee * (xmat - 1.0 + np.sqrt(tmp * tmp + 4.0 * s13sq * xmat))
B = Tmm_base + Amatter * See
for _ in range(N_Newton):
lambda3 = (lambda3 * lambda3 * (lambda3 - A) + C) / (lambda3 * (2.0 * lambda3 - A) + B)
tmp = A - lambda3
Dlambda21 = np.sqrt(tmp * tmp - 4.0 * C / lambda3)
lambda2 = 0.5 * (A - lambda3 + Dlambda21)
Dlambda32 = lambda3 - lambda2
Dlambda31 = Dlambda32 + Dlambda21
PiDlambdaInv = 1.0 / (Dlambda31 * Dlambda32 * Dlambda21)
Xp3 = PiDlambdaInv * Dlambda21
Xp2 = -PiDlambdaInv * Dlambda31
Ue3sq = (lambda3 * (lambda3 - See) + Tee) * Xp3
Ue2sq = (lambda2 * (lambda2 - See) + Tee) * Xp2
Smm = A - Dmsq21 * Um2sq - Dmsq31 * Um3sq
Tmm = Tmm_base * (1.0 - Um3sq - Um2sq) + Amatter * (See + Smm - A_sum)
Um3sq = (lambda3 * (lambda3 - Smm) + Tmm) * Xp3
Um2sq = (lambda2 * (lambda2 - Smm) + Tmm) * Xp2
Jmatter = Jmatter * Dmsq21 * Dmsq31 * (Dmsq31 - Dmsq21) * PiDlambdaInv
Ue1sq = 1.0 - Ue3sq - Ue2sq
Um1sq = 1.0 - Um3sq - Um2sq
Ut3sq = 1.0 - Um3sq - Ue3sq
Ut2sq = 1.0 - Um2sq - Ue2sq
Ut1sq = 1.0 - Um1sq - Ue1sq
Lover4E = eVsqkm_to_GeV_over4 * L / E
D21 = Dlambda21 * Lover4E
D32 = Dlambda32 * Lover4E
sinD21 = np.sin(D21)
sinD31 = np.sin(D32 + D21)
sinD32 = np.sin(D32)
triple_sin = sinD21 * sinD31 * sinD32
sinsqD21_2 = 2.0 * sinD21 * sinD21
sinsqD31_2 = 2.0 * sinD31 * sinD31
sinsqD32_2 = 2.0 * sinD32 * sinD32
Pme_CPC = ((Ut3sq - Um2sq * Ue1sq - Um1sq * Ue2sq) * sinsqD21_2 +
(Ut2sq - Um3sq * Ue1sq - Um1sq * Ue3sq) * sinsqD31_2 +
(Ut1sq - Um3sq * Ue2sq - Um2sq * Ue3sq) * sinsqD32_2)
Pme_CPV = -Jmatter * triple_sin
Pmm = 1.0 - 2.0 * (Um2sq * Um1sq * sinsqD21_2 +
Um3sq * Um1sq * sinsqD31_2 +
Um3sq * Um2sq * sinsqD32_2)
Pee = 1.0 - 2.0 * (Ue2sq * Ue1sq * sinsqD21_2 +
Ue3sq * Ue1sq * sinsqD31_2 +
Ue3sq * Ue2sq * sinsqD32_2)
probs = np.zeros((3, 3))
probs[0, 0] = Pee
probs[0, 1] = Pme_CPC - Pme_CPV
probs[0, 2] = 1.0 - Pee - probs[0, 1]
probs[1, 0] = Pme_CPC + Pme_CPV
probs[1, 1] = Pmm
probs[1, 2] = 1.0 - probs[1, 0] - Pmm
probs[2, 0] = 1.0 - Pee - probs[1, 0]
probs[2, 1] = 1.0 - probs[0, 1] - Pmm
probs[2, 2] = 1.0 - probs[0, 2] - probs[1, 2]
return probs
def main():
n = 100000 Emin, Emax = 0.5, 5.0
s12sq, s13sq, s23sq = 0.31, 0.02, 0.55
delta = -0.7 * PI
Dmsq21, Dmsq31 = 7.5e-5, 2.5e-3
L, rho, Ye = 1300.0, 3.0, 0.5
print(f"NuFast Python Benchmark (n={n} iterations)")
print("=" * 44)
print()
print("Single-point calculations:")
total = 0.0
t1 = time.perf_counter()
for i in range(n):
E = Emin + (Emax - Emin) * (i % 1000) / 1000.0
probs = probability_vacuum_lbl(s12sq, s13sq, s23sq, delta, Dmsq21, Dmsq31, L, E)
total += probs[1, 0]
t2 = time.perf_counter()
ns_vac = (t2 - t1) * 1e9 / n
print(f" Vacuum: {ns_vac:10.2f} ns")
for N in range(4):
total = 0.0
t1 = time.perf_counter()
for i in range(n):
E = Emin + (Emax - Emin) * (i % 1000) / 1000.0
probs = probability_matter_lbl(s12sq, s13sq, s23sq, delta, Dmsq21, Dmsq31,
L, E, rho, Ye, N)
total += probs[1, 0]
t2 = time.perf_counter()
ns = (t2 - t1) * 1e9 / n
print(f" Matter N_Newton={N}: {ns:10.2f} ns")
print()
print("Throughput:")
print(f" Vacuum: {n / (ns_vac * 1e-9) / 1e6:10.4f} M/s")
print(f" Matter N_Newton=0: {n / (ns * 1e-9) / 1e6:10.4f} M/s")
if __name__ == "__main__":
main()