Metadata-Version: 2.4
Name: RionMASS
Version: 1.0.1
Summary: Toolkit for mass measurements of ringed ions.
Author: David Freire-Fernández
License-Expression: GPL-3.0-or-later
Project-URL: Homepage, https://github.com/GSI-Nuclear-Astrophysics/RionMASS
Project-URL: Repository, https://github.com/GSI-Nuclear-Astrophysics/RionMASS
Project-URL: Issues, https://github.com/GSI-Nuclear-Astrophysics/RionMASS/issues
Project-URL: Changelog, https://github.com/GSI-Nuclear-Astrophysics/RionMASS/blob/main/CHANGELOG.md
Keywords: mass spectrometry,nuclear physics,mass calibration,storage ring,Schottky,time-of-flight
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Environment :: X11 Applications :: Qt
Classifier: Intended Audience :: Science/Research
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Physics
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.24
Requires-Dist: pandas>=2.0
Requires-Dist: scipy>=1.10
Provides-Extra: data
Requires-Dist: ezodf>=0.3.2; extra == "data"
Requires-Dist: lxml>=4.9; extra == "data"
Requires-Dist: fortranformat>=1.0; extra == "data"
Requires-Dist: requests>=2.31; extra == "data"
Requires-Dist: beautifulsoup4>=4.12; extra == "data"
Provides-Extra: plot
Requires-Dist: matplotlib>=3.7; extra == "plot"
Provides-Extra: gui
Requires-Dist: ezodf>=0.3.2; extra == "gui"
Requires-Dist: lxml>=4.9; extra == "gui"
Requires-Dist: fortranformat>=1.0; extra == "gui"
Requires-Dist: requests>=2.31; extra == "gui"
Requires-Dist: beautifulsoup4>=4.12; extra == "gui"
Requires-Dist: PySide6>=6.6; extra == "gui"
Requires-Dist: matplotlib>=3.7; extra == "gui"
Provides-Extra: dev
Requires-Dist: RionMASS[data,gui,plot]; extra == "dev"
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-cov>=5; extra == "dev"
Requires-Dist: ruff>=0.6; extra == "dev"
Requires-Dist: pyright>=1.1.380; extra == "dev"
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: twine>=5; extra == "dev"
Requires-Dist: pre-commit>=3.7; extra == "dev"
Dynamic: license-file

# RionMASS

RionMASS converts storage-ring revolution frequencies or times into atomic
mass excesses. Python, command-line and Qt interfaces share a polynomial
calibration engine and return the same reference diagnostics and result tables.

The workflow includes AME2020 references, nuclear-state and charge-state
handling, custom reference masses, electronic-input covariance, leave-one-out
validation and saved-run replay. Frequency extraction belongs upstream;
RionMASS starts from observables and their uncertainties.

## Installation

Python 3.10 or later is required.

```sh
python -m pip install RionMASS              # calibration engine
python -m pip install 'RionMASS[data,plot]'  # spreadsheets and plots
python -m pip install 'RionMASS[gui]'        # complete desktop workflow
```

For development, install `python -m pip install -e '.[dev]'` from a checkout.

## Python workflow

```python
from rionmass.api import export_result_tables, run_full_calibration_workflow
from rionmass.configuration import CalibrationConfig, ODSImportConfig

ods = ODSImportConfig("frequency_observables.ods", 0, unmeasured_list=("15N7+",), observable="frequency")
calibration = CalibrationConfig(elbien_source="nist", p=3)
result = run_full_calibration_workflow(ods, calibration)
print(result.unknown_df)
export_result_tables(result, "results")
```

`p` counts polynomial coefficients; the degree is `p - 1`. ODS input requires
three columns: ion label, centroid frequency and centroid uncertainty, with
frequencies in Hz. Fourth and fifth columns may supply RMS width and its
uncertainty. Widths are optional metadata for inspection; missing or blank
values remain unavailable and do not enter calibration or mass uncertainties.
Supply `harmonic` when input frequencies have not been reduced to the fundamental.
The time branch returns revolution times
in ps. Isomer excitation energies are supplied separately in MeV.

`python examples/quickstart.py` runs an offline demonstration with public
AME2020 records and the packaged NIST table. Its observables are constructed
to demonstrate the interfaces; they are not experimental measurements.

## Command line and desktop application

```sh
rionmass run --ods frequency_observables.ods --sheet-index 0 \
  --elbien-source nist --unmeasured 15N7+ --p 3 --outdir results
rionmass-gui
```

The GUI shows calibration plots, unknown masses, held-out reference predictions,
AME2020 differences and separate uncertainty terms. Calibration and export run
in background tasks. The selected references, order, states and electronic
inputs remain inspectable.

## Reference inputs and uncertainties

The GUI's **Custom masses (keV)** field and repeatable CLI `--reference-mass`
options accept `NUCLIDE=ME_KEV,SIGMA_KEV`, a neutral-atom ground-state mass
excess and positive one-standard-deviation error. Python callers use
`CalibrationConfig(reference_mass_overrides=...)`. Replacements enter the
calibration and LOO comparisons; AME2020 remains a separately labelled comparator.

Explicit **LOO anchors** remain in the final fit with their input uncertainty.
Their own holdouts are shown as diagnostics and excluded from the extra-scatter
estimate. The default policy retains them in other folds' training sets.
Select anchors from reference geometry or independent information before
examining residuals.

Result tables separate calibration-curve, unknown-observable, LOO extra-scatter
and electronic terms. The correction is cumulative ionization energy:
`I_q = B_neutral - B_ion`. ElBiEn columns count remaining electrons; NIST
total-binding rows use ion charge. Shared electronic inputs are propagated
through calibration and atomic-mass recovery, retaining cancellation and
cross-covariance. Missing covariance remains explicitly unavailable.

The extra-scatter estimate uses held-out predictions, not the full-fit reduced
chi-square. LOO folds share references, so the marginal-pull convention is an
empirical validation diagnostic. Unprovided reference or observable correlations
are not inferred. See [Scientific method](docs/SCIENTIFIC_METHOD.md) and
[Electronic inputs](docs/UNCERTAINTIES.md) for units and covariance assumptions.

## Saved runs and replay

**Save config + tables**, **Load config…** and **Replay config…** create or
restore `DATE_RionMASS_CONFIG_suffix` bundles. Completed runs freeze reference
records, electronic inputs, software versions, constants and numerical
checkpoints. Input spreadsheets are referenced rather than copied.

```python
from rionmass.session import save_run_bundle, replay_run_configuration

folder, files = save_run_bundle("outputs", "label", ods, calibration, result)
report = replay_run_configuration(folder / "config.json")
print(report.mismatches, report.warnings)
```

An edited ODS file produces a hash warning and is still replayed with the saved
sheet index. Numerical differences are reported separately. Settings-only
snapshots contain no completed-result checkpoints. See
[Reproducibility](docs/REPRODUCIBILITY.md).

## Development, citation and license

```sh
pytest
ruff check .
ruff format --check .
pyright
python -m build
twine check dist/*
python scripts/check_release.py dist/*
```

Tests use constructed numerical fixtures and published reference inputs.
See [CONTRIBUTING.md](CONTRIBUTING.md), [CITATION.cff](CITATION.cff),
[release instructions](docs/RELEASE.md) and [LICENSE](LICENSE).
Versioned releases are archived on [Zenodo](https://doi.org/10.5281/zenodo.23501661);
use the DOI for the version used in your analysis.
The license is GPL-3.0-or-later.
