Uncertainty quantification of partial wave transmission coefficients

This notebook extends the uncertainty-propagation workflow to angular reaction observables. It shows how the same model choices that affect transmission coefficients flow through to angle-dependent reaction outputs.

1import numpy as np
2from IPython.display import Math, display
3from periodictable import elements
1from matplotlib import pyplot as plt

Compare mass-model inputs to Koning-Delaroche

1A, Z = (24, 12)
1name_core = str(elements[Z].symbol)
2display(Math(f"^{{{A}}} \\rm{{{name_core}}}"))
\[\displaystyle ^{24} \rm{Mg}\]

Compute transmission coefficients

Let’s use jitr to calculate UQ’ed transmission coefficients using KDUQ Fermi energies and those from a variety of mass models

1from tqdm import tqdm
2
3import jitr
1neutron = (1, 0)
2proton = (1, 1)
3projectile = proton
4target = (A, Z)
1# we have 416 samples from the KDUQ posterior
2kduq_omp_samples = jitr.optical_potentials.kduq.get_samples(proton)
1# com_energy_grid = np.logspace(-1, 1.3, 100)
2lab_energy_grid = np.array([65, 200])
3range_fm = 15
4lmax = 20
1reaction = jitr.reactions.Reaction(target=target, projectile=projectile, process="EL")
 1def set_up_grid(core, lab_energy_grid):
 2    solvers = []
 3    for _i, Elab in enumerate(tqdm(lab_energy_grid)):
 4        kinematics = reaction.kinematics(Elab)
 5        a = range_fm * kinematics.k + np.pi / 2
 6        N = jitr.utils.suggested_basis_size(a)
 7        solvers.append(
 8            jitr.xs.elastic.IntegralWorkspace(
 9                reaction=reaction,
10                kinematics=kinematics,
11                channel_radius_fm=a / kinematics.k,
12                solver=jitr.rmatrix.Solver(N),
13                lmax=lmax,
14                smatrix_abs_tol=0,
15            )
16        )
17    return solvers
1solvers = set_up_grid(target, lab_energy_grid)
100%|███████████████████████████████████████████████████████████████████████████████████| 2/2 [00:22<00:00, 11.07s/it]

Run the uncertainty propagation

KDUQ

 1tcoeff_kduq = np.zeros((lab_energy_grid.size, kduq_omp_samples.shape[0], 2, lmax + 1))
 2for j, sample in enumerate(tqdm(kduq_omp_samples)):
 3    for i, _Elab in enumerate(lab_energy_grid):
 4        rgrid = solvers[i].radial_grid()
 5        central_params, spin_orbit_params, coulomb_params = (
 6            jitr.optical_potentials.kduq.calculate_params(
 7                projectile,
 8                target,
 9                solvers[i].kinematics.Elab,
10                *sample,
11            )
12        )
13
14        tplus, tminus = solvers[i].transmission_coefficients(
15            jitr.optical_potentials.kduq.central(rgrid, *central_params),
16            jitr.optical_potentials.kduq.spin_orbit(rgrid, *spin_orbit_params),
17            jitr.optical_potentials.kduq.coulomb_charged_sphere(rgrid, *coulomb_params),
18        )
19        tcoeff_kduq[i, j, 0, :] = tplus
20        tcoeff_kduq[i, j, 1, :] = tminus
 97%|████████████████████████████████████████████████████████████████████████████▎  | 402/416 [03:51<00:01,  7.99it/s]/home/kyle/umich/jitr/src/jitr/optical_potentials/kduq.py:470: RuntimeWarning: overflow encountered in exp
  d2 = d2_0 + d2_A / (1 + np.exp((A - d2_A3) / d2_A2))
