From 750a6125a98b7bafbbb71b106b114e3b6982bf50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ne=C4=8Dada?= Date: Tue, 9 Jul 2019 20:25:29 +0300 Subject: [PATCH] Overview of Legendre function and spherical harmonics conventions. Former-commit-id: 163846444cce82f34982d67ab7ab0b951c20e29e --- README.md | 5 ++- TODO.md | 3 ++ notes/Electrodynamics.bib | 17 +++++++- notes/conventions.md | 79 ++++++++++++++++++++++++++++++++++-- notes/mathjax_newcommands.js | 11 ++++- tests/gsl_leg_phase.c | 22 ++++++++++ 6 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 tests/gsl_leg_phase.c diff --git a/README.md b/README.md index 925623c..c3faf3f 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,9 @@ Infinite systems (lattices) Installation ============ -The package depends on several python modules and GSL (>= 2.0). +The package depends on several python modules, a BLAS/LAPACK library with +the respective C bindings (incl. the `lapacke.h` and `cblas.h` headers; +[OpenBLAS][OpenBLAS] does have it all and is recommended) and GSL (>= 2.0). The python module dependencies should be installed automatically when running the installation script. If you have a recent enough OS, you can get GSL easily from the repositories; on Debian and derivatives, @@ -84,6 +86,7 @@ Tutorials * [Finite system tutorial][tutorial-finite] [SCUFF-EM]: https://homerreid.github.io/scuff-em-documentation/ +[OpenBLAS]: https://www.openblas.net/ [GSL]: https://www.gnu.org/software/gsl/ [cmake]: https://cmake.org [TRITON-README]: README.Triton.md diff --git a/TODO.md b/TODO.md index 026d624..d9792ce 100644 --- a/TODO.md +++ b/TODO.md @@ -25,5 +25,8 @@ TODO list before public release - Prefix all identifiers. Maybe think about a different prefix than qpms? - Consistent indentation and style overall. +Nice but less important features +-------------------------------- +- Static, thread-safe caches of constant coefficients + API without the current "calculators". diff --git a/notes/Electrodynamics.bib b/notes/Electrodynamics.bib index cb5ccd8..56c9269 100644 --- a/notes/Electrodynamics.bib +++ b/notes/Electrodynamics.bib @@ -1733,6 +1733,13 @@ The anapole is an intriguing example of a nonradiating source useful in the stud file = {/u/46/necadam1/unix/.mozilla/firefox/6m8fw48s.default/zotero/storage/Q7ZEETFQ/Kristensson ja Waterman - 1982 - The T matrix for acoustic and electromagnetic scat.pdf;/u/46/necadam1/unix/.mozilla/firefox/6m8fw48s.default/zotero/storage/XAQLYYR5/1.html} } +@article{NIST:DLMF, + title = {{{NIST Digital Library}} of {{Mathematical Functions}}}, + url = {http://dlmf.nist.gov/}, + key = {DLMF}, + note = {F.~W.~J. Olver, A.~B. Olde Daalhuis, D.~W. Lozier, B.~I. Schneider, R.~F. Boisvert, C.~W. Clark, B.~R. Miller and B.~V. Saunders, eds.} +} + @article{enoch_sums_2001, title = {Sums of Spherical Waves for Lattices, Layers, and Lines}, volume = {42}, @@ -1813,7 +1820,7 @@ The anapole is an intriguing example of a nonradiating source useful in the stud author = {Kristensson, Gerhard}, month = jul, year = {2016}, - file = {/u/46/necadam1/unix/.mozilla/firefox/6m8fw48s.default/zotero/storage/3R7VYZUK/Kristensson - 2016 - Scattering of Electromagnetic Waves by Obstacles.pdf} + file = {/u/46/necadam1/unix/.mozilla/firefox/6m8fw48s.default/zotero/storage/ZRYZ4KLK/Kristensson - 2016 - Scattering of Electromagnetic Waves by Obstacles.pdf} } @article{kristensson_priori_2015, @@ -1940,4 +1947,12 @@ expansion in terms of Cartesian multipole moments under the rigidity approximati file = {/u/46/necadam1/unix/.mozilla/firefox/6m8fw48s.default/zotero/storage/NIQFEUGY/Nemkov ym. - 2018 - Electromagnetic sources beyond common multipoles.pdf;/u/46/necadam1/unix/.mozilla/firefox/6m8fw48s.default/zotero/storage/9SYKXLI3/PhysRevA.98.html} } +@misc{GSL, + title = {{{GNU Scientific Library}} \textemdash{} {{GSL}} 2.5 Documentation}, + urldate = {2019-07-09}, + file = {/u/46/necadam1/unix/.mozilla/firefox/6m8fw48s.default/zotero/storage/TG3YNXVC/index.html}, + url = {http://dlmf.nist.gov/}, + key = {GSL} +} + diff --git a/notes/conventions.md b/notes/conventions.md index 60b1dc6..d5ac868 100644 --- a/notes/conventions.md +++ b/notes/conventions.md @@ -27,18 +27,89 @@ Let us define the "dual" vector spherical harmonics \f$ \vshD_{\tau lm} \f$ as f where the \f$ \cdot \f$ symbol here means the bilinear form of the vector components without complex conjugation (which is included in the "duality" mapping). -For the sake of non-ambiguity, let us define the "canonical" associated Legendre polynomials -as in \cite DLMF TODO exact refs: +The problem with conventions starts with the very definition of associated Legendre / Ferrers functions. + +For the sake of non-ambiguity, let us first define the "canonical" associated Legendre/Ferrers polynomials +*without* the Condon-Shortley phase. \f[ \rawLeg{l}{0}(x) = \frac{1}{2^n n!} \frac{\ud^n}{\ud x^n} \pr{x^2-1}^n , \\ \rawLeg{l}{m}(x) = \pr{1-x^2}^{m/2} \frac{\ud^m}{\ud x^m} \rawLeg{l}{0},\quad\abs{x}\le 1, m \ge 0, \\ \rawLeg{l}{m}(x) = (-1)^\abs{m} \frac{(l-\abs{m})!}{(l+\abs{m})!} \rawLeg{l}{\abs{m}}, \quad \abs{x} \le 1, m < 0. \f] +DLMF \cite NIST:DLMF has for non-negative integer \f$m\f$ (18.5.5), (14.6.1), (14.9.3): +\f[ + \dlmfFer{\nu}{} = \dlmfLeg{\nu}{} = \frac{1}{2^n n!} \frac{\ud^n}{\ud x^n} \pr{x^2-1}^n , \\ + \dlmfFer{\nu}{m}\left(x\right)=(-1)^{m}\left(1-x^2\right)^{m/2}\frac{{ + \ud}^{m}\dlmfFer{\nu}{}\left(x\right)}{{\ud x}^{m}},\\ + %\dlmfLeg{\nu}{m}\left(x\right)=\left(-1+x^2\right)^{m/2}\frac{{ + %\ud}^{m}\dlmfLeg{\nu}{}\left(x\right)}{{\ud x}^{m}},\\ +\f] +where the connection to negative orders is +\f[ + \dlmfFer{\nu}{m}(x) = (-1)^m \frac{\Gamma\pr{\nu-m+1}}{\Gamma\pr{\nu+m+1}}\dlmfFer{\nu}{m}(x),\\ + %\dlmfLeg{\nu}{m}(x) = \frac{\Gamma\pr{\nu-m+1}}{\Gamma\pr{\nu+m+1}}\dlmfLeg{\nu}{m}(x).\\ +\f] +Note that there are called "Ferrers" functions in DLMF, while the "Legendre" functions have slightly +different meaning / conventions (Ferrers functions being defined for \f$ \abs{x} \le 1 \f$, whereas +Legendre for \f$ \abs{x} \ge 1 \f$. We will not use the DLMF "Legendre" functions here. + +One sees that \f$ \dlmfFer{l}{m} = (-1)^m \rawFer{l}{m} \f$, i.e. the Condon-Shortley phase is +already included in the DLMF definitions of Ferrers functions. + +GSL computes \f$ \rawFer{l}{m} \f$ unless the corresponding `csphase` argument is set to +\f$-1\f$ (then it computes \f$ \dlmfFer{l}{m} \f$). This is not explicitly obvious from the docs +\cite GSL, +but can be tested by running `gsl_sf_legendre_array_e` for some specific arguments and comparing signs. -Literature convention table ---------------------------- +Literature convention tables +---------------------------- + +### Legendre functions and spherical harmonics + +| Source | Ferrers function | Negative \f$m\f$ | Spherical harmonics | +|------------------------|-----------------------|--------------------|---------------------| +| DLMF \cite NIST:DLMF | \f[ + \dlmfFer{\nu}{m}\left(x\right)=(-1)^{m}\left(1-x^2\right)^{m/2}\frac{{ + \ud}^{m}\dlmfFer{\nu}{}\left(x\right)}{{\ud x}^{m}} + \f] | \f[ + \dlmfFer{\nu}{m}(x) = (-1)^m \frac{\Gamma\pr{\nu-m+1}}{\Gamma\pr{\nu+m+1}}\dlmfFer{\nu}{m}(x) + \f] | Complex (14.30.1): \f[ + \dlmfYc{l}{m} = \sqrt{\frac{(l-m)!(2l+1)}{4\pi(l+m)!}} e^{im\phi} \dlmfFer{l}{m}(\cos\theta). + \f] Real, unnormalized (14.30.2): \f$ + \dlmfYrUnnorm{l}{m}\pr{\theta,\phi} = \cos\pr{m\phi} \dlmfFer{l}{m}\pr{\cos\theta} + \f$ or \f$ + \dlmfYrUnnorm{l}{m}\pr{\theta,\phi} = \sin\pr{m\phi} \dlmfFer{l}{m}\pr{\cos\theta} + \f$. | +| GSL \cite GSL | \f[ + \Fer[GSL]{l}{m} = \csphase^m N \rawFer{l}{m} + \f] for non-negative \f$m\f$. \f$ + \csphase\f$ is one by default and can be set to \f$ + -1\f$ using the functions ending with \_e with argument `csphase = -1`. \f$ + N\f$ is a positive normalisation factor from from `gsl_sf_legendre_t`. | N/A. Must be calculated manually. | The asimuthal part must be calculated manually. Use `norm = GSL_SF_LEGENDRE_SPHARM` to get the usual normalisation factor \f$ + N= \sqrt{\frac{(l-m)!(2l+1)}{4\pi(l+m)!}} \f$. | +| Kristensson I \cite kristensson_spherical_2014 | \f$ \rawFer{l}{m} \f$ | As in \f$ \rawFer{l}{m} \f$. | \f[ + \spharm[Kc]{l}{m} = (-1)^m \sqrt{\frac{(l-m)!(2l+1)}{4\pi(l+m)!}} \rawFer{l}{m}(\cos\theta) e^{im\phi}, + \f] cf. Sec. D.2. | +| Kristensson II \cite kristensson_scattering_2016 | \f$ \rawFer{l}{m} \f$ | As in \f$ \rawFer{l}{m} \f$. | \f[ + \spharm[Kr]{\begin{Bmatrix}e \\ o\end{Bmatrix}}{l}{m} = + \sqrt{2-\delta_{m0}}\sqrt{\frac{(l-m)!(2l+1)}{4\pi(l+m)!}} + \rawFer{l}{m}(\cos\theta) + \begin{Bmatrix}\cos\phi \\ \sin\phi\end{Bmatrix}, + \f] \f$ m \ge 0 \f$. Cf. Appendix C.3. | +| Reid \cite reid_electromagnetism_2016 | Not described in the memos. Superficial look into the code suggests that the `GetPlm` function *does* include the Condon-Shortley phase and spherical harmonic normalisation, so \f[ + \Fer[GetPlm]{l}{m} = (-1)^m \sqrt{\frac{(l-m)!(2l+1)}{4\pi(l+m)!}} \rawFer{l}{m} +\f] for non-negative \f$ m \f$. | N/A. Must be calculated manually. | \f[ + \spharm[GetYlm]{l}{m}(\theta,\phi) = \Fer[GetPlm]{l}{m}(\cos\theta) e^{im\phi},\quad m\le 0, \\ + \spharm[GetYlm]{l}{m}(\theta,\phi) = (-1)^m\Fer[GetPlm]{l}{\abs{m}}(\cos\theta) e^{-im\phi},\quad m<0, + \f] and the negative sign in the second line's exponent is quite concerning, because that would mean the asimuthal part is actually \f$ e^{i\abs{m}\phi} \f$. _Is this a bug in scuff-em_? Without it, it would be probably equivalent to DLMF's \f$ \dlmfYc{l}{m} \f$s for both positive and negative \f$ m\f$s. However, it seems that `GetYlmDerivArray` has it consistent, with \f[ + \spharm[GetYlmDerivArray]{l}{m} = \dlmfYc{l}{m} + \f] for all \f$m\f$, and this is what is actually used in `GetMNlmArray` (used by both `SphericalWave` in `libIncField` (via `GetMNlm`) and `GetSphericalMoments` in `libscuff` (via `GetWaveMatrix`)) and `GetAngularFunctionArray` (not used). | + + + +### VSWF conventions | Source | VSWF definition | E/M interrelations | VSWF norm | CS Phase | Field expansion | Radiated power | Notes | |--- |--- |--- |--- |--- |--- |--- |--- | diff --git a/notes/mathjax_newcommands.js b/notes/mathjax_newcommands.js index 89ac46f..bb0b271 100644 --- a/notes/mathjax_newcommands.js +++ b/notes/mathjax_newcommands.js @@ -21,7 +21,16 @@ MathJax.Hub.Config({ wfe: "{\\mathbf{N}}", // Electric wave general wfm: "{\\mathbf{M}}", // Magnetic wave general sphbes: "{z}", // General spherical Bessel fun - rawLeg: ["{P_{#1}^{#2}}", 2], // "Canonical" associated Legendre polynomial + rawLeg: ["{\\mathfrak{P}_{#1}^{#2}}", 2], // "Canonical" associated Legendre polynomial without C.S. phase + rawFer: ["\\rawLeg{#1}{#2}", 2], // "Canonical" associated Legendre polynomial without C.S. phase + dlmfLeg: ["{P_{#1}^{#2}}", 2], // Associated Legendre function as in DLMF (14.3.6) + dlmfFer: ["{\\mathsf{P}_{#1}^{#2}}", 2], // Ferrers Function as in DLMF (14.3.1) + dlmfYc: ["{Y_{{#1},{#2}}}", 2], // Complex spherical harmonics as in DLMF (14.30.1) + dlmfYrUnnorm: ["{Y_{#1}^{#2}}", 2], // Real spherical harmonics as in DLMF (14.30.2) + Fer: ["{{P_{\\mathrm{#1}}}_{#2}^{#3}}", 3, ""], // Legendre / Ferrers function + spharm: ["{{Y_{\\mathrm{#1}}}_{#2}^{#3}}", 3, ""], // Spherical harmonics + spharmR: ["{{Y_{\\mathrm{#1}}}_{\\mathrm{#1}{#2}{#3}}", 4, ""], // Spherical harmonics + csphase: "\\mathsf{C_{CS}}", // Condon-Shortley phase // Kristensson's VSWFs, complex version (2014 notes) wfkcreg: "{\\vect{v}}", // regular wave diff --git a/tests/gsl_leg_phase.c b/tests/gsl_leg_phase.c new file mode 100644 index 0000000..72ef092 --- /dev/null +++ b/tests/gsl_leg_phase.c @@ -0,0 +1,22 @@ +#include +#include +#include + +int main() { + const size_t lmax = 2; + const double x = .5; + size_t arrsiz = gsl_sf_legendre_array_n(lmax); + double csphase = 1; + double target[arrsiz]; + printf("lmax = %zd, x = %g, csphase = %g:\n", lmax, x, csphase); + gsl_sf_legendre_array_e(GSL_SF_LEGENDRE_NONE, lmax, x, csphase, target); + for(int l = 0; l <= lmax; ++l) for (int m = 0; m <= l; ++m) + printf("P_%d^%d(%g)\t= %g\n", l, m, x, target[gsl_sf_legendre_array_index(l,m)]); + csphase = -1; + printf("lmax = %zd, x = %g, csphase = %g:\n", lmax, x, csphase); + gsl_sf_legendre_array_e(GSL_SF_LEGENDRE_NONE, lmax, x, csphase, target); + for(int l = 0; l <= lmax; ++l) for (int m = 0; m <= l; ++m) + printf("P_%d^%d(%g)\t= %g\n", l, m, x, target[gsl_sf_legendre_array_index(l,m)]); + return 0; +} +