diff --git a/.cspell.json b/.cspell.json index 983eca55..2dbbd97b 100644 --- a/.cspell.json +++ b/.cspell.json @@ -73,10 +73,14 @@ "eval", "flatté", "functools", + "Hankel", "helicities", "helicity", + "Hippel", "itertools", "JHEP", + "JPAC", + "Ketzer", "kwargs", "Källén", "lambdification", @@ -106,6 +110,7 @@ "pytest", "PYTHONHASHSEED", "qrules", + "Quigg", "Reana", "roadmap", "Schwarz", @@ -121,6 +126,8 @@ "traceback", "unbinned", "unitarity", + "unitless", + "unnormalized", "unphysical", "vectorize", "weisskopf", @@ -297,6 +304,7 @@ "phsp", "pkpi", "pmatrix", + "ppnp", "preorder", "prereleased", "println", diff --git a/docs/bibliography.bib b/docs/bibliography.bib index b81a5385..624afe1c 100644 --- a/docs/bibliography.bib +++ b/docs/bibliography.bib @@ -1,5 +1,4 @@ - -@article{aitchisonMatrixFormalismOverlapping1972, +@article{Aitchison:1972ay, title = {The 𝐾-Matrix Formalism for Overlapping Resonances}, author = {Aitchison, I.J.R.}, year = {1972}, @@ -19,11 +18,8 @@ @article{aitchisonUnitarityAnalyticityCrossing2015 year = {2015}, month = jul, journal = {arXiv:1507.02697 [hep-ph]}, - eprint = {1507.02697}, - eprinttype = {arxiv}, - primaryclass = {hep-ph}, url = {http://arxiv.org/abs/1507.02697}, - archiveprefix = {arXiv} + archiveprefix = {arxiv} } @book{beckTestDrivenDevelopmentExample2003, @@ -32,23 +28,34 @@ @book{beckTestDrivenDevelopmentExample2003 author = {Beck, Kent}, year = {2003}, series = {The {{Addison-Wesley}} Signature Series}, - publisher = {{Addison-Wesley}}, - address = {{Boston}}, + publisher = {Addison-Wesley}, + address = {Boston}, isbn = {978-0-321-14653-3}, lccn = {QA76.76.T48 B43 2003} } -@book{bycklingParticleKinematics1973, +@book{Blatt:1952ije, + title = {Theoretical {{Nuclear Physics}}}, + author = {Blatt, John M and Weisskopf, Victor F}, + year = {1979}, + publisher = {Springer New York}, + address = {New York, NY}, + url = {https://doi.org/10.1007/978-1-4612-9959-2}, + isbn = {978-1-4612-9959-2 978-1-4612-9961-5}, + annotation = {OCLC: 840280777} +} + +@book{Byckling:1971vca, title = {Particle {{Kinematics}}}, author = {Byckling, Eero and Kajantie, Keijo}, year = {1973}, - publisher = {{Wiley}}, - address = {{London, New York}}, + publisher = {Wiley}, + address = {London, New York}, isbn = {978-0-471-12885-4}, lccn = {QC794.6.K5 B95} } -@article{chungPartialWaveAnalysis1995, +@article{Chung:1995dx, title = {{Partial wave analysis in 𝐾-matrix formalism}}, author = {Chung, Suh-Urk and Brose, J. and Hackmann, R. and Klempt, E. and Spanier, S. and Strassburger, C.}, year = {1995}, @@ -68,7 +75,7 @@ @techreport{chungSpinFormalismsUpdated2014 year = {2014}, month = jul, pages = {BNL--76975-2006-IR, 890945}, - institution = {{Brookhaven National Laboratory}}, + institution = {Brookhaven National Laboratory}, url = {https://suchung.web.cern.ch/spinfm1.pdf} } @@ -78,13 +85,13 @@ @book{gammaDesignPatternsElements1995 editor = {Gamma, Erich}, year = {1995}, series = {Addison-{{Wesley}} Professional Computing Series}, - publisher = {{Addison-Wesley}}, - address = {{Reading, Mass}}, + publisher = {Addison-Wesley}, + address = {Reading, Mass}, isbn = {978-0-201-63361-0}, lccn = {QA76.64 .D47 1995} } -@article{jacobGeneralTheoryCollisions1959, +@article{Jacob:1959at, title = {On the General Theory of Collisions for Particles with Spin}, author = {Jacob, M. and Wick, G.C.}, year = {1959}, @@ -98,6 +105,35 @@ @article{jacobGeneralTheoryCollisions1959 url = {https://linkinghub.elsevier.com/retrieve/pii/000349165990051X} } +@article{JPAC:2019ufm, + title = {Dalitz-Plot Decomposition for Three-Body Decays}, + author = {Mikhasenko, M. and Albaladejo, M. and Bibrzycki, Ł. and {Fernandez-Ramirez}, C. and Mathieu, V. and Mitchell, S. and Pappagallo, M. and Pilloni, A. and Winney, D. and Skwarnicki, T. and Szczepaniak, A. P.}, + year = {2020}, + month = feb, + journal = {Physical Review D: Particles and Fields}, + volume = {101}, + number = {3}, + pages = {034033}, + issn = {2470-0010, 2470-0029}, + doi = {10.1103/PhysRevD.101.034033}, + url = {https://journals.aps.org/prd/abstract/10.1103/PhysRevD.101.034033}, + archiveprefix = {arxiv} +} + +@article{Ketzer:2019wmd, + title = {Light-Meson Spectroscopy with {{COMPASS}}}, + author = {Ketzer, B. and Grube, B. and Ryabchikov, D.}, + year = {2020}, + month = jul, + journal = {Progress in Particle and Nuclear Physics}, + volume = {113}, + pages = {103755}, + issn = {01466410}, + doi = {10.1016/j.ppnp.2020.103755}, + url = {https://linkinghub.elsevier.com/retrieve/pii/S0146641020300028}, + archiveprefix = {arxiv} +} + @misc{kutschkeAngularDistributionCookbook1996, title = {An {{Angular Distribution Cookbook}}}, author = {Kutschke, Rob}, @@ -106,7 +142,7 @@ @misc{kutschkeAngularDistributionCookbook1996 url = {https://home.fnal.gov/~kutschke/Angdist/angdist.ps} } -@article{marangottoHelicityAmplitudesGeneric2020, +@article{Marangotto:2019ucc, title = {Helicity {{Amplitudes}} for {{Generic Multibody Particle Decays Featuring Multiple Decay Chains}}}, author = {Marangotto, Daniele}, editor = {Vagnozzi, Sunny}, @@ -117,7 +153,8 @@ @article{marangottoHelicityAmplitudesGeneric2020 pages = {1--15}, issn = {1687-7365, 1687-7357}, doi = {10.1155/2020/6674595}, - url = {https://www.hindawi.com/journals/ahep/2020/6674595/} + url = {https://www.hindawi.com/journals/ahep/2020/6674595/}, + archiveprefix = {arxiv} } @book{martinCleanCodeHandbook2009, @@ -125,8 +162,8 @@ @book{martinCleanCodeHandbook2009 shorttitle = {Clean Code}, editor = {Martin, Robert C.}, year = {2009}, - publisher = {{Prentice Hall}}, - address = {{Upper Saddle River, NJ}}, + publisher = {Prentice Hall}, + address = {Upper Saddle River, NJ}, isbn = {978-0-13-235088-4}, lccn = {QA76.76.D47 C583 2009} } @@ -136,35 +173,18 @@ @misc{meyerMatrixTutorial2008 author = {Meyer, Curtis A.}, year = {2008}, month = oct, - address = {{Munich, Germany}}, + address = {Munich, Germany}, url = {http://www.curtismeyer.com/talks/PWA_Munich_KMatrix.pdf} } -@article{mikhasenkoDalitzplotDecompositionThreebody2020, - title = {Dalitz-Plot Decomposition for Three-Body Decays}, - author = {Mikhasenko, M. and Albaladejo, M. and Bibrzycki, Ł. and {Fernandez-Ramirez}, C. and Mathieu, V. and Mitchell, S. and Pappagallo, M. and Pilloni, A. and Winney, D. and Skwarnicki, T. and Szczepaniak, A. P.}, - year = {2020}, - month = feb, - journal = {Physical Review D}, - volume = {101}, - number = {3}, - eprint = {1910.04566}, - eprinttype = {arxiv}, - pages = {034033}, - issn = {2470-0010, 2470-0029}, - doi = {10.1103/PhysRevD.101.034033}, - url = {https://journals.aps.org/prd/abstract/10.1103/PhysRevD.101.034033}, - archiveprefix = {arXiv} -} - @book{percivalTestDrivenDevelopmentPython2017, title = {Test-{{Driven Development}} with {{Python}}: {{Obey}} the {{Testing Goat}}: {{Using Django}}, {{Selenium}}, and {{JavaScript}}}, shorttitle = {Test-Driven Development with {{Python}}}, author = {Percival, Harry}, year = {2017}, edition = {Second edition}, - publisher = {{O'Reilly Media}}, - address = {{Sebastopol, CA}}, + publisher = {O'Reilly Media}, + address = {Sebastopol, CA}, isbn = {978-1-4919-5870-4}, lccn = {QA76.73.P98 P46 2017}, annotation = {OCLC: ocn953432202} @@ -175,11 +195,11 @@ @misc{petersPartialWaveAnalysis2004 author = {Peters, Klaus}, year = {2004}, month = jun, - address = {{Varenna}}, + address = {Varenna}, url = {https://slideplayer.com/slide/1676572} } -@misc{richmanExperimenterGuideHelicity1984, +@misc{Richman:1984gh, title = {An {{Experimenter}}'s {{Guide}} to the {{Helicity Formalism}}}, author = {Richman, Jeffrey D.}, year = {1984}, @@ -191,9 +211,9 @@ @book{sedgewickAlgorithms2011 title = {Algorithms}, author = {Sedgewick, Robert and Wayne, Kevin Daniel}, year = {2011}, - edition = {Fourth}, - publisher = {{Addison-Wesley}}, - address = {{Upper Saddle River, NJ}}, + edition = {4th}, + publisher = {Addison-Wesley}, + address = {Upper Saddle River, NJ}, isbn = {978-0-321-57351-3}, lccn = {QA76.9.A43 S429 2011} } @@ -204,21 +224,36 @@ @book{slatkinEffectivePython902019 author = {Slatkin, Brett}, year = {2019}, month = nov, - publisher = {{Addison-Wesley}}, + publisher = {Addison-Wesley}, isbn = {978-0-13-485398-7}, annotation = {OCLC: 1127093006} } -@article{wangNovelMethodTest2020, - title = {A Novel Method to Test Particle Ordering and Final State Alignment in Helicity Formalism}, - author = {Wang, Mengzhen and Jiang, Yi and Liu, Yinrui and Qian, Wenbin and Lyu, Xiaorui and Zhang, Liming}, - year = {2020}, - month = dec, - journal = {arXiv}, - eprint = {2012.03699}, - eprinttype = {arxiv}, - url = {http://arxiv.org/abs/2012.03699}, - archiveprefix = {arXiv} +@article{VonHippel:1972fg, + title = {Centrifugal-{{Barrier Effects}} in {{Resonance Partial Decay Widths}}, {{Shapes}}, and {{Production Amplitudes}}}, + author = {{von Hippel}, Frank and Quigg, C.}, + year = {1972}, + month = feb, + journal = {Physical Review D}, + volume = {5}, + number = {3}, + pages = {624--638}, + issn = {0556-2821}, + doi = {10.1103/PhysRevD.5.624}, + url = {https://link.aps.org/doi/10.1103/PhysRevD.5.624} } - +@article{Wang:2020giv, + title = {A Novel Method to Test Particle Ordering and Final State Alignment in Helicity Formalism}, + author = {Wang, Mengzhen and Jiang, Yi and Liu, Yinrui and Qian, Wenbin and Lyu, Xiao-Rui and Zhang, Liming}, + year = {2021}, + month = jun, + journal = {Chinese Physics C}, + volume = {45}, + number = {6}, + pages = {063103}, + issn = {1674-1137, 2058-6132}, + doi = {10.1088/1674-1137/abf139}, + url = {https://iopscience.iop.org/article/10.1088/1674-1137/abf139}, + archiveprefix = {arxiv} +} diff --git a/docs/report/005.ipynb b/docs/report/005.ipynb index 39dc1183..acd88349 100644 --- a/docs/report/005.ipynb +++ b/docs/report/005.ipynb @@ -49,9 +49,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This report investigates how to implement $K$-matrix dynamics with {doc}`SymPy `. We here describe only the version that is **not Lorentz-invariant**, because it is simplest and allows us to check whether the case $n_R=1, n=1$ (single resonance, single channel) reduces to a Breit-Wigner function. We followed the physics as described by {pdg-review}`Resonances` and {cite}`chungPartialWaveAnalysis1995,petersPartialWaveAnalysis2004,meyerMatrixTutorial2008`. For the Lorentz-invariant version, see [TR-009](009.ipynb).\n", + "This report investigates how to implement $K$-matrix dynamics with {doc}`SymPy `. We here describe only the version that is **not Lorentz-invariant**, because it is simplest and allows us to check whether the case $n_R=1, n=1$ (single resonance, single channel) reduces to a Breit-Wigner function. We followed the physics as described by {pdg-review}`Resonances` and {cite}`Chung:1995dx,petersPartialWaveAnalysis2004,meyerMatrixTutorial2008`. For the Lorentz-invariant version, see [TR-009](009.ipynb).\n", "\n", - "A brief overview of the origin of the $\\boldsymbol{K}$-matrix is given first. This overview follows {cite}`chungPartialWaveAnalysis1995`, but skips over quite a few details, as this is only an attempt to provide some context of what is going on." + "A brief overview of the origin of the $\\boldsymbol{K}$-matrix is given first. This overview follows {cite}`Chung:1995dx`, but skips over quite a few details, as this is only an attempt to provide some context of what is going on." ] }, { @@ -233,7 +233,7 @@ "\n", "The dynamical part $\\boldsymbol{T}$ is usually called the **transition operator**. The reason is that it describes the interacting part of the **scattering operator** $\\boldsymbol{S}$, which describes the (complex) amplitude $\\langle f|\\boldsymbol{S}|i\\rangle$ of an initial state $|i\\rangle$ transitioning to a final state $|f\\rangle$. The scattering operator describes both the non-interacting amplitude and the transition amplitude, so it relates to the transition operator as:[^1]\n", "\n", - "[^1]: Some authors like {cite}`chungPartialWaveAnalysis1995` multiply the transition operator by a factor 2.\n", + "[^1]: Some authors like {cite}`Chung:1995dx` multiply the transition operator by a factor 2.\n", "\n", "$$\n", "\\boldsymbol{S} = \\boldsymbol{I} + i\\boldsymbol{T}\n", diff --git a/docs/report/010.ipynb b/docs/report/010.ipynb index 563c5093..57c8c028 100644 --- a/docs/report/010.ipynb +++ b/docs/report/010.ipynb @@ -136,7 +136,7 @@ ] }, "source": [ - "As described in [TR-005](005.ipynb), the $\\boldsymbol{K}$-matrix describes **scattering processes** of the type $cd \\to ab$. The $P$-vector approach is one of two generalizations for **production processes** of the type $c \\to ab$. For more details on this approach, {cite}`chungPartialWaveAnalysis1995` refers to {cite}`aitchisonMatrixFormalismOverlapping1972`.\n", + "As described in [TR-005](005.ipynb), the $\\boldsymbol{K}$-matrix describes **scattering processes** of the type $cd \\to ab$. The $P$-vector approach is one of two generalizations for **production processes** of the type $c \\to ab$. For more details on this approach, {cite}`Chung:1995dx` refers to {cite}`Aitchison:1972ay`.\n", "\n", "If we take the production vector $P$ to be:\n", "\n", diff --git a/docs/report/013.ipynb b/docs/report/013.ipynb index 7a18e3e3..b810be94 100644 --- a/docs/report/013.ipynb +++ b/docs/report/013.ipynb @@ -20,7 +20,7 @@ ":::{card} Spin alignment with data\n", "TR-013\n", "^^^\n", - "In this report, we attempt to check the effect of activating spin alignment ([ampform#245](https://github.com/ComPWA/ampform/pull/245)) and compare it with [Figure 2](https://downloads.hindawi.com/journals/ahep/2020/6674595.pdf#page=9) in {cite}`marangottoHelicityAmplitudesGeneric2020`.\n", + "In this report, we attempt to check the effect of activating spin alignment ([ampform#245](https://github.com/ComPWA/ampform/pull/245)) and compare it with [Figure 2](https://downloads.hindawi.com/journals/ahep/2020/6674595.pdf#page=9) in {cite}`Marangotto:2019ucc`.\n", "\n", "See also [TR-014](014.ipynb) and [TR-015](015.ipynb).\n", "+++\n", diff --git a/docs/report/014.ipynb b/docs/report/014.ipynb index 530cee2f..c7324d38 100644 --- a/docs/report/014.ipynb +++ b/docs/report/014.ipynb @@ -134,7 +134,7 @@ "\n", "[ampform#245](https://github.com/ComPWA/ampform/pull/245) implements spin alignment, which results in large sum combinatorics for all helicity combinations. The result is an amplitude model expression that is too large to be rendered as LaTeX.\n", "\n", - "To some extend, this is already the case with the [current implementation](https://ampform.readthedocs.io/en/0.12.3/usage/formalism.html) of the 'standard' helicity formalism {cite}`jacobGeneralTheoryCollisions1959, richmanExperimenterGuideHelicity1984, kutschkeAngularDistributionCookbook1996, chungSpinFormalismsUpdated2014`: many of the terms in the total intensity expression differ only by the helicities of the final and initial state." + "To some extend, this is already the case with the [current implementation](https://ampform.readthedocs.io/en/0.12.3/usage/formalism.html) of the 'standard' helicity formalism {cite}`Jacob:1959at, Richman:1984gh, kutschkeAngularDistributionCookbook1996, chungSpinFormalismsUpdated2014`: many of the terms in the total intensity expression differ only by the helicities of the final and initial state." ] }, { diff --git a/docs/report/015.ipynb b/docs/report/015.ipynb index 22ee0fa8..17a13877 100644 --- a/docs/report/015.ipynb +++ b/docs/report/015.ipynb @@ -242,7 +242,7 @@ "![](https://user-images.githubusercontent.com/29308176/164992511-98d8fa79-06dc-40ac-b91c-388ee2fb06f6.svg)\n", "\n", "\n", - "When formulating the amplitude model for this reaction, the {class}`~ampform.helicity.HelicityAmplitudeBuilder` implements the 'standard' helicity formalism as described in {cite}`richmanExperimenterGuideHelicity1984, kutschkeAngularDistributionCookbook1996, chungSpinFormalismsUpdated2014` and simply sums over the different amplitudes to get the full amplitude:" + "When formulating the amplitude model for this reaction, the {class}`~ampform.helicity.HelicityAmplitudeBuilder` implements the 'standard' helicity formalism as described in {cite}`Richman:1984gh, kutschkeAngularDistributionCookbook1996, chungSpinFormalismsUpdated2014` and simply sums over the different amplitudes to get the full amplitude:" ] }, { @@ -273,7 +273,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "As pointed out in {cite}`marangottoHelicityAmplitudesGeneric2020, mikhasenkoDalitzplotDecompositionThreebody2020, wangNovelMethodTest2020`, this is wrong because of the mismatch in reference frames for the helicities." + "As pointed out in {cite}`Marangotto:2019ucc, JPAC:2019ufm, Wang:2020giv`, this is wrong because of the mismatch in reference frames for the helicities." ] }, { @@ -287,11 +287,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In the rest of this document, we follow {cite}`marangottoHelicityAmplitudesGeneric2020` to align all amplitudes in the different topologies back to the initial state reference frame $A$, so that they can be correctly summed up. Specifically, we want to formulate a new, correctly aligned amplitude $\\mathcal{A}^{A\\to 0,1,\\dots}_{m_A,m_0,m_1,\\dots}$ from the original amplitudes $\\mathcal{A}^{A\\to R,S,i,...\\to 0,1,\\dots}_{\\lambda_A,\\lambda_0,\\lambda_1,\\dots}$ by applying Eq.(45) and Eq.(47) for generic, multi-body decays. Here, the $\\lambda$ values are the helicities in the parent rest frame of each two-body decay and the $m$ are the canonical[^canonical] spin projections in the rest frame of the mother particle that is the same no matter the {class}`~qrules.topology.Topology`.\n", + "In the rest of this document, we follow {cite}`Marangotto:2019ucc` to align all amplitudes in the different topologies back to the initial state reference frame $A$, so that they can be correctly summed up. Specifically, we want to formulate a new, correctly aligned amplitude $\\mathcal{A}^{A\\to 0,1,\\dots}_{m_A,m_0,m_1,\\dots}$ from the original amplitudes $\\mathcal{A}^{A\\to R,S,i,...\\to 0,1,\\dots}_{\\lambda_A,\\lambda_0,\\lambda_1,\\dots}$ by applying Eq.(45) and Eq.(47) for generic, multi-body decays. Here, the $\\lambda$ values are the helicities in the parent rest frame of each two-body decay and the $m$ are the canonical[^canonical] spin projections in the rest frame of the mother particle that is the same no matter the {class}`~qrules.topology.Topology`.\n", "\n", "[^canonical]: The canonical rest frame differs from the 'helicity' rest frame in that it is reached by a direct Lorentz boost without rotating the coordinate system in such a way that the $z$-axis aligns with the momentum of one of the decay products.\n", "\n", - "Just as in {cite}`marangottoHelicityAmplitudesGeneric2020`, we test the implementation with 1-to-3 body decays. We use the notation from {func}`~ampform.helicity.naming.get_boost_chain_suffix` to indicate resonances $R,S,U$. This results in the following figure for the two alignments sums of Equations (45) and (46) in {cite}`marangottoHelicityAmplitudesGeneric2020`:" + "Just as in {cite}`Marangotto:2019ucc`, we test the implementation with 1-to-3 body decays. We use the notation from {func}`~ampform.helicity.naming.get_boost_chain_suffix` to indicate resonances $R,S,U$. This results in the following figure for the two alignments sums of Equations (45) and (46) in {cite}`Marangotto:2019ucc`:" ] }, { @@ -362,7 +362,7 @@ "\n", "The dashed edges and bars above the state IDs indicate \"opposite helicity\" states. The helicity of an **opposite helicity state** gets a minus sign in the Wigner-$D$ function for a two-body state as formulated by {external+ampform-0.14.x:func}`.formulate_wigner_d` (see {ref}`report/015:Helicity formalism`) and therefore needs to be defined consistently. AmpForm does this with {external+ampform-0.14.x:func}`.is_opposite_helicity_state`.\n", "\n", - "Opposite helicity states are also of importance in the spin alignment procedure sketched by {cite}`marangottoHelicityAmplitudesGeneric2020`. The Wigner-$D$ functions that appear in Equations (45) and (46) from {cite}`marangottoHelicityAmplitudesGeneric2020`, operate on the spin of the final state, but the angles in the Wigner-$D$ function are taken from the sibling state:" + "Opposite helicity states are also of importance in the spin alignment procedure sketched by {cite}`Marangotto:2019ucc`. The Wigner-$D$ functions that appear in Equations (45) and (46) from {cite}`Marangotto:2019ucc`, operate on the spin of the final state, but the angles in the Wigner-$D$ function are taken from the sibling state:" ] }, { @@ -489,7 +489,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Finally, the total intensity can be computed from these amplitudes by incoherently summing over the initial and final state canonical spin projections (see [Equation (47)](https://downloads.hindawi.com/journals/ahep/2020/6674595.pdf#page=7) in {cite}`marangottoHelicityAmplitudesGeneric2020`):\n", + "Finally, the total intensity can be computed from these amplitudes by incoherently summing over the initial and final state canonical spin projections (see [Equation (47)](https://downloads.hindawi.com/journals/ahep/2020/6674595.pdf#page=7) in {cite}`Marangotto:2019ucc`):\n", "\n", "$$\n", "I = \\sum_{m_A,m_0,m_1,m_2}\\left|\n", @@ -1061,7 +1061,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now it's still a matter of computing the values for the angles $\\alpha,\\beta,\\gamma$ in the Wigner rotation matrices. These angles represents the difference between the canonical spin frame as attained by a direct boost from the initial state versus a chain of boosts through each resonance. See Equation (36) in {cite}`marangottoHelicityAmplitudesGeneric2020`.\n", + "Now it's still a matter of computing the values for the angles $\\alpha,\\beta,\\gamma$ in the Wigner rotation matrices. These angles represents the difference between the canonical spin frame as attained by a direct boost from the initial state versus a chain of boosts through each resonance. See Equation (36) in {cite}`Marangotto:2019ucc`.\n", "\n", "The {mod}`~ampform.kinematics` module can generate an expression for the chain of Lorentz boosts from the initial state to the final state with {func}`~ampform.kinematics.lorentz.compute_boost_chain`:" ] @@ -1211,7 +1211,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The result of this matrix product is the rotation matrix for the Wigner rotation. The function {func}`~ampform.kinematics.angles.compute_wigner_angles` computes the required Euler angles from this rotation matrix by implementing Equations (B.2-3) from {cite}`marangottoHelicityAmplitudesGeneric2020`:" + "The result of this matrix product is the rotation matrix for the Wigner rotation. The function {func}`~ampform.kinematics.angles.compute_wigner_angles` computes the required Euler angles from this rotation matrix by implementing Equations (B.2-3) from {cite}`Marangotto:2019ucc`:" ] }, { diff --git a/docs/report/017.ipynb b/docs/report/017.ipynb index 5cccfc3f..4887d0e9 100644 --- a/docs/report/017.ipynb +++ b/docs/report/017.ipynb @@ -123,7 +123,7 @@ "Kinematics for a three-body decay $0 \\to 123$ can be fully described by two **Mandelstam variables** $\\sigma_1, \\sigma_2$, because the third variable $\\sigma_3$ can be expressed in terms $\\sigma_1, \\sigma_2$, the mass $m_0$ of the initial state, and the masses $m_1, m_2, m_3$ of the final state. As can be seen, the roles of $\\sigma_1, \\sigma_2, \\sigma_3$ are interchangeable.\n", "\n", "```{margin}\n", - "See Eq. (1.2) in {cite}`bycklingParticleKinematics1973`\n", + "See Eq. (1.2) in {cite}`Byckling:1971vca`\n", "```" ] }, @@ -173,7 +173,7 @@ "\n", "\n", "```{margin}\n", - "See §V.2 in {cite}`bycklingParticleKinematics1973`\n", + "See §V.2 in {cite}`Byckling:1971vca`\n", "```" ] }, @@ -585,7 +585,7 @@ "The boundary cannot be parametrized analytically in polar coordinates, but there is a numeric solution. The idea is to solve the condition $\\phi(\\sigma_1,\\sigma_2)=0$ after the following substitutions:\n", "\n", "```{margin}\n", - "See {cite}`bycklingParticleKinematics1973`, pp. 109–112\n", + "See {cite}`Byckling:1971vca`, pp. 109–112\n", "```" ] }, diff --git a/docs/report/021.ipynb b/docs/report/021.ipynb index 5d96be0a..706d0165 100644 --- a/docs/report/021.ipynb +++ b/docs/report/021.ipynb @@ -1087,7 +1087,7 @@ "\\end{align}\n", "$$\n", "\n", - "The expressions for the cosine of the positive (anticlockwise) angles, $\\theta_{12}, \\theta_{23}, \\theta_{13}$ and $\\hat\\theta_{1(2)}, \\hat\\theta_{3(1)}, \\zeta^1_{1(3)}$ can be expressed in terms of Mandelstam variables $\\sigma_1, \\sigma_2, \\sigma_3$ using {cite}`mikhasenkoDalitzplotDecompositionThreebody2020`, Appendix A:" + "The expressions for the cosine of the positive (anticlockwise) angles, $\\theta_{12}, \\theta_{23}, \\theta_{13}$ and $\\hat\\theta_{1(2)}, \\hat\\theta_{3(1)}, \\zeta^1_{1(3)}$ can be expressed in terms of Mandelstam variables $\\sigma_1, \\sigma_2, \\sigma_3$ using {cite}`JPAC:2019ufm`, Appendix A:" ] }, { diff --git a/docs/report/024.ipynb b/docs/report/024.ipynb index ffaf4a52..7b700b49 100644 --- a/docs/report/024.ipynb +++ b/docs/report/024.ipynb @@ -412,7 +412,7 @@ "tags": [] }, "source": [ - "Now, let's build up a more complicated expression that contains this phase space factor. Here, we use SymPy to derive a Breit-Wigner using a single-channel [$K$ matrix](https://doi.org/10.1002/andp.19955070504) {cite}`chungPartialWaveAnalysis1995`:" + "Now, let's build up a more complicated expression that contains this phase space factor. Here, we use SymPy to derive a Breit-Wigner using a single-channel [$K$ matrix](https://doi.org/10.1002/andp.19955070504) {cite}`Chung:1995dx`:" ] }, { diff --git a/docs/report/029.ipynb b/docs/report/029.ipynb new file mode 100644 index 00000000..e117e7a0 --- /dev/null +++ b/docs/report/029.ipynb @@ -0,0 +1,727 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "```{autolink-concat}\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "PDG" + ] + }, + "source": [ + "::::{margin}\n", + ":::{card} Definition of the normalized Blatt–Weisskopf form factor from Hankel functions of the first kind.\n", + "TR-029\n", + "^^^\n", + "This report investigates how to implement [ComPWA/ampform#417](https://github.com/ComPWA/ampform/issues/417), where it was suggested to define the 'normalized' Blatt–Weisskopf function $B_L^2(z)$ from a Hankel function of the first kind, $h_l^{(1)}$.\n", + ":::\n", + "::::" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "# Blatt–Weisskopf from Hankel function" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "%pip install -q ampform==0.15.1 sympy==1.12" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "jupyter": { + "source_hidden": true + }, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "hide-input" + ] + }, + "outputs": [], + "source": [ + "from __future__ import annotations\n", + "\n", + "from functools import lru_cache\n", + "\n", + "import sympy as sp\n", + "from ampform.dynamics.phasespace import BreakupMomentumSquared\n", + "from ampform.io import aslatex\n", + "from ampform.sympy import unevaluated\n", + "from IPython.display import Math, display" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Introduction" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "As of AmpForm [v0.15](https://github.com/ComPWA/ampform/releases/tag/0.15.1), the implementation of [`BlattWeisskopfSquared`](https://ampform.readthedocs.io/0.15.x/api/ampform.dynamics/#ampform.dynamics.BlattWeisskopfSquared) contains hard-coded polynomials, see implementation [here](https://github.com/ComPWA/ampform/blob/0.15.1/src/ampform/dynamics/__init__.py#L66-L134).\n", + "The motivation for this can be found in the citations mentioned in [its API documentation](https://ampform.readthedocs.io/0.15.x/api/ampform.dynamics/#ampform.dynamics.BlattWeisskopfSquared).\n", + "However, as noted by [@mmikhasenko](https://github.com/mmikhasenko) in [ComPWA/ampform#417](https://github.com/ComPWA/ampform/issues/417), the polynomials can be derived from the spherical[^1] Hankel functions of the first kind.\n", + "Von Hippel and Quigg[^2] derived a generalization of the centrifugal barrier factor $F_L$, also called form factor, that was introduced by {cite}`Blatt:1952ije`, showing that\n", + "\n", + "[^1]: See [this page](https://mathworld.wolfram.com/SphericalHankelFunctionoftheFirstKind.html) on Wolfram MathWorld for an explanation about the difference between $h_\\ell^{(1)}$ and $H_\\ell^{(1)}$.\n", + "[^2]: See {cite}`VonHippel:1972fg`, pp. 626 and 637, and a review by COMPASS, {cite}`Ketzer:2019wmd`, p. 31." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "```{math}\n", + "F_\\ell^2(z^2) = \\frac{1}{z^2\\left|h^{(1)}_\\ell\\left(z\\right)\\right|^2}\\,,\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "where $h_\\ell^{(1)}$ is a Hankel function of the first kind. They also noted that, if $z\\in\\mathbb{R}$," + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "$$\n", + "h_\\ell^{(1)}(z) =\n", + " \\left(- i\\right)^{\\ell+1}\n", + " \\frac{e^{iz}}{z}\n", + " \\sum_{k=0}^\\ell\n", + " \\frac{(\\ell+k)!}{(\\ell-k)! \\, k!}\n", + " \\left(\\frac{i}{2z}\\right)^k.\n", + "$$ (hankel-sum)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "In the following, we call $F_\\ell(z)$ the _unnormalized_ Blatt–Weisskopf form factor.\n", + "Following Chung and other resources (see e.g. {cite}`Chung:1995dx`, p. 415), AmpForm implements a unitless, _normalized_ Blatt–Weisskopf factor $B_L$, meaning that $B_L(1)=1$.[^3]\n", + "It can be defined in terms of $F_L$ as\n", + "\n", + "[^3]: We switch to notating angular momentum with $L$ instead of $\\ell$ here to indicate that we are talking about a normalized function here." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "```{math}\n", + "B_L^2(z^2)\n", + " = \\frac{F_L^2(z^2)}{F_L^2(1)}\n", + " = \\frac{\\left|h^{(1)}_L(1)\\right|^2}{z^2\\left|h^{(1)}_L(z)\\right|^2}\\,.\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ":::{note}\n", + "As of writing, AmpForm uses $z$ as argument in [`BlattWeisskopfSquared`](https://ampform.readthedocs.io/0.15.x/api/ampform.dynamics/#ampform.dynamics.BlattWeisskopfSquared).\n", + "This means we have to work with a square root and assume that $z \\geq 0$, meaning\n", + "\n", + "$$\n", + "B_L^2(z) = \\frac{\\left|h^{(1)}_L(1)\\right|^2}{z\\left|h^{(1)}_L\\left(\\sqrt{z}\\right)\\right|^2}\\,.\n", + "$$ (blatt-weisskopf)\n", + "\n", + ":::" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "## Hankel function of the first kind" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "### Built-in SymPy function" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "SymPy offers a Hankel function of the first kind, [`scipy.special.hankel1`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.hankel1.html)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "z = sp.Symbol(\"z\", nonnegative=True, real=True)\n", + "ell = sp.Symbol(R\"\\ell\", integer=True, nonnegative=True)\n", + "sp.hankel1(ell, z)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This function is the general[^1] Hankel function $H_\\ell$ and the class does not offer algebraic simplifications for specific values or assumptions of $\\ell$ and $z$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "display(\n", + " sp.hankel1(ell, z).doit(),\n", + " sp.hankel1(ell, 0).doit(),\n", + " sp.hankel1(0, z).doit(),\n", + " sp.hankel1(0, 0).doit(),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "### Custom class definition" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "To implement Equation {eq}`hankel-sum` for the _spherical_ Hankel function, we have to define a custom [`@unevaluated`](https://ampform.readthedocs.io/0.15.x/api/ampform.sympy/#ampform.sympy.unevaluated) expression class.\n", + "The following class evaluates to the sum given in Equation {eq}`hankel-sum`.\n", + "We introduce a special [`sympy.Sum`](https://docs.sympy.org/latest/modules/concrete.html#sympy.concrete.summations.Sum) class that does not 'unfold' on symbolic input for $\\ell$ if [`doit()`](https://docs.sympy.org/latest/modules/core.html#sympy.core.basic.Basic.doit) is called (see [](#nested-doit))." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "scroll-input" + ] + }, + "outputs": [], + "source": [ + "@unevaluated\n", + "class SphericalHankel1(sp.Expr):\n", + " l: sp.Symbol | int\n", + " z: sp.Symbol | float\n", + " _latex_repr_ = R\"h_{{{l}}}^{{(1)}}\\left({z}\\right)\"\n", + "\n", + " def evaluate(self) -> sp.Expr:\n", + " l, z = self.args\n", + " k = sp.Dummy(\"k\", integer=True, nonnegative=True)\n", + " return (\n", + " (-sp.I) ** (1 + l)\n", + " * (sp.exp(z * sp.I) / z)\n", + " * SymbolicSum(\n", + " sp.factorial(l + k)\n", + " / (sp.factorial(l - k) * sp.factorial(k))\n", + " * (sp.I / (2 * z)) ** k,\n", + " (k, 0, l),\n", + " )\n", + " )\n", + "\n", + "\n", + "class SymbolicSum(sp.Sum):\n", + " def doit(self, deep: bool = True, **kwargs) -> sp.Expr:\n", + " if _get_indices(self):\n", + " expression = self.args[0]\n", + " indices = self.args[1:]\n", + " return SymbolicSum(expression.doit(deep=deep, **kwargs), *indices)\n", + " return super().doit(deep=deep, **kwargs)\n", + "\n", + "\n", + "@lru_cache(maxsize=None)\n", + "def _get_indices(expr: sp.Sum) -> set[sp.Symbol]:\n", + " free_symbols = set()\n", + " for index in expr.args[1:]:\n", + " free_symbols.update(index.free_symbols)\n", + " return {s for s in free_symbols if not isinstance(s, sp.Dummy)}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "jupyter": { + "source_hidden": true + }, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "hide-input" + ] + }, + "outputs": [], + "source": [ + "h1lz = SphericalHankel1(ell, z)\n", + "Math(aslatex({h1lz: h1lz.doit()}))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Indeed, the absolute squared value $\\left|h_\\ell^{(1)}\\right|^2$ results in a clean fraction of polynomials (after some algebraic [simplifications](https://docs.sympy.org/latest/tutorials/intro-tutorial/simplification.html))." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "jupyter": { + "source_hidden": true + }, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "hide-input" + ] + }, + "outputs": [], + "source": [ + "exprs = [sp.Abs(h1lz.xreplace({ell: i})) ** 2 for i in range(3)]\n", + "Math(aslatex({e: e.doit().simplify() for e in exprs}))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "jupyter": { + "source_hidden": true + }, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "hide-input" + ] + }, + "outputs": [], + "source": [ + "exprs = [sp.Abs(h1lz.xreplace({ell: i, z: 1})) ** 2 for i in range(3)]\n", + "Math(aslatex({e: e.doit() for e in exprs}))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "## Normalized Blatt–Weisskopf form factor" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "We now have the required expression classes for re-implementing [`BlattWeisskopfSquared`](https://ampform.readthedocs.io/0.15.x/api/ampform.dynamics/#ampform.dynamics.BlattWeisskopfSquared) using Equation {eq}`blatt-weisskopf` (with $z$ as input, instead of $z^2$)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "@unevaluated\n", + "class BlattWeisskopfSquared(sp.Expr):\n", + " L: sp.Symbol | int\n", + " z: sp.Symbol | float\n", + " _latex_repr_ = R\"B^2_{{{L}}}\\left({z}\\right)\"\n", + "\n", + " def evaluate(self) -> sp.Expr:\n", + " L = self.L\n", + " z = sp.Dummy(\"z\", nonnegative=True, real=True)\n", + " expr = (\n", + " sp.Abs(SphericalHankel1(L, 1)) ** 2\n", + " / sp.Abs(SphericalHankel1(L, sp.sqrt(z))) ** 2\n", + " / z\n", + " )\n", + " if not L.free_symbols:\n", + " expr = expr.doit().simplify()\n", + " return expr.xreplace({z: self.z})" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + ":::{note}\n", + "An explicit [`simplify()`](https://docs.sympy.org/latest/tutorials/intro-tutorial/simplification.html#simplify) is required in order to reproduce the polynomial form upon evaluation.\n", + "To make the simplification as fast as possible, it is done internally within `evaluate()` with $z$ as a dummy variable.\n", + "This is to avoid performing nested simplifications if $z$ is in itself an expression (see [](#nested-doit)).\n", + ":::" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "jupyter": { + "source_hidden": true + }, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "hide-input" + ] + }, + "outputs": [], + "source": [ + "L = sp.Symbol(\"L\", integer=True, nonnegative=True)\n", + "BL2 = BlattWeisskopfSquared(L, z)\n", + "Math(aslatex({BL2: BL2.doit(deep=False)}))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "Indeed the polynomials are exactly the same as the [original `BlattWeisskopfSquared`](https://ampform.readthedocs.io/0.15.x/api/ampform.dynamics/#ampform.dynamics.BlattWeisskopfSquared)!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "jupyter": { + "source_hidden": true + }, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "hide-input" + ] + }, + "outputs": [], + "source": [ + "exprs = [BL2.xreplace({L: i}) for i in range(9)]\n", + "Math(aslatex({e: e.doit() for e in exprs}))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "## Nested doit" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "Eventually, the barrier factors take $z=q/q_R$, with $q$ the break-up momentum and $q_R$ an impact factor. Here it becomes crucial that only $\\left|h_\\ell^{(1)}(z)\\right|^2$ is simplified to a polynomial fraction, not $q$ itself. The break-up momentum does need to unfold though." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "jupyter": { + "source_hidden": true + }, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "hide-input" + ] + }, + "outputs": [], + "source": [ + "s, m1, m2, qR = sp.symbols(\"s m1 m2 q_R\", nonnegative=True)\n", + "q2 = BreakupMomentumSquared(s, m1, m2)\n", + "Math(aslatex({q2: q2.doit()}))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "### Symbolic angular momentum" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "BlattWeisskopfSquared(L, z=q2 / qR**2).doit(deep=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "full-width" + ] + }, + "outputs": [], + "source": [ + "BlattWeisskopfSquared(L, z=q2 / qR**2).doit(deep=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "### Numeric angular momentum" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "BlattWeisskopfSquared(L=2, z=q2 / qR**2).doit(deep=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "full-width" + ] + }, + "outputs": [], + "source": [ + "BlattWeisskopfSquared(L=2, z=q2 / qR**2).doit(deep=True)" + ] + } + ], + "metadata": { + "colab": { + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}