IceCube · Phys. Rev. D 108, 012014 (2023)

Measurement of atmospheric neutrino mixing with improved IceCube DeepCore calibration and data processing

Experimental results IceCube DeepCore 2023 θ23 Δm²32 Reproduced

Atmospheric νμ disappearance with 7.5 years of IceCube DeepCore data (2012–2019), using the public verification sample (binned Monte Carlo and data, with hypersurface detector systematics), normal ordering.

Figures

sin²θ₂₃ – Δm²₃₂, 90% C.L. · Fig. 27

Paper · Fig. 27
Original: sin²θ₂₃ – Δm²₃₂, 90% C.L.

Original figure: IceCube, Phys. Rev. D 108, 012014 (2023), Fig. 27, doi:10.1103/PhysRevD.108.012014. Not our work; shown for comparison, all rights with the authors and publisher.

Newtrinos.jl
Reproduction: sin²θ₂₃ – Δm²₃₂, 90% C.L.

Δχ² profile in sin²θ₂₃ · Fig. 23 (top)

Paper · Fig. 23 (top)
Original: Δχ² profile in sin²θ₂₃

Original figure: IceCube, Phys. Rev. D 108, 012014 (2023), Fig. 23 (top), doi:10.1103/PhysRevD.108.012014. Not our work; shown for comparison, all rights with the authors and publisher.

Newtrinos.jl
Reproduction: Δχ² profile in sin²θ₂₃

Δχ² profile in Δm²₃₂ · Fig. 23 (bottom)

Paper · Fig. 23 (bottom)
Original: Δχ² profile in Δm²₃₂

Original figure: IceCube, Phys. Rev. D 108, 012014 (2023), Fig. 23 (bottom), doi:10.1103/PhysRevD.108.012014. Not our work; shown for comparison, all rights with the authors and publisher.

Newtrinos.jl
Reproduction: Δχ² profile in Δm²₃₂

Known limitations

Reproduce

  1. git clone https://github.com/Newtrinos-org/Newtrinos.jl.git && cd Newtrinos.jl && git checkout e1b5a89439
  2. Download reproduce.jl into an empty directory.
  3. julia -t 8 --project=/path/to/Newtrinos.jl reproduce.jl
# Reproduction of IceCube, Phys. Rev. D 108, 012014 (2023) [arXiv:2304.12236] with Newtrinos.jl (module `deepcore`),
# using the public DeepCore verification sample (Harvard Dataverse doi:10.7910/DVN/B4RITM).
# Run from this directory with the Newtrinos.jl environment at the pinned commit:
#   julia -t 8 --project=<path to Newtrinos.jl> reproduce.jl
using Newtrinos, Distributions, DataStructures, Accessors, FileIO, CairoMakie, CSV, DataFrames

cd(@__DIR__); mkpath("ours"); mkpath("results"); mkpath("cache")

# CSV export of a profile scan: one row per grid point, ASCII column names, oscillation parameters in physical
# units (sin²θ, Δm²₃₂ = Δm²₃₁ − Δm²₂₁ in eV², δCP in rad), dchi2 = -2Δlog L w.r.t. `ref` (default: the scan's best fit)
function save_csv(path, r; ref = maximum(r.values.log_posterior))
    ascii(k) = replace(string(k), "θ" => "theta", "Δm²" => "dm2_", "δ" => "d", "₁" => "1", "₂" => "2", "₃" => "3", "CP" => "cp")
    cols = OrderedDict{String,Any}()
    for (k, v) in pairs(r.values)
        x = vec(v)
        if startswith(string(k), "θ")
            cols["sin2_" * ascii(k)] = sin.(x) .^ 2
        elseif k == :Δm²₃₁
            cols["dm2_32"] = x .- vec(r.values.Δm²₂₁)
        end
        cols[ascii(k)] = x
    end
    cols["dchi2"] = 2 .* (ref .- vec(r.values.log_posterior))
    haskey(cols, "llh") && (cols["log_likelihood"] = pop!(cols, "llh"))
    first_cols = filter(in(keys(cols)), ["sin2_theta23", "dm2_32", "dcp", "dchi2", "log_likelihood", "log_posterior"])
    CSV.write(path, DataFrame(cols)[:, vcat(first_cols, setdiff(collect(keys(cols)), first_cols))])
end

experiments = (deepcore = Newtrinos.deepcore.configure(),)
likelihood = Newtrinos.generate_likelihood(experiments)
p = Newtrinos.get_params(experiments)
priors = Newtrinos.get_priors(experiments)

