Spin alignment with data#
Show code cell content
%config InlineBackend.figure_formats = ['svg']
import logging
import warnings
from pathlib import Path
from IPython.display import display
LOGGER = logging.getLogger()
LOGGER.setLevel(logging.ERROR)
warnings.filterwarnings("ignore")
Phase space sample#
Show code cell content
import qrules
PDG = qrules.load_pdg()
from tensorwaves.data import TFPhaseSpaceGenerator, TFUniformRealNumberGenerator
phsp_generator = TFPhaseSpaceGenerator(
initial_state_mass=PDG["Lambda(c)+"].mass,
final_state_masses={
0: PDG["p"].mass,
1: PDG["K-"].mass,
2: PDG["pi+"].mass,
},
)
rng = TFUniformRealNumberGenerator(seed=0)
phsp_momenta = phsp_generator.generate(1_000_000, rng)
Generate transitions#
Show code cell content
from qrules.particle import ParticleCollection, create_particle
particle_db = ParticleCollection()
particle_db.add(PDG["Lambda(c)+"])
particle_db.add(PDG["p"])
particle_db.add(PDG["K-"])
particle_db.add(PDG["pi+"])
particle_db.add(
create_particle(
PDG["K*(892)0"],
name="K*",
latex="K^*",
)
)
particle_db.add(
create_particle(
PDG["Lambda(1405)"],
name="Lambda*",
latex=R"\Lambda^*",
)
)
particle_db.add(
create_particle(
PDG["Delta(1232)++"],
name="Delta*++",
latex=R"\Delta^*",
)
)
reaction = qrules.generate_transitions(
initial_state=("Lambda(c)+", [-0.5, +0.5]),
final_state=["p", "K-", "pi+"],
formalism="helicity",
particle_db=particle_db,
)
Show code cell source
import graphviz
n = len(reaction.transitions)
for i, t in enumerate(reaction.transitions[:: n // 3]):
dot = qrules.io.asdot([t], collapse_graphs=True, size=3.5)
graph = graphviz.Source(dot)
output_file = Path(f"graph{i}")
graph.render(output_file, format="svg")
output_file.unlink()
display(graph)
Distribution without alignment#
Amplitude model formulated following Appendix C:
import ampform
from ampform.dynamics.builder import RelativisticBreitWignerBuilder
builder = ampform.get_builder(reaction)
builder.align_spin = False
builder.stable_final_state_ids = list(reaction.final_state)
builder.scalar_initial_state_mass = True
bw_builder = RelativisticBreitWignerBuilder()
for name in reaction.get_intermediate_particles().names:
builder.set_dynamics(name, bw_builder)
standard_model = builder.formulate()
standard_model.intensity
\[\displaystyle \sum_{m_{A}=-1/2}^{1/2} \sum_{m_{0}=-1/2}^{1/2} \sum_{m_{1}=0} \sum_{m_{2}=0}{\left|{{A^{01}}_{m_{A},m_{0},m_{1},m_{2}} + {A^{02}}_{m_{A},m_{0},m_{1},m_{2}} + {A^{12}}_{m_{A},m_{0},m_{1},m_{2}}}\right|^{2}}\]
Importing the parameter values given by Table 1:
Show code cell content
from ampform.helicity import HelicityModel
# fmt: off
parameter_table = {
# K*
R"C_{\Lambda_{c}^{+} \to K^*_{0} p_{+1/2}; K^* \to K^{-}_{0} \pi^{+}_{0}}": 1,
R"C_{\Lambda_{c}^{+} \to K^*_{+1} p_{+1/2}; K^* \to K^{-}_{0} \pi^{+}_{0}}": 0.5 + 0.5j,
R"C_{\Lambda_{c}^{+} \to K^*_{-1} p_{-1/2}; K^* \to K^{-}_{0} \pi^{+}_{0}}": 1j,
R"C_{\Lambda_{c}^{+} \to K^*_{0} p_{-1/2}; K^* \to K^{-}_{0} \pi^{+}_{0}}": -0.5 - 0.5j,
"m_{K^*}": 0.9, # GeV
R"\Gamma_{K^*}": 0.2, # GeV
# Λ*
R"C_{\Lambda_{c}^{+} \to \Lambda^*_{-1/2} \pi^{+}_{0}; \Lambda^* \to K^{-}_{0} p_{+1/2}}": 1j,
R"C_{\Lambda_{c}^{+} \to \Lambda^*_{+1/2} \pi^{+}_{0}; \Lambda^* \to K^{-}_{0} p_{+1/2}}": 0.8 - 0.4j,
R"m_{\Lambda^*}": 1.6, # GeV
R"\Gamma_{\Lambda^*}": 0.2, # GeV
# Δ*
R"C_{\Lambda_{c}^{+} \to \Delta^*_{+1/2} K^{-}_{0}; \Delta^* \to p_{+1/2} \pi^{+}_{0}}": 0.6 - 0.4j,
R"C_{\Lambda_{c}^{+} \to \Delta^*_{-1/2} K^{-}_{0}; \Delta^* \to p_{+1/2} \pi^{+}_{0}}": 0.1j,
R"m_{\Delta^*}": 1.4, # GeV
R"\Gamma_{\Delta^*}": 0.2, # GeV
}
# fmt: on
def set_coefficients(model: HelicityModel) -> None:
for name, value in parameter_table.items():
model.parameter_defaults[name] = value
Show code cell source
\[\begin{split}\displaystyle \begin{array}{lc}
C_{\Lambda_{c}^{+} \to K^*_{0} p_{+1/2}; K^* \to K^{-}_{0} \pi^{+}_{0}} & 1 \\
C_{\Lambda_{c}^{+} \to K^*_{+1} p_{+1/2}; K^* \to K^{-}_{0} \pi^{+}_{0}} & 0.5+0.5i \\
C_{\Lambda_{c}^{+} \to K^*_{-1} p_{-1/2}; K^* \to K^{-}_{0} \pi^{+}_{0}} & 1i \\
C_{\Lambda_{c}^{+} \to K^*_{0} p_{-1/2}; K^* \to K^{-}_{0} \pi^{+}_{0}} & -0.5-0.5i \\
m_{K^*} & 0.9 \\
\Gamma_{K^*} & 0.2 \\
C_{\Lambda_{c}^{+} \to \Lambda^*_{-1/2} \pi^{+}_{0}; \Lambda^* \to K^{-}_{0} p_{+1/2}} & 1i \\
C_{\Lambda_{c}^{+} \to \Lambda^*_{+1/2} \pi^{+}_{0}; \Lambda^* \to K^{-}_{0} p_{+1/2}} & 0.8-0.4i \\
m_{\Lambda^*} & 1.6 \\
\Gamma_{\Lambda^*} & 0.2 \\
C_{\Lambda_{c}^{+} \to \Delta^*_{+1/2} K^{-}_{0}; \Delta^* \to p_{+1/2} \pi^{+}_{0}} & 0.6-0.4i \\
C_{\Lambda_{c}^{+} \to \Delta^*_{-1/2} K^{-}_{0}; \Delta^* \to p_{+1/2} \pi^{+}_{0}} & 0.1i \\
m_{\Delta^*} & 1.4 \\
\Gamma_{\Delta^*} & 0.2 \\
\end{array}\end{split}\]
Generate data#
Show code cell content
import matplotlib.pyplot as plt
import numpy as np
from tensorwaves.data import SympyDataTransformer
from tensorwaves.function.sympy import create_function
def compute_sub_intensities(
model: HelicityModel, resonance_name: str, phsp, full_expression
) -> np.ndarray:
parameter_values = {}
for symbol, value in model.parameter_defaults.items():
if resonance_name not in symbol.name and symbol.name.startswith("C"):
parameter_values[symbol] = 0
else:
parameter_values[symbol] = value
sub_expression = full_expression.subs(parameter_values)
sub_intensity = create_function(sub_expression, backend="jax")
return np.array(sub_intensity(phsp).real)
def plot_distributions(model: HelicityModel) -> None:
helicity_transformer = SympyDataTransformer.from_sympy(
model.kinematic_variables, backend="jax"
)
phsp = helicity_transformer(phsp_momenta)
phsp = {k: v.real for k, v in phsp.items()}
full_expression = model.expression.doit()
substituted_expression = full_expression.xreplace(model.parameter_defaults)
intensity_func = create_function(substituted_expression, backend="jax")
intensities_all = np.array(intensity_func(phsp).real)
intensities_k = compute_sub_intensities(model, "K^*", phsp, full_expression)
intensities_delta = compute_sub_intensities(model, "Delta^*", phsp, full_expression)
intensities_lambda = compute_sub_intensities(
model, "Lambda^*", phsp, full_expression
)
fig, ax = plt.subplots(nrows=2, ncols=3, figsize=(8, 5))
hist_kwargs = {
"bins": 80,
"histtype": "step",
}
for x in ax.flatten():
x.set_yticks([])
ax[0, 0].set_xlabel("$m^2(pK^-)$ [GeV$^2/c^4$]")
ax[0, 1].set_xlabel(R"$m^2(K^-\pi^+)$ [GeV$^2/c^4$]")
ax[0, 2].set_xlabel(R"$m^2(p\pi^+)$ [GeV$^2/c^4$]")
ax[1, 0].set_xlabel(R"$\cos\theta(p)$")
ax[1, 1].set_xlabel(R"$\phi(p)$")
ax[1, 2].set_xlabel(R"$\chi$")
for x, xticks in {
ax[0, 0]: [2, 2.5, 3, 3.5, 4, 4.5],
ax[0, 1]: [0.4, 0.6, 0.8, 1, 1.2, 1.4, 1.6, 1.8, 2],
ax[0, 2]: [1, 1.5, 2, 2.5, 3],
ax[1, 0]: [-1, -0.5, 0, 0.5, 1],
ax[1, 1]: [-3, -2, -1, 0, 1, 2, 3],
}.items():
x.set_xticks(xticks)
x.set_xticklabels(xticks)
for weights, color, label in [
(intensities_all, "red", "Model"),
(intensities_k, "orange", R"$K^*\to\,K^{^-}\pi^+$"),
(intensities_delta, "brown", R"$\Delta^{*^{++}} \to\,p\pi^+$"),
(intensities_lambda, "purple", R"$\Lambda^* \to\,p K^{^-}$"),
]:
kwargs = dict(weights=weights, color=color, **hist_kwargs)
ax[0, 0].hist(np.array(phsp["m_01"] ** 2), **kwargs)
ax[0, 1].hist(np.array(phsp["m_12"] ** 2), **kwargs)
ax[0, 2].hist(np.array(phsp["m_02"] ** 2), **kwargs)
ax[1, 0].hist(np.array(np.cos(phsp["theta_01"])), **kwargs)
ax[1, 1].hist(np.array(phsp["phi_01"]), **kwargs, label=label)
ax[1, 2].remove()
handles, labels = ax[1, 1].get_legend_handles_labels()
fig.legend(handles, labels, loc="lower right")
ax[0, 2].set_xlim(1, 3.4)
ax[1, 0].set_xlim(-1, +1)
ax[1, 1].set_xlim(-np.pi, +np.pi)
fig.tight_layout()
plt.show()
Warning
It takes several minutes to lambdify the full expression and expressions for the Wigner rotation angles.
Show code cell source
plot_distributions(standard_model)
Spin alignment sum#
Now, with the spin alignment sum from ampform#245 inserted:
builder.align_spin = True
aligned_model = builder.formulate()
set_coefficients(aligned_model)
aligned_model.intensity
\[\displaystyle \sum_{m_{A}=-1/2}^{1/2} \sum_{m_{0}=-1/2}^{1/2} \sum_{m_{1}=0} \sum_{m_{2}=0}{\left|{\sum_{\lambda^{01}_{0}=-1/2}^{1/2} \sum_{\mu^{01}_{0}=-1/2}^{1/2} \sum_{\nu^{01}_{0}=-1/2}^{1/2} \sum_{\lambda^{01}_{1}=0} \sum_{\mu^{01}_{1}=0} \sum_{\nu^{01}_{1}=0} \sum_{\lambda^{01}_{2}=0}{{A^{01}}_{m_{A},\lambda^{01}_{0},- \lambda^{01}_{1},- \lambda^{01}_{2}} D^{0}_{m_{1},\nu^{01}_{1}}\left(\alpha^{01}_{1},\beta^{01}_{1},\gamma^{01}_{1}\right) D^{0}_{m_{2},\lambda^{01}_{2}}\left(\phi_{01},\theta_{01},0\right) D^{0}_{\mu^{01}_{1},\lambda^{01}_{1}}\left(\phi^{01}_{0},\theta^{01}_{0},0\right) D^{0}_{\nu^{01}_{1},\mu^{01}_{1}}\left(\phi_{01},\theta_{01},0\right) D^{\frac{1}{2}}_{m_{0},\nu^{01}_{0}}\left(\alpha^{01}_{0},\beta^{01}_{0},\gamma^{01}_{0}\right) D^{\frac{1}{2}}_{\mu^{01}_{0},\lambda^{01}_{0}}\left(\phi^{01}_{0},\theta^{01}_{0},0\right) D^{\frac{1}{2}}_{\nu^{01}_{0},\mu^{01}_{0}}\left(\phi_{01},\theta_{01},0\right)} + \sum_{\lambda^{02}_{0}=-1/2}^{1/2} \sum_{\mu^{02}_{0}=-1/2}^{1/2} \sum_{\nu^{02}_{0}=-1/2}^{1/2} \sum_{\lambda^{02}_{1}=0} \sum_{\lambda^{02}_{2}=0} \sum_{\mu^{02}_{2}=0} \sum_{\nu^{02}_{2}=0}{{A^{02}}_{m_{A},\lambda^{02}_{0},- \lambda^{02}_{1},- \lambda^{02}_{2}} D^{0}_{m_{1},\lambda^{02}_{1}}\left(\phi_{02},\theta_{02},0\right) D^{0}_{m_{2},\nu^{02}_{2}}\left(\alpha^{02}_{2},\beta^{02}_{2},\gamma^{02}_{2}\right) D^{0}_{\mu^{02}_{2},\lambda^{02}_{2}}\left(\phi^{02}_{0},\theta^{02}_{0},0\right) D^{0}_{\nu^{02}_{2},\mu^{02}_{2}}\left(\phi_{02},\theta_{02},0\right) D^{\frac{1}{2}}_{m_{0},\nu^{02}_{0}}\left(\alpha^{02}_{0},\beta^{02}_{0},\gamma^{02}_{0}\right) D^{\frac{1}{2}}_{\mu^{02}_{0},\lambda^{02}_{0}}\left(\phi^{02}_{0},\theta^{02}_{0},0\right) D^{\frac{1}{2}}_{\nu^{02}_{0},\mu^{02}_{0}}\left(\phi_{02},\theta_{02},0\right)} + \sum_{\lambda^{12}_{0}=-1/2}^{1/2} \sum_{\lambda^{12}_{1}=0} \sum_{\mu^{12}_{1}=0} \sum_{\nu^{12}_{1}=0} \sum_{\lambda^{12}_{2}=0} \sum_{\mu^{12}_{2}=0} \sum_{\nu^{12}_{2}=0}{{A^{12}}_{m_{A},\lambda^{12}_{0},\lambda^{12}_{1},- \lambda^{12}_{2}} D^{0}_{m_{1},\nu^{12}_{1}}\left(\alpha^{12}_{1},\beta^{12}_{1},\gamma^{12}_{1}\right) D^{0}_{m_{2},\nu^{12}_{2}}\left(\alpha^{12}_{2},\beta^{12}_{2},\gamma^{12}_{2}\right) D^{0}_{\mu^{12}_{1},\lambda^{12}_{1}}\left(\phi^{12}_{1},\theta^{12}_{1},0\right) D^{0}_{\mu^{12}_{2},\lambda^{12}_{2}}\left(\phi^{12}_{1},\theta^{12}_{1},0\right) D^{0}_{\nu^{12}_{1},\mu^{12}_{1}}\left(\phi_{0},\theta_{0},0\right) D^{0}_{\nu^{12}_{2},\mu^{12}_{2}}\left(\phi_{0},\theta_{0},0\right) D^{\frac{1}{2}}_{m_{0},\lambda^{12}_{0}}\left(\phi_{0},\theta_{0},0\right)}}\right|^{2}}\]
Show code cell source
plot_distributions(aligned_model)
Compare with Figure 2. Note that the distributions differ close to threshold, because the distributions in the paper are produced with form factors and an energy-dependent width.