Source code for pytomography.utils.nist_data
from __future__ import annotations
import warnings
import numpy as np
import re
from scipy.optimize import curve_fit
np.seterr(all="ignore")
[docs]def dual_sqrt_exponential(
energy: float,
c1: float,
c2: float,
d1: float,
d2: float
) -> float:
"""Function used for curve fitting of linear attenuation coefficient vs. photon energy curves from NIST. It's given by the functional form :math:`f(x) = c_1e^{-d_1\sqrt{x}} + c_2e^{-d_2\sqrt{x}}`. It was chosen purely because it gave good fit results.
Args:
energy (float): Energy of photon
c1 (float): Fit parameter 1
c2 (float): Fit parameter 2
d1 (float): Fit parameter 3
d2 (float): Fit parameter 4
Returns:
float: _description_
"""
return c1*np.exp(-d1*np.sqrt(energy)) + c2*np.exp(-d2*np.sqrt(energy))
[docs]def get_E_mu_data_from_datasheet(file: str) -> tuple[np.array, np.array]:
"""Return energy and linear attenuation data from NIST datafiles of mass attenuation coefficients between 50keV and 511keV.
Args:
file (str): Location of NIST data file. Corresponds to a particular element/material.
Returns:
tuple[np.array, np.array]: Energy and linear attenuation values.
"""
with open(file) as f:
lines = f.readlines()
rho = float(lines[0])
lines = lines[1:]
for i in range(len(lines)):
lines[i] = re.split(r'\s+', lines[i])[-4:-1]
E, mu_rho, _ = np.array(lines).astype(float).T
E*=1000
mu = mu_rho * rho
idx = (E>50)*(E<550)
return E[idx], mu[idx]
[docs]def get_mu_from_spectrum_interp(
file: str,
energy: float
) -> np.array:
"""Gets linear attenuation corresponding to a given energy in in the data from ``file``.
Args:
file (str): Filepath of the mu-energy data
energy (float): Energy at which mu is computed
Returns:
np.array: Linear attenuation coefficient (in 1/cm) at the desired energies.
"""
Edata, mudata = get_E_mu_data_from_datasheet(file)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
p_f2_opt = curve_fit(dual_sqrt_exponential, Edata, mudata)[0]
return dual_sqrt_exponential(energy, *p_f2_opt)