J. N. Bahcall, M. H. Pinsonneault · Phys. Rev. Lett. 92, 121301 (2004)
What do we (not) know theoretically about solar neutrino fluxes?
Chlorine and gallium capture rates without oscillations for the BP04 standard solar model (Table 1, last two rows), per solar-neutrino source, from Newtrinos' solar spectra (solar_flux) and absorption cross sections (solar_xsec), with the solar-model fluxes set to the BP04 values. The per-source reference is the output of Bahcall's own rate code (exportrates.f with the BP04 input of the paper). Newtrinos finds Cl = 8.51 SNU and Ga = 131.6 SNU (Bahcall: 8.50 and 130.5; Table 1: 8.5 ± 1.8 and 131 +12/−10).
Figures
Cl and Ga capture rates per source, no oscillations (BP04) · Table 1
Known limitations
- The ⁸B spectrum is Bahcall et al. (1996), as in BP04 (
solar_fluxoptionb8_spectrum = :bahcall). With the Newtrinos default, Winter et al. (2006), the ⁸B chlorine rate is 6.80 instead of 6.64 SNU (+2.5 %; Cl total 8.68 SNU) and the ⁸B gallium rate 14.29 instead of 14.03 SNU. - The per-source reference is Bahcall's published code output (exportrates.output), which uses the ⁸B flux 5.82×10⁶ cm⁻²s⁻¹ of the code input instead of the 5.79×10⁶ of Table 1; the totals of Table 1 are rounded.
- Gallium pp: Newtrinos integrates Bahcall's tabulated σ(E) (Phys. Rev. C 56, 3391) over the pp spectrum and obtains a spectrum-averaged cross section of 11.90×10⁻⁴⁶ cm², 1.5 % above the 11.72×10⁻⁴⁶ cm² used in the code (within the 2.3 % 1σ uncertainty).
- This comparison found a bug in Newtrinos (fixed in the pinned commit): the chlorine cross section at the 0.862 MeV ⁷Be line was set to the value per ⁷Be neutrino of both lines (2.38×10⁻⁴⁶ cm²) instead of 2.38/0.8956 = 2.66×10⁻⁴⁶ cm², which made the ⁷Be chlorine rate 11 % low.
Reproduce
git clone https://github.com/Newtrinos-org/Newtrinos.jl.git && cd Newtrinos.jl && git checkout c6612c255a- Download reproduce.jl and the
data/folder of this entry into an empty directory. julia -t 8 --project=/path/to/Newtrinos.jl reproduce.jl
# Verification of the Newtrinos.jl solar spectra and absorption cross sections (modules `solar_flux`, `solar_xsec`)
# against the chlorine and gallium capture rates of Bahcall & Pinsonneault, Phys. Rev. Lett. 92, 121301 (2004),
# Table 1, per neutrino source as given by Bahcall's rate code (data/exportrates.output).
# Run from this directory with the Newtrinos.jl environment at the pinned commit:
# julia --project=<path to Newtrinos.jl> reproduce.jl
using Newtrinos, CairoMakie, CSV, DataFrames, Printf
cd(@__DIR__); mkpath("ours"); mkpath("results")
const SF = Newtrinos.solar_flux
sf = SF.configure(SF.SolarFluxConfig(b8_spectrum = :bahcall)) # BP04 uses Bahcall et al. (1996) ⁸B spectrum; Newtrinos default is Winter et al. (2006)
xs = Newtrinos.solar_xsec.configure()
p = merge(sf.params, xs.params)
# BP04 fluxes [cm⁻² s⁻¹] of the code input (data/exportrates.dat; Table 1 has ⁸B = 5.79e6)
bp04 = (pp = 5.938e10, pep = 1.401e8, hep = 7.88e3, be7 = 4.857e9, b8 = 5.822e6, n13 = 5.712e8, o15 = 5.031e8, f17 = 5.912e6)
p = merge(p, (solar_norms = [bp04[c] / sf.nominal[c] for c in SF.COMPONENTS],))
# Bahcall's per-source capture rates [SNU] (data/exportrates.output, "Case number 1")
lines = readlines("data/exportrates.output")
i0 = findfirst(l -> occursin("Source Fluxes", l), lines)
key = Dict("pp" => :pp, "pep" => :pep, "7Be" => :be7, "8B" => :b8, "13N" => :n13, "15O" => :o15, "17F" => :f17, "hep" => :hep)
ref = Dict{Symbol, Tuple{Float64, Float64}}()
for l in lines[i0+1:i0+10]
w = split(l)
length(w) == 5 && haskey(key, w[1]) && (ref[key[w[1]]] = (parse(Float64, w[3]), parse(Float64, w[4])))
end
# capture rates without oscillations: flux × cross section, integrated above threshold
const THR = (cl37 = Newtrinos.solar_xsec.CL_THRESHOLD, ga71 = Newtrinos.solar_xsec.GA_THRESHOLD)
const ENDPOINT = (pp = 0.4234, hep = 18.79, b8 = 16.56, n13 = 1.199, o15 = 1.732, f17 = 1.740)
function rate(comp, target)
if haskey(sf.lines, comp)
l = sf.lines[comp]
return sf.flux(comp, p) * sum(l.br .* [xs.capture(target, e, p) for e in l.E]) / 1e-36
end
THR[target] >= ENDPOINT[comp] && return 0.0
E = range(THR[target], ENDPOINT[comp], length = 4001)
f = sf.spectrum(comp, collect(E), p) .* [xs.capture(target, e, p) for e in E]
step(E) * (sum(f) - (f[1] + f[end]) / 2) / 1e-36
end
comps = collect(SF.COMPONENTS)
df = DataFrame(source = string.(comps),
cl_newtrinos = [rate(c, :cl37) for c in comps], cl_bahcall = [ref[c][1] for c in comps],
ga_newtrinos = [rate(c, :ga71) for c in comps], ga_bahcall = [ref[c][2] for c in comps])
push!(df, ("total", sum(df.cl_newtrinos), 8.50, sum(df.ga_newtrinos), 130.54)) # totals of exportrates.output
CSV.write("results/capture_rates.csv", df)
show(stdout, df; allrows = true); println()
labels = ["pp", "pep", "hep", "⁷Be", "⁸B", "¹³N", "¹⁵O", "¹⁷F"]
fig = Figure(size = (900, 420))
for (k, (col, name, unit)) in enumerate(((:cl, "Chlorine (³⁷Cl)", "rate (SNU)"), (:ga, "Gallium (⁷¹Ga)", "rate (SNU)")))
ours = df[1:8, Symbol(col, :_newtrinos)]; theirs = df[1:8, Symbol(col, :_bahcall)]
tot_o, tot_b = df[9, Symbol(col, :_newtrinos)], df[9, Symbol(col, :_bahcall)]
ax = Axis(fig[1, k], xticks = (1:8, labels), ylabel = unit, yscale = log10,
title = @sprintf("%s: Newtrinos %.2f SNU, Bahcall %.2f SNU", name, tot_o, tot_b), titlesize = 13)
sel = theirs .> 0
barplot!(ax, (1:8)[sel] .- 0.18, theirs[sel], width = 0.36, fillto = 0.01, color = :gray, label = "Bahcall (BP04)")
barplot!(ax, (1:8)[sel] .+ 0.18, ours[sel], width = 0.36, fillto = 0.01, color = :dodgerblue, label = "Newtrinos")
ylims!(ax, 0.01, 200)
k == 1 && axislegend(ax, position = :rt)
end
Label(fig[0, :], "Capture rates without oscillations, BP04 fluxes", fontsize = 15, font = :bold)
save("ours/capture_rates.png", fig)
Provenance
| Newtrinos.jl commit | c6612c255a (solar_flux, solar_xsec) |
|---|---|
| Run date | 2026-10-22T07:00:11Z |
| Wall time | 1.0 min (8 threads) |
| Julia | 1.12.5 |
| Machine | AMD EPYC 7702P 64-Core Processor, 128 hardware threads, Linux |
| Environment | newtrinos_Manifest.toml · run.toml |
Downloads
CSV files hold one row per scan point: the scanned and profiled parameters
(sin2_theta23, dm2_32 in eV², dcp in rad, nuisance parameters), dchi2 = −2Δ log L
and the log-likelihood. JLD2 files contain the full NewtrinosResult objects.
| File | Size | SHA-256 |
|---|---|---|
| ours/capture_rates.png | 106.8 kB | 5f7ab089753d… |
| results/capture_rates.csv | 503 B | 3a7fdebe7012… |
