Installation
NuOscProbExact is written entirely in Python, so there is nothing to compile or link.
Requirements
The dependencies are deliberately minimal, and split by what you actually want to do:
To do this |
You need |
|---|---|
Compute probabilities ( |
|
Use the bundled sample Hamiltonians |
|
Run the notebooks ( |
|
Run the regression suite ( |
|
Speed up large scans (optional) |
|
Build this documentation |
the contents of |
scipy is used only by the test suite, to check the evolution operator
against an independent matrix exponential. The library itself never imports
it.
NuOscProbExact requires Python 3.9 or newer, and every release is tested
on 3.9, 3.10, 3.11, 3.12, and 3.13. The floor comes from
numpy.broadcast_shapes(), which the batched paths use and which arrived
in NumPy 1.20; 3.9 is also the oldest version for which the optional numba
backend still has a wheel.
Installing
From PyPI (recommended)
pip install nuoscprobexact
That is the whole installation. The only required dependency is numpy.
The optional extras add what each task needs, and can be combined:
pip install "nuoscprobexact[fast]" # numba, for the compiled kernels
pip install "nuoscprobexact[notebooks]" # Jupyter, matplotlib and scipy
pip install "nuoscprobexact[test]" # pytest, scipy and coverage
pip install "nuoscprobexact[docs]" # Sphinx and friends
This puts oscprob2nu, oscprob3nu, oscprob4nu, hamiltonians2nu,
hamiltonians3nu, hamiltonians4nu, globaldefs, fastkernels,
slabs and earth on your Python path under exactly those names — the
same names the paper and the worked examples use.
From GitHub
Install from a clone if you want the notebooks, the worked examples from the paper, the regression suite, or a version that is not yet released:
git clone https://github.com/mbustama/NuOscProbExact.git
cd NuOscProbExact
pip install -e .
-e installs in editable mode, so edits to src/ take effect without
reinstalling. The extras work the same way, for example
pip install -e ".[fast,test]".
Without installing anything
The three core modules are self-contained — they need only numpy and
the standard library — so copying src/oscprob2nu.py,
src/oscprob3nu.py or src/oscprob4nu.py into your own project is a
supported way to use NuOscProbExact. Each imports fastkernels
if it is there and does without it if it is not, so a lone copy works and
simply runs the NumPy path; a test copies each of the three out and
exercises it that way. Adding
src/ to the path works too, and is what the bundled examples do:
import sys
sys.path.append('/path/to/NuOscProbExact/src')
import oscprob3nu
Checking the installation
Run the regression suite:
pytest
Every test should either pass or be skipped, and skips are expected rather
than a sign of trouble: the only tests that skip are those for the optional
Numba backend, which stand down when numba is not installed — the
default. Install the fast extra and the whole suite runs. It is several
hundred tests and takes a few seconds.
The suite checks the SU(2), SU(3) and SU(4) machinery against independent
computations: unitarity of the evolution operator, agreement with
scipy.linalg.expm, agreement with the standard oscillation formulas, the
d tensor and star product of the SU(3) algebra, and the sign conventions
of the sample Hamiltonians. Beyond that it exercises the batched evaluation
paths against the scalar ones, the two backends against each other, degenerate
and near-degenerate Hamiltonians, the energies and baselines the library is
actually used at, and the agreement between the type annotations and the
docstrings — and it runs every example embedded in the docstrings.
Then run one of the worked examples:
cd examples
python example_3nu_vacuum.py
Note
This directory was called test/ in version 1.0.0 of the code, and is
named that way in version 2 of the paper. It was renamed to examples/ to
stop it being confused with tests/, which holds the regression suite.
Building the documentation
pip install -r docs/requirements.txt
cd docs
make html
The result lands in docs/build/html; open index.html.
File tree
NuOscProbExact/
├── .github/ # Continuous integration (GitHub Actions)
│ └── workflows/
│ ├── tests.yml # The suite: five Pythons, all three backends
│ ├── lint.yml # ruff, and the docs build under -W
│ ├── pages.yml # Builds and deploys the docs to GitHub Pages
│ └── publish.yml # Publishes to PyPI on a GitHub Release
├── .gitignore # Build, cache, and generated-output artefacts
├── CHANGELOG.md # Notable changes, rendered as a docs page
├── LICENSE # MIT license
├── README.md # Project overview and worked examples
├── pyproject.toml # Packaging metadata and pytest configuration
├── examples/ # Runnable scripts, one per scenario, linked from README.md
│ ├── example_2nu_trivial.py # Two-flavor, arbitrary Hamiltonian
│ ├── example_2nu_vacuum.py # Two-flavor, oscillations in vacuum
│ ├── example_2nu_vacuum_coeffs.py # Two-flavor, expansion coefficients
│ ├── example_3nu_trivial.py # Three-flavor, arbitrary Hamiltonian
│ ├── example_3nu_vacuum.py # Three-flavor, oscillations in vacuum
│ ├── example_3nu_vacuum_coeffs.py # Three-flavor, expansion coefficients
│ ├── example_3nu_matter.py # Three-flavor, oscillations in matter
│ ├── example_3nu_nsi.py # Three-flavor, matter with NSI
│ └── example_3nu_liv.py # Three-flavor, LIV background
├── docs/ # Sphinx documentation
│ ├── Makefile # `make html` on Linux and macOS
│ ├── make.bat # `make html` on Windows
│ ├── requirements.txt # Documentation-only dependencies
│ └── source/
│ ├── conf.py # Sphinx configuration
│ ├── index.rst # Landing page
│ ├── installation.rst # Requirements, installation, file tree
│ ├── quickstart.rst # Shortest path to a probability
│ ├── recipes.rst # Numerical recipes, with pre-generated figures
│ ├── methodology.rst # The SU(2), SU(3) and SU(4) expansions
│ ├── functions.rst # API reference, from the docstrings
│ ├── references.rst # Bibliography
│ ├── refs.bib # BibTeX entries for the bibliography
│ ├── changelog.rst # Includes the root CHANGELOG.md
│ └── _static/
│ ├── nuoscprobexact_logo.png
│ └── slabs_composition.svg # How slabs compose, drawn for quickstart.rst
├── img/ # Figures from earlier versions of README.md
│ ├── prob_3nu_vacuum_vs_baseline_ee_em_et.png
│ ├── prob_3nu_vacuum_vs_energy_ee_em_et.png
│ └── gallery/ # Figures lifted from the notebooks, shown in README.md
│ ├── gallery_biprobability.png
│ ├── gallery_earth.png
│ ├── gallery_matter.png
│ ├── gallery_ordering.png
│ ├── gallery_oscillogram.png
│ ├── gallery_prem.png
│ ├── gallery_profiles.png
│ ├── gallery_sterile.png
│ ├── gallery_sterile_earth.png
│ └── gallery_vacuum.png
├── notebooks/ # Worked examples, with their figures stored inline
│ ├── 01_basics.ipynb # Units, one probability, and broadcasting
│ ├── 02_vacuum_oscillations.ipynb # Against baseline and against energy
│ ├── 03_matter_nsi_liv.ipynb # Constant-density matter, NSI, and LIV
│ ├── 04_oscillogram.ipynb # Energy-baseline maps in one call
│ ├── 05_biprobability.ipynb # CP ellipses, in vacuum and in matter
│ ├── 06_earth_and_prem.ipynb # PREM, chord geometry, and slabs
│ ├── 07_earth_probabilities.ipynb # Through the Earth, and between sites
│ ├── 08_unusual_density_profiles.ipynb # Castle-wall and other hand-built profiles
│ ├── 09_performance.ipynb # Looping vs broadcasting, and the backend
│ ├── 10_paper_figures.ipynb # The two figures from arXiv:1904.12391
│ ├── 11_exact_vs_approximations.ipynb # Where the textbook formulas break down
│ ├── 12_ordering_and_octant.ipynb # Normal vs inverted, and the 23 octant
│ ├── 13_antineutrinos.ipynb # Conjugate and flip, and two ways to slip
│ ├── 14_solar_and_adiabatic_msw.ipynb # The MSW resonance, and the cost wall
│ ├── 15_numerical_edge_cases.ipynb # Degeneracies, and what does not go NaN
│ ├── 16_four_neutrinos.ipynb # A 3+1 sterile state, through the SU(4) expansion
│ ├── 17_cross_checks.ipynb # Corroboration from nuSQuIDS and Zaglauer-Schwarzer
│ ├── 18_evolution_operator.ipynb # The operator, and the SU(n) coefficients
│ └── make_notebooks.py # Generates and executes all of the above
├── src/ # The library
│ ├── oscprob2nu.py # Two-flavor probabilities, SU(2) expansion
│ ├── oscprob3nu.py # Three-flavor probabilities, SU(3) expansion
│ ├── oscprob4nu.py # Four-flavor probabilities, SU(4) expansion
│ ├── hamiltonians2nu.py # Example two-flavor Hamiltonians
│ ├── hamiltonians3nu.py # Example three-flavor Hamiltonians
│ ├── hamiltonians4nu.py # Example four-flavor (3+1) Hamiltonians
│ ├── globaldefs.py # Physical constants and unit conversions
│ ├── fastkernels.py # Optional Numba kernels, with a NumPy fallback
│ ├── slabs.py # Propagation across adjacent slabs
│ └── earth.py # PREM, chord geometry, and Earth crossings
└── tests/ # Regression suite, run with pytest
├── conftest.py # Shared fixtures and path setup
├── test_su3_algebra.py # d tensor, star product, SU(3) invariants
├── test_oscprob4nu.py # SU(4) algebra, quartic roots, 3+1 physics
├── test_evolution_operator.py # U against an independent matrix exponential
├── test_probabilities.py # Normalization, positivity, P = |U|^2
├── test_hamiltonians.py # Sample Hamiltonians and sign conventions
├── test_reference_formulas.py # Exact result against the standard formulas
├── test_matter_eigenvalues.py # Matter spectrum, against Zaglauer-Schwarzer
├── test_edge_cases.py # Degenerate and near-degenerate Hamiltonians
├── test_docstrings.py # Runs the examples embedded in the docstrings
├── test_vectorized.py # The batched path, against the scalar one
├── test_vectorized_hamiltonians.py # Hamiltonians built for an array of energies
├── test_annotations.py # Annotations, and their agreement with the docs
├── test_fastkernels.py # Both backends, against each other
├── test_physical_scales.py # Both backends at the scales actually used
├── test_slabs.py # Slab composition, against expm
├── test_earth.py # PREM, geometry, and Earth probabilities
├── test_documented_figures.py # Keeps the quoted performance figures agreeing
├── test_version_consistency.py # Keeps the version agreeing wherever it is implied
├── test_nusquids_comparison.py # Against nuSQuIDS, an independent external code
├── nusquids_reference.py # Regenerates the frozen nuSQuIDS reference data
├── nusquids_reference.json # Those reference values, with their provenance
└── test_file_tree.py # Keeps this tree in step with the repository