100%|███████████████████████████████████████████████████████████████████████████████| 416/416 [03:57<00:00,  1.75it/s]
 1data = [np.zeros(lmax + 1)] * 8
 2names = [
 3    "E=65 MeV, j = l + 1/2",
 4    "E=65 MeV, j = l - 1/2",
 5    "E=65 MeV, j = l + 1/2, err",
 6    "E=65 MeV, j = l - 1/2, err",
 7    "E=200 MeV, j = l + 1/2",
 8    "E=200 MeV, j = l - 1/2",
 9    "E=200 MeV, j = l + 1/2, err",
10    "E=200 MeV, j = l - 1/2, err",
11]
1from pandas import DataFrame as df
1data = df.from_dict(dict(zip(names, data, strict=False)))
1plus_color = "tab:blue"
2minus_color = "tab:orange"
1ci_plus = np.percentile(tcoeff_kduq[0, :, 0, :], 50, axis=0)
2ci_plus_errs = np.percentile(tcoeff_kduq[0, :, 0, :], 84, axis=0) - np.percentile(
3    tcoeff_kduq[0, :, 0, :], 16, axis=0
4)
1ci_minus = np.percentile(tcoeff_kduq[0, :, 1, :], 50, axis=0)
2ci_minus_errs = np.percentile(tcoeff_kduq[0, :, 1, :], 84, axis=0) - np.percentile(
3    tcoeff_kduq[0, :, 1, :], 16, axis=0
4)
1ci_minus[0] = None
2ci_minus_errs[0] = None
1data["E=65 MeV, j = l + 1/2"] = ci_plus
2data["E=65 MeV, j = l + 1/2, err"] = ci_plus_errs
3data["E=65 MeV, j = l - 1/2"] = ci_minus
4data["E=65 MeV, j = l - 1/2, err"] = ci_minus_errs
 1fig = plt.figure(figsize=(6, 4))
 2ls = np.arange(lmax + 1)
 3plt.errorbar(
 4    ls,
 5    ci_plus * (2 * ls + 1),
 6    ci_plus_errs * (2 * ls + 1),
 7    linestyle="none",
 8    marker="^",
 9    label="$j = l + 1/2$",
10)
11
12plt.errorbar(
13    ls[1:],
14    ci_minus[1:] * (2 * ls[1:] + 1),
15    ci_minus_errs[1:] * (2 * ls[1:] + 1),
16    linestyle="none",
17    marker="v",
18    label="$j = l - 1/2$",
19)
20
21# plt.yscale("log")
22plt.xticks([0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20])
23plt.xlabel(r"$\ell$")
24plt.ylabel(r"$(2  \ell +1) \mathcal{T}_{lj}$")
25plt.title(r"$^{24}$Mg(p,p) 65 MeV", fontsize=14)
26plt.legend()
27plt.tight_layout()
../../_images/90e92a34a642b08328e96a0dd60186c551a5d81510f2933a103a40ed9c68cfe4.png
1ci_plus = np.percentile(tcoeff_kduq[1, :, 0, :], 50, axis=0)
2ci_plus_errs = np.percentile(tcoeff_kduq[1, :, 0, :], 84, axis=0) - np.percentile(
3    tcoeff_kduq[1, :, 0, :], 16, axis=0
4)
1ci_minus = np.percentile(tcoeff_kduq[1, :, 1, :], 50, axis=0)
2ci_minus_errs = np.percentile(tcoeff_kduq[1, :, 1, :], 84, axis=0) - np.percentile(
3    tcoeff_kduq[1, :, 1, :], 16, axis=0
4)
5ci_minus[0] = None
6ci_minus_errs[0] = None
1data["E=200 MeV, j = l + 1/2"] = ci_plus
2data["E=200 MeV, j = l + 1/2, err"] = ci_plus_errs
3data["E=200 MeV, j = l - 1/2"] = ci_minus
4data["E=200 MeV, j = l - 1/2, err"] = ci_minus_errs
 1fig = plt.figure(figsize=(6, 4))
 2plt.errorbar(
 3    ls,
 4    ci_plus * (2 * ls + 1),
 5    ci_plus_errs * (2 * ls + 1),
 6    linestyle="none",
 7    marker="^",
 8    label="$j = l + 1/2$",
 9)
10
11plt.errorbar(
12    ls[1:],
13    ci_minus[1:] * (2 * ls[1:] + 1),
14    ci_minus_errs[1:] * (2 * ls[1:] + 1),
15    linestyle="none",
16    marker="v",
17    label="$j = l - 1/2$",
18)
19
20# plt.yscale("log")
21plt.xticks([0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20])
22plt.xlabel(r"$\ell$")
23plt.ylabel(r"$(2  \ell +1) \mathcal{T}_{lj}$")
24plt.title(r"$^{24}$Mg(p,p) 200 MeV", fontsize=14)
25plt.legend()
26plt.tight_layout()
../../_images/7263f46b7ee6522a59eca580f017a8fe99eecb327ebd7357e9dba775ed3b43e4.png
1# NBVAL_CHECK_OUTPUT
2data.head()
E=65 MeV, j = l + 1/2 E=65 MeV, j = l - 1/2 E=65 MeV, j = l + 1/2, err E=65 MeV, j = l - 1/2, err E=200 MeV, j = l + 1/2 E=200 MeV, j = l - 1/2 E=200 MeV, j = l + 1/2, err E=200 MeV, j = l - 1/2, err
0 0.732306 NaN 0.103491 NaN 0.793631 NaN 0.083665 NaN
1 0.714397 0.733912 0.106325 0.101622 0.781721 0.806950 0.086771 0.084428
2 0.707490 0.740207 0.101053 0.093985 0.765326 0.809628 0.089057 0.087703
3 0.678968 0.730161 0.100371 0.088427 0.741524 0.808922 0.090451 0.094959
4 0.656383 0.725234 0.095936 0.075356 0.709459 0.804422 0.101630 0.100298