Helicity versus canonical

import logging

import graphviz
import qrules
import sympy as sp
from IPython.display import HTML, Math
from rich.table import Table

import ampform

LOGGER = logging.getLogger()
LOGGER.setLevel(logging.ERROR)

In this notebook, we have a look at the decay

\[D_1(2420)^0 \to a_1(1260)^+ K^- \to (K^+K^0)K^-\]

in order to see the difference between a HelicityModel formulated in the canonical basis and one formulated in the helicity basis. To simplify things, we only look at spin projection \(+1\) for \(D_1(2420)^0\), because the intensities for each of the spin projections of \(D_1(2420)^0\) are incoherent, no matter which spin formalism we choose.

Tip

For more information about the helicity formalism, see Chung 2014, Richman 1984, and Kutschke 1996.

First, we use qrules.generate_transitions() to generate a ReactionInfo instance for both formalisms:

def generate_transitions(formalism: str):
    reaction = qrules.generate_transitions(
        initial_state=("D(1)(2420)0", [+1]),
        final_state=["K+", "K-", "K~0"],
        allowed_intermediate_particles=["a(1)(1260)+"],
        formalism=formalism,
    )
    builder = ampform.get_builder(reaction)
    return builder.formulate()


cano_model = generate_transitions("canonical-helicity")
heli_model = generate_transitions("helicity")

From components and parameter_defaults, we can see that the canonical formalism has a larger number of amplitudes.

table = Table(show_edge=False)
table.add_column("Formalism")
table.add_column("Coefficients", justify="right")
table.add_column("Amplitudes", justify="right")
table.add_row(
    "Canonical",
    str(len(cano_model.parameter_defaults)),
    str(len(cano_model.components) - 1),
)
table.add_row(
    "Helicity",
    str(len(heli_model.parameter_defaults)),
    str(len(heli_model.components) - 1),
)
table
 Formalism  Coefficients  Amplitudes 
━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━
 Canonical │            3 │          8 
 Helicity  │            3 │          3 

The reason for this is that canonical basis distinguishes amplitudes over their \(LS\)-combinations. This becomes clear if we define \(a\) to be the amplitude without coefficient (\(A = C a\)), and consider what the full, coherent intensity looks like.

If we write the full intensity as \(I = \left|\sum_i A_i\right|^2\), then we have, in the case of the canonical basis:

def extract_amplitude_substitutions(model):
    amplitude_to_symbol = {}
    for name, expr in model.components.items():
        if not name.startswith("A"):
            continue
        for par in model.parameter_defaults:
            if par in expr.args:
                expr /= par
        name = "a" + name[1:]
        symbol = sp.Symbol(name)
        amplitude_to_symbol[expr] = symbol
    return amplitude_to_symbol


cano_amplitude_to_symbol = extract_amplitude_substitutions(cano_model)
heli_amplitude_to_symbol = extract_amplitude_substitutions(heli_model)


def render_amplitude_summation(model):
    amplitude_to_symbol = extract_amplitude_substitutions(model)
    collected_expr = sp.collect(
        model.expression.subs(amplitude_to_symbol).args[0].args[0],
        tuple(model.parameter_defaults),
    )
    terms = collected_expr.args
    latex = ""
    latex += R"\begin{align}"
    latex += fR"\sum_i A_i & = {sp.latex(terms[0])}\\"
    for term in terms[1:]:
        latex += fR"& + {sp.latex(term)} \\"
    latex += R"\end{align}"
    return Math(latex)


