Skip to main content

radionuclide-emission-db

Ideal radionuclide photon-emission spectra and energy-dependent material attenuation in Python.

radionuclide-emission-db separates three tasks that should not be confused:

  1. Emission: obtain gamma-ray, characteristic X-ray, and annihilation-photon emission lines from nuclear decay data.
  2. Filtering: calculate the attenuation of those photons as they pass through one or more materials.
  3. Detection: apply a detector response separately (not implemented in this package).

The package is useful for creating source spectra, studying photon transmission through absorbers, preparing labeled photon-energy samples, and supplying idealized spectra to downstream simulations. It does not simulate a measured gamma-ray spectrum or perform full radiation transport.

Data download required: The normal code-only installation does not provide the emission-line CSVs or the 92 NIST attenuation tables. Download both datasets after installation (instructions below). A privately built data-inclusive wheel is possible, subject to the data providers' redistribution terms.

Installation

Python 3.10 or later is recommended. Install the package and the optional plotting and material-composition dependencies:

python -m pip install 'radionuclide-emission-db[all]'

For development from the extracted source directory (the directory containing pyproject.toml):

python -m pip install -e '.[all]'

matplotlib is needed for spectrum.plot(). xraylib is used for chemical-formula parsing and may also support alternative attenuation calculations. In current releases, NIST SRD 126 elemental tables are the default source of attenuation coefficients; xraylib is not a bundled replacement for the NIST tables.

Check your installation:

python -m pip show radionuclide-emission-db
python -c "from radionuclide_emission_db import Radionuclide, MaterialFilter, AttenuationMaterial; print('Imports OK')"

Required post-installation step 1 — download emission-line data

Emission data come from MIRDspecs / ICRP Publication 107: https://mirdsoft.org/resources/mirdspecs. Files are downloaded as radionuclide-specific summary-spectrum CSVs; they are not embedded in the standard code-only distribution.

# Download the radionuclides listed in the online MIRDspecs index:
radionuclide-emission-db cache-all --workers 4

# Confirm which files were saved:
radionuclide-emission-db list-cached

To download a few nuclides first:

radionuclide-emission-db cache-all --isotopes Co-60 Cs-137 Ba-137m Am-241

To refresh the local copy:

radionuclide-emission-db cache-all --refresh

Storage: In the project-local-data workflow, CSVs are placed in src/radionuclide_emission_db/data/. You can choose a writable directory explicitly:

radionuclide-emission-db cache-all --cache-dir "$HOME/NuclearData/MIRDspecs"

If installed from PyPI into a protected site-packages directory, do not rely on writing into the installed package. Specify a user-writable cache directory if needed, and pass the same directory when loading a radionuclide:

from radionuclide_emission_db import Radionuclide

spectrum = Radionuclide(
    "Co-60", cache_dir="~/NuclearData/MIRDspecs"
).load(offline=True)

The ~ path is supported in the previously documented interface; if your local version does not expand it, use an absolute path. After download, .load(offline=True) prevents network access and raises an error if the required file is unavailable. The bulk index reflects the nuclides currently exposed by the MIRDspecs website; it is not necessarily every radionuclide included in ICRP 107. Some nuclides have no selected photon lines.

Required post-installation step 2 — download NIST attenuation tables

The default attenuation backend uses the NIST X-Ray Mass Attenuation Coefficients (SRD 126) for elements Z = 1–92, nominally covering photon energies from 1 keV to 20 MeV: https://physics.nist.gov/PhysRefData/XrayMassCoef/tab3.html.

# Download all 92 tables into your writable user-data area:
python -m radionuclide_emission_db.nist_cache --all

# Or download just Al (13), Fe (26), and Pb (82):
python -m radionuclide_emission_db.nist_cache --elements 13 26 82

# Check availability (if supported by your installed version):
python -m radionuclide_emission_db.nist_cache --status

The default user-data location documented for the attenuation tables on Linux is:

~/.local/share/radionuclide-emission-db/nist-attenuation/
    z01.json
    z02.json
    ...
    z92.json

A first calculation can retrieve a missing table online, but pre-downloading is strongly recommended for reproducible offline work. To prevent network access:

from radionuclide_emission_db import AttenuationMaterial
lead = AttenuationMaterial.from_name("Pb", offline=True)

