diff --git a/.cspell.json b/.cspell.json index 041360a6..e3175f27 100644 --- a/.cspell.json +++ b/.cspell.json @@ -71,6 +71,7 @@ "defaultdict", "dummifies", "dummify", + "eigenstates", "eval", "flatté", "functools", diff --git a/docs/report/033.ipynb b/docs/report/033.ipynb index aba11071..3ef30f55 100644 --- a/docs/report/033.ipynb +++ b/docs/report/033.ipynb @@ -3,7 +3,9 @@ { "cell_type": "markdown", "metadata": { - "tags": [] + "tags": [ + "remove-cell" + ] }, "source": [ "```{autolink-concat}\n", @@ -153,7 +155,6 @@ { "cell_type": "markdown", "metadata": { - "jp-MarkdownHeadingCollapsed": true, "tags": [] }, "source": [ @@ -163,7 +164,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, "source": [ "### Theory" ] @@ -315,7 +318,9 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, "source": [ "### Implementation" ] @@ -324,41 +329,68 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Spherical harmonics" + "In the following, we define a few functions that implement parts of the amplitude model of Equation {eq}`BW_SH_label`. Later on in [](#visualization), we can use these functions to visualize each components of the model individually." ] }, { "cell_type": "markdown", "metadata": { + "jp-MarkdownHeadingCollapsed": true, "tags": [] }, "source": [ - "The calculation of $Y_l^m(\\phi, \\theta)$ is done via [`scipy.special.sph_harm(m, l, phi, theta)`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.sph_harm.html) \n", - "\n", - "We have changed the use of symbol $\\phi$ and $\\theta$ according to the more common used definition in physics.\n", - "\n", - "Here the notation of $\\theta$ and $\\phi$ are not using the same as in `scipy` special function [scipy.special.sph_harm()](https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.sph_harm.html)\n", - "\n", - "(in `scipy`, $\\theta$ is the azimuthal from -$\\pi$ to $\\pi$ and $\\phi$ is the polar angle from 0 to $\\pi$)\n", + "(breit-wigner-model)=\n", + "#### Breit-Wigner (only) Model" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [ + "full-width" + ] + }, + "source": [ + "The following functions define the Breit–Wigner function, as well as the following intensity function that only contains the Breit–Wigner (dynamics) component of each amplitude.\n", "\n", - "where the notation we used here is more common in physics:\n", - "- $\\phi$ is the azimuthal from -$\\pi$ to $\\pi$ in this document (where in `scipy` it is represented as $\\theta$ and ranged from 0 to $2\\pi$)\n", + "$$\n", + "\\begin{array}{rcl}\n", + "I &= &\n", + "\\left\\lvert \\frac{1}{s-m^2_{a_2}+im_{a_2} \\Gamma_{a_2}} +\n", + "\\frac{1}{s-m^2_{\\Delta}+im_{\\Delta} \\Gamma_{\\Delta}} +\n", + "\\frac{1}{s-m^2_{N^*}+im_{N^*} \\Gamma_{N^*}} \\right\\rvert ^2\n", + "\\end{array}\n", + "$$ (B_W_model_only)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def BW_model(s12, s23, s31, *, M12, Gamma12, M23, Gamma23, M31, Gamma31, **kwargs):\n", + " A12 = BW(s12, M12, Gamma12)\n", + " A23 = BW(s23, M23, Gamma23)\n", + " A31 = BW(s31, M31, Gamma31)\n", + " return np.abs(A12 + A23 + A31) ** 2\n", "\n", - "- $\\theta$ is the polar angle from 0 to $\\pi$ in this document (where in `scipy` it is represented as $\\phi$ with the same range)\n", "\n", - "```{math}\n", - ":label: spherical_harmonics_def\n", - "Y_l^m(\\phi, \\theta) = \\sqrt{\\frac{2n+1}{4\\pi}\\frac{(n-m)!}{(n+m)!}}e^{im\\phi}P_l^m(\\cos(\\theta))\n", - "```" + "def BW(s, m, Gamma):\n", + " return 1 / (s - m**2 + m * Gamma * 1j)" ] }, { "cell_type": "markdown", "metadata": { + "jp-MarkdownHeadingCollapsed": true, "tags": [] }, "source": [ - "In the following, we accordingly define functions to compute three terms of spherical harmonics in Equation {eq}`BW_SH_label`, and the explicit form of spherical harmonics as shown in Equation {eq}`spherical_harmonics_def`." + "(spherical-harmonics-model)=\n", + "#### Spherical Harmonics (only) Model" ] }, { @@ -367,13 +399,32 @@ "tags": [] }, "source": [ - ":::{admonition} **Extra Information**\n", + "The calculation of $Y_l^m(\\phi, \\theta)$ is done via [`scipy.special.sph_harm()`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.sph_harm.html). However, we use a different definition of $\\phi$ and $\\theta$, following a notation that is more common in hadron physics.\n", + "- $\\phi$ is the **azimuthal angle** and ranges from -$\\pi$ to $\\pi$. SciPy represents this as $\\theta$, ranging from $0$ to $2\\pi$.\n", + "- $\\theta$ is the **polar angle** and ranges from $0$ to $\\pi$. SciPy represents this as $\\phi$ with the same range.\n", "\n", - "Alternatively,\n", - "we can also calculate the spherical harmonics using the Wigner d-function,\n", - "and the Wigner d-function can be related to the associated Legendre polynomials\n", + "This leads to\n", "\n", - "$Y_l^m(\\theta,\\phi) = \\sqrt{\\frac{2l+1}{4\\pi}\\frac{(l-m)!}{(l+m)!}}e^{im\\phi} d^l_{m0}(\\theta)$\n", + "```{math}\n", + ":label: spherical_harmonics_def\n", + "Y_\\ell^m(\\phi, \\theta) = \\sqrt{\\frac{2n+1}{4\\pi}\\frac{(n-m)!}{(n+m)!}}e^{im\\phi}P_\\ell^m\\left(\\cos\\theta\\right) \\,.\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + ":::{tip}\n", + "Alternatively, we can formulate the spherical harmonics in terms of a Wigner-$d$ or Wigner-$D$ function, as\n", + "\n", + "$$\n", + "\\begin{eqnarray}\n", + "Y_\\ell^m(\\theta,\\phi) = \\sqrt{\\frac{2\\ell+1}{4\\pi}}D^\\ell_{m0}(-\\phi, \\theta, 0) = \\sqrt{\\frac{2\\ell+1}{4\\pi}}e^{im\\phi} d^\\ell_{m0}(\\theta) \\,.\n", + "\\end{eqnarray}\n", + "$$\n", ":::" ] }, @@ -383,7 +434,7 @@ "tags": [] }, "source": [ - "Firstly, the term in $A^{12}$:" + "In the following, we define functions to compute the spherical harmonics of the three subsystem amplitudes in Equation {eq}`BW_SH_label`. Note how the function signature consists of two input data columns, `theta` and `phi`, and how the rest of the arguments are parameters. The final `kwargs` (key-word arguments) is there so that we can compose larger functions from these function definitions." ] }, { @@ -397,11 +448,11 @@ "def compute_spherical_harmonics12(\n", " theta: np.ndarray,\n", " phi: np.ndarray,\n", - " a_minus2,\n", - " a_minus1,\n", - " a_0,\n", - " a_plus1,\n", - " a_plus2,\n", + " a_minus2: complex,\n", + " a_minus1: complex,\n", + " a_0: complex,\n", + " a_plus1: complex,\n", + " a_plus2: complex,\n", " **kwargs,\n", ") -> np.ndarray:\n", " return (\n", @@ -413,15 +464,6 @@ " )" ] }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "Next, the term in $A^{23}$" - ] - }, { "cell_type": "code", "execution_count": null, @@ -431,7 +473,12 @@ "outputs": [], "source": [ "def compute_spherical_harmonics23(\n", - " theta: np.ndarray, phi: np.ndarray, b_minus1, b_0, b_plus1, **kwargs\n", + " theta: np.ndarray,\n", + " phi: np.ndarray,\n", + " b_minus1: complex,\n", + " b_0: complex,\n", + " b_plus1: complex,\n", + " **kwargs,\n", ") -> np.ndarray:\n", " return (\n", " b_plus1 * sp.special.sph_harm(1, 1, phi, theta)\n", @@ -440,15 +487,6 @@ " )" ] }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "Lastly, the corresponding term in $A^{31}$" - ] - }, { "cell_type": "code", "execution_count": null, @@ -458,20 +496,11 @@ "outputs": [], "source": [ "def compute_spherical_harmonics31(\n", - " theta: np.ndarray, phi: np.ndarray, c_0, **kwargs\n", + " theta: np.ndarray, phi: np.ndarray, c_0: complex, **kwargs\n", ") -> np.ndarray:\n", " return c_0 * sp.special.sph_harm(0, 0, phi, theta)" ] }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "#### Breit-Wigner (only) Model" - ] - }, { "cell_type": "markdown", "metadata": { @@ -480,62 +509,16 @@ ] }, "source": [ - ":::{admonition} Reminder\n", - "```{math}\n", - ":label: B_W_model_only\n", - "I = \n", - "\\left\\lvert \\frac{1}{s-m^2_{a_2}+im_{a_2} \\Gamma_{a_2}} +\n", - "\\frac{1}{s-m^2_{\\Delta}+im_{\\Delta} \\Gamma_{\\Delta}} +\n", - "\\frac{1}{s-m^2_{N^*}+im_{N^*} \\Gamma_{N^*}} \\right\\rvert ^2\n", - "```\n", - ":::" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "def BW_model(s12, s23, s31, *, M12, Gamma12, M23, Gamma23, M31, Gamma31, **kwargs):\n", - " A12 = BW(s12, M12, Gamma12)\n", - " A23 = BW(s23, M23, Gamma23)\n", - " A31 = BW(s31, M31, Gamma31)\n", - " return np.abs(A12 + A23 + A31) ** 2\n", - "\n", + "We now have the ingredients to define an intensity function that only contains spherical harmonics, that is, the angular part of the amplitude model:\n", "\n", - "def BW(s, m, Gamma):\n", - " return 1 / (s - m**2 + m * Gamma * 1j)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "#### Spherical Harmonics (only) Model" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [ - "full-width" - ] - }, - "source": [ - ":::{admonition} Reminder\n", - "```{math}\n", - ":label: S_H_only\n", - "I = \n", + "$$\n", + "\\begin{array}{rcl}\n", + "I &=&\n", "\\left\\lvert \\sum a_m Y_2^m (\\Omega_1) +\n", "\\sum b_m Y_1^m (\\Omega_2) +\n", - "c_0 \\right\\rvert ^2\n", - "```\n", - ":::" + "c_0 \\right\\rvert ^2 \\,.\n", + "\\end{array}\n", + "$$ (S_H_only)" ] }, { @@ -593,15 +576,17 @@ ] }, "source": [ - ":::{admonition} Reminder\n", - "```{math}\n", - ":label: B_W_S_H_combine\n", - "I = \\left\\lvert A^{12}+A^{23}+A^{31} \\right\\rvert ^2 =\n", + "Finally, we combine the [](#breit-wigner-model) and [](#spherical-harmonics-model) to get an implementation for Equation {eq}`BW_SH_label`,\n", + "\n", + "$$\n", + "\\begin{array}{rcl}\n", + "I &=& \\left\\lvert A^{12}+A^{23}+A^{31} \\right\\rvert ^2 \\nonumber \\\\\n", + "&=&\n", "\\left\\lvert \\frac{\\sum a_m Y_2^m (\\Omega_1)}{s-m^2_{a_2}+im_{a_2} \\Gamma_{a_2}} +\n", "\\frac{\\sum b_m Y_1^m (\\Omega_2)}{s-m^2_{\\Delta}+im_{\\Delta} \\Gamma_{\\Delta}} +\n", - "\\frac{c_0}{s-m^2_{N^*}+im_{N^*} \\Gamma_{N^*}} \\right\\rvert ^2\n", - "```\n", - ":::" + "\\frac{c_0}{s-m^2_{N^*}+im_{N^*} \\Gamma_{N^*}} \\right\\rvert ^2 \\,.\n", + "\\end{array}\n", + "$$ (B_W_S_H_combine)" ] }, { @@ -655,10 +640,16 @@ "## Visualization" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As discussed in [](#theory), the amplitude model contains variables that are provided by experiment (\"events\" as data input) as well as parameters that are to be optimized. The data input is usually in the form of **four-momenta**, while the model is formulated in the form of Mandelstam variables and helicity angles. We therefore have to compute these variables from the four-momenta." + ] + }, { "cell_type": "markdown", "metadata": { - "jp-MarkdownHeadingCollapsed": true, "tags": [] }, "source": [ @@ -671,14 +662,25 @@ "tags": [] }, "source": [ - "In this section, the phase space of this reaction is generated using [`phasespace`](https://github.com/zfit/phasespace) python package.\n", - "\n", - "Phase space represents the set of all possible states (positions and momenta) of a system.\n", - "Understanding phase space is essential for analyzing particle collisions, decays, and interactions. It involves calculating the likelihood of different final states from given initial conditions while obeying conservation laws (energy, momentum, angular momentum, etc.). The available phase space volume for a process directly correlates with the probability of that process occurring.\n", - "\n", - "In the following, variables that are not labeled with \"lab\" are in the CM frame.\n", - "\n", - "Firstly, some kinematic considerations. In Center-of-Mass (CM) frame the 4-momentum of the total system can be acquired by 4-momentum conservation:" + "First, however, we need to generate a phase space sample of four-momenta in order to plot the amplitude model as a distribution over each of the variables. In this section, we use the [`phasespace`](https://github.com/zfit/phasespace) package for generating four-momenta for the reaction $p\\gamma \\to p\\eta\\pi^0$. The phase space sample will also be used later on to normalize the model when calculating the likelihood over the data sample (see [](#fit-model))." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, + "source": [ + "#### Lab frame and CM frame" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "In Center-of-Mass (CM) frame, the 4-momentum of the total system can be acquired by 4-momentum conservation:" ] }, { @@ -734,7 +736,7 @@ ] }, "source": [ - "For the record, we need to add parameters of beam momentum (or beam energy) in the lab frame and CM total energy" + "From this we can see that the system depends mainly on beam momentum $p_z$ and CM total energy $E_0$." ] }, { @@ -744,7 +746,7 @@ }, "source": [ ":::{caution}\n", - "The calculation here involved using the values from CM frame. While this frame is commonly used for theoretical calculations, experimental data is often analyzed in the lab frame. However, it's worth noting that for collider experiments, the CM frame can coincide with the lab frame.\n", + "The calculation here involved using values from the CM frame. While this frame is commonly used for theoretical calculations, experimental data is often analyzed in the lab frame. However, it's worth noting that oin some collider experiments that do not have a fixed target, the CM frame can coincide with the lab frame.\n", ":::" ] }, @@ -763,60 +765,55 @@ "tags": [] }, "source": [ - "We use the $\\gamma$ beam energy in the lab frame as input:\n", - "\n", - "$$\n", - "E_{\\gamma, \\text{lab}} = 8.5 \\; \\text{GeV}\n", - "$$ (beam_energy_label)\n", + "We use the $\\gamma$ beam energy in the lab frame as input, e.g. $E_{\\gamma, \\text{lab}} = 8.5 \\; \\text{GeV}$, and want to know the collision energy in the CM frame.\n", "\n", - "From this, we can calculate the energy of the gamma in the CM frame as follows.\n", - "\n", - "The four-momentum of photon (beam) in the lab frame:\n", + "We can calculate the energy of the photon in the CM frame as follows. The four-momentum of photon (beam) in the lab frame is\n", "\n", "$$\n", - "p_{\\gamma,\\text{lab}} = (E_{\\gamma, \\text{lab}}, \\vec{p}_{\\gamma,\\text{lab}})\n", + "p_{\\gamma,\\text{lab}} = \\left(E_{\\gamma, \\text{lab}}, \\vec{p}_{\\gamma,\\text{lab}}\\right) \\,.\n", "$$ (beam_four_momentum)\n", "\n", - "Since photon is massless, \n", - "\n", - "$$\n", - "m_{\\gamma}=0\n", - "$$ (massless_photon)\n", - "\n", - "with \n", + "Since the photon is massless, $m_\\gamma=0$, and\n", "\n", "$$\n", - "m^2 = E^2 - \\vec{p}^2\n", + "m^2 = E^2 - \\left|\\vec{p}\\right|^2 \\,,\n", "$$ (four_momentum_conservation)\n", "\n", - "and thus,\n", + "we get\n", "\n", "$$\n", "E_{\\gamma} = |\\vec{p_{\\gamma}}| .\n", - "$$ (gamma_energy)\n", - "\n", - "The four-momentum of proton (target) in the lab frame:\n", + "$$ (gamma_energy)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "The proton (target) is at rest in the lab frame, so we have\n", "\n", "$$\n", - "p_{p,\\text{lab}} = (m_p, \\vec{0})\n", + "p_{p,\\text{lab}} = (m_p, \\vec{0})\\,,\n", "$$ (four_momentum_target_lab)\n", "\n", - "where $m_p$ is the proton mass.\n", - "\n", - "We have the total four-momentum in lab frame:\n", + "where $m_p$ is the proton mass. We have a total four-momentum in the lab frame of\n", "\n", "$$\n", "p_{\\text{tot},\\text{lab}} = p_{\\gamma,\\text{lab}} + p_{p,\\text{lab}}\n", "$$ (total_four_momentum_lab_frame)\n", "\n", + "and we know\n", + "\n", "$$\n", - "E_{p} = \\sqrt { p_{p}^2+ m_{p}^2}\n", + "E_p = \\sqrt{p_p^2+ m_p^2} \\,.\n", "$$ (label_p_four_momentum)\n", "\n", - "From the **lab frame** perspective, the CM total energy with expression in quantities from the **lab frame** is thus:\n", + "The CM total energy $E_0$ expressed in terms of quantities from the **lab frame** is thus\n", "\n", "$$\n", - "\\sqrt{s} = E_0 = m_0 = \\sqrt{2 E_{\\gamma,\\text{lab}} m_p + m_p^2}\n", + "m_0 \\equiv E_0 = \\sqrt{2 E_{\\gamma,\\text{lab}} m_p + m_p^2} \\,.\n", "$$ (lab_frame_CM_total_energy)" ] }, @@ -826,10 +823,10 @@ "tags": [] }, "source": [ - "Equivalently, from the **CM frame** perspective, since $\\vec{p}_{\\gamma} = -\\vec{p}_{p}$ and $|\\vec{p}_{\\gamma}| = |\\vec{p}_{p}|= p_{z}$, we can find out the CM total energy with expression in quantities from the CM frame is:\n", + "Equivalently, from the **CM frame** perspective, since $\\vec{p}_{\\gamma} = -\\vec{p}_{p}$ and $|\\vec{p}_{\\gamma}| = |\\vec{p}_{p}|= p_{z}$, we find\n", "\n", "$$\n", - "\\sqrt{s} = E_0 = m_0 = |p_{z}|+\\sqrt{p_{z}^2 + m_p^2}\n", + "E_0 = m_0 = |p_{z}|+\\sqrt{p_{z}^2 + m_p^2} \\,.\n", "$$ (total_energy_CM_frame_still)" ] }, @@ -841,9 +838,11 @@ ] }, "source": [ - "Therefore $\\gamma$ energy ($E_{\\gamma}$) and $\\gamma$ beam momentum ($p_{\\gamma}$) in **CM frame** can be found,they are:\n", + "Therefore, the energy of the photon ($E_{\\gamma}$) and its momentum ($p_{\\gamma}$) in the **CM frame** are:\n", "\n", - "$E_{\\gamma} = |\\vec{p}_{\\gamma}| = p_{z} = 1.944 \\; \\text{GeV}$" + "$$\n", + "E_{\\gamma} = |\\vec{p}_{\\gamma}| = p_{z} = 1.944 \\; \\text{GeV} \\,.\n", + "$$" ] }, { @@ -896,58 +895,20 @@ "tags": [] }, "source": [ - "Thus, we then have the mass of the system $m_0$ (or $m_{p\\gamma}$ in this case) in CM frame:\n", + "Thus, we then have the mass of the system $m_0$ (or the mass of a 'virtual' particle $p\\gamma$) in CM frame of\n", "\n", "$$\n", - "E_{0} = m_0\\approx 4.102 \\;\\; \\text{GeV} \n", + "E_{0} = m_0\\approx 4.102 \\;\\; \\text{GeV} \\,.\n", "$$" ] }, { "cell_type": "markdown", "metadata": { - "tags": [] - }, - "source": [ - ":::{note}\n", - "The [`phasespace`](https://github.com/zfit/phasespace) library is a Python package designed to simulate particle decays according to the principles of relativistic kinematics and phase space distributions. \n", - "\n", - "We use the [`phasespace`](https://github.com/zfit/phasespace) to generate decay particles (4-momentum and weights):\n", - ":::" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "phsp_events = 500_000\n", - "weights, particles = phasespace.nbody_decay(m_0, [m_eta, m_pi, m_proton]).generate(\n", - " n_events=phsp_events\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] + "jp-MarkdownHeadingCollapsed": true }, "source": [ - ":::{admonition} **weights**\n", - "the statistical weights for each generated event. These weights represent how likely each particular event configuration (set of momenta and energies) is, based on phase space considerations.\n", - ":::" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - ":::{admonition} **`particles`**\n", - "this (python array) contains the information of the generated four-momenta (energy and momentum components) of the decay products for each event. \n", - ":::" + "#### Final state four-momenta" ] }, { @@ -956,16 +917,7 @@ "tags": [] }, "source": [ - "#### 4 momentum of decay particles" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "The following code defines some functions for generating a phase space sample of 4-momenta." + "The [`phasespace`](https://github.com/zfit/phasespace) library is a Python package designed to simulate particle decays according to the principles of relativistic kinematics and phase space distributions. We first use the [`phasespace`](https://github.com/zfit/phasespace) to generate decay particles." ] }, { @@ -976,11 +928,10 @@ }, "outputs": [], "source": [ - "pγ_mass = m_0\n", - "eta_mass = m_eta\n", - "pi_mass = m_pi\n", - "p_mass = m_proton\n", - "n_final_state = 3" + "phsp_events = 500_000\n", + "weights, particles = phasespace.nbody_decay(m_0, [m_eta, m_pi, m_proton]).generate(\n", + " n_events=phsp_events\n", + ")" ] }, { @@ -989,9 +940,7 @@ "tags": [] }, "source": [ - ":::{tip}\n", - "The function block below is scrollable.\n", - ":::" + "Note that each event comes with a statistical weights for each generated event. These weights represent how likely each particular event configuration (set of momenta and energies) is, based on phase space considerations. In order to generate a flat distribution, we will have to use a hit-and-miss method over these weights." ] }, { @@ -1029,12 +978,13 @@ " size: int, seed: int | None = None\n", ") -> tuple[tf.Tensor, tf.Tensor, tf.Tensor]:\n", " rng = np.random.default_rng(seed=seed)\n", - " weights, particles = phasespace.nbody_decay(\n", - " pγ_mass, [eta_mass, pi_mass, p_mass]\n", - " ).generate(n_events=size, seed=seed)\n", + " final_state = [m_eta, m_pi, m_proton]\n", + " weights, particles = phasespace.nbody_decay(m_0, final_state).generate(\n", + " n_events=size, seed=seed\n", + " )\n", " random_weights = rng.uniform(0, weights.numpy().max(), size=weights.shape)\n", " selector = weights > random_weights\n", - " return tuple(particles[f\"p_{i}\"][selector] for i in range(n_final_state))\n", + " return tuple(particles[f\"p_{i}\"][selector] for i in range(len(final_state)))\n", "\n", "\n", "def get_size(phsp: tuple[tf.Tensor, tf.Tensor, tf.Tensor]):\n", @@ -1064,73 +1014,29 @@ "tags": [] }, "source": [ - "A few functions are defined above for generating phase space samples of particle decays and converting them into four-momentum vectors. The main ideas of them are:\n", - "\n", - ":::{note}\n", - "- Step 1, Generate Phase Space Sample (`generate_phsp_bunch()`)\n", - " - Random Number Generator\n", + ":::{admonition} Hit-and-miss sampling\n", + "- **Step 1**: Generate a small phase space sample bunch with `generate_phsp_bunch()`\n", + " - A NumPy random number generator (`rng`) is initialized with a fixed seed for reproducibility. This ensures that every time the simulation is run, it produces the same random numbers.\n", + " - The `phasespace` package is used to simulate a decay process where a parent particle decays into three daughter particles. This is set up by specifying the masses of the parent particle (`m_0`) and the daughter particles (`m_eta`, `m_pi`, `m_proton`). The function `nbody_decay` followed by generate is used to create the phase space and return both the weights of each decay event and the momenta of the decay products.\n", + " - As mentioned, the `phasespace` package generates four-momenta that are not evenly distributed .The distributions appear even only when multiplied by the generated weights. To get a sample bunch that is uniformly distributed, rejection sampling (\"hit-and-miss\") is applied over the weights. To achieve this, a random set of weights (`random_weights`) is generated, and only those events where the original weight exceeds the random weight are selected.\n", "\n", - " A NumPy random number generator (`rng`) is initialized with a fixed seed for reproducibility. This ensures that every time the simulation is run, it produces the same random numbers, which is crucial for debugging and validating simulation results.\n", - " \n", - " - Phase Space Generation\n", + "- **Step 2**, Ensure sufficient sample size with `generate_phsp_decay()`\n", + " - The function starts by generating an initial phase space sample. If this initial sample does not meet the required size, more samples are generated and concatenated until the requested size is reached.\n", + " - Once the target sample size is reached or exceeded, `remove_overflow()` trims the sample to precisely match the requested size.\n", "\n", - " \n", - " The `phasespace` package is used to simulate a decay process where a parent particle decays into three daughter particles. This is set up by specifying the masses of the parent particle (`pγ_mass`) and the daughter particles (`eta_mass`, `pi_mass`, `p_mass`). The function `nbody_decay` followed by generate is used to create the phase space and return both the weights of each decay event and the momenta of the decay products.\n", - " \n", - " \n", - " - Rejection Sampling\n", - " \n", - " To refine the sample, rejection sampling is applied. The `phasespace` package generates four-momenta that are not evenly distributed. The distributions appear even only when multiplied by the generated weights. To achieve this, a random set of weights (`random_weights`) is generated, and only those events where the original weight exceeds the random weight are selected. \n", - " \n", - " \n", - " \n", - "- Step 2, Ensure Sufficient Sample Size (`generate_phsp_decay()`)\n", - " - Iterative Sampling\n", - " \n", - " The function starts by generating an initial phase space sample. If this initial sample does not meet the required size, more samples are generated and concatenated until the cumulative size is adequate.\n", - " \n", - " - Removing Excess\n", - "\n", - " \n", - " Once the target sample size is reached or exceeded, `remove_overflow()` trims the sample to precisely match the requested size.\n", - "\n", - "- Step 3, Convert to [Four-Momentum Vectors](https://vector.readthedocs.io/en/latest/api/backends/vector.backends.numpy.html#vector.backends.numpy.MomentumNumpy4D) (`to_vector()`)\n", - " - Four-Momentum Representation\n", - "\n", - " For each tensor in the phase space tuple (representing the momentum components like px, py, pz), the `to_vector` function converts them into a structured array (`MomentumNumpy4D`). This structured array includes keys for each momentum component and possibly the energy component, arranged as needed for subsequent physics analysis.\n", + "- **Step 3**, Convert tensors to [four-momentum vectors](https://vector.readthedocs.io/en/latest/api/backends/vector.backends.numpy.html#vector.backends.numpy.MomentumNumpy4D) objects\n", + " The `phasespace` package generates four-momenta in the form of $4\\times N$ TensorFlow tensors, with $N$ the number of events. For each tensor in the phase space tuple (representing the momentum components like $E, p_x, p_y, p_z$), the `to_vector` function converts them into a structured `MomentumNumpy4D` array. This structured array includes keys for each momentum component and possibly the energy component and provides convenient methods for computing boosts etc.\n", ":::" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "%%time\n", - "p1_phsp_test, p2_phsp_test, p3_phsp_test = generate_phsp_decay(\n", - " size=phsp_events, seed=42\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "The time is for reference of this phase space generation algorithm (see also the section of [data sample generation](#data-generation))." - ] - }, { "cell_type": "markdown", "metadata": { + "jp-MarkdownHeadingCollapsed": true, "tags": [] }, "source": [ - "#### 4 momentum of initial state particles" + "#### Initial state four-momenta" ] }, { @@ -1139,7 +1045,7 @@ "tags": [] }, "source": [ - "The initial state, $\\gamma$ (a) and $p$ (b), are generated." + "Because of the simple relation in Equation {eq}`4momentum_label`, the four-momenta for the initial state, $\\gamma$ (a) and $p$ (b), do not have to be generated by a phase space generator." ] }, { @@ -1148,66 +1054,53 @@ "tags": [] }, "source": [ - "To find $p_a$ and $p_b$ by 4-momentum conservation, energy conservation in this case.\n", + "To find $p_a$ and $p_b$ by 4-momentum conservation, we can use\n", "\n", - "Given that:\n", - "\n", - "```{math}\n", - ":label: m_a_m_b_p_a_x_p_a_z\n", - "\n", - "m_a = m_{\\gamma} =0 \\\\\n", - "\n", - "m_b = m_p \\\\\n", - "\n", - "p_{a,x} = p_{a,y} = 0 = p_{b,x} = p_{b,y} \\\\\n", - "\n", - "p_{a,z} = - p_{b,z}\n", - "\n", - "```\n", - "\n", - "Due to energy conservation, we have:\n", - "\n", - "```{math}\n", - ":label: E_a_+_E_b_E_0\n", - "\n", - "E_a + E_b = E_1 + E_2 + E_3 = E_0 \\\\\n", + "$$\n", + "\\begin{array}{rcl}\n", + "m_a &=& m_{\\gamma} =0 \\\\\n", + "m_b &=& m_p \\\\\n", + "p_{a,x} &=& p_{a,y} = 0 = p_{b,x} = p_{b,y} \\\\\n", + "p_{a,z} &=& - p_{b,z} \\,.\n", + "\\end{array}\n", + "$$ (m_a_m_b_p_a_x_p_a_z)\n", "\n", - "E_a+ E_b = \\sqrt{m_a^2 + p_a^2} + \\sqrt{m_b^2 + p_b^2} = E_0\n", + "Due to energy conservation, we have\n", "\n", - "```\n", + "$$\n", + "\\begin{array}{rcl}\n", + "E_a + E_b &=& E_1 + E_2 + E_3 = E_0 \\\\\n", + "E_a + E_b &=& \\sqrt{m_a^2 + p_a^2} + \\sqrt{m_b^2 + p_b^2} = E_0 \\,.\n", + "\\end{array}\n", + "$$ (E_a_+_E_b_E_0)\n", "\n", - "Since $m_a=0$ and $p_a = -p_b$, thus\n", - "```{math}\n", - ":label: p_a_+_m_b_2_-_p_a_2\n", + "Since $m_a=0$ and $p_a = -p_b$, we have\n", "\n", - "p_a + \\sqrt{m_b^2 + (-p_a)^2} = E_0\n", - "```\n", + "$$\n", + "p_a + \\sqrt{m_b^2 + (-p_a)^2} = E_0 \\,.\n", + "$$ (p_a_+_m_b_2_-_p_a_2)\n", "\n", "Reorganizing, we get,\n", - "```{math}\n", - ":label: p_a_z_m_p_2_p_a_2\n", "\n", + "$$\n", "p_{a,z} + \\sqrt{m_p^2 + p_a^2} - E_0 = 0\n", - "```\n", - "thus\n", + "$$ (p_a_z_m_p_2_p_a_2)\n", "\n", - "```{math}\n", - ":label: p_a_z_E_0_2_-_m_p_2\n", + "and\n", "\n", + "$$\n", "p_{a,z} = \\frac{E_0^2 - m_p^2}{2E_0}\n", - "```\n", + "$$ (p_a_z_E_0_2_-_m_p_2)\n", "\n", - "then\n", - "\n", - "```{math}\n", - ":label: label_p_b_E_a_E_b\n", + "Finally, this gives us\n", "\n", - "p_{b,z} = -p_{a,z} \\\\\n", - "\n", - "E_a =p_a \\\\\n", - "\n", - "E_{b} = \\sqrt{m_b^2+p_b^2}\n", - "```" + "$$\n", + "\\begin{array}{rcl}\n", + "p_{b,z} &=& -p_{a,z} \\\\\n", + "E_a &=& p_a \\\\\n", + "E_{b} &=& \\sqrt{m_b^2+p_b^2} \\,.\n", + "\\end{array}\n", + "$$ (label_p_b_E_a_E_b)" ] }, { @@ -1216,7 +1109,7 @@ "tags": [] }, "source": [ - "And now we can implement the function `compute_pa_pb()` to compute four-momentum of $p_a$ and $p_b$ based on Equations {eq}`label_p_b_E_a_E_b`." + "With this, our numerical implementation to compute four-momentum of $p_a$ and $p_b$ from Equation {eq}`label_p_b_E_a_E_b` becomes:" ] }, { @@ -1231,38 +1124,27 @@ "outputs": [], "source": [ "def compute_pa_pb(\n", - " p1_phsp: MomentumNumpy4D, p2_phsp: MomentumNumpy4D, p3_phsp: MomentumNumpy4D\n", + " p1: MomentumNumpy4D, p2: MomentumNumpy4D, p3: MomentumNumpy4D\n", ") -> tuple[MomentumNumpy4D, MomentumNumpy4D]:\n", - " shape = p1_phsp.shape\n", - " E_0 = (p1_phsp + p2_phsp + p3_phsp).e\n", + " shape = p1.shape\n", + " E0 = (p1 + p2 + p3).e\n", " px = np.zeros(shape)\n", " py = np.zeros(shape)\n", - " pz = np.ones(shape) * (E_0**2 - p3_phsp.m.mean() ** 2) / (2 * E_0)\n", - " E = np.ones(shape) * np.sqrt((p3_phsp.m.mean()) ** 2 + pz.mean() ** 2)\n", - " pa_phsp = MomentumNumpy4D({\"E\": pz, \"px\": px, \"py\": py, \"pz\": pz})\n", - " pb_phsp = MomentumNumpy4D({\"E\": E, \"px\": px, \"py\": py, \"pz\": -pz})\n", - " return pa_phsp, pb_phsp" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "%%time\n", - "pa_phsp_test, pb_phsp_test = compute_pa_pb(p1_phsp_test, p2_phsp_test, p3_phsp_test)" + " pz = np.ones(shape) * (E0**2 - p3.m.mean() ** 2) / (2 * E0)\n", + " E = np.ones(shape) * np.sqrt(p3.m.mean() ** 2 + pz.mean() ** 2)\n", + " pa = MomentumNumpy4D({\"E\": pz, \"px\": px, \"py\": py, \"pz\": pz})\n", + " pb = MomentumNumpy4D({\"E\": E, \"px\": px, \"py\": py, \"pz\": -pz})\n", + " return pa, pb" ] }, { "cell_type": "markdown", "metadata": { + "jp-MarkdownHeadingCollapsed": true, "tags": [] }, "source": [ - "#### 4 momentum of all particles" + "#### Four-momenta of all particles" ] }, { @@ -1271,8 +1153,7 @@ "tags": [] }, "source": [ - "After testing the feasibility of the functions (`generate_phsp_decay()` and `compute_pa_pb()`) to generate the four-momentum of decay particles in phase space and computing the corresponding four-momentum of reaction particles.\n", - "We now create a function `generate_phsp_all()` to create and compute all particles in phase space all-in-once (combine the two functions previously all into this function)." + "We now create a function `generate_phsp_all()` to create and compute all particles in phase space all-at-once, combining the two functions from the previous sections into one function." ] }, { @@ -1288,9 +1169,9 @@ ") -> tuple[\n", " MomentumNumpy4D, MomentumNumpy4D, MomentumNumpy4D, MomentumNumpy4D, MomentumNumpy4D\n", "]:\n", - " p1_phsp, p2_phsp, p3_phsp = generate_phsp_decay(size, seed, bunch_size)\n", - " pa_phsp, pb_phsp = compute_pa_pb(p1_phsp, p2_phsp, p3_phsp)\n", - " return p1_phsp, p2_phsp, p3_phsp, pa_phsp, pb_phsp" + " p1, p2, p3 = generate_phsp_decay(size, seed, bunch_size)\n", + " pa, pb = compute_pa_pb(p1, p2, p3)\n", + " return p1, p2, p3, pa, pb" ] }, { @@ -1308,96 +1189,77 @@ ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Kinematic variable calculation" + ] + }, + { + "cell_type": "markdown", "metadata": { "tags": [] }, - "outputs": [], "source": [ - "p0_phsp = pa_phsp + pb_phsp\n", - "p12_phsp = p1_phsp + p2_phsp\n", - "p23_phsp = p2_phsp + p3_phsp\n", - "p31_phsp = p3_phsp + p1_phsp\n", + "#### Mandelstam variables" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "jp-MarkdownHeadingCollapsed": true, + "tags": [] + }, + "source": [ + "#### Spherical coordinate system" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "Before introducing CM and helicity angles, we first introduce **polar angles** and **azimuthal angles** in spherical coordinates." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "In the spherical coordinates, the **polar angle** $\\theta$ and **azimuthal angle** $\\phi$ are defined as\n", "\n", - "s12_phsp = p12_phsp.m2\n", - "s23_phsp = p23_phsp.m2\n", - "s31_phsp = p31_phsp.m2\n", - "t1_phsp = (pa_phsp - p1_phsp).m2\n", - "t2_phsp = (pa_phsp - p2_phsp).m2\n", - "u3_phsp = (pb_phsp - p3_phsp).m2" + "$$\n", + "\\begin{array}{rcl}\n", + "\\theta &=& \\arccos \\frac{p_z}{|p|} \\nonumber \\\\\n", + "\\phi &=& \\arctan2(p_y , p_x) \\,.\n", + "\\end{array}\n", + "$$ (polar_azimuthal_angle)" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": { - "jupyter": { - "source_hidden": true - }, - "mystnb": { - "code_prompt_show": "Code testing" - }, "tags": [ - "hide-cell", - "scroll-input" + "full-width" ] }, - "outputs": [], "source": [ - "np.testing.assert_almost_equal(\n", - " s12_phsp,\n", - " (p1_phsp.e + p2_phsp.e) ** 2\n", - " - (\n", - " p1_phsp.p**2\n", - " + p2_phsp.p**2\n", - " + 2\n", - " * (p1_phsp.px * p2_phsp.px + p1_phsp.py * p2_phsp.py + p1_phsp.pz * p2_phsp.pz)\n", - " ),\n", - ")\n", - "\n", - "np.testing.assert_almost_equal(p0_phsp.p2.max(), 0)\n", - "\n", - "np.testing.assert_almost_equal(\n", - " t1_phsp,\n", - " (pa_phsp.e - p1_phsp.e) ** 2\n", - " - (\n", - " pa_phsp.p**2\n", - " + p1_phsp.p**2\n", - " - 2\n", - " * (pa_phsp.px * p1_phsp.px + pa_phsp.py * p1_phsp.py + pa_phsp.pz * p1_phsp.pz)\n", - " ),\n", - ")\n", - "np.testing.assert_almost_equal(\n", - " t2_phsp,\n", - " (pa_phsp.e - p2_phsp.e) ** 2\n", - " - (\n", - " pa_phsp.p**2\n", - " + p2_phsp.p**2\n", - " - 2\n", - " * (pa_phsp.px * p2_phsp.px + pa_phsp.py * p2_phsp.py + pa_phsp.pz * p2_phsp.pz)\n", - " ),\n", - ")\n", - "np.testing.assert_almost_equal(\n", - " u3_phsp,\n", - " (pb_phsp.e - p3_phsp.e) ** 2\n", - " - (\n", - " pb_phsp.p**2\n", - " + p3_phsp.p**2\n", - " - 2\n", - " * (pb_phsp.px * p3_phsp.px + pb_phsp.py * p3_phsp.py + pb_phsp.pz * p3_phsp.pz)\n", - " ),\n", - ")" + "```{image} https://github.com/ComPWA/compwa.github.io/assets/29308176/89e1ad6e-3a7b-4895-b747-8bd644652504\n", + ":align: center\n", + ":width: 40%\n", + "```" ] }, { "cell_type": "markdown", "metadata": { - "jp-MarkdownHeadingCollapsed": true, "tags": [] }, "source": [ - "### Dalitz Plot of Phase Space" + "In Equation {eq}`polar_azimuthal_angle`, $p_z$ is equivalent to $z$, and $|p|$ is $r$ in figure above, while $p_y$ equivalent to $y$, and $p_x$ is $x$." ] }, { @@ -1406,9 +1268,21 @@ "tags": [] }, "source": [ - "The sample is plotted to check whether the distribution looks even in the Dalitz plane (as shown below it is!).\n", - "\n", - "Following this in later sections, we will present Dalitz plots for both experimental data and the fitted model. These plots will allow us to compare the theoretical predictions with actual observations, and to assess the accuracy and effectiveness of the fitted model in describing the decay process." + "The sample is plotted to check whether the distribution looks uniformly distributed in the Dalitz plane. The Mandelstam variable $s$ of each of the three subsystems can be easily computed with from the four-momentum objects as follows. Here, we use the methods and attributes provided by the [`vector`](https://vector.readthedocs.io) package." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "p12_phsp = p1_phsp + p2_phsp\n", + "p23_phsp = p2_phsp + p3_phsp\n", + "p31_phsp = p3_phsp + p1_phsp\n", + "s12_phsp = p12_phsp.m2\n", + "s23_phsp = p23_phsp.m2\n", + "s31_phsp = p31_phsp.m2" ] }, { @@ -1460,13 +1334,12 @@ "tags": [] }, "source": [ - "\n", ":::{tip}\n", "There are different ways to represent the Dalitz plot, each with its advantages.\n", "\n", "- *Scatter Plot*: This method plots individual events as points, offering a clear view of the density and distribution of events within the phase space. It is particularly useful for visualizing smaller datasets or when high resolution is needed to identify specific features or clusters.\n", "\n", - "- *2D Histogram*: This approach divides the phase space into bins and counts the number of events within each bin, representing the density of events using a colour scale. It is effective for large datasets, providing a smooth and continuous representation of the phase space that highlights overall trends and structures.\n", + "- *2D Histogram*: This approach divides the phase space into bins and counts the number of events within each bin, representing the density of events using a color scale. It is effective for large datasets, providing a smooth and continuous representation of the phase space that highlights overall trends and structures.\n", "\n", "In conclusion, to check if the phase space sample is evenly distributed, a scatter plot is typically more straightforward and visually clear.\n", ":::" @@ -1479,16 +1352,7 @@ "tags": [] }, "source": [ - "### Calculation of Angles" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "Before introducing CM and helicity angles, we first introduce **polar angles** and **azimuthal angles** in spherical coordinates." + "#### CM Angles " ] }, { @@ -1497,70 +1361,7 @@ "tags": [] }, "source": [ - "In the spherical coordinates, the **polar angles**:\n", - "\n", - "```{math}\n", - ":label: polar_angle_sh\n", - "\\theta = \\arccos \\frac{p_z}{|p|}\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "In spherical coordinates are **azimuthal angles**:\n", - "\n", - "```{math}\n", - ":label: azimuthal_angle_sh\n", - "\\phi = \\arctan2(p_y , p_x)\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [ - "full-width" - ] - }, - "source": [ - "```{image} https://github.com/ComPWA/compwa.github.io/assets/29308176/89e1ad6e-3a7b-4895-b747-8bd644652504\n", - ":align: center\n", - ":width: 40%\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "In Equation {eq}`polar_angle_sh`, $p_z$ is equivalent to $z$, and $|p|$ is $r$ in figure above.\n", - "\n", - "In Equation {eq}`azimuthal_angle_sh`, $p_y$ equivalent to $y$, and $p_x$ is $x$ in figure above." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "jp-MarkdownHeadingCollapsed": true, - "tags": [] - }, - "source": [ - "### CM Angles " - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "Angles in the CM frame (CM Angles) are the polar and azimuthal angles in the phase space generation and also in the data generation in the CM frame (i.e. the frame that satisfies the relations in Equation {eq}`4momentum_label`), they are different than the helicity angles in the subsystem (which is after rotation and boost into the subsystem)." + "Angles in the CM frame are the polar and azimuthal angles of the spatial components of the four-momenta in the CM frame (i.e. the frame that satisfies the relations in Equation {eq}`4momentum_label`). They are different than the [helicity angles](#helicity-angles) in each subsystem (which is after rotation and boost into the subsystem)." ] }, { @@ -1570,9 +1371,11 @@ }, "source": [ "The values for phase space can be obtained directly in the CM frame, without boosting into a different frame after the generation.\n", - "We denote these angles as:\n", + "We denote these angles as\n", "\n", - "$(\\theta_1^{\\text{CM}}, \\theta_2^{\\text{CM}}, \\theta_3^{\\text{CM}}, \\phi_1^{\\text{CM}}, \\phi_2^{\\text{CM}}, \\phi_3^{\\text{CM}})$:" + "$$\n", + "\\theta_1^\\text{CM}, \\theta_2^\\text{CM}, \\theta_3^\\text{CM}, \\phi_1^\\text{CM}, \\phi_2^\\text{CM}, \\phi_3^\\text{CM} \\,.\n", + "$$" ] }, { @@ -1594,11 +1397,20 @@ { "cell_type": "markdown", "metadata": { - "jp-MarkdownHeadingCollapsed": true, "tags": [] }, "source": [ - "### Helicity angles" + "#### Helicity angles" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ":::{seealso}\n", + "- [Section of helicity formalism in **TR-015** (Spin alignment implementation)](https://compwa.github.io/report/015.html#helicity-formalism)\n", + "- [Helicity versus canonical in Ampform](https://ampform.readthedocs.io/stable/usage/helicity/formalism.html)\n", + ":::" ] }, { @@ -1607,8 +1419,7 @@ "tags": [] }, "source": [ - ":::{admonition} **Helicity formalism**\n", - "\n", + ":::{admonition} Helicity formalism\n", "The helicity formalism is a crucial framework or powerful tool in nuclear and particle physics for describing and analyzing the spin states of particles in reactions and decays. \n", "\n", "It simplifies the analysis of complex processes by projecting the particle's spin onto its direction of motion. This formalism allows for a clear understanding of angular distributions and polarization effects, facilitating the calculation of **transition amplitudes**, which can provide useful insight into particle interaction and dynamics.\n", @@ -1621,7 +1432,6 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", ":::{note}\n", "**Helicity definition**:\n", "\n", @@ -1662,17 +1472,6 @@ ":::" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - ":::{seealso}\n", - "[Section of helicity formalism in TR-015(Spin alignment implementation)](https://compwa.github.io/report/015.html#helicity-formalism)\n", - "\n", - "[Helicity versus canonical in Ampform](https://ampform.readthedocs.io/stable/usage/helicity/formalism.html)\n", - ":::" - ] - }, { "cell_type": "markdown", "metadata": { @@ -1765,6 +1564,13 @@ ":::" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Numerical angle computation" + ] + }, { "cell_type": "markdown", "metadata": {