render_amplitude_summation(cano_model)
\[\begin{split}\displaystyle \begin{align}\sum_i A_i & = C_{D_{1}(2420)^{0} \xrightarrow[S=1]{L=0} K^{-} a_{1}(1260)^{+}; a_{1}(1260)^{+} \xrightarrow[S=0]{L=1} K^{+} \overline{K}^{0}} \left(a_{D_{1}(2420)^{0}_{+1} \xrightarrow[S=1]{L=0} K^{-}_{0} a_{1}(1260)^{+}_{+1}; a_{1}(1260)^{+}_{+1} \xrightarrow[S=0]{L=1} K^{+}_{0} \overline{K}^{0}_{0}} + a_{D_{1}(2420)^{0}_{+1} \xrightarrow[S=1]{L=0} K^{-}_{0} a_{1}(1260)^{+}_{-1}; a_{1}(1260)^{+}_{-1} \xrightarrow[S=0]{L=1} K^{+}_{0} \overline{K}^{0}_{0}} + a_{D_{1}(2420)^{0}_{+1} \xrightarrow[S=1]{L=0} K^{-}_{0} a_{1}(1260)^{+}_{0}; a_{1}(1260)^{+}_{0} \xrightarrow[S=0]{L=1} K^{+}_{0} \overline{K}^{0}_{0}}\right)\\& + C_{D_{1}(2420)^{0} \xrightarrow[S=1]{L=1} K^{-} a_{1}(1260)^{+}; a_{1}(1260)^{+} \xrightarrow[S=0]{L=1} K^{+} \overline{K}^{0}} \left(a_{D_{1}(2420)^{0}_{+1} \xrightarrow[S=1]{L=1} K^{-}_{0} a_{1}(1260)^{+}_{+1}; a_{1}(1260)^{+}_{+1} \xrightarrow[S=0]{L=1} K^{+}_{0} \overline{K}^{0}_{0}} + a_{D_{1}(2420)^{0}_{+1} \xrightarrow[S=1]{L=1} K^{-}_{0} a_{1}(1260)^{+}_{-1}; a_{1}(1260)^{+}_{-1} \xrightarrow[S=0]{L=1} K^{+}_{0} \overline{K}^{0}_{0}}\right) \\& + C_{D_{1}(2420)^{0} \xrightarrow[S=1]{L=2} K^{-} a_{1}(1260)^{+}; a_{1}(1260)^{+} \xrightarrow[S=0]{L=1} K^{+} \overline{K}^{0}} \left(a_{D_{1}(2420)^{0}_{+1} \xrightarrow[S=1]{L=2} K^{-}_{0} a_{1}(1260)^{+}_{+1}; a_{1}(1260)^{+}_{+1} \xrightarrow[S=0]{L=1} K^{+}_{0} \overline{K}^{0}_{0}} + a_{D_{1}(2420)^{0}_{+1} \xrightarrow[S=1]{L=2} K^{-}_{0} a_{1}(1260)^{+}_{-1}; a_{1}(1260)^{+}_{-1} \xrightarrow[S=0]{L=1} K^{+}_{0} \overline{K}^{0}_{0}} + a_{D_{1}(2420)^{0}_{+1} \xrightarrow[S=1]{L=2} K^{-}_{0} a_{1}(1260)^{+}_{0}; a_{1}(1260)^{+}_{0} \xrightarrow[S=0]{L=1} K^{+}_{0} \overline{K}^{0}_{0}}\right) \\\end{align}\end{split}\]

In the helicity basis, the \(LS\)-combinations have been summed over already and we can only see an amplitude for each helicity:

render_amplitude_summation(heli_model)
\[\begin{split}\displaystyle \begin{align}\sum_i A_i & = C_{D_{1}(2420)^{0} \to K^{-}_{0} a_{1}(1260)^{+}_{+1}; a_{1}(1260)^{+} \to K^{+}_{0} \overline{K}^{0}_{0}} a_{D_{1}(2420)^{0}_{+1} \to K^{-}_{0} a_{1}(1260)^{+}_{+1}; a_{1}(1260)^{+}_{+1} \to K^{+}_{0} \overline{K}^{0}_{0}}\\& + C_{D_{1}(2420)^{0} \to K^{-}_{0} a_{1}(1260)^{+}_{-1}; a_{1}(1260)^{+} \to K^{+}_{0} \overline{K}^{0}_{0}} a_{D_{1}(2420)^{0}_{+1} \to K^{-}_{0} a_{1}(1260)^{+}_{-1}; a_{1}(1260)^{+}_{-1} \to K^{+}_{0} \overline{K}^{0}_{0}} \\& + C_{D_{1}(2420)^{0} \to K^{-}_{0} a_{1}(1260)^{+}_{0}; a_{1}(1260)^{+} \to K^{+}_{0} \overline{K}^{0}_{0}} a_{D_{1}(2420)^{0}_{+1} \to K^{-}_{0} a_{1}(1260)^{+}_{0}; a_{1}(1260)^{+}_{0} \to K^{+}_{0} \overline{K}^{0}_{0}} \\\end{align}\end{split}\]

Amplitudes in the canonical basis are formulated with regard to their \(LS\)-couplings. As such, they contain additional Clebsch-Gordan coefficients that serve as expansion coefficients.

def extract_amplitudes(model):
    return {
        expr: sp.Symbol(name)
        for name, expr in model.components.items()
        if name.startswith("A")
    }


cano_amplitudes = extract_amplitudes(cano_model)
heli_amplitudes = extract_amplitudes(heli_model)

expression, symbol = next(iter(cano_amplitude_to_symbol.items()))
display(symbol, Math(fR"\quad = {sp.latex(expression)}"))
\[\displaystyle a_{D_{1}(2420)^{0}_{+1} \xrightarrow[S=1]{L=0} K^{-}_{0} a_{1}(1260)^{+}_{-1}; a_{1}(1260)^{+}_{-1} \xrightarrow[S=0]{L=1} K^{+}_{0} \overline{K}^{0}_{0}}\]
\[\displaystyle \quad = {C^{0,0}_{0,0,0,0}} {C^{1,-1}_{0,0,1,-1}} {C^{1,-1}_{1,-1,0,0}} {C^{1,0}_{1,0,0,0}} D^{1}_{-1,0}\left(- \phi_{1,1+2},\theta_{1,1+2},0\right) D^{1}_{1,-1}\left(- \phi_{1+2},\theta_{1+2},0\right)\]

In the helicity basis, these Clebsch-Gordan coefficients and Wigner-\(D\) functions have been summed up, leaving only a Wigner-\(D\) for each node in the decay chain (two in this case):

expression, symbol = next(iter(heli_amplitude_to_symbol.items()))
display(symbol, Math(fR"\quad = {sp.latex(expression)}"))
\[\displaystyle a_{D_{1}(2420)^{0}_{+1} \to K^{-}_{0} a_{1}(1260)^{+}_{-1}; a_{1}(1260)^{+}_{-1} \to K^{+}_{0} \overline{K}^{0}_{0}}\]
\[\displaystyle \quad = D^{1}_{-1,0}\left(- \phi_{1,1+2},\theta_{1,1+2},0\right) D^{1}_{1,-1}\left(- \phi_{1+2},\theta_{1+2},0\right)\]

We can see this also from the original ReactionInfo objects. Let’s select only the transitions where the \(a_1(1260)^+\) resonance has spin projection \(-1\) (taken to be helicity \(-1\) in the helicity formalism). We then see just one StateTransition in the helicity basis and three transitions in the canonical basis:

def render_selection(model):
    transitions = model.adapter.reaction_info.transitions
    selection = filter(
        lambda s: s.states[3].spin_projection == -1, transitions
    )
    dot = qrules.io.asdot(
        selection, render_node=True, render_final_state_id=False
    )
    return graphviz.Source(dot)


display(
    HTML("<b>Helicity</b> basis:"),
    render_selection(heli_model),
    HTML("<b>Canonical</b> basis:"),
    render_selection(cano_model),
)
Helicity basis:
../_images/formalism_16_1.svg
Canonical basis:
../_images/formalism_16_3.svg