If the relevant table is missing, offline mode fails rather than silently substituting a coefficient.

Optional: store the tables inside the project

From the editable source checkout:

python -m radionuclide_emission_db.nist_cache --all --project

This writes z01.json through z92.json to:

src/radionuclide_emission_db/data/nist-attenuation/

The library checks bundled tables before the user cache. A wheel built after these files are populated can include them, but redistribution requires separate permission review (see Data provenance and licenses). This --project command is intended for a writable source checkout, not for an installed read-only wheel.

Quick start: ideal photon-emission spectrum

from radionuclide_emission_db import Radionuclide

spectrum = Radionuclide("Co-60").load(offline=True)
print("Photons per decay:", spectrum.photons_per_decay)

for line in spectrum.lines:
    print(line.energy_keV, line.yield_per_decay, line.radiation_type)

spectrum.plot()                   # requires matplotlib
spectrum.to_csv("Co60_lines.csv")

For an emission CSV supplied separately, the API also supports:

spectrum = Radionuclide("Co-60").load(csv_file="Co-60 Summary Spectrum.csv")

What the numbers mean

Each discrete emission line is represented by energy E (keV), photon yield per nuclear transformation, and radiation type. MIRDspecs' tabulated yields are per nuclear transformation, not per 100 decays; CSV energies expressed in MeV are converted to keV. The default photon selection includes gamma rays, X-rays, and annihilation photons, rather than electrons or beta particles.

For a source of activity A in Bq observed for t seconds, the expected number of emitted photons in line i is:

[ N_i = A,t,Y_i, ]

where Y_i is the yield per transformation. This is not the number of detected counts: it includes neither solid-angle acceptance nor detection efficiency.

expected_emitted = spectrum.as_counts(activity_Bq=1000, duration_s=60)

Mixtures and radioactive equilibrium

SourceMixture combines several radionuclide emission spectra using activities in Bq, not percentages:

from radionuclide_emission_db import SourceMixture

mix = SourceMixture({"Co-60": 1000, "Am-241": 500})
combined = mix.spectrum()  # line weights: emitted photons per second
combined.to_csv("mixture.csv")
combined.plot()

Daughter activities and equilibrium are not calculated automatically. For example, the main 661.7 keV gamma ray associated with a Cs-137 source is emitted by its daughter Ba-137m. For a Cs-137 source sufficiently old for daughter ingrowth equilibrium, a useful approximation is:

[ A_{\mathrm{Ba\text{-}137m}} \simeq 0.946, A_{\mathrm{Cs\text{-}137}}. ]

Illustrative mixture:

mix = SourceMixture({"Cs-137": 1000.0, "Ba-137m": 946.0})
spectrum = mix.spectrum()

Check whether the source CSV includes daughter emissions before explicitly combining parent and daughter, or those emissions may be counted twice. This example assumes the parent-only emission file and equilibrium branching approximation; the package has no general Bateman-equation solver.

Material attenuation: physical model

For a monoenergetic photon line, the package calculates narrow-beam, uncollided transmission through a homogeneous absorber:

[ T(E) = \frac{I(E)}{I_0(E)} = \exp[-\mu(E)x] = \exp\left[-\left(\frac{\mu}{\rho}\right)(E)\rho x\right]. ]

Here:

Symbol Meaning Units
E Photon energy keV
μ/ρ Total mass attenuation coefficient cm²/g
ρ Material density g/cm³
μ Linear attenuation coefficient cm⁻¹
x Absorber thickness cm
T Fraction of uncollided photons transmitted dimensionless

When a thickness is specified in millimeters, the program uses x_cm = thickness_mm / 10.

Built-in material coefficients

For elemental absorbers, the current default uses tabulated NIST SRD 126 mass attenuation coefficients. For compounds, xraylib parses the chemical formula to obtain elemental mass fractions and the package applies the mixture rule:

[ \left(\frac{\mu}{\rho}\right)_{!\mathrm{compound}}(E) =\sum_j w_j\left(\frac{\mu}{\rho}\right)_j(E). ]

The package has documented default material densities for Pb, Al, Fe, Cu, W, Si, water (H2O), NaI, and CZT. For other compounds, supply the formula and physical density explicitly.