# as in the paper: normal ordering, solar parameters and δCP fixed, θ₁₃ constrained, ντ CC normalisation fixed
priors = merge(priors, (Δm²₂₁ = p.Δm²₂₁, θ₁₂ = p.θ₁₂, δCP = p.δCP, nutau_cc_norm = p.nutau_cc_norm,
                        θ₁₃ = Truncated(Normal(0.156, 0.008), 0.13, 0.18),
                        Δm²₃₁ = Uniform(0.0022, 0.0027), θ₂₃ = Uniform(0.685, 0.9)))

contour = Newtrinos.profile(likelihood, priors, OrderedDict(:θ₂₃ => 13, :Δm²₃₁ => 13), p, cache_dir = "cache/th23dm31")
th23 = Newtrinos.profile(likelihood, priors, OrderedDict(:θ₂₃ => 21), p, cache_dir = "cache/th23")
dm31 = Newtrinos.profile(likelihood, priors, OrderedDict(:Δm²₃₁ => 21), p, cache_dir = "cache/dm31")
FileIO.save("results/deepcore.jld2", Dict("th23dm31" => contour, "th23" => th23, "dm31" => dm31))
save_csv("results/deepcore_ssth23_dm32.csv", contour); save_csv("results/deepcore_ssth23.csv", th23); save_csv("results/deepcore_dm32.csv", dm31)

# Fig. 27: 90% C.L. contour, with the official contour of the data release
official = CSV.read(joinpath(pkgdir(Newtrinos), "src/experiments/icecube/deepcore_8y_verification_sample",
                             "DeepCore_oscNext_verification_sample__sin2_theta23_dm2_32__90pc_result_bugfix.csv"), DataFrame; header = false)
fig = Figure(size = (700, 520))
ax = Axis(fig[1, 1], title = "IceCube DeepCore, NO: 90% C.L.", xlabel = "sin²θ₂₃", ylabel = "Δm²₃₂ (10⁻³ eV²)")
lines!(ax, official.Column1, official.Column2 .* 1e3, color = :red, label = "IceCube (data release)")
plot!(ax, Newtrinos.NewtrinosResult(axes = (ss23 = sin.(contour.axes.θ₂₃) .^ 2, dm2 = (contour.axes.Δm²₃₁ .- p.Δm²₂₁) .* 1e3), values = contour.values),
      levels = [0.9], color = :blue, label = "Newtrinos (profile)")
axislegend(ax, position = :rt)
save("ours/contour_90.png", fig)

# Fig. 23: 1D profiles
for (name, r, x, xlabel) in (("mixing", th23, sin.(th23.axes.θ₂₃) .^ 2, "sin²θ₂₃"),
                             ("mass_splitting", dm31, (dm31.axes.Δm²₃₁ .- p.Δm²₂₁) .* 1e3, "Δm²₃₂ (10⁻³ eV²)"))
    fig = Figure(size = (700, 480))
    ax = Axis(fig[1, 1], title = "IceCube DeepCore, NO", xlabel = xlabel, ylabel = "-2 Δ log L")
    lines!(ax, x, 2 .* (maximum(r.values.log_posterior) .- r.values.log_posterior), color = :blue, linewidth = 2, label = "Newtrinos (profile)")
    hlines!(ax, [1.0, 2.71], color = :gray, linestyle = :dot)
    ylims!(ax, 0, 6)
    axislegend(ax, position = :ct)
    save("ours/$(name)_profile.png", fig)
end

Provenance

Newtrinos.jl commite1b5a89439 (deepcore)
Run date2026-10-11T14:22:14Z
Wall time42.2 min (8 threads)
Julia1.12.5
MachineAMD EPYC 7702P 64-Core Processor, 128 hardware threads, Linux
Environmentnewtrinos_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.

FileSizeSHA-256
ours/contour_90.png104.7 kB5ab8efda7dc8…
ours/mass_splitting_profile.png71.3 kBc338c5b4ebd7…
ours/mixing_profile.png76.9 kB5552c7ce4186…
results/deepcore.jld291.8 kBf69ffa123ad3…
results/deepcore_dm32.csv10.6 kB1935ca041f1a…
results/deepcore_ssth23.csv10.8 kBb4dd5e0e2ea9…
results/deepcore_ssth23_dm32.csv82.7 kB0fd01f0fa7b7…