from radionuclide_emission_db import AttenuationMaterial

lead = AttenuationMaterial.from_name("Pb", offline=True)
print("mu/rho [cm2/g]:", lead.mass_attenuation_cm2_g(661.7))
print("mu [1/cm]:", lead.linear_attenuation_cm_inv(661.7))
print("Transmission:", lead.transmission(661.7, thickness_mm=5.0))

quartz = AttenuationMaterial.from_name("SiO2", density_g_cm3=2.65)
print(quartz.transmission(661.7, thickness_mm=10.0))

One filter, then two filters

from radionuclide_emission_db import Radionuclide, MaterialFilter

spectrum = Radionuclide("Co-60").load(offline=True)

pb = MaterialFilter.from_material("Pb", thickness_mm=2.0, offline=True)
al = MaterialFilter.from_material("Al", thickness_mm=5.0, offline=True)

after_pb = spectrum.apply_filter(pb, min_energy_keV=5.0)
after_both = after_pb.apply_filter(al, min_energy_keV=5.0)

after_pb.to_csv("Co60_after_Pb.csv")
after_both.to_csv("Co60_after_Pb_Al.csv")

For several uniform layers, the transmissions multiply:

[ T_{\mathrm{total}}(E) = \prod_j \exp[-\mu_j(E)x_j]. ]

The implementation changes the intensity of each existing line. It does not create a Compton continuum, scattered photons, secondary characteristic X-rays, or a detector peak shape.

User-supplied coefficient tables

You can also define your own linear attenuation coefficients in cm⁻¹:

custom_filter = MaterialFilter.from_table(
    name="illustrative",
    thickness_mm=2.0,
    mu_table={100: 2.0, 2000: 0.2},  # illustrative values ONLY
)
custom_result = spectrum.apply_filter(custom_filter)

User-supplied tables require sufficient coverage of the requested photon energies. Values beyond the table's range are not extrapolated; use validated physical data rather than the illustrative coefficients above.

Absorption edges, energy limits, and interpolation

These limits are scientifically important; they are not arbitrary plotting limits.

1. Coefficient energy coverage: 1 keV–20 MeV

The NIST SRD 126 tabulations used by the package cover approximately 1–20,000 keV. The package must not extrapolate the tabulated coefficients beyond this range. A requested photon line outside the coefficient range can raise an exception unless it is deliberately excluded by a spectrum-selection cutoff.

2. Lower-energy cutoff when filtering

MIRDspecs files can contain very low-energy photons. For example, an entry of 0.014503 keV corresponds to 14.503 eV, well below 1 keV. Attempting to obtain a NIST/X-ray coefficient at such an energy is not valid.

For automatically generated material filters, the documented default is to omit lines below 1 keV and issue a warning. You can request a higher threshold:

filtered = spectrum.apply_filter(pb, min_energy_keV=5.0)

This excludes all lines with E < 5 keV from the filtered output. They are not assumed to be fully absorbed; rather, their transmission is not calculated. The original source spectrum remains available unchanged. Set min_energy_keV=0 only if you intentionally want strict evaluation of every line, accepting that out-of-range energies may raise an error.

The cutoff should reflect your intended energy range of interest; it does not change the physical NIST data range or extend the model to lower energies.

3. Absorption-edge discontinuities

Photoelectric attenuation changes sharply at an element's absorption edges (K, L, etc.). Near an edge, attenuation immediately below and above the threshold can differ substantially. The NIST tables include edge-specific information; the package is designed to preserve the discontinuity rather than interpolate smoothly across it.

Away from edges, coefficients are obtained by log–log interpolation between valid tabulated energies. Near edges, accurate calculations require the tabulated pre-edge and post-edge values to be interpreted on the correct side of the discontinuity. Avoid collapsing duplicated edge energies into one row or smoothing across an edge. For a photon exactly at a tabulated edge, the choice of side depends on the interpolation convention; consult the implementation and source table when edge-level precision matters.

4. Upper limit and unsupported physics

High-energy emission lines up to 20 MeV are within the NIST tabulation domain, including the prominent Co-60 photons near 1173 and 1332 keV. Values above 20 MeV are not computed by extrapolation. Photon production via absorber interactions (including scattered and fluorescent photons) remains outside the narrow-beam model at all energies.

Photon sampling and output

sampled_energies_keV = spectrum.sample_energies(10000, seed=42)

These are energies sampled from the relative photon-line weights, conditional on selecting an emitted photon. They are not full decay histories: event time, photon direction, emission point, and coincidences are not simulated.

The package exports generic CSV line tables through to_csv(). These are not OASYS-native ray files. An OASYS interface would additionally have to define ray positions, directions, statistical weights, and any expected source format.

Working offline

  1. Download the necessary MIRDspecs emission CSVs.
  2. Download the necessary NIST elemental attenuation tables (or all 92 tables).
  3. Use Radionuclide(...).load(offline=True).
  4. Use AttenuationMaterial.from_name(..., offline=True) or MaterialFilter.from_material(..., offline=True).

Keep both local datasets when moving between computers. If you install a code-only PyPI wheel on another machine, repeat both downloads there. An editable checkout with data saved under src/.../data/ is different from an installed wheel with user cache files.

Building a distribution

python -m pip install --upgrade build twine
rm -rf build dist src/*.egg-info
python -m build
python -m twine check dist/*
unzip -l dist/*.whl

Before any public upload, inspect the wheel and source distribution for MIRDspecs CSVs and NIST JSONs. If redistribution permissions have not been established, omit those files from the public artifacts even if they are present in your local checkout. Building a wheel from a populated data/ directory may automatically bundle the files.

For a private offline wheel, after permission checks, populate the source-tree data directories and rebuild. Be aware that an installed wheel's package directory may be read-only; prefer a user-writable location for subsequent dataset updates.

Data provenance and licenses

The package's software license does not automatically grant rights to redistribute third-party emission data or NIST tables. Review the corresponding notices and DATA_LICENSE.md before publishing data-inclusive wheels or archives. Respect the providers' terms for automated downloading.

Known limitations and validation

  • The package represents ideal discrete photon lines, not realistic detector spectra.
  • No automatic daughter ingrowth/equilibrium calculation or general radioactive-chain solver.
  • No photon transport, scattering, fluorescence, buildup, source self-attenuation, collimator geometry, or detector response.
  • Compounds are treated with an elemental mass-fraction mixture rule; chemical and material-specific effects beyond that approximation are not modeled.
  • The NIST backend relies on downloaded, correctly parsed reference tables; validate the actual files against selected NIST reference values before quantitative publication.
  • CSV formats and online site markup may change. A complete bulk download can include individual failures; inspect the command output and confirm the saved file count.
  • xraylib is an optional dependency, not a guarantee of broader energy coverage than the NIST tables.

For scientific results, report the nuclear-data source, data-download date, selected photon types, emission normalization, absorber composition and density, absorber thickness, energy cutoff, interpolation convention, and whether calculations included only uncollided photons.

Metadata

Release files for radionuclide-emission-db 0.4.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for radionuclide-emission-db 0.4.5
File Size Uploaded Provenance
radionuclide_emission_db-0.4.5.tar.gz 29.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for radionuclide-emission-db 0.4.5
File Interpreter ABI Platform
radionuclide_emission_db-0.4.5-py3-none-any.whl Python 3 none any Details

Total release size: 51.9 kB

Release files / radionuclide_emission_db-0.4.5.tar.gz

Download URL radionuclide_emission_db-0.4.5.tar.gz
Size 29.5 kB
Tags Source
SHA-256 checksum
How to use checksums
c6cc2dd82646507d98d930597ca10de5170645bc0f96efab433c7b0a44b28b0b
BLAKE2b-256 checksum
How to use checksums
41c82d6738008d133b143dedc61fc45ad112a7848c1da275c7809ed2f3a5e2ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release files / radionuclide_emission_db-0.4.5-py3-none-any.whl

Download URL radionuclide_emission_db-0.4.5-py3-none-any.whl
Size 22.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
65d1431dd28233bd1912006a667aa7cd068a7c8c88c5f599c28fef21e4f175b5
BLAKE2b-256 checksum
How to use checksums
3aee02e1541cbadb0a3dd6a5ed09715555533e7f7cde711b9a29cb2cb8ccac13
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Security for radionuclide-emission-db 0.4.5

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.4.5 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page