diff --git a/previews/PR49/.documenter-siteinfo.json b/previews/PR49/.documenter-siteinfo.json index 83dc1e8..8074294 100644 --- a/previews/PR49/.documenter-siteinfo.json +++ b/previews/PR49/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.11.2","generation_timestamp":"2024-12-24T05:47:17","documenter_version":"1.8.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.11.2","generation_timestamp":"2024-12-24T05:49:25","documenter_version":"1.8.0"}} \ No newline at end of file diff --git a/previews/PR49/conventions/comparisons/index.html b/previews/PR49/conventions/comparisons/index.html index fe550d9..ee1226b 100644 --- a/previews/PR49/conventions/comparisons/index.html +++ b/previews/PR49/conventions/comparisons/index.html @@ -1,2 +1,2 @@ -Comparisons ยท SphericalFunctions.jl

Comparisons

Here, we compare our conventions to other sources, including references in the literature as well as other software that implements some of these. Each of these comparisons is also performed explicitly in this package's test suite.

Among the items that would be good to compare are the following, when actually used by any of these sources:

  • Quaternions
    • Order of components
    • Basis
    • Operation as rotations
  • Euler angles
  • Spherical coordinates
  • Spherical harmonics
    • Condon-Shortley phase
    • Formula
  • Spin-weighted spherical harmonics
    • Behavior under rotation
  • Wigner D-matrices
    • Order of indices
    • Conjugation
    • Function of rotation or inverse rotation
    • Formula

One major result of this is that almost everyone since 1935 has used the same exact expression for the (scalar) spherical harmonics.

Condon-Shortley

Wigner

Newman-Penrose

Goldberg

Wikipedia

Mathematica

SymPy

Sakurai

Thorne

Torres del Castillo

NINJA

LALSuite

+Comparisons ยท SphericalFunctions.jl

Comparisons

Here, we compare our conventions to other sources, including references in the literature as well as other software that implements some of these. Each of these comparisons is also performed explicitly in this package's test suite.

Among the items that would be good to compare are the following, when actually used by any of these sources:

  • Quaternions
    • Order of components
    • Basis
    • Operation as rotations
  • Euler angles
  • Spherical coordinates
  • Spherical harmonics
    • Condon-Shortley phase
    • Formula
  • Spin-weighted spherical harmonics
    • Behavior under rotation
  • Wigner D-matrices
    • Order of indices
    • Conjugation
    • Function of rotation or inverse rotation
    • Formula

One major result of this is that almost everyone since 1935 has used the same exact expression for the (scalar) spherical harmonics.

Condon-Shortley

Wigner

Newman-Penrose

Goldberg

Wikipedia

Mathematica

SymPy

Sakurai

Thorne

Torres del Castillo

NINJA

LALSuite

diff --git a/previews/PR49/conventions/conventions/index.html b/previews/PR49/conventions/conventions/index.html index f5a701c..f8ed919 100644 --- a/previews/PR49/conventions/conventions/index.html +++ b/previews/PR49/conventions/conventions/index.html @@ -1,13 +1,42 @@ -Conventions ยท SphericalFunctions.jl

Conventions

In the following subsections, we work through all the conventions used in this package, starting from first principles to motivate the choices and ensure that each step is on firm footing. First, we can just list the most important conventions. Note that we will use Euler angles and spherical coordinates here. It is almost always a bad idea to use Euler angles in computing; quaternions are clearly the preferred representation for numerous reasons. However, Euler angles are important for (a) comparing to other sources, and (b) performing analytic integrations. These are the only two uses we will make of Euler angles.

  1. Right-handed Cartesian coordinates $(x, y, z)$ and unit basis vectors $(๐ฑ, ๐ฒ, ๐ณ)$.
  2. Spherical coordinates $(r, \theta, \phi)$ and unit basis vectors $(๐ซ, \boldsymbol{\theta}, \boldsymbol{\phi})$. The "polar angle" $\theta \in [0, \pi]$ measures the angle between the specified direction and the positive $๐ณ$ axis. The "azimuthal angle" $\phi \in [0, 2\pi)$ measures the angle between the projection of the specified direction onto the $๐ฑ$-$๐ฒ$ plane and the positive $๐ฑ$ axis, with the positive $๐ฒ$ axis corresponding to the positive angle $\phi = \pi/2$.
  3. Quaternions $๐ = W + X๐ข + Y๐ฃ + Z๐ค$, where $๐ข๐ฃ๐ค = -1$. In software, this quaternion is represented by $(W, X, Y, Z)$. We will depict a three-dimensional vector $๐ฏ = v_x ๐ฑ + v_y ๐ฒ + v_z ๐ณ$ interchangeably as a quaternion $v_x ๐ข + v_y ๐ฃ + v_z ๐ค$.
  4. A rotation represented by the unit quaternion $๐‘$ acts on a vector $๐ฏ$ as $๐‘\, ๐ฏ\, ๐‘^{-1}$.
  5. Where relevant, rotations will be assumed to be right-handed, so that a quaternion characterizing the rotation through an angle $\vartheta$ about a unit vector $๐ฎ$ can be expressed as $๐‘ = \exp(\vartheta ๐ฎ/2)$. Note that $-๐‘$ would deliver the same rotation, which is why the group of unit quaternions $\mathrm{Spin}(3) = \mathrm{SU}(2)$ is a double cover of the group of rotations $\mathrm{SO}(3)$.
  6. Euler angles parametrize a unit quaternion as $๐‘ = \exp(\alpha ๐ค/2)\, \exp(\beta ๐ฃ/2)\, \exp(\gamma ๐ค/2)$. The angles $\alpha$ and $\beta$ take values in $[0, 2\pi)$. The angle $\beta$ takes values in $[0, 2\pi]$ to parametrize the group of unit quaternions $\mathrm{Spin}(3) = \mathrm{SU}(2)$, or in $[0, \pi]$ to parametrize the group of rotations $\mathrm{SO}(3)$.
  7. A point on the unit sphere with spherical coordinates $(\theta, \phi)$ can be represented by Euler angles $(\alpha, \beta, \gamma) = (\phi, \theta, 0)$. The rotation with these Euler angles takes the positive $๐ณ$ axis to the specified direction. In particular, any function of spherical coordinates can be promoted to a function on Euler angles using this identification.
  8. For a complex-valued function $f(๐‘)$, we define two operators, the left and right Lie derivatives:

    \[L_๐ฎ f(๐‘) = \left.-i \frac{d}{d\epsilon}\right|_{\epsilon=0} +Conventions ยท SphericalFunctions.jl

    Conventions

    In the following subsections, we work through all the conventions used in this package, starting from first principles to motivate the choices and ensure that each step is on firm footing. First, we can just list the most important conventions. Note that we will use Euler angles and spherical coordinates here. It is almost always a bad idea to use Euler angles in computing; quaternions are clearly the preferred representation for numerous reasons. However, Euler angles are important for (a) comparing to other sources, and (b) performing analytic integrations. These are the only two uses we will make of Euler angles.

    1. Right-handed Cartesian coordinates $(x, y, z)$ and unit basis vectors $(๐ฑ, ๐ฒ, ๐ณ)$.

    2. Spherical coordinates $(r, \theta, \phi)$ and unit basis vectors $(๐ซ, \boldsymbol{\theta}, \boldsymbol{\phi})$. The "polar angle" $\theta \in [0, \pi]$ measures the angle between the specified direction and the positive $๐ณ$ axis. The "azimuthal angle" $\phi \in [0, 2\pi)$ measures the angle between the projection of the specified direction onto the $๐ฑ$-$๐ฒ$ plane and the positive $๐ฑ$ axis, with the positive $๐ฒ$ axis corresponding to the positive angle $\phi = \pi/2$.

    3. Quaternions $๐ = W + X๐ข + Y๐ฃ + Z๐ค$, where $๐ข๐ฃ๐ค = -1$. In software, this quaternion is represented by $(W, X, Y, Z)$. We will depict a three-dimensional vector $๐ฏ = v_x ๐ฑ + v_y ๐ฒ + v_z ๐ณ$ interchangeably as a quaternion $v_x ๐ข + v_y ๐ฃ + v_z ๐ค$.

    4. A rotation represented by the unit quaternion $๐‘$ acts on a vector $๐ฏ$ as $๐‘\, ๐ฏ\, ๐‘^{-1}$.

    5. Where relevant, rotations will be assumed to be right-handed, so that a quaternion characterizing the rotation through an angle $\vartheta$ about a unit vector $๐ฎ$ can be expressed as $๐‘ = \exp(\vartheta ๐ฎ/2)$. Note that $-๐‘$ would deliver the same rotation, which is why the group of unit quaternions $\mathrm{Spin}(3) = \mathrm{SU}(2)$ is a double cover of the group of rotations $\mathrm{SO}(3)$.

    6. Euler angles parametrize a unit quaternion as $๐‘ = \exp(\alpha ๐ค/2)\, \exp(\beta ๐ฃ/2)\, \exp(\gamma ๐ค/2)$. The angles $\alpha$ and $\beta$ take values in $[0, 2\pi)$. The angle $\beta$ takes values in $[0, 2\pi]$ to parametrize the group of unit quaternions $\mathrm{Spin}(3) = \mathrm{SU}(2)$, or in $[0, \pi]$ to parametrize the group of rotations $\mathrm{SO}(3)$.

    7. A point on the unit sphere with spherical coordinates $(\theta, \phi)$ can be represented by Euler angles $(\alpha, \beta, \gamma) = (\phi, \theta, 0)$. The rotation with these Euler angles takes the positive $๐ณ$ axis to the specified direction. In particular, any function of spherical coordinates can be promoted to a function on Euler angles using this identification.

    8. For a complex-valued function $f(๐‘)$, we define two operators, the left and right Lie derivatives:

      \[L_๐ฎ f(๐‘) = \left.-i \frac{d}{d\epsilon}\right|_{\epsilon=0} f\left(e^{\epsilon ๐ฎ/2}\, ๐‘\right) \qquad \text{and} \qquad R_๐ฎ f(๐‘) = \left.-i \frac{d}{d\epsilon}\right|_{\epsilon=0} -f\left(๐‘\, e^{\epsilon ๐ฎ/2}\right),\]

      where $๐ฎ$ can be any pure-vector quaternion. In particular, $L$ represents the standard angular-momentum operators, and we can compute the expressions in Euler angles for the basis vectors:

      \[\begin{aligned} -L_x = L_๐ข &= -i \left( \sin\alpha \frac{\partial}{\partial\beta} + \cos\alpha \cot\beta \frac{\partial}{\partial\alpha} \right), \\ -L_y = L_๐ฃ &= -i \left( \cos\alpha \frac{\partial}{\partial\beta} - \sin\alpha \cot\beta \frac{\partial}{\partial\alpha} \right), \\ -L_z = L_๐ค &= -i \frac{\partial}{\partial\alpha}. -\end{aligned}\]

      Angular-momentum operators defined in Lie terms, translated to Euler angles and spherical coordinates.
    9. Spherical harmonics
    10. Wigner D-matrices
    11. Spin-weighted spherical harmonics

    Three-dimensional space

    The space we are working in is naturally three-dimensional Euclidean space, so we start with a right-handed Cartesian coordinate system $(x, y, z)$. These also give us the unit basis vectors $(๐ฑ, ๐ฒ, ๐ณ)$. Note that these basis vectors are assumed to have unit norm, but we omit the hats just to keep the notation simple. Any vector in this space can be written as

    \[\mathbf{v} = v_x \mathbf{๐ฑ} + v_y \mathbf{๐ฒ} + v_z \mathbf{๐ณ},\]

    in which case the Euclidean norm is given by

    \[\| \mathbf{v} \| = \sqrt{v_x^2 + v_y^2 + v_z^2}.\]

    Equivalently, we can write the components of the Euclidean metric as

    \[g_{ij} = \left( \begin{array}{ccc} +f\left(๐‘\, e^{\epsilon ๐ฎ/2}\right),\]

    where $๐ฎ$ can be any pure-vector quaternion. In particular, $L$ represents the standard angular-momentum operators, and we can compute the expressions in Euler angles for the basis vectors:

    \[\begin{aligned} + L_x = L_๐ข &= -i \left\{ + -\frac{\cos\alpha}{\tan\beta} \frac{\partial} {\partial \alpha} + - \sin\alpha \frac{\partial} {\partial \beta} + +\frac{\cos\alpha}{\sin\beta} \frac{\partial} {\partial \gamma} + \right\} \\ + L_y = L_๐ฃ &= -i \left\{ + -\frac{\sin\alpha}{\tan\beta} \frac{\partial} {\partial \alpha} + + \cos\alpha \frac{\partial} {\partial \beta} + +\frac{\sin\alpha}{\sin\beta} \frac{\partial} {\partial \gamma} + \right\} \\ + L_z = L_๐ค &= -i \frac{\partial} {\partial \alpha} \\ + K_x = K_๐ข &= -i \left\{ + -\frac{\cos\gamma}{\sin\beta} \frac{\partial} {\partial \alpha} + +\sin\gamma \frac{\partial} {\partial \beta} + +\frac{\cos\gamma}{\tan\beta} \frac{\partial} {\partial \gamma} + \right\} \\ + K_y = K_๐ฃ &= -i \left\{ + \frac{\sin\gamma}{\sin\beta} \frac{\partial} {\partial \alpha} + +\cos\gamma \frac{\partial} {\partial \beta} + -\frac{\sin\gamma}{\tan\beta} \frac{\partial} {\partial \gamma} + \right\} \\ + K_z = K_๐ค &= -i \frac{\partial} {\partial \gamma} +\end{aligned}\]

    We can lift any function on $S^2$ to a function on $S^3$ โ€” or more precisely any function on spherical coordinates to a function on the space of Euler angles โ€” by the correspondence $(\theta, \phi) \mapsto (\alpha, \beta, \gamma) = (\phi, \theta, 0)$. We can then express the angular-momentum operators in their more common form, in terms of spherical coordinates:

    \[\begin{aligned} + L_x &= -i \left\{ + -\frac{\cos\phi}{\tan\theta} \frac{\partial} {\partial \phi} + - \sin\phi \frac{\partial} {\partial \theta} + \right\} \\ + L_y &= -i \left\{ + -\frac{\sin\phi}{\tan\theta} \frac{\partial} {\partial \phi} + + \cos\phi \frac{\partial} {\partial \theta} + \right\} \\ + L_z &= -i \frac{\partial} {\partial \phi} +\end{aligned}\]

    (The $R$ operators make less sense for a function of spherical coordinates.)

  9. Spherical harmonics

  10. Wigner D-matrices

  11. Spin-weighted spherical harmonics

Three-dimensional space

The space we are working in is naturally three-dimensional Euclidean space, so we start with a right-handed Cartesian coordinate system $(x, y, z)$. These also give us the unit basis vectors $(๐ฑ, ๐ฒ, ๐ณ)$. Note that these basis vectors are assumed to have unit norm, but we omit the hats just to keep the notation simple. Any vector in this space can be written as

\[\mathbf{v} = v_x \mathbf{๐ฑ} + v_y \mathbf{๐ฒ} + v_z \mathbf{๐ณ},\]

in which case the Euclidean norm is given by

\[\| \mathbf{v} \| = \sqrt{v_x^2 + v_y^2 + v_z^2}.\]

Equivalently, we can write the components of the Euclidean metric as

\[g_{ij} = \left( \begin{array}{ccc} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 @@ -88,4 +117,18 @@ + \cos\rho\, ๐ฏ_โŸ‚ + \sin\rho\, \hat{\mathfrak{r}}\times ๐ฏ_โŸ‚ \end{aligned}\]

The final expression shows that this is precisely what we expect when rotating $๐ฏ$ through an angle $\rho$ (in a positive, right-handed sense) about the axis $\hat{\mathfrak{r}}$.

Note that the presence of two factors of $๐‘$ in the expression for rotating a vector explains two things. First, it explains why the angle of rotation is twice the angle of the quaternion: one factor of $๐‘$ either commutes and cancels or anti-commutes and combines with the the other factor. Second, it explains why the quaternion group is a double cover of the rotation group: negating $๐‘$ results in the same rotation. Thus, for any rotation, there are two (precisely opposite) quaternions that represent it.

Euler angles and spherical coordinates

Now that we understand how rotations work, we can provide geometric intuition for the expressions given above for Euler angles. The Euler angles in our convention represent an initial rotation through $\gamma$ about the $๐ณ$ axis, followed by a rotation through $\beta$ about the $๐ฒ$ axis, and finally a rotation through $\alpha$ about the $๐ณ$ axis. Note that the axes are fixed, and not subject to any preceding rotations. More precisely, we can write the unit quaternion as

\[๐‘ = \exp\left(\frac{\alpha}{2} ๐ค\right) \exp\left(\frac{\beta}{2} ๐ฃ\right) - \exp\left(\frac{\gamma}{2} ๐ค\right).\]

  • 1Note that quaternions will only be spanned by elements made from an even number of the basis vectors. It turns out that those with an odd number will produce reflections, rather than rotations, when acting on a vector โ€” as discussed below. This explains why quaternions are restricted to just those elements with an even number to represent rotations. For details see any geometric algebra text, like Doran and Lasenby.
+ \exp\left(\frac{\gamma}{2} ๐ค\right).\]

One of the more important interpretations of a rotor is considering what it does to the basis triad $(๐ฑ, ๐ฒ, ๐ณ)$. In particular, the vector $๐ณ$ is rotated onto the point given by spherical coordinates $(\theta, \phi) = (\beta, \alpha)$, while $๐ฑ$ and $๐ฒ$ are rotated into the plane spanned by the unit basis vectors $\boldsymbol{\theta}$ and $\boldsymbol{\phi}$ corresponding to that point. If $\gamma = 0$ the rotation is precise, meaning that $๐ฑ$ is rotated onto $\boldsymbol{\theta}$ and $๐ฒ$ onto $\boldsymbol{\phi}$; if $\gamma โ‰  0$ then they are rotated within that plane by the angle $\gamma$ about the $\mathbf{r}$ axis. Thus, we identify the spherical coordinates $(\theta, \phi)$ with the Euler angles $(\alpha, \beta, \gamma) = (\phi, \theta, 0)$.

Rotation and angular-momentum operators

We have defined the spaces $\mathrm{Spin}(3) = \mathrm{SU}(2)$ (topologically $S^3$), $\mathrm{SO}(3)$ (topologically $\mathbb{RP}^3$), and $S^2$. Specifically, we have constructed each of those spaces starting with Cartesian coordinates and the Euclidean norm on $\mathbb{R}^3$, which naturally supplies coordinates on each of those spaces. We will define functions from these spaces (and their corresponding coordinates) to the complex numbers. However, to construct and classify those functions, we will need to define operators on them. We will start with operators transforming them by finite rotations, then differentiate those operators to get the angular-momentum operators.

Angular-momentum operators in Euler angles

The idea here is to express, e.g., $e^{\theta \mathbf{e}_i / 2}\mathbf{R}_{\alpha, \beta, \gamma}$ in quaternion components, then solve for the new Euler angles $\mathbf{R}_{\alpha', \beta', \gamma'}$ in terms of the quaternion components, where these new angles all depend on $\theta$. We then use the chain rule to express $\partial_\theta$ in terms of $\partial_{\alpha'}$, etc., which become $\partial_\alpha$, etc., when $\theta=0$.

\[ +\begin{align} + L_i f(\mathbf{R}) + &= + \left. -\mathbf{z} \frac{\partial} {\partial \theta} f \left( e^{\theta \mathbf{e}_i / 2} \mathbf{R}_{\alpha, \beta, \gamma} \right) \right|_{\theta=0} \\ + &= + \left. -\mathbf{z} \frac{\partial} {\partial \theta} f \left( \mathbf{R}_{\alpha', \beta', \gamma'} \right) \right|_{\theta=0} \\ + &= + \left. -\mathbf{z} \left[ \frac{\partial \alpha'} {\partial \theta}\frac{\partial} {\partial \alpha'} + \frac{\partial \beta'} {\partial \theta}\frac{\partial} {\partial \beta'} + \frac{\partial \gamma'} {\partial \theta}\frac{\partial} {\partial \gamma'} \right] f \left( \mathbf{R}_{\alpha', \beta', \gamma'} \right) \right|_{\theta=0} \\ + &= + -\mathbf{z} \left[ \frac{\partial \alpha'} {\partial \theta}\frac{\partial} {\partial \alpha} + \frac{\partial \beta'} {\partial \theta}\frac{\partial} {\partial \beta} + \frac{\partial \gamma'} {\partial \theta}\frac{\partial} {\partial \gamma} \right]_{\theta=0} f \left( \mathbf{R}_{\alpha, \beta, \gamma} \right) \\ + K_i f(\mathbf{R}) + &= + -\mathbf{z} \left[ \frac{\partial \alpha''} {\partial \theta}\frac{\partial} {\partial \alpha} + \frac{\partial \beta''} {\partial \theta}\frac{\partial} {\partial \beta} + \frac{\partial \gamma''} {\partial \theta}\frac{\partial} {\partial \gamma} \right]_{\theta=0} f \left( \mathbf{R}_{\alpha, \beta, \gamma} \right), +\end{align}\]

diff --git a/previews/PR49/conventions/outline/index.html b/previews/PR49/conventions/outline/index.html index ae5d208..dbd6c62 100644 --- a/previews/PR49/conventions/outline/index.html +++ b/previews/PR49/conventions/outline/index.html @@ -70,4 +70,4 @@ &= ๐‘\, ๐ฏ\, ๐ฏ\, ๐‘^{-1} \\ &= \|๐ฏ\|^2\, ๐‘\, ๐‘^{-1} \\ &= \|๐ฏ\|^2 -\end{aligned}\]

That is, $๐ฏ' = ๐‘\, ๐ฏ\, ๐‘^{-1}$ has the same norm as $๐ฏ$, which means that $๐ฏ'$ is a rotation of $๐ฏ$. Given the constraint on the norm of $๐‘$, we can rewrite it as

+\end{aligned}\]

That is, $๐ฏ' = ๐‘\, ๐ฏ\, ๐‘^{-1}$ has the same norm as $๐ฏ$, which means that $๐ฏ'$ is a rotation of $๐ฏ$. Given the constraint on the norm of $๐‘$, we can rewrite it as

diff --git a/previews/PR49/functions/index.html b/previews/PR49/functions/index.html index 505aefe..ff6c9de 100644 --- a/previews/PR49/functions/index.html +++ b/previews/PR49/functions/index.html @@ -1,2 +1,2 @@ -Complete function list ยท SphericalFunctions.jl

Complete function list

The following list contains all documented functions inside the SphericalFunctions module.

+Complete function list ยท SphericalFunctions.jl

Complete function list

The following list contains all documented functions inside the SphericalFunctions module.

diff --git a/previews/PR49/index.html b/previews/PR49/index.html index 74f7b3c..68e9795 100644 --- a/previews/PR49/index.html +++ b/previews/PR49/index.html @@ -1,2 +1,2 @@ -Introduction ยท SphericalFunctions.jl

Introduction

This is a Julia package for evaluating and transforming Wigner's ๐”‡ matrices, and spin-weighted spherical harmonics ${}_{s}Y_{\ell,m}$ (which includes the ordinary scalar spherical harmonics). Because both ๐”‡ and the harmonics are most correctly considered functions on the rotation group $๐’๐Ž(3)$ โ€” or more generally, the spin group $๐’๐ฉ๐ข๐ง(3)$ that covers it โ€” these functions are evaluated directly in terms of quaternions. Concessions are also made for more standard forms of spherical coordinates and Euler angles.[1] Among other applications, those functions permit "synthesis" (evaluation of the spin-weighted spherical functions) of spin-weighted spherical harmonic coefficients on regular or distorted grids. This package also includes functions enabling efficient "analysis" (decomposition into mode coefficients) of functions evaluated on regular grids to high order and accuracy.

These quantities are computed using recursion relations, which makes it possible to compute to very high โ„“ values. Unlike direct evaluation of individual elements, which would generally cause overflow or underflow beyond โ„“โ‰ˆ30 when using double precision, these recursion relations should be valid for far higher โ„“ values. More precisely, when using this package, Inf values appear starting at โ„“=128 for Float16, but I have not yet found any for values up to at least โ„“=1024 with Float32, and presumably far higher for Float64. BigFloat also works, and presumably will not overflow for any โ„“ value that could reasonably fit into computer memory โ€” though it is far slower. Also note that DoubleFloats will work, and achieve significantly greater accuracy (but no greater โ„“ range) than Float64. In all cases, results are typically accurate to roughly โ„“ times the precision of the input quaternion.

The conventions for this package are mostly inherited from โ€” and are described in detail by โ€” its predecessors found here and here.

Note that numerous other packages cover some of these use cases, including FastTransforms.jl, FastSphericalHarmonics.jl, WignerSymbols.jl, and WignerFamilies.jl. However, I need support for quaternions (via Quaternionic.jl) and for higher-precision numbers โ€” even at the cost of a very slight decrease in speed in some cases โ€” which are what this package provides.

  • 1Euler angles are quite generally a very poor choice for computing with rotations. (The only context in which they may be preferred is when analytically integrating some analytically known functions.) Almost universally, it is best to use quaternions when computing with rotations. All the computations done within this package use quaternions; the user interfaces involving Euler angles essentially convert to/from quaternions. While the calculations needed for those conversions would still need to be done if this package used Euler angles internally โ€” meaning that this approach is as efficient as any โ€” that work can be avoided entirely if you work with quaternions directly.
+Introduction ยท SphericalFunctions.jl

Introduction

This is a Julia package for evaluating and transforming Wigner's ๐”‡ matrices, and spin-weighted spherical harmonics ${}_{s}Y_{\ell,m}$ (which includes the ordinary scalar spherical harmonics). Because both ๐”‡ and the harmonics are most correctly considered functions on the rotation group $๐’๐Ž(3)$ โ€” or more generally, the spin group $๐’๐ฉ๐ข๐ง(3)$ that covers it โ€” these functions are evaluated directly in terms of quaternions. Concessions are also made for more standard forms of spherical coordinates and Euler angles.[1] Among other applications, those functions permit "synthesis" (evaluation of the spin-weighted spherical functions) of spin-weighted spherical harmonic coefficients on regular or distorted grids. This package also includes functions enabling efficient "analysis" (decomposition into mode coefficients) of functions evaluated on regular grids to high order and accuracy.

These quantities are computed using recursion relations, which makes it possible to compute to very high โ„“ values. Unlike direct evaluation of individual elements, which would generally cause overflow or underflow beyond โ„“โ‰ˆ30 when using double precision, these recursion relations should be valid for far higher โ„“ values. More precisely, when using this package, Inf values appear starting at โ„“=128 for Float16, but I have not yet found any for values up to at least โ„“=1024 with Float32, and presumably far higher for Float64. BigFloat also works, and presumably will not overflow for any โ„“ value that could reasonably fit into computer memory โ€” though it is far slower. Also note that DoubleFloats will work, and achieve significantly greater accuracy (but no greater โ„“ range) than Float64. In all cases, results are typically accurate to roughly โ„“ times the precision of the input quaternion.

The conventions for this package are mostly inherited from โ€” and are described in detail by โ€” its predecessors found here and here.

Note that numerous other packages cover some of these use cases, including FastTransforms.jl, FastSphericalHarmonics.jl, WignerSymbols.jl, and WignerFamilies.jl. However, I need support for quaternions (via Quaternionic.jl) and for higher-precision numbers โ€” even at the cost of a very slight decrease in speed in some cases โ€” which are what this package provides.

  • 1Euler angles are quite generally a very poor choice for computing with rotations. (The only context in which they may be preferred is when analytically integrating some analytically known functions.) Almost universally, it is best to use quaternions when computing with rotations. All the computations done within this package use quaternions; the user interfaces involving Euler angles essentially convert to/from quaternions. While the calculations needed for those conversions would still need to be done if this package used Euler angles internally โ€” meaning that this approach is as efficient as any โ€” that work can be avoided entirely if you work with quaternions directly.
diff --git a/previews/PR49/internal/index.html b/previews/PR49/internal/index.html index 8da5aec..a15ca26 100644 --- a/previews/PR49/internal/index.html +++ b/previews/PR49/internal/index.html @@ -1,18 +1,18 @@ Internal functions ยท SphericalFunctions.jl

Internal functions

There are various functions that are only used internally, some of which are likely to be deprecated in the near future. These are documented here for completeness.

$H$ recursion and ALFs

The fundamental algorithm is the $H$ recursion, which is the core computation needed for Wigner's $d$ and $๐”‡$ matrices, and the spin-weighted spherical harmonics ${}_{s}Y_{\ell,m}$, as well as map2salm functions.

SphericalFunctions.H! โ€” Method
H!(H, expiฮฒ, โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“, H_rec_coeffs)
-H!(H, expiฮฒ, โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“, H_rec_coeffs, Hindex)

Compute the $H$ matrix defined by Gumerov and Duraiswami [8].

This computation forms the basis for computing Wigner's $d$ and $๐”‡$ matrices via d_matrices! and D_matrices!, the spin-weighted spherical harmonics via sYlm_values!, and for transforming from values of spin-weighted spherical functions evaluated on a grid to the corresponding mode weights via map2salm.

Due to symmetries, we only need to compute ~1/4 of the elements of this matrix, so only those elements with $m โ‰ฅ |mโ€ฒ|$ are computed. The relevant indices of the H vector are computed based on the Hindex function โ€” which defaults to WignerHindex, but could reasonably be WignerDindex if the input H vector contains all valid indices. However, it is assumed that the storage scheme used for H is such that the successive $m$ values are located in successive elements.

If $mโ€ฒโ‚˜โ‚โ‚“ < โ„“โ‚˜โ‚โ‚“$, we don't even need 1/4 of the elements, and only values with $|mโ€ฒ| โ‰ค mโ€ฒโ‚˜โ‚โ‚“$ will be computed. This is particularly useful for computing spin-weighted spherical harmonics.

Note that the recursion coefficients H_rec_coeffs should be the quantity returned by H_recursion_coefficients.

source

Internally, the $H$ recursion relies on calculation of the Associated Legendre Functions (ALFs), which can also be called on their own:

SphericalFunctions.ALFcompute! โ€” Method
ALFcompute(expiฮฒ, nmax)
+H!(H, expiฮฒ, โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“, H_rec_coeffs, Hindex)

Compute the $H$ matrix defined by Gumerov and Duraiswami [8].

This computation forms the basis for computing Wigner's $d$ and $๐”‡$ matrices via d_matrices! and D_matrices!, the spin-weighted spherical harmonics via sYlm_values!, and for transforming from values of spin-weighted spherical functions evaluated on a grid to the corresponding mode weights via map2salm.

Due to symmetries, we only need to compute ~1/4 of the elements of this matrix, so only those elements with $m โ‰ฅ |mโ€ฒ|$ are computed. The relevant indices of the H vector are computed based on the Hindex function โ€” which defaults to WignerHindex, but could reasonably be WignerDindex if the input H vector contains all valid indices. However, it is assumed that the storage scheme used for H is such that the successive $m$ values are located in successive elements.

If $mโ€ฒโ‚˜โ‚โ‚“ < โ„“โ‚˜โ‚โ‚“$, we don't even need 1/4 of the elements, and only values with $|mโ€ฒ| โ‰ค mโ€ฒโ‚˜โ‚โ‚“$ will be computed. This is particularly useful for computing spin-weighted spherical harmonics.

Note that the recursion coefficients H_rec_coeffs should be the quantity returned by H_recursion_coefficients.

source

Internally, the $H$ recursion relies on calculation of the Associated Legendre Functions (ALFs), which can also be called on their own:

SphericalFunctions.ALFcompute! โ€” Method
ALFcompute(expiฮฒ, nmax)
 ALFcompute!(Pฬ„, expiฮฒ, nmax)
 ALFcompute(expiฮฒ, nmax, recursion_coefficients)
-ALFcompute!(Pฬ„, expiฮฒ, nmax, recursion_coefficients)

Compute the "fully normalized" Associated Legendre Functions up to some maximum n value nmax.

These functions can take a vector Pฬ„, to store the data, stored in order of increasing m most rapidly varying and then increasing n. If not supplied, Pฬ„ will be constructed for you and returned.

The optional recursion_coefficients argument must be an ALFRecursionCoefficients, which stores various constant coefficients used in the recursion. This object requires more than 3x the memory and more than 20x the time to compute a single Pฬ„ vector without this argument, but passing it will typically speed up the calculation of each Pฬ„ by a factor of 8x or so. Thus, if you expect to compute Pฬ„ more than a few times, it will take less time to pre-compute those factors, and pass them to this function.

Note that the base real type will be inferred from the (complex) type of expiฮฒ. If present, the base types of Pฬ„ and recursion_coefficients must agree.

source

The function ${}_{s}\lambda_{\ell,m}$ is defined as essentially ${}_{s}Y_{\ell,0}$, and is important internally for computing the ALFs. We have some important utilities for computing it:

SphericalFunctions.ฮป_recursion_initialize โ€” Function
ฮป_recursion_initialize(cosฮธ, sinยฝฮธ, cosยฝฮธ, s, โ„“, m)

This provides initial values for the recursion to find ${}_{s}\lambda_{\ell,m}$ along indices of increasing $\ell$, due to Kostelec & Rockmore Specifically, this function computes values with $\ell=m$.

\[{}_{s}\lambda_{\ell,m}(\theta) +ALFcompute!(Pฬ„, expiฮฒ, nmax, recursion_coefficients)

Compute the "fully normalized" Associated Legendre Functions up to some maximum n value nmax.

These functions can take a vector Pฬ„, to store the data, stored in order of increasing m most rapidly varying and then increasing n. If not supplied, Pฬ„ will be constructed for you and returned.

The optional recursion_coefficients argument must be an ALFRecursionCoefficients, which stores various constant coefficients used in the recursion. This object requires more than 3x the memory and more than 20x the time to compute a single Pฬ„ vector without this argument, but passing it will typically speed up the calculation of each Pฬ„ by a factor of 8x or so. Thus, if you expect to compute Pฬ„ more than a few times, it will take less time to pre-compute those factors, and pass them to this function.

Note that the base real type will be inferred from the (complex) type of expiฮฒ. If present, the base types of Pฬ„ and recursion_coefficients must agree.

source

The function ${}_{s}\lambda_{\ell,m}$ is defined as essentially ${}_{s}Y_{\ell,0}$, and is important internally for computing the ALFs. We have some important utilities for computing it:

SphericalFunctions.ฮป_recursion_initialize โ€” Function
ฮป_recursion_initialize(cosฮธ, sinยฝฮธ, cosยฝฮธ, s, โ„“, m)

This provides initial values for the recursion to find ${}_{s}\lambda_{\ell,m}$ along indices of increasing $\ell$, due to Kostelec & Rockmore Specifically, this function computes values with $\ell=m$.

\[{}_{s}\lambda_{\ell,m}(\theta) := {}_{s}Y_{\ell,m}(\theta, 0) - = (-1)^m\, \sqrt{\frac{2\ell+1}{4\pi}} d^\ell_{-m,s}(\theta)\]

source
SphericalFunctions.ฮป_iterator โ€” Type
ฮป_iterator(ฮธ, s, m)

Construct an object to iterate over โ‚›ฮปโ‚—โ‚˜ values.

The $โ‚›ฮปโ‚—โ‚˜(ฮธ)$ function is defined as the spin-weighted spherical harmonic evaluated at spherical coordinates $(ฮธ, ฯ•)$, with $ฯ•=0$. In particular, note that it is real-valued. The return type is determined by the type of ฮธ (or more precisely, cosยฝฮธ).

This algorithm by Kostelec & Rockmore allows us to iterate over increasing $โ„“$ values, for given fixed $s$ and $m$ values.

Note that this iteration has no inherent bound, so if you try to iterate over all values, you will end up in an infinite loop. Instead, you can zip this iterator with another:

ฮธ = 0.1
+    = (-1)^m\, \sqrt{\frac{2\ell+1}{4\pi}} d^\ell_{-m,s}(\theta)\]

source
SphericalFunctions.ฮป_iterator โ€” Type
ฮป_iterator(ฮธ, s, m)

Construct an object to iterate over โ‚›ฮปโ‚—โ‚˜ values.

The $โ‚›ฮปโ‚—โ‚˜(ฮธ)$ function is defined as the spin-weighted spherical harmonic evaluated at spherical coordinates $(ฮธ, ฯ•)$, with $ฯ•=0$. In particular, note that it is real-valued. The return type is determined by the type of ฮธ (or more precisely, cosยฝฮธ).

This algorithm by Kostelec & Rockmore allows us to iterate over increasing $โ„“$ values, for given fixed $s$ and $m$ values.

Note that this iteration has no inherent bound, so if you try to iterate over all values, you will end up in an infinite loop. Instead, you can zip this iterator with another:

ฮธ = 0.1
 s = -2
 m = 1
 ฮป = ฮป_iterator(ฮธ, s, m)
 ฮ” = max(abs(s), abs(m))
 for (โ„“, โ‚›ฮปโ‚—โ‚˜) โˆˆ zip(ฮ”:ฮ”+5, ฮป)
     @show (โ„“, โ‚›ฮปโ‚—โ‚˜)
-end

Alternatively, you could use Iterates.take(ฮป, 6), for example.

Note that the iteration always begins with โ„“ = ฮ” = max(abs(s), abs(m)).

source
SphericalFunctions.AlternatingCountdown โ€” Type

Simple iterator to count down to 0, with alternating signs

julia> collect(AlternatingCountdown(5))
+end

Alternatively, you could use Iterates.take(ฮป, 6), for example.

Note that the iteration always begins with โ„“ = ฮ” = max(abs(s), abs(m)).

source

โ‚›๐˜

Various d, D, and sYlm functions are important in the main API. Their names and signatures have been tweaked from older versions of this package. The only one with remaining documentation is โ‚›๐˜, which could probably be replaced by sYlm_values, except that the default pixelization is golden_ratio_spiral_rotors, which makes it very convenient for interacting with SSHT.

SphericalFunctions.โ‚›๐˜ โ€” Function
โ‚›๐˜(s, โ„“โ‚˜โ‚โ‚“, [T=Float64], [Rฮธฯ•=golden_ratio_spiral_rotors(s, โ„“โ‚˜โ‚โ‚“, T)])

Construct a matrix of $โ‚›Yโ‚—โ‚˜(Rฮธฯ•)$ values for the input s and all nontrivial $(\ell, m)$ up to โ„“โ‚˜โ‚โ‚“.

This is a fast and accurate method for mapping between the vector of spin-weighted spherical-harmonic mode weights $โ‚›๐Ÿโ‚—โ‚˜$ and the vector of function values on the sphere $โ‚›๐Ÿโฑผโ‚–$, as

\[โ‚›๐Ÿโฑผโ‚– = โ‚›๐˜\, โ‚›๐Ÿโ‚—โ‚˜,\]

where the right-hand side represents the matrix-vector product. As usual, we assume that the $โ‚›๐Ÿโ‚—โ‚˜$ modes are ordered by increasing $m โˆˆ [-โ„“:โ„“]$, and $โ„“ โˆˆ [|s|:โ„“โ‚˜โ‚โ‚“]$. The ordering of the $โ‚›๐Ÿโฑผโ‚–$ values will be determined by the ordering of the argument Rฮธฯ•.

Note that the number of modes need not be the same as the number of points on which the function is evaluated, which would imply that the output matrix is not square. To be able to invert the relationship, however, we need the number of points $โ‚›๐Ÿโฑผโ‚–$ to be at least as large as the number of modes $โ‚›๐Ÿโ‚—โ‚˜$.

Note that the usefulness of this approach is limited by the fact that the size of this matrix scales as โ„“โ‚˜โ‚โ‚“โด. As such, it is mostly useful only for โ„“โ‚˜โ‚โ‚“ of order dozens, rather than โ€” say โ€” the tens of thousands that CMB astronomy or lensing require, for example.

Direct application and inversion of this matrix are used in the "direct" methods of $s$-SHT transformations. See SSHTDirect for details about the implementation.

source

Transformation

The newer SSHT interface is more efficient for most purposes, but this package used to use functions named map2salm, which is still present, but may be deprecated.

SphericalFunctions.map2salm! โ€” Method
map2salm!(salm, map, spin, โ„“max)
-map2salm!(salm, map, plan)

Transform map values sampled on the sphere to ${}_sa_{\ell, m}$ modes in place.

For details, see map2salm.

source
SphericalFunctions.map2salm โ€” Method
map2salm(map, spin, โ„“max)
-map2salm(map, plan)

Transform map values sampled on the sphere to ${}_sa_{\ell, m}$ modes.

The map array should have size Nฯ† along its first dimension and Nฯ‘ along its second; any number of dimensions may follow. The spin must be entered explicitly, and โ„“max is the highest โ„“ value you want in the output.

For repeated applications of this function with different values of map, it is more efficient to pre-compute plan using plan_map2salm. These functions will create a new salm array on each call. To operate in place on a pre-allocated salm array, use map2salm!.

The core of this function follows the method described by Reinecke and Seljebotn.

source
SphericalFunctions.plan_map2salm โ€” Method
plan_map2salm(map, spin, โ„“max)

Precompute values to use in executing map2salm or map2salm!.

The arguments to this function exactly mirror those of the first form of map2salm, and all but the first argument in the first form of map2salm!. The plan returned by this function can be passed to the second forms of those functions to avoid some computation and allocation costs.

Note that the plan object is not thread safe; a separate plan should be created for each thread that will use one, or locks should be used to ensure that a single plan is not used at the same time on different threads.

source
+ 0source

โ‚›๐˜

Various d, D, and sYlm functions are important in the main API. Their names and signatures have been tweaked from older versions of this package. The only one with remaining documentation is โ‚›๐˜, which could probably be replaced by sYlm_values, except that the default pixelization is golden_ratio_spiral_rotors, which makes it very convenient for interacting with SSHT.

SphericalFunctions.โ‚›๐˜ โ€” Function
โ‚›๐˜(s, โ„“โ‚˜โ‚โ‚“, [T=Float64], [Rฮธฯ•=golden_ratio_spiral_rotors(s, โ„“โ‚˜โ‚โ‚“, T)])

Construct a matrix of $โ‚›Yโ‚—โ‚˜(Rฮธฯ•)$ values for the input s and all nontrivial $(\ell, m)$ up to โ„“โ‚˜โ‚โ‚“.

This is a fast and accurate method for mapping between the vector of spin-weighted spherical-harmonic mode weights $โ‚›๐Ÿโ‚—โ‚˜$ and the vector of function values on the sphere $โ‚›๐Ÿโฑผโ‚–$, as

\[โ‚›๐Ÿโฑผโ‚– = โ‚›๐˜\, โ‚›๐Ÿโ‚—โ‚˜,\]

where the right-hand side represents the matrix-vector product. As usual, we assume that the $โ‚›๐Ÿโ‚—โ‚˜$ modes are ordered by increasing $m โˆˆ [-โ„“:โ„“]$, and $โ„“ โˆˆ [|s|:โ„“โ‚˜โ‚โ‚“]$. The ordering of the $โ‚›๐Ÿโฑผโ‚–$ values will be determined by the ordering of the argument Rฮธฯ•.

Note that the number of modes need not be the same as the number of points on which the function is evaluated, which would imply that the output matrix is not square. To be able to invert the relationship, however, we need the number of points $โ‚›๐Ÿโฑผโ‚–$ to be at least as large as the number of modes $โ‚›๐Ÿโ‚—โ‚˜$.

Note that the usefulness of this approach is limited by the fact that the size of this matrix scales as โ„“โ‚˜โ‚โ‚“โด. As such, it is mostly useful only for โ„“โ‚˜โ‚โ‚“ of order dozens, rather than โ€” say โ€” the tens of thousands that CMB astronomy or lensing require, for example.

Direct application and inversion of this matrix are used in the "direct" methods of $s$-SHT transformations. See SSHTDirect for details about the implementation.

source

Transformation

The newer SSHT interface is more efficient for most purposes, but this package used to use functions named map2salm, which is still present, but may be deprecated.

SphericalFunctions.map2salm! โ€” Method
map2salm!(salm, map, spin, โ„“max)
+map2salm!(salm, map, plan)

Transform map values sampled on the sphere to ${}_sa_{\ell, m}$ modes in place.

For details, see map2salm.

source
SphericalFunctions.map2salm โ€” Method
map2salm(map, spin, โ„“max)
+map2salm(map, plan)

Transform map values sampled on the sphere to ${}_sa_{\ell, m}$ modes.

The map array should have size Nฯ† along its first dimension and Nฯ‘ along its second; any number of dimensions may follow. The spin must be entered explicitly, and โ„“max is the highest โ„“ value you want in the output.

For repeated applications of this function with different values of map, it is more efficient to pre-compute plan using plan_map2salm. These functions will create a new salm array on each call. To operate in place on a pre-allocated salm array, use map2salm!.

The core of this function follows the method described by Reinecke and Seljebotn.

source
SphericalFunctions.plan_map2salm โ€” Method
plan_map2salm(map, spin, โ„“max)

Precompute values to use in executing map2salm or map2salm!.

The arguments to this function exactly mirror those of the first form of map2salm, and all but the first argument in the first form of map2salm!. The plan returned by this function can be passed to the second forms of those functions to avoid some computation and allocation costs.

Note that the plan object is not thread safe; a separate plan should be created for each thread that will use one, or locks should be used to ensure that a single plan is not used at the same time on different threads.

source
diff --git a/previews/PR49/notes/H_recursions/index.html b/previews/PR49/notes/H_recursions/index.html index 4165af8..b73c494 100644 --- a/previews/PR49/notes/H_recursions/index.html +++ b/previews/PR49/notes/H_recursions/index.html @@ -52,4 +52,4 @@ + d^{m}_{n} H^{m', m+1}_{n}\]

(where the last term drops out for $m=n$). The constants are defined by

\[d^{m}_{n} = \frac{\mathrm{sgn}(m)}{2} \sqrt{(n-m)(n+m+1)}.\]

Note that we can drop the factor of $1/2$, and for this case only the sign is always +1.

Step 5

Recursively compute $H^{m'โˆ’1, m}_{n}(ฮฒ)$ for $m'=0,\ldots,โˆ’n+1$, $m=โˆ’m',\ldots,n$ using relation (50) resolved with respect to $H^{m'โˆ’1, m}_{n}$:

\[d^{m'โˆ’1}_{n} H^{m'โˆ’1, m}_{n} = d^{m'}_{n} H^{m'+1, m}_{n} + d^{mโˆ’1}_{n} H^{m', mโˆ’1}_{n} - โˆ’ d^{m}_{n} H^{m', m+1}_{n}\]

(where the last term drops out for $m=n$).

NOTE: Although Gumerov and Duraiswami specify the loop over $m'$ to start at -1, I find it necessary to start at 0, or there will be missing information. This also requires setting the $H^{0, -1}_{n}$ components (for all $n$) before beginning this loop.

Pre-computing constants versus computing on the fly

Each of the constants $a^{m}_{n}$, $b^{m}_{n}$, and $c^{m}_{n}$ involves divisions and square-roots, which can be very costly to compute. It can be advantageous to pre-compute the constants, and simply index the pre-computed arrays rather than re-computing them on each recursion.

If we include the cost of computing all these constants in a single call to the $H$ recurrence, it can be much cheaper to compute each constant as needed within the algorithm, rather than computing them all at once at the beginning of the algorithm โ€” but only for very small computations, such as those involving $n_{\mathrm{max}} โ‰ˆ 10$. Beyond this, despite the storage penalties for all those constants, it turns out to be better to pre-compute them. However, it should be noted that the fractional cost of storing the constants is $\sim 3/n_{\mathrm{max}}$ compared to just storing $H$ itself, so this will never be a very significant amount of space.

On the other hand, if we can pre-compute the constants just once, and store them between multiple calls to the $H$ recurrence, then it is always advantageous to do so โ€” typically by factors of 2 or 3 in speed. The only difficulty here is ensuring that each call to the recurrence has access to the constants, which can be a little awkward when using multiple processes and/or threads. However, it should be thread safe, since we only need to read those constants within the $H$ recurrence. All in all, I conclude that it is probably not worth the effort to maintain separate versions of the recurrence for pre-computed and on-the-fly constants.

+ โˆ’ d^{m}_{n} H^{m', m+1}_{n}\]

(where the last term drops out for $m=n$).

NOTE: Although Gumerov and Duraiswami specify the loop over $m'$ to start at -1, I find it necessary to start at 0, or there will be missing information. This also requires setting the $H^{0, -1}_{n}$ components (for all $n$) before beginning this loop.

Pre-computing constants versus computing on the fly

Each of the constants $a^{m}_{n}$, $b^{m}_{n}$, and $c^{m}_{n}$ involves divisions and square-roots, which can be very costly to compute. It can be advantageous to pre-compute the constants, and simply index the pre-computed arrays rather than re-computing them on each recursion.

If we include the cost of computing all these constants in a single call to the $H$ recurrence, it can be much cheaper to compute each constant as needed within the algorithm, rather than computing them all at once at the beginning of the algorithm โ€” but only for very small computations, such as those involving $n_{\mathrm{max}} โ‰ˆ 10$. Beyond this, despite the storage penalties for all those constants, it turns out to be better to pre-compute them. However, it should be noted that the fractional cost of storing the constants is $\sim 3/n_{\mathrm{max}}$ compared to just storing $H$ itself, so this will never be a very significant amount of space.

On the other hand, if we can pre-compute the constants just once, and store them between multiple calls to the $H$ recurrence, then it is always advantageous to do so โ€” typically by factors of 2 or 3 in speed. The only difficulty here is ensuring that each call to the recurrence has access to the constants, which can be a little awkward when using multiple processes and/or threads. However, it should be thread safe, since we only need to read those constants within the $H$ recurrence. All in all, I conclude that it is probably not worth the effort to maintain separate versions of the recurrence for pre-computed and on-the-fly constants.

diff --git a/previews/PR49/notes/sampling_theorems/index.html b/previews/PR49/notes/sampling_theorems/index.html index bb53720..f824835 100644 --- a/previews/PR49/notes/sampling_theorems/index.html +++ b/previews/PR49/notes/sampling_theorems/index.html @@ -80,4 +80,4 @@ for j โˆˆ abs(s):โ„“โ‚˜โ‚โ‚“ ifftshift!(โ‚›fฬƒ[j]) # Cycle order of modes in place to match order of FFT elements bfft!(โ‚›fฬƒโฑผ[j]) # Perform in-place BFFT -end +end diff --git a/previews/PR49/objects.inv b/previews/PR49/objects.inv index f78e06f..b37e861 100644 Binary files a/previews/PR49/objects.inv and b/previews/PR49/objects.inv differ diff --git a/previews/PR49/operators/index.html b/previews/PR49/operators/index.html index bb0d163..8353249 100644 --- a/previews/PR49/operators/index.html +++ b/previews/PR49/operators/index.html @@ -47,5 +47,5 @@ \sum_{\ell',m'} f_{\ell',m'}\, \sqrt{(\ell'-s)(\ell'+s+1)} \delta_{\ell,\ell'} \delta_{m,m'} \\ &= f_{\ell,m}\, \sqrt{(\ell-s)(\ell+s+1)} -\end{aligned}\]

Similarly $\bar{\eth}$ โ€” and $R_\pm$ of course โ€” obey this more "covariant" form of transformation.

Docstrings

SphericalFunctions.Lz โ€” Method
Lz(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the angular-momentum operator associated with the $z$ direction. This is the standard $L_z$ operator, familiar from basic physics, extended to work with SWSHs. Note that this is the left Lie derivative; see Rz for the equivalent right Lie derivative. See the documentation or Boyle for more details.

In terms of the SWSHs, we can write the action of $L_z$ as

\[L_z {}_{s}Y_{\ell,m} = m\, {}_{s}Y_{\ell,m}\]

See also Lยฒ, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.

source
SphericalFunctions.Lยฒ โ€” Method
Lยฒ(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the total angular-momentum operator from โ„“โ‚˜แตขโ‚™ up to โ„“โ‚˜โ‚โ‚“. If not present, โ„“โ‚˜แตขโ‚™ is assumed to be abs(s). The argument s is ignored; it is present only for consistency with other operators, and is assumed to be 0 if not present.

This is the standard $Lยฒ$ operator, familiar from basic physics, extended to work with SWSHs. It is also known as the Casimir operator, and is equal to

\[L^2 = L_x^2 + L_y^2 + L_z^2 = \frac{L_+L_- + L_-L_+ + 2L_zL_z}{2}.\]

Note that these are the left Lie derivatives, but $L^2 = R^2$, where R is the right Lie derivative. See the documentation or Boyle for more details.

In terms of the SWSHs, we can write the action of $L^2$ as

\[L^2 {}_{s}Y_{\ell,m} = \ell\,(\ell+1) {}_{s}Y_{\ell,m}\]

See also Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.

source
SphericalFunctions.Lโ‚Š โ€” Method
Lโ‚Š(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the angular-momentum raising operator. This is the standard $L_+$ operator, familiar from basic physics, extended to work with SWSHs. Note that this is the left Lie derivative; see Rโ‚Š for the equivalent right Lie derivative. See the documentation or Boyle for more details.

We define $L_+$ to be the raising operator for the left Lie derivative with respect to rotation about $z$: $L_z$. By definition, this implies the commutator relation $[L_z, L_+] = L_+$, which allows us to derive $L_+ = L_x + i\, L_y.$

In terms of the SWSHs, we can write the action of $L_+$ as

\[L_+ {}_{s}Y_{\ell,m} = \sqrt{(\ell-m)(\ell+m+1)}\, {}_{s}Y_{\ell,m+1}.\]

Consequently, the mode weights of a function are affected as

\[\left\{L_+(f)\right\}_{s,\ell,m} = \sqrt{(\ell+m)(\ell-m+1)}\,\left\{f\right\}_{s,\ell,m-1}.\]

See also Lยฒ, Lz, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.

source
SphericalFunctions.Lโ‚‹ โ€” Method
Lโ‚‹(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the angular-momentum lowering operator. This is the standard $L_-$ operator, familiar from basic physics, extended to work with SWSHs. Note that this is the left Lie derivative; see Rโ‚‹ for the equivalent right Lie derivative. See the documentation or Boyle for more details.

We define $L_-$ to be the lowering operator for the left Lie derivative with respect to rotation about $z$: $L_z$. By definition, this implies the commutator relation $[L_z, L_-] = -L_-$, which allows us to derive $L_- = L_x - i\, L_y.$

In terms of the SWSHs, we can write the action of $L_-$ as

\[L_- {}_{s}Y_{\ell,m} = \sqrt{(\ell+m)(\ell-m+1)}\, {}_{s}Y_{\ell,m-1}.\]

Consequently, the mode weights of a function are affected as

\[\left\{L_-(f)\right\}_{s,\ell,m} = \sqrt{(\ell-m)(\ell+m+1)}\,\left\{f\right\}_{s,\ell,m+1}.\]

See also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.

source
SphericalFunctions.Rz โ€” Method
Rz(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the right angular-momentum operator associated with the $z$ direction.

This is the $R_z$ operator, much like the $L_z$ operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. See Lz for the equivalent left Lie derivative. See the documentation or Boyle for more details.

In terms of the SWSHs, we can write the action of $R_z$ as

\[R_z {}_{s}Y_{\ell,m} = -s\, {}_{s}Y_{\ell,m}\]

Note the unfortunate sign of $s$, which seems to be opposite to what we expect, and arises from the choice of definition of $s$ in the original paper by Newman and Penrose.

See also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.

source
SphericalFunctions.Rยฒ โ€” Method
Rยฒ(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the total angular-momentum operator from โ„“โ‚˜แตขโ‚™ up to โ„“โ‚˜โ‚โ‚“. If not present, โ„“โ‚˜แตขโ‚™ is assumed to be abs(s). The argument s is ignored; it is present only for consistency with other operators, and is assumed to be 0 if not present.

This is the $R^2$ operator, much like the $L^2$ operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. It is also known as the Casimir operator, and is equal to

\[R^2 = R_x^2 + R_y^2 + R_z^2 = \frac{R_+R_- + R_-R_+ + 2R_zR_z}{2}.\]

Note that these are the right Lie derivatives, but $L^2 = R^2$, where L is the left Lie derivative. See the documentation or Boyle for more details.

In terms of the SWSHs, we can write the action of $R^2$ as

\[R^2 {}_{s}Y_{\ell,m} = \ell\,(\ell+1) {}_{s}Y_{\ell,m}\]

See also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.

source
SphericalFunctions.Rโ‚Š โ€” Method
Rโ‚Š(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the right angular-momentum raising operator.

This is the $R_+$ operator, much like the $L_+$ operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. See Lโ‚Š for the equivalent left Lie derivative. See the documentation or Boyle for more details.

We define $R_+$ to be the raising operator for the right Lie derivative with respect to rotation about $z$: $R_z$. By definition, this implies the commutator relation $[R_z, R_+] = R_+$, which allows us to derive $R_+ = R_x - i\, R_y.$

In terms of the SWSHs, we can write the action of $R_+$ as

\[R_+ {}_{s}Y_{\ell,m} = \sqrt{(\ell+s)(\ell-s+1)}\, {}_{s-1}Y_{\ell,m}\]

Consequently, the mode weights of a function are affected as

\[\left\{R_+(f)\right\}_{s,\ell,m} = \sqrt{(\ell+s)(\ell-s+1)}\,\left\{f\right\}_{s-1,\ell,m}.\]

Because of the unfortunate sign of $s$ arising from the choice of definition of $s$ in the original paper by Newman and Penrose, this is a lowering operator for $s$, though it really is a raising operator for $R_z$, and raises the eigenvalue of the corresponding Wigner matrix.

See also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚‹, รฐ, รฐฬ„.

source
SphericalFunctions.Rโ‚‹ โ€” Method
Rโ‚‹(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the right angular-momentum lowering operator.

This is the $R_-$ operator, much like the $L_-$ operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. See Lโ‚‹ for the equivalent left Lie derivative. See the documentation or Boyle for more details.

We define $R_-$ to be the raising operator for the right Lie derivative with respect to rotation about $z$: $R_z$. By definition, this implies the commutator relation $[R_z, R_-] = -R_-$, which allows us to derive $R_- = R_x + i\, R_y.$

In terms of the SWSHs, we can write the action of $R_-$ as

\[R_- {}_{s}Y_{\ell,m} = \sqrt{(\ell-s)(\ell+s+1)}\, {}_{s+1}Y_{\ell,m}\]

Consequently, the mode weights of a function are affected as

\[\left\{R_-(f)\right\}_{s,\ell,m} = \sqrt{(\ell-s)(\ell+s+1)}\,\left\{f\right\}_{s+1,\ell,m}.\]

Because of the unfortunate sign of $s$ arising from the choice of definition of $s$ in the original paper by Newman and Penrose, this is a raising operator for $s$, though it really is a lowering operator for $R_z$, and lowers the eigenvalue of the corresponding Wigner matrix - though that raises the eigenvalue of the corresponding Wigner matrix.

See also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, รฐ, รฐฬ„.

source
SphericalFunctions.รฐ โ€” Method
รฐ(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute coefficients for the spin-raising operator $\eth$.

This operator was originally defined by Newman and Penrose, but is more completely defined by Boyle. It is identical to Rโ‚‹. Refer to that function's documentation for more details.

By definition, the spin-raising operator satisfies the commutator relation $[S, \eth] = \eth$ (where $S$ is the spin operator, which just multiplies the function by its spin). In terms of the SWSHs, we can write the action of $\eth$ as

\[ \eth {}_{s}Y_{\ell,m} = \sqrt{(\ell-s)(\ell+s+1)} {}_{s+1}Y_{\ell,m}.\]

Consequently, the mode weights of a function are affected as

\[\left\{\eth f\right\}_{s,\ell,m} = \sqrt{(\ell-s)(\ell+s+1)}\,\left\{f\right\}_{s+1,\ell,m}.\]

See also รฐฬ„, Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š.

source
SphericalFunctions.รฐฬ„ โ€” Method
รฐฬ„(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute coefficients for the spin-lowering operator $\bar{\eth}$.

This operator was originally defined by Newman and Penrose, but is more completely defined by Boyle. It is opposite to Rโ‚Š โ€” meaning that $\bar{\eth} = -Rโ‚Š$. Refer to that function's documentation for more details.

By definition, the spin-lowering operator satisfies the commutator relation $[S, \bar{\eth}] = -\bar{\eth}$ (where $S$ is the spin operator, which just multiplies the function by its spin). In terms of the SWSHs, we can write the action of $\bar{\eth}$ as

\[\bar{\eth} {}_{s}Y_{\ell,m} = -\sqrt{(\ell+s)(\ell-s+1)} {}_{s-1}Y_{\ell,m}.\]

Consequently, the mode weights of a function are affected as

\[\left\{\bar{\eth} f\right\}_{s,\ell,m} -= -\sqrt{(\ell-s)(\ell+s+1)}\,\left\{f\right\}_{s+1,\ell,m}.\]

See also รฐ, Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š.

source
+\end{aligned}\]

Similarly $\bar{\eth}$ โ€” and $R_\pm$ of course โ€” obey this more "covariant" form of transformation.

Docstrings

SphericalFunctions.Lz โ€” Method
Lz(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the angular-momentum operator associated with the $z$ direction. This is the standard $L_z$ operator, familiar from basic physics, extended to work with SWSHs. Note that this is the left Lie derivative; see Rz for the equivalent right Lie derivative. See the documentation or Boyle for more details.

In terms of the SWSHs, we can write the action of $L_z$ as

\[L_z {}_{s}Y_{\ell,m} = m\, {}_{s}Y_{\ell,m}\]

See also Lยฒ, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.

source
SphericalFunctions.Lยฒ โ€” Method
Lยฒ(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the total angular-momentum operator from โ„“โ‚˜แตขโ‚™ up to โ„“โ‚˜โ‚โ‚“. If not present, โ„“โ‚˜แตขโ‚™ is assumed to be abs(s). The argument s is ignored; it is present only for consistency with other operators, and is assumed to be 0 if not present.

This is the standard $Lยฒ$ operator, familiar from basic physics, extended to work with SWSHs. It is also known as the Casimir operator, and is equal to

\[L^2 = L_x^2 + L_y^2 + L_z^2 = \frac{L_+L_- + L_-L_+ + 2L_zL_z}{2}.\]

Note that these are the left Lie derivatives, but $L^2 = R^2$, where R is the right Lie derivative. See the documentation or Boyle for more details.

In terms of the SWSHs, we can write the action of $L^2$ as

\[L^2 {}_{s}Y_{\ell,m} = \ell\,(\ell+1) {}_{s}Y_{\ell,m}\]

See also Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.

source
SphericalFunctions.Lโ‚Š โ€” Method
Lโ‚Š(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the angular-momentum raising operator. This is the standard $L_+$ operator, familiar from basic physics, extended to work with SWSHs. Note that this is the left Lie derivative; see Rโ‚Š for the equivalent right Lie derivative. See the documentation or Boyle for more details.

We define $L_+$ to be the raising operator for the left Lie derivative with respect to rotation about $z$: $L_z$. By definition, this implies the commutator relation $[L_z, L_+] = L_+$, which allows us to derive $L_+ = L_x + i\, L_y.$

In terms of the SWSHs, we can write the action of $L_+$ as

\[L_+ {}_{s}Y_{\ell,m} = \sqrt{(\ell-m)(\ell+m+1)}\, {}_{s}Y_{\ell,m+1}.\]

Consequently, the mode weights of a function are affected as

\[\left\{L_+(f)\right\}_{s,\ell,m} = \sqrt{(\ell+m)(\ell-m+1)}\,\left\{f\right\}_{s,\ell,m-1}.\]

See also Lยฒ, Lz, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.

source
SphericalFunctions.Lโ‚‹ โ€” Method
Lโ‚‹(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the angular-momentum lowering operator. This is the standard $L_-$ operator, familiar from basic physics, extended to work with SWSHs. Note that this is the left Lie derivative; see Rโ‚‹ for the equivalent right Lie derivative. See the documentation or Boyle for more details.

We define $L_-$ to be the lowering operator for the left Lie derivative with respect to rotation about $z$: $L_z$. By definition, this implies the commutator relation $[L_z, L_-] = -L_-$, which allows us to derive $L_- = L_x - i\, L_y.$

In terms of the SWSHs, we can write the action of $L_-$ as

\[L_- {}_{s}Y_{\ell,m} = \sqrt{(\ell+m)(\ell-m+1)}\, {}_{s}Y_{\ell,m-1}.\]

Consequently, the mode weights of a function are affected as

\[\left\{L_-(f)\right\}_{s,\ell,m} = \sqrt{(\ell-m)(\ell+m+1)}\,\left\{f\right\}_{s,\ell,m+1}.\]

See also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.

source
SphericalFunctions.Rz โ€” Method
Rz(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the right angular-momentum operator associated with the $z$ direction.

This is the $R_z$ operator, much like the $L_z$ operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. See Lz for the equivalent left Lie derivative. See the documentation or Boyle for more details.

In terms of the SWSHs, we can write the action of $R_z$ as

\[R_z {}_{s}Y_{\ell,m} = -s\, {}_{s}Y_{\ell,m}\]

Note the unfortunate sign of $s$, which seems to be opposite to what we expect, and arises from the choice of definition of $s$ in the original paper by Newman and Penrose.

See also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.

source
SphericalFunctions.Rยฒ โ€” Method
Rยฒ(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the total angular-momentum operator from โ„“โ‚˜แตขโ‚™ up to โ„“โ‚˜โ‚โ‚“. If not present, โ„“โ‚˜แตขโ‚™ is assumed to be abs(s). The argument s is ignored; it is present only for consistency with other operators, and is assumed to be 0 if not present.

This is the $R^2$ operator, much like the $L^2$ operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. It is also known as the Casimir operator, and is equal to

\[R^2 = R_x^2 + R_y^2 + R_z^2 = \frac{R_+R_- + R_-R_+ + 2R_zR_z}{2}.\]

Note that these are the right Lie derivatives, but $L^2 = R^2$, where L is the left Lie derivative. See the documentation or Boyle for more details.

In terms of the SWSHs, we can write the action of $R^2$ as

\[R^2 {}_{s}Y_{\ell,m} = \ell\,(\ell+1) {}_{s}Y_{\ell,m}\]

See also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.

source
SphericalFunctions.Rโ‚Š โ€” Method
Rโ‚Š(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the right angular-momentum raising operator.

This is the $R_+$ operator, much like the $L_+$ operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. See Lโ‚Š for the equivalent left Lie derivative. See the documentation or Boyle for more details.

We define $R_+$ to be the raising operator for the right Lie derivative with respect to rotation about $z$: $R_z$. By definition, this implies the commutator relation $[R_z, R_+] = R_+$, which allows us to derive $R_+ = R_x - i\, R_y.$

In terms of the SWSHs, we can write the action of $R_+$ as

\[R_+ {}_{s}Y_{\ell,m} = \sqrt{(\ell+s)(\ell-s+1)}\, {}_{s-1}Y_{\ell,m}\]

Consequently, the mode weights of a function are affected as

\[\left\{R_+(f)\right\}_{s,\ell,m} = \sqrt{(\ell+s)(\ell-s+1)}\,\left\{f\right\}_{s-1,\ell,m}.\]

Because of the unfortunate sign of $s$ arising from the choice of definition of $s$ in the original paper by Newman and Penrose, this is a lowering operator for $s$, though it really is a raising operator for $R_z$, and raises the eigenvalue of the corresponding Wigner matrix.

See also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚‹, รฐ, รฐฬ„.

source
SphericalFunctions.Rโ‚‹ โ€” Method
Rโ‚‹(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute the right angular-momentum lowering operator.

This is the $R_-$ operator, much like the $L_-$ operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. See Lโ‚‹ for the equivalent left Lie derivative. See the documentation or Boyle for more details.

We define $R_-$ to be the raising operator for the right Lie derivative with respect to rotation about $z$: $R_z$. By definition, this implies the commutator relation $[R_z, R_-] = -R_-$, which allows us to derive $R_- = R_x + i\, R_y.$

In terms of the SWSHs, we can write the action of $R_-$ as

\[R_- {}_{s}Y_{\ell,m} = \sqrt{(\ell-s)(\ell+s+1)}\, {}_{s+1}Y_{\ell,m}\]

Consequently, the mode weights of a function are affected as

\[\left\{R_-(f)\right\}_{s,\ell,m} = \sqrt{(\ell-s)(\ell+s+1)}\,\left\{f\right\}_{s+1,\ell,m}.\]

Because of the unfortunate sign of $s$ arising from the choice of definition of $s$ in the original paper by Newman and Penrose, this is a raising operator for $s$, though it really is a lowering operator for $R_z$, and lowers the eigenvalue of the corresponding Wigner matrix - though that raises the eigenvalue of the corresponding Wigner matrix.

See also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, รฐ, รฐฬ„.

source
SphericalFunctions.รฐ โ€” Method
รฐ(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute coefficients for the spin-raising operator $\eth$.

This operator was originally defined by Newman and Penrose, but is more completely defined by Boyle. It is identical to Rโ‚‹. Refer to that function's documentation for more details.

By definition, the spin-raising operator satisfies the commutator relation $[S, \eth] = \eth$ (where $S$ is the spin operator, which just multiplies the function by its spin). In terms of the SWSHs, we can write the action of $\eth$ as

\[ \eth {}_{s}Y_{\ell,m} = \sqrt{(\ell-s)(\ell+s+1)} {}_{s+1}Y_{\ell,m}.\]

Consequently, the mode weights of a function are affected as

\[\left\{\eth f\right\}_{s,\ell,m} = \sqrt{(\ell-s)(\ell+s+1)}\,\left\{f\right\}_{s+1,\ell,m}.\]

See also รฐฬ„, Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š.

source
SphericalFunctions.รฐฬ„ โ€” Method
รฐฬ„(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])

Compute coefficients for the spin-lowering operator $\bar{\eth}$.

This operator was originally defined by Newman and Penrose, but is more completely defined by Boyle. It is opposite to Rโ‚Š โ€” meaning that $\bar{\eth} = -Rโ‚Š$. Refer to that function's documentation for more details.

By definition, the spin-lowering operator satisfies the commutator relation $[S, \bar{\eth}] = -\bar{\eth}$ (where $S$ is the spin operator, which just multiplies the function by its spin). In terms of the SWSHs, we can write the action of $\bar{\eth}$ as

\[\bar{\eth} {}_{s}Y_{\ell,m} = -\sqrt{(\ell+s)(\ell-s+1)} {}_{s-1}Y_{\ell,m}.\]

Consequently, the mode weights of a function are affected as

\[\left\{\bar{\eth} f\right\}_{s,\ell,m} += -\sqrt{(\ell-s)(\ell+s+1)}\,\left\{f\right\}_{s+1,\ell,m}.\]

See also รฐ, Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š.

source
diff --git a/previews/PR49/references/index.html b/previews/PR49/references/index.html index 35e7478..d726ab2 100644 --- a/previews/PR49/references/index.html +++ b/previews/PR49/references/index.html @@ -1,2 +1,2 @@ -References ยท SphericalFunctions.jl

References

The most important routine in this package is the computation of the ๐”‡ matrices โ€” or more specifically, of terms proportional to parts of the ๐”‡ matrices. This mostly follows the treatment of Gumerov and Duraiswami [8] (with minor modifications to account for errors in their presentation, as described here). To seed the recursions they present, we also need to calculate the associated Legendre functions. This is now done using the "fully normalized column-wise recurrence formula" (fnCWF) given by Eqs. (12)โ€”(14) of Xing et al. [12]. This improves significantly over the older implementation using the "modified forward row method" of Holmes and Featherstone [14], for which the results would fail to be finite starting at โ„“=22 for Float16, โ„“=183 for Float32, and โ„“=1474 for Float64. Another approach that was never precisely implemented in this package was due to Fukushima [15], who showed that using "X-numbers", wherein the exponent is stored as a separate integer, (implemented in this package) in the core of the recursion could increase the range to โ„“โ‰ˆ2ยณยฒ. Xing et al. showed that Fukushima's results exhibited increased error for certain angles, whereas their Eqs. (12)โ€”(14) could be used directly to obtain results with greater accuracy for those certain angles, and comparable accuracy for other angles.

The other major functionality of this package is map2salm / salm2map, which decomposes function values on regular grids into mode weights (coefficients), and vice versa. The approach used here is taken from Reinecke and Seljebotn [3], with weights based on the method by Waldvogel [6]. However, this interface has been superseded by the SSHT object, which implements several approaches, including the Reinecke-Seljebotn-Waldvogel method, as well as the optimal-dimensionality method due to Elahi et al. [2], as well as a new unpublished optimal-dimensionality method I (Mike Boyle) created.

Bibliography

[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
N.ย A.ย Gumerov and R.ย Duraiswami. Recursive Computation of Spherical Harmonic Rotation Coefficients of Large Degree. In: Excursions in Harmonic Analysis, Volume 3 (Springer International Publishing, 2015); pp.ย 105โ€“141, arXiv:1403.7698 [math.NA].
[9]
[10]
[11]
H.ย Sommer, I.ย Gilitschenski, M.ย Bloesch, S.ย Weiss, R.ย Siegwart and J.ย Nieto. Why and How to Avoid the Flipped Quaternion Multiplication, arXiv:1801.07478ย cs, arXiv:1801.07478 [cs.RO].
[12]
[13]
[14]
[15]
[16]
G.ย B.ย Folland. A Course in Abstract Harmonic Analysis. 2ย Edition (Chapman and Hall/CRC, New York, 2016).
[17]
G.ย W.ย Hanson and A.ย B.ย Yakovlev. Operator Theory for Electromagnetics (Springer, New York, NY, 2002).
[18]
E.ย U.ย Condon and G.ย H.ย Shortley. The Theory Of Atomic Spectra (Cambridge University Press, London, 1935).
[19]
C.ย W.ย Ufford and G.ย H.ย Shortley. Atomic Eigenfunctions and Energies. Physicalย Review 42, 167โ€“175 (1932).
[20]
J.ย vanย Neerven. Functional Analysis. Cambridge Studies in Advanced Mathematics (Cambridge University Press, Cambridge, 2022).
[21]
[22]
P.ย Ajith, M.ย Boyle, D.ย A.ย Brown, S.ย Fairhurst, M.ย Hannam, I.ย Hinder, S.ย Husa, B.ย Krishnan, R.ย A.ย Mercer, F.ย Ohme, C.ย D.ย Ott, J.ย S.ย Read, L.ย Santamaria and J.ย T.ย Whelan. Data formats for numerical relativity waves (2007), arXiv:0709.0093 [gr-qc].
[23]
W.ย Fulton and J.ย Harris. Representation Theory. Vol.ย 129 of Graduate Texts in Mathematics (Springer, New York, NY, 2004).
[24]
J.ย N.ย Goldberg, A.ย J.ย Macfarlane, E.ย T.ย Newman, F.ย Rohrlich and E.ย C.ย Sudarshan. Spinโ€s Spherical Harmonics and รฐ. Journalย ofย Mathematicalย Physics 8, 2155โ€“2161 (1967).
[25]
J.ย J.ย Sakurai. Modern Quantum Mechanics, revisedย Edition (Addison Wesley, New York, 1994).
[26]
[27]
G.ย F.ย Torres Del Castillo. 3-D Spinors, Spin-Weighted Functions and their Applications. Vol.ย 52 no.ย 2 (Birkhรคuser, Boston, MA, 2003); p.ย 299.
[28]
+References ยท SphericalFunctions.jl

References

The most important routine in this package is the computation of the ๐”‡ matrices โ€” or more specifically, of terms proportional to parts of the ๐”‡ matrices. This mostly follows the treatment of Gumerov and Duraiswami [8] (with minor modifications to account for errors in their presentation, as described here). To seed the recursions they present, we also need to calculate the associated Legendre functions. This is now done using the "fully normalized column-wise recurrence formula" (fnCWF) given by Eqs. (12)โ€”(14) of Xing et al. [12]. This improves significantly over the older implementation using the "modified forward row method" of Holmes and Featherstone [14], for which the results would fail to be finite starting at โ„“=22 for Float16, โ„“=183 for Float32, and โ„“=1474 for Float64. Another approach that was never precisely implemented in this package was due to Fukushima [15], who showed that using "X-numbers", wherein the exponent is stored as a separate integer, (implemented in this package) in the core of the recursion could increase the range to โ„“โ‰ˆ2ยณยฒ. Xing et al. showed that Fukushima's results exhibited increased error for certain angles, whereas their Eqs. (12)โ€”(14) could be used directly to obtain results with greater accuracy for those certain angles, and comparable accuracy for other angles.

The other major functionality of this package is map2salm / salm2map, which decomposes function values on regular grids into mode weights (coefficients), and vice versa. The approach used here is taken from Reinecke and Seljebotn [3], with weights based on the method by Waldvogel [6]. However, this interface has been superseded by the SSHT object, which implements several approaches, including the Reinecke-Seljebotn-Waldvogel method, as well as the optimal-dimensionality method due to Elahi et al. [2], as well as a new unpublished optimal-dimensionality method I (Mike Boyle) created.

Bibliography

[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
N.ย A.ย Gumerov and R.ย Duraiswami. Recursive Computation of Spherical Harmonic Rotation Coefficients of Large Degree. In: Excursions in Harmonic Analysis, Volume 3 (Springer International Publishing, 2015); pp.ย 105โ€“141, arXiv:1403.7698 [math.NA].
[9]
[10]
[11]
H.ย Sommer, I.ย Gilitschenski, M.ย Bloesch, S.ย Weiss, R.ย Siegwart and J.ย Nieto. Why and How to Avoid the Flipped Quaternion Multiplication, arXiv:1801.07478ย cs, arXiv:1801.07478 [cs.RO].
[12]
[13]
[14]
[15]
[16]
G.ย B.ย Folland. A Course in Abstract Harmonic Analysis. 2ย Edition (Chapman and Hall/CRC, New York, 2016).
[17]
G.ย W.ย Hanson and A.ย B.ย Yakovlev. Operator Theory for Electromagnetics (Springer, New York, NY, 2002).
[18]
E.ย U.ย Condon and G.ย H.ย Shortley. The Theory Of Atomic Spectra (Cambridge University Press, London, 1935).
[19]
C.ย W.ย Ufford and G.ย H.ย Shortley. Atomic Eigenfunctions and Energies. Physicalย Review 42, 167โ€“175 (1932).
[20]
J.ย vanย Neerven. Functional Analysis. Cambridge Studies in Advanced Mathematics (Cambridge University Press, Cambridge, 2022).
[21]
[22]
P.ย Ajith, M.ย Boyle, D.ย A.ย Brown, S.ย Fairhurst, M.ย Hannam, I.ย Hinder, S.ย Husa, B.ย Krishnan, R.ย A.ย Mercer, F.ย Ohme, C.ย D.ย Ott, J.ย S.ย Read, L.ย Santamaria and J.ย T.ย Whelan. Data formats for numerical relativity waves (2007), arXiv:0709.0093 [gr-qc].
[23]
W.ย Fulton and J.ย Harris. Representation Theory. Vol.ย 129 of Graduate Texts in Mathematics (Springer, New York, NY, 2004).
[24]
J.ย N.ย Goldberg, A.ย J.ย Macfarlane, E.ย T.ย Newman, F.ย Rohrlich and E.ย C.ย Sudarshan. Spinโ€s Spherical Harmonics and รฐ. Journalย ofย Mathematicalย Physics 8, 2155โ€“2161 (1967).
[25]
J.ย J.ย Sakurai. Modern Quantum Mechanics, revisedย Edition (Addison Wesley, New York, 1994).
[26]
[27]
G.ย F.ย Torres Del Castillo. 3-D Spinors, Spin-Weighted Functions and their Applications. Vol.ย 52 no.ย 2 (Birkhรคuser, Boston, MA, 2003); p.ย 299.
[28]
diff --git a/previews/PR49/sYlm/index.html b/previews/PR49/sYlm/index.html index 917607f..96beb79 100644 --- a/previews/PR49/sYlm/index.html +++ b/previews/PR49/sYlm/index.html @@ -10,7 +10,7 @@ Y = sYlm_values!(Y_storage, R, s)

(Beware that, as noted in the documentation for sYlm_values!, the output Y is just a reference to part of the Y_storage object, so you should not reuse Y_storage until you have copied or otherwise finished using Y.)

The output Y is a single vector of Complex numbers with the same base type as R. The ordering of the elements is described in the documentation for sYlm_values!. It is also possible to efficiently view slices of this vector as a series of individual vectors using a sYlm_iterator:

for (โ„“, Yหก) in zip(0:โ„“โ‚˜โ‚โ‚“, sYlm_iterator(Y, โ„“โ‚˜โ‚โ‚“))
     # Do something with the matrix Yหก[โ„“+mโ€ฒ+1, โ„“+m+1]
 end

Docstrings

SphericalFunctions.sYlm_values โ€” Function
sYlm_values(R, โ„“โ‚˜โ‚โ‚“, spin)
-sYlm_values(ฮธ, ฯ•, โ„“โ‚˜โ‚โ‚“, spin)

Compute values of the spin-weighted spherical harmonic ${}_{s}Y_{\ell, m}(R)$ for all $\ell \leq \ell_\mathrm{max}$.

See sYlm_values! for details about the input and output values.

This function only appropriate when you need to evaluate the ${}_{s}Y_{\ell, m}$ for a single value of R or ฮธ, ฯ• because it allocates large arrays and performs many calculations that could be reused. If you need to evaluate the matrices for many values of R or ฮธ, ฯ•, you should pre-allocate the storage with sYlm_prep, and then call sYlm_values! with the result instead.

source
SphericalFunctions.sYlm_values! โ€” Function
sYlm_values!(sYlm_storage, R, spin)
+sYlm_values(ฮธ, ฯ•, โ„“โ‚˜โ‚โ‚“, spin)

Compute values of the spin-weighted spherical harmonic ${}_{s}Y_{\ell, m}(R)$ for all $\ell \leq \ell_\mathrm{max}$.

See sYlm_values! for details about the input and output values.

This function only appropriate when you need to evaluate the ${}_{s}Y_{\ell, m}$ for a single value of R or ฮธ, ฯ• because it allocates large arrays and performs many calculations that could be reused. If you need to evaluate the matrices for many values of R or ฮธ, ฯ•, you should pre-allocate the storage with sYlm_prep, and then call sYlm_values! with the result instead.

source
SphericalFunctions.sYlm_values! โ€” Function
sYlm_values!(sYlm_storage, R, spin)
 sYlm_values!(sYlm_storage, ฮธ, ฯ•, spin)
 sYlm_values!(sYlm, R, โ„“โ‚˜โ‚โ‚“, spin)
 sYlm_values!(sYlm, ฮธ, ฯ•, โ„“โ‚˜โ‚โ‚“, spin)

Compute values of the spin-weighted spherical harmonic ${}_{s}Y_{\ell, m}(R)$ for all $\ell \leq \ell_\mathrm{max}$.

The spherical harmonics of spin weight $s$ are related to Wigner's $\mathfrak{D}$ matrix as

\[\begin{aligned} @@ -27,8 +27,8 @@ T = Float64 R = Rotor{T}(1, 2, 3, 4) # Will be normalized automatically sYlm_storage = sYlm_prep(โ„“โ‚˜โ‚โ‚“, spin, T) -sYlm = sYlm_values!(sYlm_storage, R, spin)

source
SphericalFunctions.sYlm_prep โ€” Function
sYlm_prep(โ„“โ‚˜โ‚โ‚“, sโ‚˜โ‚โ‚“, [T=Float64, [โ„“โ‚˜แตขโ‚™=0]])

Construct storage space and pre-compute recursion coefficients to compute spin-weighted spherical-harmonic values ${}_{s}Y_{\ell, m}$ in place.

This returns the sYlm_storage arguments needed by sYlm_values!.

Note that the result of this function can be passed to sYlm_values!, even if the value of spin passed to that function is smaller (in absolute value) than the sโ‚˜โ‚โ‚“ passed to this function. That is, the sYlm_storage returned by this function can be used to compute ${}_{s}Y_{\ell, m}$ values for numerous values of the spin.

source
SphericalFunctions.sYlm_iterator โ€” Type
sYlm_iterator(Y, โ„“โ‚˜โ‚โ‚“, [โ„“โ‚˜แตขโ‚™, [iโ‚˜แตขโ‚™]])

Construct an Iterator that returns sub-vectors of Y, each of which consists of elements $(โ„“,-โ„“)$ through $(โ„“,โ„“)$, for $โ„“$ from โ„“โ‚˜แตขโ‚™ through โ„“โ‚˜โ‚โ‚“.

Note that the returned objects are views into the original Y data โ€” meaning that you may alter their values.

Because the result is a vector restricted to a particular $โ„“$ value, you can index the $(โ„“, m)$ element as [โ„“+m+1]. For example, you might use this as something like

for (โ„“, Yหก) in zip(โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“, sYlm_iterator(Y, โ„“โ‚˜โ‚โ‚“))
+sYlm = sYlm_values!(sYlm_storage, R, spin)
source
SphericalFunctions.sYlm_prep โ€” Function
sYlm_prep(โ„“โ‚˜โ‚โ‚“, sโ‚˜โ‚โ‚“, [T=Float64, [โ„“โ‚˜แตขโ‚™=0]])

Construct storage space and pre-compute recursion coefficients to compute spin-weighted spherical-harmonic values ${}_{s}Y_{\ell, m}$ in place.

This returns the sYlm_storage arguments needed by sYlm_values!.

Note that the result of this function can be passed to sYlm_values!, even if the value of spin passed to that function is smaller (in absolute value) than the sโ‚˜โ‚โ‚“ passed to this function. That is, the sYlm_storage returned by this function can be used to compute ${}_{s}Y_{\ell, m}$ values for numerous values of the spin.

source
SphericalFunctions.sYlm_iterator โ€” Type
sYlm_iterator(Y, โ„“โ‚˜โ‚โ‚“, [โ„“โ‚˜แตขโ‚™, [iโ‚˜แตขโ‚™]])

Construct an Iterator that returns sub-vectors of Y, each of which consists of elements $(โ„“,-โ„“)$ through $(โ„“,โ„“)$, for $โ„“$ from โ„“โ‚˜แตขโ‚™ through โ„“โ‚˜โ‚โ‚“.

Note that the returned objects are views into the original Y data โ€” meaning that you may alter their values.

Because the result is a vector restricted to a particular $โ„“$ value, you can index the $(โ„“, m)$ element as [โ„“+m+1]. For example, you might use this as something like

for (โ„“, Yหก) in zip(โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“, sYlm_iterator(Y, โ„“โ‚˜โ‚โ‚“))
     for m in -โ„“:โ„“
         Yหก[โ„“+m+1]  # ... do something with Yหก
     end
-end

By default, Y is assumed to contain all possible values, beginning with (0,0). However, if โ„“โ‚˜แตขโ‚™ is not 0, this can be ambiguous: do we mean that Y really starts with the (0,0) element and we are just asking to begin the iteration higher? Or do we mean that Y doesn't even contain data for lower โ„“ values? We can resolve this using iโ‚˜แตขโ‚™, which gives the index of โ„“โ‚˜แตขโ‚™ in Y. By default, we assume the first case, and set iโ‚˜แตขโ‚™=Ysize(โ„“โ‚˜แตขโ‚™-1)+1. However, if Y doesn't contain data below โ„“โ‚˜แตขโ‚™, we could use iโ‚˜แตขโ‚™=1 to indicate the index in Y at which to find $(โ„“โ‚˜แตขโ‚™,-โ„“โ‚˜แตขโ‚™)$.

Also note that no bounds checking is done, either at instantiation time or during iteration. You are responsible for ensuring that the size of Y and the values of โ„“โ‚˜โ‚โ‚“, โ„“โ‚˜แตขโ‚™, and iโ‚˜แตขโ‚™ make sense.

source
+end

By default, Y is assumed to contain all possible values, beginning with (0,0). However, if โ„“โ‚˜แตขโ‚™ is not 0, this can be ambiguous: do we mean that Y really starts with the (0,0) element and we are just asking to begin the iteration higher? Or do we mean that Y doesn't even contain data for lower โ„“ values? We can resolve this using iโ‚˜แตขโ‚™, which gives the index of โ„“โ‚˜แตขโ‚™ in Y. By default, we assume the first case, and set iโ‚˜แตขโ‚™=Ysize(โ„“โ‚˜แตขโ‚™-1)+1. However, if Y doesn't contain data below โ„“โ‚˜แตขโ‚™, we could use iโ‚˜แตขโ‚™=1 to indicate the index in Y at which to find $(โ„“โ‚˜แตขโ‚™,-โ„“โ‚˜แตขโ‚™)$.

Also note that no bounds checking is done, either at instantiation time or during iteration. You are responsible for ensuring that the size of Y and the values of โ„“โ‚˜โ‚โ‚“, โ„“โ‚˜แตขโ‚™, and iโ‚˜แตขโ‚™ make sense.

source diff --git a/previews/PR49/search_index.js b/previews/PR49/search_index.js index 572cfe4..06ca60b 100644 --- a/previews/PR49/search_index.js +++ b/previews/PR49/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"references/#References","page":"References","title":"References","text":"","category":"section"},{"location":"references/","page":"References","title":"References","text":"The most important routine in this package is the computation of the ๐”‡ matrices โ€” or more specifically, of terms proportional to parts of the ๐”‡ matrices. This mostly follows the treatment of Gumerov and Duraiswami [8] (with minor modifications to account for errors in their presentation, as described here). To seed the recursions they present, we also need to calculate the associated Legendre functions. This is now done using the \"fully normalized column-wise recurrence formula\" (fnCWF) given by Eqs. (12)โ€”(14) of Xing et al. [12]. This improves significantly over the older implementation using the \"modified forward row method\" of Holmes and Featherstone [14], for which the results would fail to be finite starting at โ„“=22 for Float16, โ„“=183 for Float32, and โ„“=1474 for Float64. Another approach that was never precisely implemented in this package was due to Fukushima [15], who showed that using \"X-numbers\", wherein the exponent is stored as a separate integer, (implemented in this package) in the core of the recursion could increase the range to โ„“โ‰ˆ2ยณยฒ. Xing et al. showed that Fukushima's results exhibited increased error for certain angles, whereas their Eqs. (12)โ€”(14) could be used directly to obtain results with greater accuracy for those certain angles, and comparable accuracy for other angles.","category":"page"},{"location":"references/","page":"References","title":"References","text":"The other major functionality of this package is map2salm / salm2map, which decomposes function values on regular grids into mode weights (coefficients), and vice versa. The approach used here is taken from Reinecke and Seljebotn [3], with weights based on the method by Waldvogel [6]. However, this interface has been superseded by the SSHT object, which implements several approaches, including the Reinecke-Seljebotn-Waldvogel method, as well as the optimal-dimensionality method due to Elahi et al. [2], as well as a new unpublished optimal-dimensionality method I (Mike Boyle) created.","category":"page"},{"location":"references/#Bibliography","page":"References","title":"Bibliography","text":"","category":"section"},{"location":"references/","page":"References","title":"References","text":"M.ย Boyle. How should spin-weighted spherical functions be defined? Journalย ofย Mathematicalย Physics 57 (2016), arXiv:1604.08140 [gr-qc].\n\n\n\nU.ย Elahi, Z.ย Khalid, R.ย A.ย Kennedy and J.ย D.ย McEwen. An Optimal-Dimensionality Sampling for Spin-s Functions on the Sphere. IEEEย Signalย Processingย Letters 25, 1470โ€“1474 (2018), arXiv:1809.01321 [astro-ph.IM].\n\n\n\nM.ย Reinecke and D.ย S.ย Seljebotn. Libsharpโ€”spherical harmonic transforms revisited. Astronomyย &ย Astrophysics 554, A112 (2013), arXiv:1303.4945 [physics.comp-ph].\n\n\n\nE.ย B.ย Saff and A.ย B.ย Kuijlaars. Distributing many points on a sphere. Theย Mathematicalย Intelligencer 19, 5โ€“11 (1997).\n\n\n\nJ.ย S.ย Brauchart and P.ย J.ย Grabner. Distributing many points on spheres: Minimal energy and designs. Journalย ofย Complexity 31, 293โ€“326 (2015).\n\n\n\nJ.ย Waldvogel. Fast Construction of the Fejรฉr and Clenshawโ€“Curtis Quadrature Rules. BITย Numericalย Mathematics 46, 195โ€“202 (2006).\n\n\n\nE.ย T.ย Newman and R.ย Penrose. Note on the Bondi-Metzner-Sachs Group. Journalย ofย Mathematicalย Physics 7, 863โ€“870 (1966).\n\n\n\nN.ย A.ย Gumerov and R.ย Duraiswami. Recursive Computation of Spherical Harmonic Rotation Coefficients of Large Degree. In: Excursions in Harmonic Analysis, Volume 3 (Springer International Publishing, 2015); pp.ย 105โ€“141, arXiv:1403.7698 [math.NA].\n\n\n\nP.ย J.ย Kostelec and D.ย N.ย Rockmore. FFTs on the Rotation Group. Journalย ofย Fourierย Analysisย andย Applications 14, 145โ€“179 (2008).\n\n\n\nC.ย Doran and A.ย Lasenby. Geometric Algebra for Physicists (Cambridge University Press, Cambridge, 2003).\n\n\n\nH.ย Sommer, I.ย Gilitschenski, M.ย Bloesch, S.ย Weiss, R.ย Siegwart and J.ย Nieto. Why and How to Avoid the Flipped Quaternion Multiplication, arXiv:1801.07478ย cs, arXiv:1801.07478 [cs.RO].\n\n\n\nZ.ย Xing, S.ย Li, M.ย Tian, D.ย Fan and C.ย Zhang. Numerical experiments on column-wise recurrence formula to compute fully normalized associated Legendre functions of ultra-high degree and order. Journalย ofย Geodesy 94 (2019).\n\n\n\nJ.ย D.ย McEwen and Y.ย Wiaux. A Novel Sampling Theorem on the Sphere. IEEEย Transactionsย onย Signalย Processing 59, 5876โ€“5887 (2011), arXiv:1110.6298 [cs.IT].\n\n\n\nS.ย A.ย Holmes and W.ย E.ย Featherstone. A unified approach to the Clenshaw summation and the recursive computation of very high degree and order normalised associated Legendre functions. Journalย ofย Geodesy 76, 279โ€“299 (2002).\n\n\n\nT.ย Fukushima. Numerical computation of spherical harmonics of arbitrary degree and order by extending exponent of floating point numbers. Journalย ofย Geodesy 86, 271โ€“285 (2011).\n\n\n\nG.ย B.ย Folland. A Course in Abstract Harmonic Analysis. 2ย Edition (Chapman and Hall/CRC, New York, 2016).\n\n\n\nG.ย W.ย Hanson and A.ย B.ย Yakovlev. Operator Theory for Electromagnetics (Springer, New York, NY, 2002).\n\n\n\nE.ย U.ย Condon and G.ย H.ย Shortley. The Theory Of Atomic Spectra (Cambridge University Press, London, 1935).\n\n\n\nC.ย W.ย Ufford and G.ย H.ย Shortley. Atomic Eigenfunctions and Energies. Physicalย Review 42, 167โ€“175 (1932).\n\n\n\nJ.ย vanย Neerven. Functional Analysis. Cambridge Studies in Advanced Mathematics (Cambridge University Press, Cambridge, 2022).\n\n\n\nA.ย R.ย Edmonds. Angular Momentum in Quantum Mechanics (Princeton University Press, 2016).\n\n\n\nP.ย Ajith, M.ย Boyle, D.ย A.ย Brown, S.ย Fairhurst, M.ย Hannam, I.ย Hinder, S.ย Husa, B.ย Krishnan, R.ย A.ย Mercer, F.ย Ohme, C.ย D.ย Ott, J.ย S.ย Read, L.ย Santamaria and J.ย T.ย Whelan. Data formats for numerical relativity waves (2007), arXiv:0709.0093 [gr-qc].\n\n\n\nW.ย Fulton and J.ย Harris. Representation Theory. Vol.ย 129 of Graduate Texts in Mathematics (Springer, New York, NY, 2004).\n\n\n\nJ.ย N.ย Goldberg, A.ย J.ย Macfarlane, E.ย T.ย Newman, F.ย Rohrlich and E.ย C.ย Sudarshan. Spinโ€s Spherical Harmonics and รฐ. Journalย ofย Mathematicalย Physics 8, 2155โ€“2161 (1967).\n\n\n\nJ.ย J.ย Sakurai. Modern Quantum Mechanics, revisedย Edition (Addison Wesley, New York, 1994).\n\n\n\nK.ย S.ย Thorne. Multipole expansions of gravitational radiation. Reviewsย ofย Modernย Physics 52, 299 (1980).\n\n\n\nG.ย F.ย Torres Del Castillo. 3-D Spinors, Spin-Weighted Functions and their Applications. Vol.ย 52 no.ย 2 (Birkhรคuser, Boston, MA, 2003); p.ย 299.\n\n\n\nE.ย P.ย Wigner. Group Theory and Its Application to the Quantum Mechanics of Atomic Spectra (Academic Press, New York, NY, 1959).\n\n\n\n","category":"page"},{"location":"wigner_matrices/#Wigner's-๐”‡-and-d-matrices","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"","category":"section"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"Wigner's ๐”‡ matrices โ€” and to a lesser extent, the related d matrices โ€” are extremely important in the theory of rotations. Each element is, itself, a special function of the rotation group: in particular, an eigenfunction of the left- and right-Lie derivatives, and thus a spin-weighted spherical function. Collectively, they describe how spin-weighted spherical functions transform under rotation. But their accurate and efficient computation is surprisingly subtle. This package implements the current state-of-the-art techniques for their fast and accurate computation, based on the H recursion.","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"The actual computations can be done with the D_matrices function:","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"using Quaternionic\nusing SphericalFunctions\n\nR = randn(RotorF64)\nโ„“โ‚˜โ‚โ‚“ = 8\n๐”‡ = D_matrices(R, โ„“โ‚˜โ‚โ‚“)","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"However, the matrices can take up a lot of memory. So for maximum efficiency when calling this function repeatedly with different R values, it is best to pre-allocate the necessary memory with the D_prep function, and the pass that in as an argument to D_matrices!:","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"D_storage = D_prep(โ„“โ‚˜โ‚โ‚“)\n๐”‡ = D_matrices!(D_storage, R)","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"(Beware that, as noted in the documentation for D_matrices!, the output ๐”‡ is just a reference to part of the D_storage object, so you should not reuse D_storage until you have copied or otherwise finished using ๐”‡.)","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"The output ๐”‡ is a (linear!) vector of Complex numbers with the same base type as R. The ordering of the elements is described in the documentation for D_matrices. It is also possible to efficiently view slices of this vector as a series of individual matrices using a D_iterator:","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"for (โ„“, Dหก) in zip(0:โ„“โ‚˜โ‚โ‚“, D_iterator(๐”‡, โ„“โ‚˜โ‚โ‚“))\n # Do something with the matrix Dหก[โ„“+mโ€ฒ+1, โ„“+m+1]\nend","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"For the d matrices, we have almost the same interface, except that instead of the input quaternion R we only need the angle ฮฒ (or its complex angle expiฮฒ, which can be computed directly in some cases), and the output is real-valued:","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"using Quaternionic\nusing SphericalFunctions\n\nฮฒ = ฯ€ * rand(Float64)\nโ„“โ‚˜โ‚โ‚“ = 8\nd = d_matrices(ฮฒ, โ„“โ‚˜โ‚โ‚“)","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"Again, for repeated calls, it is best to pre-allocate storage:","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"d_storage = d_prep(โ„“โ‚˜โ‚โ‚“)\nd = d_matrices!(d_storage, ฮฒ)","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"The output d is a vector of numbers of the same type as ฮฒ, ordered in the same way as the output of D_matrices. And similarly, we can iterate over the individual matrices using a d_iterator.","category":"page"},{"location":"wigner_matrices/#Docstrings","page":"Wigner's ๐”‡ and d matrices","title":"Docstrings","text":"","category":"section"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"D_matrices\nD_matrices!\nD_prep\nD_iterator\nd_matrices\nd_matrices!\nd_prep\nd_iterator","category":"page"},{"location":"wigner_matrices/#SphericalFunctions.D_matrices","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.D_matrices","text":"D_matrices(R, โ„“โ‚˜โ‚โ‚“)\nD_matrices(ฮฑ, ฮฒ, ฮณ, โ„“โ‚˜โ‚โ‚“)\n\nCompute Wigner's ๐”‡ matrices mathfrakD^(ell)_mm(beta) for all ell leq ell_mathrmmax.\n\nSee D_matrices! for details about the input and output values.\n\nThis function only appropriate when you need to evaluate the matrices for a single value of R or ฮฑ, ฮฒ, ฮณ because it allocates large arrays and performs many calculations that could be reused. If you need to evaluate the matrices for many values of R or ฮฑ, ฮฒ, ฮณ, you should pre-allocate the storage with D_prep, and then call D_matrices! with the result instead.\n\n\n\n\n\n","category":"function"},{"location":"wigner_matrices/#SphericalFunctions.D_matrices!","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.D_matrices!","text":"D_matrices!(D_storage, R)\nD_matrices!(D_storage, ฮฑ, ฮฒ, ฮณ)\nD_matrices!(D, R, โ„“โ‚˜โ‚โ‚“)\nD_matrices!(D, ฮฑ, ฮฒ, ฮณ, โ„“โ‚˜โ‚โ‚“)\n\nCompute Wigner's ๐”‡ matrices mathfrakD^(ell)_mm(beta) for all ell leq ell_mathrmmax.\n\nIn all cases, the result is returned in a 1-dimensional array ordered as\n\n[\n ๐”‡หกโ‚˜โ‚š,โ‚˜(R)\n for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“\n for mp โˆˆ -โ„“:โ„“\n for m โˆˆ -โ„“:โ„“\n]\n\nWhen the first argument is D, it will be modified, so it must be at least as large as that array. When the first argument is D_storage, it should be the quantity returned by D_prep, and the result will be written into the D field of that tuple. Both of these options โ€” especially the latter โ€” reduce the number of allocations needed on each call to the corresponding functions, which should increase the speed significantly. Note that the D or D_storage arguments must have types compatible with the type of R or ฮฑ, ฮฒ, ฮณ.\n\nwarn: Warn\nWhen using the D_storage argument (which is recommended), the returned quantity D will be an alias of D_storage[1]. If you want to retain that data after the next call to D_matrices!, you should copy it with copy(D).\n\nThe ฮฑ, ฮฒ, ฮณ arguments are Euler angles as described in the documentation of Quaternionic.from_euler_angles.\n\nSee also D_matrices for a simpler function call when you only need to evaluate the matrices for a single value of R or ฮฑ, ฮฒ, ฮณ.\n\nExamples\n\nusing Quaternionic, SphericalFunctions\nโ„“โ‚˜โ‚โ‚“ = 8\nT = Float64\nR = Rotor{T}(1, 2, 3, 4) # Will be normalized automatically\nD_storage = D_prep(โ„“โ‚˜โ‚โ‚“, T)\nD = D_matrices!(D_storage, R)\n\n\n\n\n\n","category":"function"},{"location":"wigner_matrices/#SphericalFunctions.D_prep","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.D_prep","text":"D_prep(โ„“โ‚˜โ‚โ‚“, [T=Float64])\n\nConstruct storage space and pre-compute recursion coefficients to compute Wigner's mathfrakD matrix in place.\n\nThis returns the D_storage arguments needed by D_matrices!.\n\n\n\n\n\n","category":"function"},{"location":"wigner_matrices/#SphericalFunctions.D_iterator","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.D_iterator","text":"D_iterator(D, โ„“โ‚˜โ‚โ‚“, [โ„“โ‚˜แตขโ‚™])\n\nConstruct an Iterator that returns sub-matrices of D, each of which consists of elements (โ„“-โ„“-โ„“) through (โ„“โ„“โ„“), for โ„“ from โ„“โ‚˜แตขโ‚™ through โ„“โ‚˜โ‚โ‚“. By default, โ„“โ‚˜แตขโ‚™ is 0.\n\ndanger: Inconsistent behavior\nThis iterator mistakenly returns the transpose of the result implied by this documentation. As a result, a warning is issued every time this function is called. Rather than actually fixing this bug in this minor/patch version โ€” which would be a breaking change โ€” this is a final release in this major version of the package to notify users of this function (and d_iterator) that there is a problem. The next major version of the package will likely change the actual behavior to the one implied by this docstring. To quiet these warnings, you can use Dit = with_logger(NullLogger()) do D_iterator(...) end.\n\nNote that the returned objects are views into the original D data โ€” meaning that you may alter their values.\n\nBecause the result is a matrix restricted to a particular โ„“ value, you can index the (โ„“ m m) element as [โ„“+mโ€ฒ+1, โ„“+m+1]. For example, you might use this as something like\n\nfor (โ„“, Dหก) in zip(โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“, D_iterator(D, โ„“โ‚˜โ‚โ‚“))\n for mโ€ฒ in -โ„“:โ„“\n for m in -โ„“:โ„“\n Dหก[โ„“+mโ€ฒ+1, โ„“+m+1] # ... do something with Dหก\n end\n end\nend\n\nAlso note that no bounds checking is done, either at instantiation time or during iteration. You are responsible for ensuring that the size of D and the values of โ„“โ‚˜โ‚โ‚“ and โ„“โ‚˜แตขโ‚™ make sense.\n\n\n\n\n\n","category":"type"},{"location":"wigner_matrices/#SphericalFunctions.d_matrices","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.d_matrices","text":"d_matrices(ฮฒ, โ„“โ‚˜โ‚โ‚“)\nd_matrices(expiฮฒ, โ„“โ‚˜โ‚โ‚“)\n\nCompute Wigner's d^(ell) matrices with elements d^(ell)_mm(beta) for all ell leq ell_mathrmmax. The d matrices are sometimes called the \"reduced\" Wigner matrices, in contrast to the full mathfrakD matrices.\n\nSee d_matrices! for details about the input and output values.\n\nThis function only appropriate when you need to evaluate the matrices for a single value of ฮฒ or expiฮฒ because it allocates large arrays and performs many calculations that could be reused. If you need to evaluate the matrices for many values of ฮฒ or expiฮฒ, you should pre-allocate the storage with d_prep, and then call d_matrices! with the result instead.\n\n\n\n\n\n","category":"function"},{"location":"wigner_matrices/#SphericalFunctions.d_matrices!","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.d_matrices!","text":"d_matrices!(d_storage, ฮฒ)\nd_matrices!(d_storage, expiฮฒ)\nd_matrices!(d, ฮฒ, โ„“โ‚˜โ‚โ‚“)\nd_matrices!(d, expiฮฒ, โ„“โ‚˜โ‚โ‚“)\n\nCompute Wigner's d^(ell) matrices with elements d^(ell)_mm(beta) for all ell leq ell_mathrmmax. The d matrices are sometimes called the \"reduced\" Wigner matrices, in contrast to the full mathfrakD matrices.\n\nIn all cases, the result is returned in a 1-dimensional array ordered as\n\n[\n dหกโ‚˜โ‚š,โ‚˜(ฮฒ)\n for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“\n for mp โˆˆ -โ„“:โ„“\n for m โˆˆ -โ„“:โ„“\n]\n\nWhen the first argument is d, it will be modified, so it must be at least as large as that array. When the first argument is d_storage, it should be the quantity returned by d_prep, and the result will be written into the d field of that tuple. Both of these options โ€” especially the latter โ€” reduce the number of allocations needed on each call to the corresponding functions, which should increase the speed significantly.\n\nwarn: Warn\nWhen using the d_storage argument (which is recommended), the returned quantity d will be an alias of d_storage[1]. If you want to retain that data after the next call to d_matrices!, you should copy it with copy(d).\n\nSee also d_matrices for a simpler function call when you only need to evaluate the matrices for a single value of ฮฒ or expiฮฒ.\n\nExamples\n\nusing SphericalFunctions\nโ„“โ‚˜โ‚โ‚“ = 8\nT = Float64\nฮฒ = T(1)/8\nd_storage = d_prep(โ„“โ‚˜โ‚โ‚“, T)\nd = d_matrices!(d_storage, ฮฒ)\n\n\n\n\n\n","category":"function"},{"location":"wigner_matrices/#SphericalFunctions.d_prep","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.d_prep","text":"d_prep(โ„“โ‚˜โ‚โ‚“, [T=Float64])\n\nConstruct space and pre-compute recursion coefficients to compute Wigner's d matrix in place.\n\nThis returns the d_storage arguments needed by d_matrices!.\n\n\n\n\n\n","category":"function"},{"location":"wigner_matrices/#SphericalFunctions.d_iterator","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.d_iterator","text":"d_iterator(d, โ„“โ‚˜โ‚โ‚“, [โ„“โ‚˜แตขโ‚™])\n\nConstruct an Iterator that returns sub-matrices of d, each of which consists of elements (โ„“-โ„“-โ„“) through (โ„“โ„“โ„“), for โ„“ from โ„“โ‚˜แตขโ‚™ through โ„“โ‚˜โ‚โ‚“. By default, โ„“โ‚˜แตขโ‚™ is 0.\n\ndanger: Inconsistent behavior\nThis iterator mistakenly returns the transpose of the result implied by this documentation. As a result, a warning is issued every time this function is called. Rather than actually fixing this bug in this minor/patch version โ€” which would be a breaking change โ€” this is a final release in this major version of the package to notify users of this function (and D_iterator) that there is a problem. The next major version of the package will likely change the actual behavior to the one implied by this docstring. To quiet these warnings, you can use Dit = with_logger(NullLogger()) do D_iterator(...) end.\n\nNote that the returned objects are views into the original d data โ€” meaning that you may alter their values.\n\nBecause the result is a matrix restricted to a particular โ„“ value, you can index the (โ„“ m m) element as [โ„“+mโ€ฒ+1, โ„“+m+1]. For example, you might use this as something like\n\nfor (โ„“, dหก) in zip(โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“, d_iterator(d, โ„“โ‚˜โ‚โ‚“))\n for mโ€ฒ in -โ„“:โ„“\n for m in -โ„“:โ„“\n dหก[โ„“+mโ€ฒ+1, โ„“+m+1] # ... do something with dหก\n end\n end\nend\n\nAlso note that no bounds checking is done, either at instantiation time or during iteration. You are responsible for ensuring that the size of d and the values of โ„“โ‚˜โ‚โ‚“ and โ„“โ‚˜แตขโ‚™ make sense.\n\n\n\n\n\n","category":"type"},{"location":"conventions/comparisons/#Comparisons","page":"Comparisons","title":"Comparisons","text":"","category":"section"},{"location":"conventions/comparisons/","page":"Comparisons","title":"Comparisons","text":"Here, we compare our conventions to other sources, including references in the literature as well as other software that implements some of these. Each of these comparisons is also performed explicitly in this package's test suite.","category":"page"},{"location":"conventions/comparisons/","page":"Comparisons","title":"Comparisons","text":"Among the items that would be good to compare are the following, when actually used by any of these sources:","category":"page"},{"location":"conventions/comparisons/","page":"Comparisons","title":"Comparisons","text":"Quaternions\nOrder of components\nBasis\nOperation as rotations\nEuler angles\nSpherical coordinates\nSpherical harmonics\nCondon-Shortley phase\nFormula\nSpin-weighted spherical harmonics\nBehavior under rotation\nWigner D-matrices\nOrder of indices\nConjugation\nFunction of rotation or inverse rotation\nFormula","category":"page"},{"location":"conventions/comparisons/","page":"Comparisons","title":"Comparisons","text":"One major result of this is that almost everyone since 1935 has used the same exact expression for the (scalar) spherical harmonics.","category":"page"},{"location":"conventions/comparisons/#Condon-Shortley","page":"Comparisons","title":"Condon-Shortley","text":"","category":"section"},{"location":"conventions/comparisons/#Wigner","page":"Comparisons","title":"Wigner","text":"","category":"section"},{"location":"conventions/comparisons/#Newman-Penrose","page":"Comparisons","title":"Newman-Penrose","text":"","category":"section"},{"location":"conventions/comparisons/#Goldberg","page":"Comparisons","title":"Goldberg","text":"","category":"section"},{"location":"conventions/comparisons/#Wikipedia","page":"Comparisons","title":"Wikipedia","text":"","category":"section"},{"location":"conventions/comparisons/#Mathematica","page":"Comparisons","title":"Mathematica","text":"","category":"section"},{"location":"conventions/comparisons/#SymPy","page":"Comparisons","title":"SymPy","text":"","category":"section"},{"location":"conventions/comparisons/#Sakurai","page":"Comparisons","title":"Sakurai","text":"","category":"section"},{"location":"conventions/comparisons/#Thorne","page":"Comparisons","title":"Thorne","text":"","category":"section"},{"location":"conventions/comparisons/#Torres-del-Castillo","page":"Comparisons","title":"Torres del Castillo","text":"","category":"section"},{"location":"conventions/comparisons/#NINJA","page":"Comparisons","title":"NINJA","text":"","category":"section"},{"location":"conventions/comparisons/#LALSuite","page":"Comparisons","title":"LALSuite","text":"","category":"section"},{"location":"utilities/#Utilities","page":"Utilities","title":"Utilities","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"While not usually the star of the show, the following utilities can be quite helpful for actually using the rest of the code.","category":"page"},{"location":"utilities/#Complex-powers","page":"Utilities","title":"Complex powers","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"One common task we find when working with spherical functions is the computation of a range of integer powers of some complex number โ€” so much so that it can be best to pre-compute the powers and cache their values. While a naive approach is generally quite accurate, and reasonably fast, we can do a little better with a specialized routine.","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"Modules = [SphericalFunctions]\nPages = [\"complex_powers.jl\"]\nOrder = [:module, :type, :constant, :function, :macro]","category":"page"},{"location":"utilities/#SphericalFunctions.complex_powers!-Tuple{Any, Any}","page":"Utilities","title":"SphericalFunctions.complex_powers!","text":"complex_powers!(zpowers, z)\n\nCompute integer powers of z from z^0 through z^m, recursively, where m is one less than the length of the input zpowers vector.\n\nNote that z is assumed to be normalized, with complex amplitude approximately 1.\n\nSee also: complex_powers\n\n\n\n\n\n","category":"method"},{"location":"utilities/#SphericalFunctions.complex_powers-Tuple{Any, Int64}","page":"Utilities","title":"SphericalFunctions.complex_powers","text":"complex_powers(z, m)\n\nCompute integer powers of z from z^0 through z^m, recursively.\n\nNote that z is assumed to be normalized, with complex amplitude approximately 1.\n\nThis algorithm is mostly due to Stoer and Bulirsch in \"Introduction to Numerical Analysis\" (page 24) โ€” with a little help from de Moivre's formula, which is essentially exp(iฮธ)โฟ = exp(inฮธ), as well as my own alterations to deal with different behaviors in different quadrants.\n\nThere isn't usually a huge advantage to using this specialized function. If you just need a particular power, it will generally be far more efficient and just as accurate to compute either exp(iฮธ)โฟ or exp(inฮธ) explicitly. However, if you need all powers from 0 to m, this function is about 10 or 5 times faster than those options, respectively, for large m. Like those options, this function is numerically stable, in the sense that its errors are usually smaller than m times the error from machine-precision errors in the input argument โ€” or at worst about 50% larger, which occurs as the phase approaches multiples of ฯ€/2.\n\nSee also: complex_powers!\n\n\n\n\n\n","category":"method"},{"location":"utilities/#Sizes-of-and-indexing-into-๐”‡,-d,-and-Y-data","page":"Utilities","title":"Sizes of and indexing into ๐”‡, d, and Y data","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"By Y data, we mean anything indexed like Y_ell m modes; by D data, we mean anything indexed like Wigner's mathfrakD matrices, or special subsets of them, like the H matrices.","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"Modules = [SphericalFunctions]\nPages = [\"indexing.jl\", \"wigner_matrices/indexing.jl\", \"wigner_matrices/Hrecursions.jl\"]\nOrder = [:module, :type, :constant, :function, :macro]","category":"page"},{"location":"utilities/#SphericalFunctions.WignerDindex","page":"Utilities","title":"SphericalFunctions.WignerDindex","text":"WignerDindex(โ„“, mโ€ฒ, m, mโ€ฒโ‚˜โ‚โ‚“=โ„“)\n\nCompute index into Wigner ๐”‡ matrix\n\nSee also WignerDrange and WignerDsize.\n\nNotes\n\nThis assumes that the Wigner ๐”‡ matrix is arranged as\n\n[\n ๐”‡(โ„“, mโ€ฒ, m)\n for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“\n for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)\n for m โˆˆ -โ„“:โ„“\n]\n\n\n\n\n\n","category":"function"},{"location":"utilities/#SphericalFunctions.WignerDrange","page":"Utilities","title":"SphericalFunctions.WignerDrange","text":"WignerDrange(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)\n\nCreate an array of (โ„“, m', m) indices as in ๐”‡ array\n\nSee also WignerDsize and WignerDindex.\n\nNotes\n\nThis assumes that the Wigner ๐”‡ matrix is arranged as\n\n[\n ๐”‡(โ„“, mโ€ฒ, m)\n for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“\n for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)\n for m โˆˆ -โ„“:โ„“\n]\n\n\n\n\n\n","category":"function"},{"location":"utilities/#SphericalFunctions.WignerDsize-Tuple{Any}","page":"Utilities","title":"SphericalFunctions.WignerDsize","text":"WignerDsize(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)\n\nCompute total size of Wigner ๐”‡ matrix\n\nSee also WignerDrange and WignerDindex.\n\nNotes\n\nThis assumes that the Wigner ๐”‡ matrix is arranged as\n\n[\n ๐”‡(โ„“, mโ€ฒ, m)\n for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“\n for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)\n for m โˆˆ -โ„“:โ„“\n]\n\n\n\n\n\n","category":"method"},{"location":"utilities/#SphericalFunctions.WignerHindex","page":"Utilities","title":"SphericalFunctions.WignerHindex","text":"WignerHindex(โ„“, mโ€ฒ, m, mโ€ฒโ‚˜โ‚โ‚“)\n\nIndex to \"wedge\" arrays.\n\nSee also WignerHsize and WignerHrange.\n\nNotes\n\nHere, it is assumed that only data with mโ‰ฅ|m'| are stored, and only corresponding values are passed. We also assume |m|โ‰คโ„“ and |m'|โ‰คโ„“. Neither of these are checked. The wedge array that this function indexes is ordered as\n\n[\n H(โ„“, mโ€ฒ, m) for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“\n for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)\n for m โˆˆ abs(mโ€ฒ):โ„“\n]\n\n\n\n\n\n","category":"function"},{"location":"utilities/#SphericalFunctions.WignerHrange","page":"Utilities","title":"SphericalFunctions.WignerHrange","text":"WignerHrange(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)\n\nCreate an array of (โ„“, m', m) indices as in H array\n\nSee also WignerHsize and WignerHindex\n\nNotes\n\nHere, it is assumed that only data with mโ‰ฅ|m'| are stored, and only corresponding values are passed. We also assume |m|โ‰คโ„“ and |m'|โ‰คโ„“. Neither of these are checked. The wedge array that this function indexes is ordered as\n\n[\n H(โ„“, mโ€ฒ, m) for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“\n for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)\n for m โˆˆ abs(mโ€ฒ):โ„“\n]\n\n\n\n\n\n","category":"function"},{"location":"utilities/#SphericalFunctions.WignerHsize-Tuple{Any}","page":"Utilities","title":"SphericalFunctions.WignerHsize","text":"WignerHsize(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)\n\nTotal size of array of wedges of width mโ€ฒโ‚˜โ‚โ‚“ up to โ„“โ‚˜โ‚โ‚“. If mโ€ฒโ‚˜โ‚โ‚“ is not given, it defaults to โ„“โ‚˜โ‚โ‚“.\n\nSee also WignerHrange and WignerHindex.\n\nNotes\n\nHere, it is assumed that only data with mโ‰ฅ|mโ€ฒ| are stored, and only corresponding values are passed. We also assume |m|โ‰คโ„“ and |mโ€ฒ|โ‰คโ„“. Neither of these are checked. The wedge array that this function indexes is ordered as\n\n[\n H(โ„“, mโ€ฒ, m) for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“\n for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)\n for m โˆˆ abs(mโ€ฒ):โ„“\n]\n\n\n\n\n\n","category":"method"},{"location":"utilities/#SphericalFunctions.Yindex","page":"Utilities","title":"SphericalFunctions.Yindex","text":"Yindex(โ„“, m, โ„“โ‚˜แตขโ‚™=0)\n\nCompute index into array of mode weights\n\nParameters\n\nโ„“ : int Integer satisfying โ„“โ‚˜แตขโ‚™ <= โ„“ <= โ„“โ‚˜โ‚โ‚“ m : int Integer satisfying -โ„“ <= m <= โ„“ โ„“โ‚˜แตขโ‚™ : int, optional Integer satisfying 0 <= โ„“โ‚˜แตขโ‚™. Defaults to 0.\n\nReturns\n\ni : int Index of a particular element of the mode-weight array as described below\n\nSee Also\n\nYsize : Total size of array of mode weights Yrange : Array of (โ„“, m) indices corresponding to this array\n\nNotes\n\nThis assumes that the modes are arranged (with fixed s value) as\n\n[\n Y(s, โ„“, m)\n for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“\n for m โˆˆ -โ„“:โ„“\n]\n\n\n\n\n\n","category":"function"},{"location":"utilities/#SphericalFunctions.Yrange-Tuple{Any}","page":"Utilities","title":"SphericalFunctions.Yrange","text":"Yrange(โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“)\n\nCreate an array of (โ„“, m) indices as in Y array\n\nParameters\n\nโ„“โ‚˜แตขโ‚™ : int Integer satisfying 0 <= โ„“โ‚˜แตขโ‚™ <= โ„“โ‚˜โ‚โ‚“ โ„“โ‚˜โ‚โ‚“ : int Integer satisfying 0 <= โ„“โ‚˜แตขโ‚™ <= โ„“โ‚˜โ‚โ‚“\n\nReturns\n\ni : int Total size of array of mode weights arranged as described below\n\nSee Also\n\nYsize : Total size of array of mode weights Yindex : Index of a particular element of the mode weight array\n\nNotes\n\nThis assumes that the modes are arranged (with fixed s value) as\n\n[\n Y(s, โ„“, m)\n for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“\n for m โˆˆ -โ„“:โ„“\n]\n\n\n\n\n\n","category":"method"},{"location":"utilities/#SphericalFunctions.Ysize-Tuple{Any}","page":"Utilities","title":"SphericalFunctions.Ysize","text":"Ysize(โ„“โ‚˜โ‚โ‚“)\n\nCompute total size of array of mode weights\n\nSee Also\n\nYrange : Array of (โ„“, m) indices corresponding to this array Yindex : Index of a particular element of the mode weight array\n\nNotes\n\nThis assumes that the modes are arranged (with fixed s value) as\n\n[\n Y(s, โ„“, m)\n for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“\n for m โˆˆ -โ„“:โ„“\n]\n\n\n\n\n\n","category":"method"},{"location":"utilities/#SphericalFunctions._WignerHindex-NTuple{4, Any}","page":"Utilities","title":"SphericalFunctions._WignerHindex","text":"WignerHindex(โ„“, mโ€ฒ, m, mโ€ฒโ‚˜โ‚โ‚“)\n\nHelper function for WignerHindex, with more constraints.\n\nThis function assumes that m โ‰ฅ |mโ€ฒ|. The main WignerHindex function uses symmetries of the H array to account for cases that violate this assumption. (But note that both that function and this one assume that |m| โ‰ค โ„“ and |mโ€ฒ| โ‰ค โ„“.)\n\n\n\n\n\n","category":"method"},{"location":"utilities/#SphericalFunctions.deduce_limits","page":"Utilities","title":"SphericalFunctions.deduce_limits","text":"deduce_limits(ysize, [โ„“min])\n\nDeduce the value of (โ„“min, โ„“max) that produces Y arrays of the given size.\n\nIf โ„“min is not given, it is assumed to be 0. If it is set to nothing, the smallest possible value of โ„“min will be used. However, note that this is not a well-posed problem; multiple combinations of (โ„“min, โ„“max) can give rise to Y arrays of the same size.\n\nSee also Ysize\n\n\n\n\n\n","category":"function"},{"location":"utilities/#SphericalFunctions.phi_theta-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"Utilities","title":"SphericalFunctions.phi_theta","text":"phi_theta(Nฯ•, Nฮธ, [T=Float64])\n\nConstruct (phi, theta) grid in order expected by this package.\n\nSee also theta_phi for the opposite ordering.\n\n\n\n\n\n","category":"method"},{"location":"utilities/#SphericalFunctions.theta_phi-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"Utilities","title":"SphericalFunctions.theta_phi","text":"theta_phi(Nฮธ, Nฯ•, [T=Float64])\n\nConstruct (theta, phi) grid in spinsfast order.\n\nNote that this order is different from the one assumed by this package; use phi_theta for the opposite ordering.\n\n\n\n\n\n","category":"method"},{"location":"utilities/#Combinatorics","page":"Utilities","title":"Combinatorics","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"Spherical functions frequently involve binomial coefficients and similar terms, with arguments proportional to โ„“, which we aim to allow to be very large โ€” of order 1,000 or more. Unfortunately, due to combinatorical explosions, this is frequently infeasible with naive methods. Here, we collect any specialized methods that help us beat the limits.","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"Modules = [SphericalFunctions]\nPages = [\"utils.jl\"]","category":"page"},{"location":"utilities/#SphericalFunctions.sqrtbinomial-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"Utilities","title":"SphericalFunctions.sqrtbinomial","text":"sqrtbinomial(n, k, [T])\n\nEvaluate the square-root of the binomial coefficient binomial(n,k) for large coefficients.\n\nOrdinarily, when n and k are standard Int arguments, the built-in binomial function will overflow around n=66, because it results in Ints. We need much larger values. This function, which is based on a related one in SpecialFunctions.jl, returns reasonably accurate results up to n โ‰ˆ 1026 when k โ‰ˆ n/2 (which is the case of interest in many applications in this package).\n\nComputations are carried out (and returned) in type T, which defaults to Float64.\n\n\n\n\n\n","category":"method"},{"location":"conventions/outline/#Outline","page":"Outline","title":"Outline","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Three-dimensional Euclidean space\nCartesian coordinates (x y z) => โ„ยณ\nCartesian basis vectors (๐ฑ ๐ฒ ๐ณ)\nEuclidean norm => Euclidean metric\nSpherical coordinates\nSpecifically give transformation to/from (x y z)\nDerive metric in these coordinates from transformation\nIntegration / measure on two-sphere\nDerive as restriction of full metric, in both coordinate systems\nFour-dimensional Euclidean space\nEight-dimensional Clifford algebra over the tangent vector space Tโ„ยณ\nFour-dimensional even sub-algebra => โ„โด\nCoordinates (W X Y Z)\nBasis vectors (๐Ÿ ๐ข ๐ฃ ๐ค), but we usually just omit ๐Ÿ\nShow a few essential formulas establishing the product and its conventions\nUnit quaternions are isomorphic to mathbfSpin(3) = mathbfSU(2); double covers mathbfSO(3)\nBe explicit about the mapping between vector in โ„ยณ and quaternions\nShow how a unit quaternion can be used to rotate a vector\nSpherical coordinates (hyperspherical / Euler)\nSpecifically give transformation to/from (W X Y Z)\nDerive metric in these coordinates from transformation\nExpress unit quaternion in Euler angles\nIntegration / measure / Haar measure on three-sphere\nDerive as restriction of full metric, in both coordinate systems\nAngular momentum operators / functional analysis\nExpress angular momentum operators in terms of quaternion components\nExpress angular momentum operators in terms of Euler angles\nShow for both the three- and two-spheres\nShow how they act on functions on the three-sphere\nRepresentation theory / harmonic analysis\nRepresentations show up in Fourier analysis on groups\nPeter-Weyl theorem\nGeneralizes Fourier analysis to compact groups\nA basis of functions on the group is given by matrix elements of group representations\nRepresentation theory of mathbfSpin(3)\nShow how the Lie algebra is represented by the angular-momentum operators\nShow how the Lie group is represented by the Wigner D-matrices\nDemonstrate that mathfrakD is a representation\nDemonstrate its behavior under left and right rotation\nDemonstrate orthonormality\nRepresentation theory of mathbfSO(3)\nThere are several places in Folland (e.g., above corollary 5.48) where he mentions that representations of a quotient group are just representations that are trivial (evidently meaning mapping everything to the identity matrix) on the factor. I can't find anywhere that he explains this explicitly, but it seems easy enough to show. He might do it using characters.\nFor mathbfSpin(3) and mathbfSO(3), the factor group is just 1 -1. Presumably, every representation acting on 1 will give the identity matrix, so that's trivial. So we just need a criterion for when a representation is trivial on -1. Noting that exp(pi vecv) = -1 for any vecv, I think we can show that this requires m in mathbbZ.\nBasically, the point is that the representations of mathbfSO(3) are just the integer representations of mathbfSpin(3).\nRestrict to homogeneous space (Sยณ -> Sยฒ)\nThe circle group is a closed (normal?) subgroup of mathbfSpin(3), which we might implement as initial multiplication about a particular axis.\nIn Eq. (2.47) Folland (2016) defines a functional taking a function on the group to a function on the homogeneous space by integrating over the factor (the circle group). This gives you the spherical harmonics, but not the spin-weighted spherical harmonics โ€” because the spin-weighted spherical harmonics cannot be defined on the 2-sphere.\nSpin weight comes from Fourier analysis on the subgroup.\nRepresentation matrices transfer to the homogeneous space, with sparsity patterns","category":"page"},{"location":"conventions/outline/#Notes","page":"Outline","title":"Notes","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Spherical harmonics as functions on homogeneous space. https://www.youtube.com/watch?v=TnFvOa9v7do gives some nice discussion; maybe the paper has better references.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Theorem 2.16 of Hanson-Yakovlev says that an orthonormal basis of a product of L^2 spaces is given by the product of the orthonormal bases of the individual spaces. Furthermore, on page 354, they point out that (1sqrt2pi) e^imphi is an orthonormal basis of L^2(02pi), while the set 1c_nm P_n^m(costheta) is an orthonormal basis of L^2(0 pi) in the theta coordinate. Therefore, the product of these two sets is an orthonormal basis of the product space L^2left((02pi) times (0 pi)right), which forms a coordinate space for S^2. I would probably modify this to point out that (02pi) is really S^1, and then we could extend it to point out that you can throw on another factor of S^1 to cover S^3, which happens to give us the Wigner D-matrices.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"We first define the rotor that takes (hatx haty hatz) onto (hattheta hatphi hatr). Then, we can invert that, so that given a rotor that specifies such a rotation exactly, we can get the spherical coordinates โ€” or specifically sintheta, costheta, and exp(iphi).","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Then, with the universally agreed-upon Y as given in terms of spherical coordinates, we can rewrite it directly to work with quaternion components, and then it immediately applies to general rotations, which allows us to figure out where the s should go. That is, we can essentially derive _sY from the universal formula for Y.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Then, we can simply follow Wigner around Eq. (15.21) to derived a transformation law in the form","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"_sY_ellm(R_theta phi) = sum_m M_mm(R)\n_sY_ellm(R_theta phi)","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"for some matrix M. Note that I have written this as if the _sY functions are column vectors. The reason this happens is because I want to write R_theta phi = R R_theta phi, rather than swapping the order of the rotations on the right-hand side.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"The big problem here is that Wigner, in his Eq. (15.21) defines the transformation matrix as if the eigenfunctions formed a row vector instead of a column vector, which means that his matrix is transposed compared to what I want to write. I suppose maybe other authors then just consider the inverse rotation, so that they can work with the conjugate transpose, which is why we see the relative conjugate.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Since Y is universal, let's start with that as non-negotiable, and see if we can derive the relationship to mathfrakD.\nR_theta phi is a unit quaternion that rotates the point described by Cartesian coordinates (0,0,1) onto the point described by spherical coordinates (theta phi).\nJust textually, it makes the most sense to write\nR_theta phi = R R_theta phi\nfor some rotation R. Now, we just need to interpret R.\nAgain, just textually, it makes the most sense to write\nY_ellm(theta phi) = sum_m mathfrakD^(ell)_mm(R)\nY_ellm(theta phi)\nor, generalizing to spin-weighted spherical harmonics\n_sY_ellm(R_theta phi) = sum_m mathfrakD^(ell)_mm(R)\n_sY_ellm(R_theta phi)\nWe also have that mathfrakD obeys the representation property, so\nmathfrakD^(ell)_mm(R_theta phi)\n= sum_m mathfrakD^(ell)_mm(R)\nmathfrakD^(ell)_mm(R_theta phi)\nThere is no reason that I can see to introduce a conjugation\nThe fact that m appears on both sides of the equation means that it must correspond to s โ€” though we have to check the behavior under final rotation to determine the sign.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"_sY_ellm(R_theta phi)\npropto\nmathfrakD^(ell)_mpropto s(R_theta phi)","category":"page"},{"location":"conventions/outline/#collapsible-markdown?","page":"Outline","title":"collapsible markdown?","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"
CLICK ME","category":"page"},{"location":"conventions/outline/#yes,-even-hidden-code-blocks!","page":"Outline","title":"yes, even hidden code blocks!","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"println(\"hello world!\")","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"
","category":"page"},{"location":"conventions/outline/#More-notes","page":"Outline","title":"More notes","text":"","category":"section"},{"location":"conventions/outline/#Spherical-harmonics","page":"Outline","title":"Spherical harmonics","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Fortunately, there does not seem to be any disagreement in the physics literature about the definition of the spherical harmonics; everyone uses the Condon-Shortley convention. Or at least, they say they do. The problem arises when people define the spherical harmonics in terms of the Legendre polynomials, for which there is a sign ambiguity. Therefore, to ensure that we are using the same conventions, we need to go back to the original definition of the spherical harmonics by Condon and Shortley.","category":"page"},{"location":"conventions/outline/#Condon-Shortley-phase","page":"Outline","title":"Condon-Shortley phase","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"The Condon-Shortley phase convention is a choice of phase factors in the definition of the spherical harmonics that requires the coefficients in","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"L_pm ellmrangle = alpha^pm_ellm ell m pm 1rangle","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"to be real and positive. The reasoning behind this choice is explained more clearly in Section 2 of Ufford and Shortley (1932). As a more practical matter, the Condon-Shortley phase describes signs chosen in the expression for spherical harmonics. The key expression is Eq. (15) of section 4ยณ (page 52) of Condon-Shortley:","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Theta(ell m) = (-1)^ell sqrtfrac2ell+12 frac(ell+m)(ell-m)\nfrac12^ell ell frac1sin^mtheta\nfracd^ell-md(costheta)^ell-m sin^2elltheta","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"When multiplied by Eq. (5) Phi(m) = e^imphi sqrt2pi, this gives the spherical harmonic function. The right-hand side of the expression above is usually immediately replaced by a simpler expression using Legendre polynomials, but this just shifts sign ambiguity into the definition of the Legendre polynomials. Instead, we can expand the above expression directly for the first few ell values and/or use automatic differentiation to actually test their original expression as such against the function implemented in this package. The first few values are given in a footnote to Condon and Shortley's Eq. (15) (and have been verified separately by hand and by computation with SymPy):","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\nTheta(00) = sqrtfrac12 \nTheta(10) = sqrtfrac32 costheta \nTheta(1pm1) = mp sqrtfrac34 sintheta \nTheta(20) = sqrtfrac58 (2cos^2theta - sin^2theta) \nTheta(2pm1) = mp sqrtfrac154 costheta sintheta \nTheta(2pm2) = sqrtfrac1516 sin^2theta \nTheta(30) = sqrtfrac78 (2cos^3theta - 3costhetasin^2theta) \nTheta(3pm1) = mp sqrtfrac2132 (4cos^2thetasintheta - sin^3theta) \nTheta(3pm2) = sqrtfrac10516 costheta sin^2theta \nTheta(3pm3) = mp sqrtfrac3532 sin^3theta\nendaligned","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"These are tested, along with the results from automatic differentiation, every time this package is updated. The result is perfect agreement, so that we can definitively say that ***the spherical-harmonic functions provided by this package obey the Condon-Shortley phase convention.***","category":"page"},{"location":"conventions/outline/#Angular-momentum-operators","page":"Outline","title":"Angular-momentum operators","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"First, a couple points about -ihbar:\nThe finite transformations look like exp-i theta L_j, but the factor of i introduced here just cancels the one in the L_j, and the sign is just chosen to make the result consistent with our notion of active or passive transformations.\nAny factors of hbar are included purely for the sake of convenience.\nThe factor i comes from plain functional analysis: We need a self-adjoint operator, and partial_x by itself is anti-self-adjoint (as can be verified by evaluating on langle x x rangle = delta(x-x), which switches sign based on which is being differentiated). We want self-adjoint operators so that we get purely real eigenvalues. Van Neerven cites this in a more rigorous context in his Example (10.40) (page 331), with more explanation around Eq. (15.17) (page 592). The \"self-adjoint iff real eigenvalues\" condition is item (1) in his Corollary 9.18.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Wigner's ๐”‡ matrices are defined as matrix elements of a rotation in the basis of spherical harmonics. That rotation is defined in terms of the generators of rotation, which are expressed in terms of the angular-momentum operators. Therefore, to really understand conventions for the ๐”‡ matrices, we need to understand conventions for the angular-momentum operators.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"There is universal agreement that the angular momentum is defined as mathbfL = mathbfx times mathbfp, where mathbfx is the position vector and mathbfp is the momentum vector. In quantum mechanics, there is further agreement that the momentum operator becomes -ihbarnabla. Thus, in operator form, the angular momentum can be decomposed as","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\nL_x = -ihbar left( y fracpartialpartial z - z fracpartialpartial y right) \nL_y = -ihbar left( z fracpartialpartial x - x fracpartialpartial z right) \nL_z = -ihbar left( x fracpartialpartial y - y fracpartialpartial x right)\nendaligned","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"We can transform these to use spherical coordinates and obtain","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\nL_x = -ihbar left( sinphi fracpartialpartialtheta + cottheta cosphi fracpartialpartialphi right) \nL_y = -ihbar left( cosphi fracpartialpartialtheta - cottheta sinphi fracpartialpartialphi right) \nL_z = -ihbar fracpartialpartialphi\nendaligned","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"The conventions we choose must be chosen to agree with these โ€” modulo factors of hbar, which are nonstandard in mathematics. We will have to check this, and the Condon-Shortley requirement that when applied to spherical harmonics they produce real and positive coefficients.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"I defined these in Eqs. (42) and (43) of Boyle (2016) as","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\nL_j f(mathbfR) colonequals -z left fracpartialpartial theta\nfleft(e^theta mathbfe_j 2 mathbfR right) right_theta=0 \nK_j f(mathbfR) colonequals -z left fracpartialpartial theta\nfleft(mathbfR e^theta mathbfe_j 2right) right_theta=0\nendaligned","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"where mathbfe_j is the unit vector in the j direction. Surprisingly, I found that Edmonds expresses essentially the same thing in the equations following his Eq. (4.1.5).","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Condon and Shortley's Eq. (1) of section 4ยณ (page 50) defines","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"L_z = -i hbar fracpartialpartial phi","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"while Eq. (8) on the following page defines","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\nL_x + i L_y = hbar e^iphi left( fracpartialpartial theta + i cottheta fracpartialpartial phi right) \nL_x - i L_y = hbar e^-iphi left(-fracpartialpartial theta + i cottheta fracpartialpartial phi right)\nendaligned","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Note that one is not the conjugate of the other! This is because of the factors of -i in the definitions of L_x and L_y.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Edmonds gives the total angular-momentum operator for a rigid body in Eq. (2.2.2) as","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\nL_x = -ihbar left(-cos alpha cotbeta fracpartialpartialalpha - sinalpha fracpartialpartialbeta + fraccosalphasinbeta fracpartialpartialgamma right) \nL_y = -ihbar left(-sinalpha cotbeta fracpartialpartial alpha + cosalpha fracpartialpartialbeta + fracsinalphasinbeta fracpartialpartialgamma right) \nL_z = -ihbar fracpartialpartialalpha\nendaligned","category":"page"},{"location":"conventions/outline/#Wigner-๐”‡-and-d-matrices","page":"Outline","title":"Wigner ๐”‡ and d matrices","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Wigner's Eqs. (11.18) and (11.19) define the real orthogonal transformation mathbfR by","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"x_i = R_ij x_j","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"and the operator mathbfP_mathbfR to act on a function f such that","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"mathbfP_mathbfR f(x_1 ldots) = f(x_1 ldots)","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Then, his Eq. (15.5) presumably implies","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Y_ellm(vartheta varphi)\n= mathbfP_alpha beta gamma Y_ellm(vartheta varphi)\n= sum_m mathfrakD^(ell)(alpha beta gamma)_mm\n Y_ellm(vartheta varphi)","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"where alpha beta gamma takes (vartheta varphi) to (vartheta varphi). In any case, we can now leave behind this mathbfP notation and just look at the beginning and end of the equation above as the critical relationship in Wigner's notation.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Eq. (44b) of Boyle (2016) says","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"L_pm mathfrakD^(ell)_mm(mathbfR)\n= sqrt(ell mp m)(ell pm m + 1) mathfrakD^(ell)_m pm 1 m(mathbfR)","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"while Eq. (21) relates the Wigner D-matrix to the spin-weighted spherical harmonics as","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"_sY_ellm(mathbfR)\n= (-1)^s sqrtfrac2ell+14pi mathfrakD^(ell)_m-s(mathbfR)","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Plugging the latter into the former, we get","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"L_pm _sY_ellm(mathbfR)\n= sqrt(ell mp m)(ell pm m + 1) _sY_ellm pm 1(mathbfR)","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"That is, in our conventions we have","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"alpha^pm_ellm = sqrt(ell mp m)(ell pm m + 1)","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"which is always real and positive, and thus consistent with the Condon-Shortley phase convention.","category":"page"},{"location":"conventions/outline/#Properties","page":"Outline","title":"Properties","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"D^j_mm(alphabetagamma) = (-1)^m-m D^j_-m-m(alphabetagamma)^*\n(-1)^m-mD^j_mm(alphabetagamma)=D^j_mm(gammabetaalpha)\nd_mm^j=(-1)^m-md_mm^j=d_-m-m^j","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\nd_mm^j(pi) = (-1)^j-m delta_m-m 6pt\nd_mm^j(pi-beta) = (-1)^j+m d_m-m^j(beta)6pt\nd_mm^j(pi+beta) = (-1)^j-m d_m-m^j(beta)6pt\nd_mm^j(2pi+beta) = (-1)^2j d_mm^j(beta)6pt\nd_mm^j(-beta) = d_mm^j(beta) = (-1)^m-m d_mm^j(beta)\nendaligned","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"begingather\nR = cosepsilon + sinepsilon hatmathfrakr \nR๐ฏ = cosepsilon ๐ฏ + sinepsilon hatmathfrakr๐ฏ \nR๐ฏR^-1 = (๐ฏcosepsilon + sinepsilon hatmathfrakr๐ฏ)(cosepsilon - sinepsilon hatmathfrakr) \nR๐ฏR^-1 = ๐ฏcos^2epsilon + sin^2epsilon hatmathfrakr๐ฏhatmathfrakr^-1 + sinepsilon cosepsilon (hatmathfrakr๐ฏ - ๐ฏhatmathfrakr) \nR๐ฏR^-1 = begincases\n๐ฏ ๐ฏ hatmathfrakr = hatmathfrakr๐ฏ \n๐ฏ(cos^2epsilon - sin^2epsilon) + 2 sinepsilon cosepsilon frachatmathfrakr ๐ฏ2 ๐ฏ hatmathfrakr = -hatmathfrakr๐ฏ \nendcases \nR๐ฏR^-1 = begincases\n๐ฏ ๐ฏ hatmathfrakr = hatmathfrakr๐ฏ \ncos2epsilon ๐ฏ + sin2epsilon frachatmathfrakr ๐ฏ2 ๐ฏ hatmathfrakr = -hatmathfrakr๐ฏ \nendcases \nendgather","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Using techniques from geometric algebra, we can easily prove that the result is another vector, so we can measure its (squared) norm just by multiplying it by itself:","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\n ๐‘ ๐ฏ ๐‘^-1 ^2\n= ๐‘ ๐ฏ ๐‘^-1 ๐‘ ๐ฏ ๐‘^-1 \n= ๐‘ ๐ฏ ๐ฏ ๐‘^-1 \n= ๐ฏ^2 ๐‘ ๐‘^-1 \n= ๐ฏ^2\nendaligned","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"That is, ๐ฏ = ๐‘ ๐ฏ ๐‘^-1 has the same norm as ๐ฏ, which means that ๐ฏ is a rotation of ๐ฏ. Given the constraint on the norm of ๐‘, we can rewrite it as","category":"page"},{"location":"functions/#Complete-function-list","page":"Complete function list","title":"Complete function list","text":"","category":"section"},{"location":"functions/","page":"Complete function list","title":"Complete function list","text":"The following list contains all documented functions inside the SphericalFunctions module.","category":"page"},{"location":"functions/","page":"Complete function list","title":"Complete function list","text":"Modules = [SphericalFunctions]","category":"page"},{"location":"transformations/#s-SHT-Transformations","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"","category":"section"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"One important capability of this package is the transformation between the two representations of a spin-weighted spherical function:","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"Values f of the function evaluated on a set of points or \"pixels\" in the domain of the function.\nValues fฬƒ of the mode weights (coefficients) of an expansion in the standard spin-weighted spherical-harmonic basis.","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"In the literature, the transformation f โ†ฆ fฬƒ is usually called \"analysis\" or map2salm, while the inverse transformation f โ†ฆ fฬƒ is called \"synthesis\" or salm2map. These are both referred to as spin-spherical-harmonic transforms, or s-SHTs.","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"To describe the values of a spin-s function up to some maximum angular resolution ell_mathrmmax, we need (ell_mathrmmax+1)^2 - s^2 mode weights. We assume throughout that the values fฬƒ are stored as","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"fฬƒ = [mode_weight(โ„“, m) for โ„“ โˆˆ abs(s):โ„“โ‚˜โ‚โ‚“ for m โˆˆ -โ„“:โ„“]","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"(Here, mode_weight is a made-up function intended to provide a schematic.) In particular, the m index varies most rapidly, and the ell index varies most slowly. Correspondingly, there must be at least (ell_mathrmmax+1)^2 - s^2 function values f. However, some s-SHT algorithms require more function values โ€” usually by a factor of 2 or 4 โ€” trading off between speed and memory usage.","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"The SSHT object implements these transformations, storing pre-computed constants and pre-allocated workspace for the transformations. The interface is designed to be similar to that of FFTW.jl, whereby an SSHT object ๐’ฏ can be used to perform the transformation as either","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"f = ๐’ฏ * fฬƒ","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"or","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"fฬƒ = ๐’ฏ \\ f","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"Currently, there are three algorithms implemented, each having different advantages and disadvantages:","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"The \"Direct\" algorithm (introduced here for the first time), which is the default, but should only be used up to ell_mathrmmax lesssim 50 because its intermediate storage requirements scale as ell_mathrmmax^4. This algorithm is the fastest for small ell_mathrmmax, it can be used with arbitrary (non-degenerate) pixelizations, and achieves optimal dimensionality.\nThe \"Minimal\" algorithm due to Elahi et al. [2], with some minor improvements. This algorithm is fast and โ€” as the name implies โ€” also achieves optimal dimensionality, and its storage scales as ell_mathrmmax^3. However, its pixelization is restricted, and its accuracy at very high ell_mathrmmax is not as good as the \"RS\" algorithm. The algorithm itself is not actually fully specified by Elahi et al., and leaves out some relatively simple improvements, so I have had to take some liberties with my interpretation.\nThe \"RS\" algorithm due to Reinecke and Seljebotn [3]. This forms the basis for the libsharp and ducc.sht packages. It requires pixelizations on \"iso-latitude rings\", and does not achieve optimal dimensionality. However, it is very fast, and its accuracy is excellent at extremely high ell_mathrmmax.","category":"page"},{"location":"transformations/#SSHT-objects","page":"s-SHT Transformations","title":"SSHT objects","text":"","category":"section"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"Modules = [SphericalFunctions]\nPages = [\"ssht.jl\", \"ssht/direct.jl\", \"ssht/minimal.jl\", \"ssht/rs.jl\"]","category":"page"},{"location":"transformations/#SphericalFunctions.SSHT","page":"s-SHT Transformations","title":"SphericalFunctions.SSHT","text":"Supertype of storage for spin-spherical-harmonic transforms\n\n\n\n\n\n","category":"type"},{"location":"transformations/#SphericalFunctions.SSHT-Tuple{Any, Any}","page":"s-SHT Transformations","title":"SphericalFunctions.SSHT","text":"SSHT(s, โ„“โ‚˜โ‚โ‚“; [method=\"Direct\"], [T=Float64], [kwargs...])\n\nConstruct an SSHT object to transform between spin-weighted spherical-harmonic mode weights and function values โ€” performing an s-SHT.\n\nThis object behaves similarly to an AbstractFFTs.Plan object โ€” specifically in the ability to use the semantics of algebra to perform transforms. For example, if the function values are stored as a vector f, the mode weights as fฬƒ, and the SSHT as ๐’ฏ, then we can compute the function values from the mode weights as\n\nf = ๐’ฏ * fฬƒ\n\nor solve for the mode weights from the function values as\n\nfฬƒ = ๐’ฏ \\ f\n\nThe first dimensions of fฬƒ must index the mode weights (as usual, for โ„“โˆˆabs(s):โ„“โ‚˜โ‚โ‚“ and mโˆˆ-โ„“:โ„“) and the first index of f must index the locations at which the function is evaluated. Any following dimensions will be broadcast over. Note that certain types will broadcast using Julia threads, while others will broadcast using BLAS threads. The relevant number of threads must be set appropriately.\n\nCertain SSHT types (currently, only Minimal and Direct) also have an option to always act in place โ€” meaning that they simply re-use the input storage, even when used in an expression like ๐’ฏ \\ f. The option must be passed as the inplace argument to the constructors, and is part of the type of the resulting object. Regardless of the value of that option, for those types where the option exists, it is also possible to use mul! and ldiv! from the LinearAlgebra package to force operation in place.\n\nNote that different algorithms require different \"pixelizations\", or sets of Rotors on which to evaluate the function. These can be obtained from the SSHT object using the pixels and rotors functions.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.pixels","page":"s-SHT Transformations","title":"SphericalFunctions.pixels","text":"pixels(๐’ฏ)\n\nReturn the spherical coordinates (ฮธ, ฯ•) on which the spin-weighted spherical harmonics are evaluated. See also rotors, which provides the actual Rotors on which they are evaluated.\n\n\n\n\n\n","category":"function"},{"location":"transformations/#SphericalFunctions.rotors","page":"s-SHT Transformations","title":"SphericalFunctions.rotors","text":"rotors(๐’ฏ)\n\nReturn the Rotors on which the spin-weighted spherical harmonics are evaluated. See also pixels, which provides the corresponding spherical coordinates.\n\n\n\n\n\n","category":"function"},{"location":"transformations/#SphericalFunctions.SSHTDirect","page":"s-SHT Transformations","title":"SphericalFunctions.SSHTDirect","text":"SSHTDirect(s, โ„“โ‚˜โ‚โ‚“; decomposition=LinearAlgebra.qr, T=Float64, Rฮธฯ•=golden_ratio_spiral_rotors(s, โ„“โ‚˜โ‚โ‚“, T), inplace=true)\n\nConstruct an s-SHT object that uses the \"Direct\" method; see โ‚›๐˜ for details about the method and optional arguments. Also see SSHT for general information about how to use these objects.\n\nBy default, this uses precisely optimal sampling โ€” meaning that the number of points on which the function is evaluated, represented by Rฮธฯ•, is equal to the number of modes. However, it is equally possible to evaluate on more points than there are modes. This can be useful, for example, when processing multiple fields with different spin weights; the function could be evaluated on points appropriate for the lowest value of s, and therefore could also be used to solve for fields of all other spin weights.\n\nNote that in-place operation is possible for this type when the length of the input Rฮธฯ• is equal to the number of modes given s and โ„“โ‚˜โ‚โ‚“ โ€” and is the default behavior when possible. See SSHT for description of in-place operation.\n\nThis method is typically better than other current implementations for โ„“โ‚˜โ‚โ‚“ 24, both in terms of speed and accuracy. However, this advantage quickly falls away. A warning will be issued if โ„“โ‚˜โ‚โ‚“ is greater than about 64, because this method is not likely to be the most efficient or most accurate choice.\n\n\n\n\n\n","category":"type"},{"location":"transformations/#SphericalFunctions.SSHTMinimal","page":"s-SHT Transformations","title":"SphericalFunctions.SSHTMinimal","text":"Storage for Minimal spin-spherical-harmonic transform\n\nThe Minimal algorithm was described by Elahi et al., and allows for the minimal number of function samples.\n\n\n\n\n\n","category":"type"},{"location":"transformations/#SphericalFunctions.SSHTMinimal-Union{Tuple{TT}, Tuple{Any, Any}} where TT","page":"s-SHT Transformations","title":"SphericalFunctions.SSHTMinimal","text":"SSHTMinimal(s, โ„“โ‚˜โ‚โ‚“; kwargs...)\n\nConstruct a SSHTMinimal object directly. This may also be achieved by calling the main SSHT function with the same keywords, along with method=\"Minimal\".\n\nThis object uses the algorithm described by Elahi et al.\n\nThe basic floating-point number type may be adjusted with the keyword argument T, which defaults to Float64.\n\nThe SSHs are evaluated on a series of \"rings\" at constant colatitude. Their locations are specified by the ฮธ keyword argument, which defaults to sorted_rings(s, โ„“โ‚˜โ‚โ‚“, T). The first element of ฮธ is the colatitude of the smallest ring (containing 2s+1 elements), and so on to the last element of ฮธ, which is the colatitude of the largest ring (containing 2โ„“โ‚˜โ‚โ‚“+1 elements).\n\nWhenever T is either Float64 or Float32, the keyword arguments plan_fft_flags and plan_fft_timelimit may also be useful for obtaining more efficient FFTs. They default to FFTW.ESTIMATE and Inf, respectively. They are passed to AbstractFFTs.plan_fft.\n\nNote that, because this algorithm achieves optimal dimensionality, the transformation will be performed in place by default. If this is not desired, pass the keyword argument inplace=false. This will cause the algorithm to copy the input and perform in-place transformation on that copy.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.SSHTRS","page":"s-SHT Transformations","title":"SphericalFunctions.SSHTRS","text":"Storage for spin-spherical-harmonic transform\n\nThe algorithm was described in by Reinecke and Seljebotn.\n\n\n\n\n\n","category":"type"},{"location":"transformations/#SphericalFunctions.SSHTRS-Union{Tuple{TT}, Tuple{Any, Any}} where TT","page":"s-SHT Transformations","title":"SphericalFunctions.SSHTRS","text":"SSHTRS(s, โ„“โ‚˜โ‚โ‚“; kwargs...)\n\nConstruct a SSHTRS object directly. This may also be achieved by calling the main SSHT function with the same keywords, along with method=\"RS\".\n\nThis object uses the algorithm described by Reinecke and Seljebotn.\n\nThe basic floating-point number type may be adjusted with the keyword argument T, which defaults to Float64.\n\nThe SSHs are evaluated on a series of \"rings\" at constant colatitude. Their locations are specified by the ฮธ keyword argument, which defaults to fejer1_rings(2โ„“โ‚˜โ‚โ‚“+1, T). If this is changed, the user should also provide the corresponding quadrature_weights argument โ€” the default being fejer1(length(ฮธ), T).\n\nOn each of these rings, an FFT is performed. To reach the band limit of m = โ„“โ‚˜โ‚โ‚“, the number of points along each ring must therefore be at least 2โ„“โ‚˜โ‚โ‚“+1, but may be greater. For example, if 2โ„“โ‚˜โ‚โ‚“+1 does not factorize neatly into a product of small primes, it may be preferable to use 2โ„“โ‚˜โ‚โ‚“+2 points along each ring. (In that case, whenever โ„“โ‚˜โ‚โ‚“ is 1 less than a power of 2, the number of points will be exactly a power of 2, which is usually particularly efficient.) The number of points on each ring can be modified independently, if given as a vector with the same length as ฮธ, or as a single number which is assumed to be the same for all rings.\n\nWhenever T is either Float64 or Float32, the keyword arguments plan_fft_flags and plan_fft_timelimit may also be useful for obtaining more efficient FFTs. They default to FFTW.ESTIMATE and Inf, respectively. They are passed to AbstractFFTs.plan_fft.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#Pixelizations","page":"s-SHT Transformations","title":"Pixelizations","text":"","category":"section"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"The algorithms implemented here require pixelizations. While the \"Direct\" algorithm can be used with arbitrary pixelizations, the \"Minimal\" and \"RS\" algorithms require more specific choices, as noted in their docstrings.","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"Typically, \"pixelization\" refers exclusively to a choice of points on the sphere ๐•Šยฒ at which to compute function values. Of course, as mentioned elsewhere, it is not technically possible to define spin-weighted functions as functions of a point on ๐•Šยฒ alone; we also need some sense of reference direction in the tangent space. Quite generally, we can define spin-weighted functions on the group ๐’๐Ž(3) or ๐’๐ฉ๐ข๐ง(3), so we will also refer to a choice of a set of points in ๐’๐ฉ๐ข๐ง(3) (which is essentially the group of unit quaternions) as a \"pixelization\". However, assuming spherical coordinates, a choice of coordinates on the sphere almost everywhere induces a choice of the reference direction in the tangent space, so it is almost possible to define pixelizations just in terms of points on ๐•Šยฒ. But using spherical coordinates is actually enough to fully specify the pixelization, because the degeneracies at the poles also allow us to define the reference direction.","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"In principle, we could be concerned about the choice of reference direction in the tangent space. That is, we might expect to care about pixelizations over ๐•Šยณ. However, we are dealing with spin-weighted functions, which are eigenfunctions of a final rotation about the reference direction. This means that once we choose any reference direction at each point, we know the function values for any other reference direction at those points. In particular, an important property of a pixelization is the condition number of the transformation matrix between the function values and the mode weights. If we rotate the reference direction at a single point, this is equivalent to multiplying the matrix by a diagonal matrix with entries of 1 everywhere except the entry corresponding to that point, where the entry is some complex phase. This does not change the condition number of the matrix, so we can ignore the choice of reference direction at every point. For other situations, where we might care about the choice of reference direction, it might be interesting to consider this work by Marc Alexa, and references therein.","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"Interesting discussions of various pixelizations and metrics can be found in Saff and Kuijlaars (1997) and Brauchart and Grabner (2015), as well as blog posts here and here. Note that the \"equal-area\" pixelizations of Healpix are very restrictiveโ€”only being available for very specific numbers of pointsโ€”and do not provide any obvious advantages over the more flexible pixelizations available here.","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"The various pixelizations may be computed as follows:","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"Modules = [SphericalFunctions]\nPages = [\"pixelizations.jl\"]","category":"page"},{"location":"transformations/#SphericalFunctions.clenshaw_curtis_rings-Union{Tuple{Any}, Tuple{T}, Tuple{Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.clenshaw_curtis_rings","text":"clenshaw_curtis_rings(N, [T=Float64])\n\nValues of the colatitude coordinate (ฮธ) appropriate for quadrature by the Clenshaw-Curtis rule, using weights provided by clenshaw_curtis.\n\nNote that the first argument to this function is N, rather than the โ„“โ‚˜โ‚โ‚“ used in some other functions. For spin-weighted spherical harmonics, you may want to use N=2โ„“โ‚˜โ‚โ‚“+1.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.fejer1_rings-Union{Tuple{Any}, Tuple{T}, Tuple{Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.fejer1_rings","text":"fejer1_rings(N, [T=Float64])\n\nValues of the colatitude coordinate (ฮธ) appropriate for quadrature by Fejรฉr's first rule, using weights provided by fejer1.\n\nNote that the first argument to this function is N, rather than the โ„“โ‚˜โ‚โ‚“ used in some other functions. For spin-weighted spherical harmonics, you may want to use N=2โ„“โ‚˜โ‚โ‚“+1.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.fejer2_rings-Union{Tuple{Any}, Tuple{T}, Tuple{Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.fejer2_rings","text":"fejer2_rings(N, [T=Float64])\n\nValues of the colatitude coordinate (ฮธ) appropriate for quadrature by Fejรฉr's second rule, using weights provided by fejer2.\n\nNote that the first argument to this function is N, rather than the โ„“โ‚˜โ‚โ‚“ used in some other functions. For spin-weighted spherical harmonics, you may want to use N=2โ„“โ‚˜โ‚โ‚“+1.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.golden_ratio_spiral_pixels-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.golden_ratio_spiral_pixels","text":"golden_ratio_spiral_pixels(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])\n\nCover the sphere ๐•Šยฒ with pixels generated by the golden-ratio spiral. Successive pixels are separated by the azimuthal angle ฮ”ฯ• = 2ฯ€(2-ฯ†), and are uniformly distributed in cos ฮธ.\n\nThis is also known as the \"Fibonacci sphere\" or \"Fibonacci lattice\".\n\nVisually, this is a very reasonable-looking pixelization, with fairly uniform distance between neighbors, and approximate isotropy. No two pixels will share the same values of either ฮธ or ฯ•. Also note that no point is present on either the North or South poles.\n\nThe returned quantity is a vector of 2-SVectors providing the spherical coordinates of each pixel. See also golden_ratio_spiral_rotors for the corresponding Rotors.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.golden_ratio_spiral_rotors-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.golden_ratio_spiral_rotors","text":"golden_ratio_spiral_rotors(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])\n\nCover the sphere ๐•Šยฒ with pixels generated by the golden-ratio spiral.\n\nSee golden_ratio_spiral_pixels for more detailed explanation. The quantity returned by this function is a vector of Rotors providing each pixel.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.sorted_ring_pixels-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.sorted_ring_pixels","text":"sorted_ring_pixels(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])\n\nCover the sphere ๐•Šยฒ with (โ„“โ‚˜โ‚โ‚“+1)ยฒ-sยฒ pixels distributed in rings provided by sorted_rings; see that function's documentation for more description.\n\nThe returned quantity is a vector of 2-SVectors containing the spherical coordinates of each pixel. See also sorted_ring_rotors for the corresponding Rotors.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.sorted_ring_rotors-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.sorted_ring_rotors","text":"sorted_ring_rotors(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])\n\nCover the sphere ๐•Šยฒ with (โ„“โ‚˜โ‚โ‚“+1)ยฒ-sยฒ pixels distributed in rings provided by sorted_rings; see that function's documentation for more description.\n\nThe returned quantity is a vector of Rotors. See also sorted_ring_rotors for the corresponding spherical coordinates.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.sorted_rings-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.sorted_rings","text":"sorted_rings(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])\n\nCompute locations of a series of rings labelled by j sโ„“โ‚˜โ‚โ‚“ (analogous to โ„“), where each ring will contain k = 2j+1 (analogous to m) pixels distributed evenly around the ring. These rings are then sorted, so that the ring with the most pixels (j = โ„“โ‚˜โ‚โ‚“) is closest to the equator, and the next-largest ring is placed just above or below the equator (depending on the sign of s), the next just below or above, and so on. This is generally a fairly good first guess when minimizing the condition number of matrices used to solve for mode weights from function values. In particular, I use this to initialize the Minimal algorithm, which is then fed into an optimizer to fine-tune the positions of the rings.\n\nThis function does not provide the individual pixels; it just provides the colatitude values of the rings on which the pixels will be placed. The pixels themselves are provided by sorted_ring_pixels.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#Quadrature-weights","page":"s-SHT Transformations","title":"Quadrature weights","text":"","category":"section"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"The \"RS\" algorithm requires quadrature weights corresponding to the input pixelization. Though there is a working default choice, it is possible to use others. There are several that are currently implemented, along with their corresponding pixelizations:","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"Modules = [SphericalFunctions]\nPages = [\"weights.jl\"]\nOrder = [:module, :type, :constant, :function, :macro]","category":"page"},{"location":"transformations/#SphericalFunctions.clenshaw_curtis-Union{Tuple{T}, Tuple{Any, Type{T}}} where T<:AbstractFloat","page":"s-SHT Transformations","title":"SphericalFunctions.clenshaw_curtis","text":"clenshaw_curtis(n, [T])\n\nCompute n weights for the Clenshaw-Curtis rule, corresponding to n evenly spaced nodes from 0 to ฯ€ inclusive. That is, the nodes are located at\n\ntheta_k = k fracpin-1 quad k=0 ldots n-1\n\nThis function uses Waldvogel's method.\n\nThe type T may be any AbstractFloat, but defaults to Float64.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.fejer1-Union{Tuple{Any}, Tuple{T}, Tuple{Any, Type{T}}} where T<:AbstractFloat","page":"s-SHT Transformations","title":"SphericalFunctions.fejer1","text":"fejer1(n, [T])\n\nCompute n weights for Fejรฉr's first rule, corresponding to n evenly spaced nodes from 0 to ฯ€ inclusive. That is, the nodes are located at\n\ntheta_k = k fracpin-1 quad k=0 ldots n-1\n\nThis function uses Waldvogel's method.\n\nThe type T may be any AbstractFloat, but defaults to Float64.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.fejer2-Union{Tuple{T}, Tuple{Any, Type{T}}} where T<:AbstractFloat","page":"s-SHT Transformations","title":"SphericalFunctions.fejer2","text":"fejer2(n, [T])\n\nCompute n weights for Fejรฉr's second rule, corresponding to n evenly spaced nodes between 0 and ฯ€ exclusive. That is, the nodes are located at\n\ntheta_k = k fracpin+1 quad k=1 ldots n\n\nThis function uses Waldvogel's method. However, contrary to Waldvogel's notation, this routine does not include the weight corresponding to the ฯ‘=0 or ฯ€ nodes, which both have weight 0.\n\nThe type T may be any AbstractFloat, but defaults to Float64.\n\n\n\n\n\n","category":"method"},{"location":"internal/#Internal-functions","page":"Internal functions","title":"Internal functions","text":"","category":"section"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"There are various functions that are only used internally, some of which are likely to be deprecated in the near future. These are documented here for completeness.","category":"page"},{"location":"internal/#H-recursion-and-ALFs","page":"Internal functions","title":"H recursion and ALFs","text":"","category":"section"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"The fundamental algorithm is the H recursion, which is the core computation needed for Wigner's d and ๐”‡ matrices, and the spin-weighted spherical harmonics _sY_ellm, as well as map2salm functions.","category":"page"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"Modules = [SphericalFunctions]\nPages = [\"Hrecursion.jl\"]","category":"page"},{"location":"internal/#SphericalFunctions.H!-Union{Tuple{T}, Tuple{AbstractVector, Complex{T}, Any, Any, Any}, Tuple{AbstractVector, Complex{T}, Vararg{Any, 4}}} where T<:Real","page":"Internal functions","title":"SphericalFunctions.H!","text":"H!(H, expiฮฒ, โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“, H_rec_coeffs)\nH!(H, expiฮฒ, โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“, H_rec_coeffs, Hindex)\n\nCompute the H matrix defined by Gumerov and Duraiswami [8].\n\nThis computation forms the basis for computing Wigner's d and ๐”‡ matrices via d_matrices! and D_matrices!, the spin-weighted spherical harmonics via sYlm_values!, and for transforming from values of spin-weighted spherical functions evaluated on a grid to the corresponding mode weights via map2salm.\n\nDue to symmetries, we only need to compute ~1/4 of the elements of this matrix, so only those elements with m m are computed. The relevant indices of the H vector are computed based on the Hindex function โ€” which defaults to WignerHindex, but could reasonably be WignerDindex if the input H vector contains all valid indices. However, it is assumed that the storage scheme used for H is such that the successive m values are located in successive elements.\n\nIf mโ‚˜โ‚โ‚“ โ„“โ‚˜โ‚โ‚“, we don't even need 1/4 of the elements, and only values with m mโ‚˜โ‚โ‚“ will be computed. This is particularly useful for computing spin-weighted spherical harmonics.\n\nNote that the recursion coefficients H_rec_coeffs should be the quantity returned by H_recursion_coefficients.\n\n\n\n\n\n","category":"method"},{"location":"internal/#SphericalFunctions.H_recursion_coefficients-Union{Tuple{T}, Tuple{Any, Type{T}}} where T<:Real","page":"Internal functions","title":"SphericalFunctions.H_recursion_coefficients","text":"H_recursion_coefficients(โ„“โ‚˜โ‚โ‚“, T)\n\nPre-compute constants used in Wigner H recursion.\n\n\n\n\n\n","category":"method"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"Internally, the H recursion relies on calculation of the Associated Legendre Functions (ALFs), which can also be called on their own:","category":"page"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"Modules = [SphericalFunctions]\nPages = [\"associated_legendre.jl\"]","category":"page"},{"location":"internal/#SphericalFunctions.ALFcompute!-Union{Tuple{T}, Tuple{Vector{T}, Complex{T}, Int64, ALFRecursionCoefficients{T}}} where T<:Real","page":"Internal functions","title":"SphericalFunctions.ALFcompute!","text":"ALFcompute(expiฮฒ, nmax)\nALFcompute!(Pฬ„, expiฮฒ, nmax)\nALFcompute(expiฮฒ, nmax, recursion_coefficients)\nALFcompute!(Pฬ„, expiฮฒ, nmax, recursion_coefficients)\n\nCompute the \"fully normalized\" Associated Legendre Functions up to some maximum n value nmax.\n\nThese functions can take a vector Pฬ„, to store the data, stored in order of increasing m most rapidly varying and then increasing n. If not supplied, Pฬ„ will be constructed for you and returned.\n\nThe optional recursion_coefficients argument must be an ALFRecursionCoefficients, which stores various constant coefficients used in the recursion. This object requires more than 3x the memory and more than 20x the time to compute a single Pฬ„ vector without this argument, but passing it will typically speed up the calculation of each Pฬ„ by a factor of 8x or so. Thus, if you expect to compute Pฬ„ more than a few times, it will take less time to pre-compute those factors, and pass them to this function.\n\nNote that the base real type will be inferred from the (complex) type of expiฮฒ. If present, the base types of Pฬ„ and recursion_coefficients must agree.\n\n\n\n\n\n","category":"method"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"The function _slambda_ellm is defined as essentially _sY_ell0, and is important internally for computing the ALFs. We have some important utilities for computing it:","category":"page"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"SphericalFunctions.ฮป_recursion_initialize\nSphericalFunctions.ฮป_iterator\nSphericalFunctions.AlternatingCountdown","category":"page"},{"location":"internal/#SphericalFunctions.ฮป_recursion_initialize","page":"Internal functions","title":"SphericalFunctions.ฮป_recursion_initialize","text":"ฮป_recursion_initialize(cosฮธ, sinยฝฮธ, cosยฝฮธ, s, โ„“, m)\n\nThis provides initial values for the recursion to find _slambda_ellm along indices of increasing ell, due to Kostelec & Rockmore Specifically, this function computes values with ell=m.\n\n_slambda_ellm(theta)\n = _sY_ellm(theta 0)\n = (-1)^m sqrtfrac2ell+14pi d^ell_-ms(theta)\n\n\n\n\n\n","category":"function"},{"location":"internal/#SphericalFunctions.ฮป_iterator","page":"Internal functions","title":"SphericalFunctions.ฮป_iterator","text":"ฮป_iterator(ฮธ, s, m)\n\nConstruct an object to iterate over โ‚›ฮปโ‚—โ‚˜ values.\n\nThe โ‚›ฮปโ‚—โ‚˜(ฮธ) function is defined as the spin-weighted spherical harmonic evaluated at spherical coordinates (ฮธ ฯ•), with ฯ•=0. In particular, note that it is real-valued. The return type is determined by the type of ฮธ (or more precisely, cosยฝฮธ).\n\nThis algorithm by Kostelec & Rockmore allows us to iterate over increasing โ„“ values, for given fixed s and m values.\n\nNote that this iteration has no inherent bound, so if you try to iterate over all values, you will end up in an infinite loop. Instead, you can zip this iterator with another:\n\nฮธ = 0.1\ns = -2\nm = 1\nฮป = ฮป_iterator(ฮธ, s, m)\nฮ” = max(abs(s), abs(m))\nfor (โ„“, โ‚›ฮปโ‚—โ‚˜) โˆˆ zip(ฮ”:ฮ”+5, ฮป)\n @show (โ„“, โ‚›ฮปโ‚—โ‚˜)\nend\n\nAlternatively, you could use Iterates.take(ฮป, 6), for example.\n\nNote that the iteration always begins with โ„“ = ฮ” = max(abs(s), abs(m)).\n\n\n\n\n\n","category":"type"},{"location":"internal/#SphericalFunctions.AlternatingCountdown","page":"Internal functions","title":"SphericalFunctions.AlternatingCountdown","text":"Simple iterator to count down to 0, with alternating signs\n\njulia> collect(AlternatingCountdown(5))\n11-element Vector{Int64}:\n 5\n -5\n 4\n -4\n 3\n -3\n 2\n -2\n 1\n -1\n 0\n\n\n\n\n\n","category":"type"},{"location":"internal/#โ‚›๐˜","page":"Internal functions","title":"โ‚›๐˜","text":"","category":"section"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"Various d, D, and sYlm functions are important in the main API. Their names and signatures have been tweaked from older versions of this package. The only one with remaining documentation is โ‚›๐˜, which could probably be replaced by sYlm_values, except that the default pixelization is golden_ratio_spiral_rotors, which makes it very convenient for interacting with SSHT.","category":"page"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"โ‚›๐˜","category":"page"},{"location":"internal/#SphericalFunctions.โ‚›๐˜","page":"Internal functions","title":"SphericalFunctions.โ‚›๐˜","text":"โ‚›๐˜(s, โ„“โ‚˜โ‚โ‚“, [T=Float64], [Rฮธฯ•=golden_ratio_spiral_rotors(s, โ„“โ‚˜โ‚โ‚“, T)])\n\nConstruct a matrix of โ‚›Yโ‚—โ‚˜(Rฮธฯ•) values for the input s and all nontrivial (ell m) up to โ„“โ‚˜โ‚โ‚“.\n\nThis is a fast and accurate method for mapping between the vector of spin-weighted spherical-harmonic mode weights โ‚›๐Ÿโ‚—โ‚˜ and the vector of function values on the sphere โ‚›๐Ÿโฑผโ‚–, as\n\nโ‚›๐Ÿโฑผโ‚– = โ‚›๐˜ โ‚›๐Ÿโ‚—โ‚˜\n\nwhere the right-hand side represents the matrix-vector product. As usual, we assume that the โ‚›๐Ÿโ‚—โ‚˜ modes are ordered by increasing m -โ„“โ„“, and โ„“ sโ„“โ‚˜โ‚โ‚“. The ordering of the โ‚›๐Ÿโฑผโ‚– values will be determined by the ordering of the argument Rฮธฯ•.\n\nNote that the number of modes need not be the same as the number of points on which the function is evaluated, which would imply that the output matrix is not square. To be able to invert the relationship, however, we need the number of points โ‚›๐Ÿโฑผโ‚– to be at least as large as the number of modes โ‚›๐Ÿโ‚—โ‚˜.\n\nNote that the usefulness of this approach is limited by the fact that the size of this matrix scales as โ„“โ‚˜โ‚โ‚“โด. As such, it is mostly useful only for โ„“โ‚˜โ‚โ‚“ of order dozens, rather than โ€” say โ€” the tens of thousands that CMB astronomy or lensing require, for example.\n\nDirect application and inversion of this matrix are used in the \"direct\" methods of s-SHT transformations. See SSHTDirect for details about the implementation.\n\n\n\n\n\n","category":"function"},{"location":"internal/#Transformation","page":"Internal functions","title":"Transformation","text":"","category":"section"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"The newer SSHT interface is more efficient for most purposes, but this package used to use functions named map2salm, which is still present, but may be deprecated.","category":"page"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"Modules = [SphericalFunctions]\nPages = [\"map2salm.jl\"]","category":"page"},{"location":"internal/#SphericalFunctions.map2salm!-Union{Tuple{T}, Tuple{AbstractArray{Complex{T}}, AbstractArray{Complex{T}}, Int64, Int64}, Tuple{AbstractArray{Complex{T}}, AbstractArray{Complex{T}}, Int64, Int64, Any}} where T<:Real","page":"Internal functions","title":"SphericalFunctions.map2salm!","text":"map2salm!(salm, map, spin, โ„“max)\nmap2salm!(salm, map, plan)\n\nTransform map values sampled on the sphere to _sa_ell m modes in place.\n\nFor details, see map2salm.\n\n\n\n\n\n","category":"method"},{"location":"internal/#SphericalFunctions.map2salm-Union{Tuple{T}, Tuple{AbstractArray{Complex{T}}, Int64, Int64}, Tuple{AbstractArray{Complex{T}}, Int64, Int64, Any}} where T<:Real","page":"Internal functions","title":"SphericalFunctions.map2salm","text":"map2salm(map, spin, โ„“max)\nmap2salm(map, plan)\n\nTransform map values sampled on the sphere to _sa_ell m modes.\n\nThe map array should have size Nฯ† along its first dimension and Nฯ‘ along its second; any number of dimensions may follow. The spin must be entered explicitly, and โ„“max is the highest โ„“ value you want in the output.\n\nFor repeated applications of this function with different values of map, it is more efficient to pre-compute plan using plan_map2salm. These functions will create a new salm array on each call. To operate in place on a pre-allocated salm array, use map2salm!.\n\nThe core of this function follows the method described by Reinecke and Seljebotn.\n\n\n\n\n\n","category":"method"},{"location":"internal/#SphericalFunctions.plan_map2salm-Union{Tuple{T}, Tuple{AbstractArray{Complex{T}}, Int64, Int64}} where T<:Real","page":"Internal functions","title":"SphericalFunctions.plan_map2salm","text":"plan_map2salm(map, spin, โ„“max)\n\nPrecompute values to use in executing map2salm or map2salm!.\n\nThe arguments to this function exactly mirror those of the first form of map2salm, and all but the first argument in the first form of map2salm!. The plan returned by this function can be passed to the second forms of those functions to avoid some computation and allocation costs.\n\nNote that the plan object is not thread safe; a separate plan should be created for each thread that will use one, or locks should be used to ensure that a single plan is not used at the same time on different threads.\n\n\n\n\n\n","category":"method"},{"location":"sYlm/#{}_{s}Y_{\\ell,m}-functions","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"","category":"section"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"The spin-weighted spherical harmonics are an important set of functions defined on the rotation group ๐’๐Ž(3), or more generally, the spin group ๐’๐ฉ๐ข๐ง(3) that covers it. They are eigenfunctions of the left- and right-Lie derivatives, and are particularly useful in describing the angular dependence of polarized fields, like the electromagnetic field and gravitational-wave field. Originally introduced by Newman and Penrose [7], they are essentially components of Wigner's frakD matrices:","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"_sY_ellm(mathbfR)\n = (-1)^s sqrtfrac2ell+14pi frakD^(ell)_m -s(mathbfR)","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"As such, they can be computed using the same H recursion algorithm as the Wigner frakD^(ell)_m -s matrices. But because not all values of s in -ellell are used, we can be much more efficient in both storage and computation time.","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"The user interface is very similar to the one for Wigner's ๐”‡ and d matrices:","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"using Quaternionic\nusing SphericalFunctions\n\nR = randn(RotorF64)\nโ„“โ‚˜โ‚โ‚“ = 8\ns = -2\nY = sYlm_values(R, โ„“โ‚˜โ‚โ‚“, s)","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"Again, the results can take up a lot of memory, so for maximum efficiency when calling this function repeatedly with different R values, it is best to pre-allocate the necessary memory with the sYlm_prep function, and the pass that in as an argument to sYlm_values!:","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"Y_storage = sYlm_prep(โ„“โ‚˜โ‚โ‚“, s)\nY = sYlm_values!(Y_storage, R, s)","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"(Beware that, as noted in the documentation for sYlm_values!, the output Y is just a reference to part of the Y_storage object, so you should not reuse Y_storage until you have copied or otherwise finished using Y.)","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"The output Y is a single vector of Complex numbers with the same base type as R. The ordering of the elements is described in the documentation for sYlm_values!. It is also possible to efficiently view slices of this vector as a series of individual vectors using a sYlm_iterator:","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"for (โ„“, Yหก) in zip(0:โ„“โ‚˜โ‚โ‚“, sYlm_iterator(Y, โ„“โ‚˜โ‚โ‚“))\n # Do something with the matrix Yหก[โ„“+mโ€ฒ+1, โ„“+m+1]\nend","category":"page"},{"location":"sYlm/#Docstrings","page":"_sY_ellm functions","title":"Docstrings","text":"","category":"section"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"sYlm_values\nsYlm_values!\nsYlm_prep\nsYlm_iterator","category":"page"},{"location":"sYlm/#SphericalFunctions.sYlm_values","page":"_sY_ellm functions","title":"SphericalFunctions.sYlm_values","text":"sYlm_values(R, โ„“โ‚˜โ‚โ‚“, spin)\nsYlm_values(ฮธ, ฯ•, โ„“โ‚˜โ‚โ‚“, spin)\n\nCompute values of the spin-weighted spherical harmonic _sY_ell m(R) for all ell leq ell_mathrmmax.\n\nSee sYlm_values! for details about the input and output values.\n\nThis function only appropriate when you need to evaluate the _sY_ell m for a single value of R or ฮธ, ฯ• because it allocates large arrays and performs many calculations that could be reused. If you need to evaluate the matrices for many values of R or ฮธ, ฯ•, you should pre-allocate the storage with sYlm_prep, and then call sYlm_values! with the result instead.\n\n\n\n\n\n","category":"function"},{"location":"sYlm/#SphericalFunctions.sYlm_values!","page":"_sY_ellm functions","title":"SphericalFunctions.sYlm_values!","text":"sYlm_values!(sYlm_storage, R, spin)\nsYlm_values!(sYlm_storage, ฮธ, ฯ•, spin)\nsYlm_values!(sYlm, R, โ„“โ‚˜โ‚โ‚“, spin)\nsYlm_values!(sYlm, ฮธ, ฯ•, โ„“โ‚˜โ‚โ‚“, spin)\n\nCompute values of the spin-weighted spherical harmonic _sY_ell m(R) for all ell leq ell_mathrmmax.\n\nThe spherical harmonics of spin weight s are related to Wigner's mathfrakD matrix as\n\nbeginaligned\n_sY_ell m(R)\n = (-1)^s sqrtfrac2ell+14pi mathfrakD^(ell)_m -s(R) \n = (-1)^s sqrtfrac2ell+14pi barmathfrakD^(ell)_-s m(barR)\nendaligned\n\nIn all cases, the result is returned in a 1-dimensional array ordered as\n\n[\n โ‚›Yโ‚—โ‚˜(R)\n for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“\n for m โˆˆ -โ„“:โ„“\n]\n\nWhen the first argument is Y, it will be modified, so it must be at least as large as that array. When the first argument is sYlm_storage, it should be the quantity returned by sYlm_prep, and the result will be written into the Y field of that tuple. Both of these options โ€” especially the latter โ€” reduce the number of allocations needed on each call to the corresponding functions, which should increase the speed significantly. Note that the Y or sYlm_storage arguments must have types compatible with the type of R or ฮธ, ฯ•.\n\nwarn: Warn\nWhen using the sYlm_storage argument (which is recommended), the returned quantity sYlm will be an alias of sYlm_storage[1]. If you want to retain that data after the next call to sYlm_values!, you should copy it with copy(sYlm).\n\nThe ฮธ, ฯ• arguments are spherical coordinates as described in the documentation of Quaternionic.from_spherical_coordinates.\n\nSee also sYlm_values for a simpler function call when you only need to evaluate the _sY_ell m for a single value of R or ฮธ, ฯ•.\n\nExamples\n\nusing Quaternionic, SphericalFunctions\nspin = -2\nโ„“โ‚˜โ‚โ‚“ = 8\nT = Float64\nR = Rotor{T}(1, 2, 3, 4) # Will be normalized automatically\nsYlm_storage = sYlm_prep(โ„“โ‚˜โ‚โ‚“, spin, T)\nsYlm = sYlm_values!(sYlm_storage, R, spin)\n\n\n\n\n\n","category":"function"},{"location":"sYlm/#SphericalFunctions.sYlm_prep","page":"_sY_ellm functions","title":"SphericalFunctions.sYlm_prep","text":"sYlm_prep(โ„“โ‚˜โ‚โ‚“, sโ‚˜โ‚โ‚“, [T=Float64, [โ„“โ‚˜แตขโ‚™=0]])\n\nConstruct storage space and pre-compute recursion coefficients to compute spin-weighted spherical-harmonic values _sY_ell m in place.\n\nThis returns the sYlm_storage arguments needed by sYlm_values!.\n\nNote that the result of this function can be passed to sYlm_values!, even if the value of spin passed to that function is smaller (in absolute value) than the sโ‚˜โ‚โ‚“ passed to this function. That is, the sYlm_storage returned by this function can be used to compute _sY_ell m values for numerous values of the spin.\n\n\n\n\n\n","category":"function"},{"location":"sYlm/#SphericalFunctions.sYlm_iterator","page":"_sY_ellm functions","title":"SphericalFunctions.sYlm_iterator","text":"sYlm_iterator(Y, โ„“โ‚˜โ‚โ‚“, [โ„“โ‚˜แตขโ‚™, [iโ‚˜แตขโ‚™]])\n\nConstruct an Iterator that returns sub-vectors of Y, each of which consists of elements (โ„“-โ„“) through (โ„“โ„“), for โ„“ from โ„“โ‚˜แตขโ‚™ through โ„“โ‚˜โ‚โ‚“.\n\nNote that the returned objects are views into the original Y data โ€” meaning that you may alter their values.\n\nBecause the result is a vector restricted to a particular โ„“ value, you can index the (โ„“ m) element as [โ„“+m+1]. For example, you might use this as something like\n\nfor (โ„“, Yหก) in zip(โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“, sYlm_iterator(Y, โ„“โ‚˜โ‚โ‚“))\n for m in -โ„“:โ„“\n Yหก[โ„“+m+1] # ... do something with Yหก\n end\nend\n\nBy default, Y is assumed to contain all possible values, beginning with (0,0). However, if โ„“โ‚˜แตขโ‚™ is not 0, this can be ambiguous: do we mean that Y really starts with the (0,0) element and we are just asking to begin the iteration higher? Or do we mean that Y doesn't even contain data for lower โ„“ values? We can resolve this using iโ‚˜แตขโ‚™, which gives the index of โ„“โ‚˜แตขโ‚™ in Y. By default, we assume the first case, and set iโ‚˜แตขโ‚™=Ysize(โ„“โ‚˜แตขโ‚™-1)+1. However, if Y doesn't contain data below โ„“โ‚˜แตขโ‚™, we could use iโ‚˜แตขโ‚™=1 to indicate the index in Y at which to find (โ„“โ‚˜แตขโ‚™-โ„“โ‚˜แตขโ‚™).\n\nAlso note that no bounds checking is done, either at instantiation time or during iteration. You are responsible for ensuring that the size of Y and the values of โ„“โ‚˜โ‚โ‚“, โ„“โ‚˜แตขโ‚™, and iโ‚˜แตขโ‚™ make sense.\n\n\n\n\n\n","category":"type"},{"location":"operators/#Differential-operators","page":"Differential operators","title":"Differential operators","text":"","category":"section"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Spin-weighted spherical functions cannot be defined on the sphere S^2, but are well defined on the group mathrmSpin(3) cong mathrmSU(2) or the rotation group mathrmSO(3). (See Boyle [1] for the explanation.) However, this also allows us to define a variety of differential operators acting on these functions, relating to infinitesimal motions in these groups, acting either from the left or the right on their arguments. Right or left matters because the groups mentioned above are all non-commutative groups.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"In general, the left Lie derivative of a function f(Q) over the unit quaternions with respect to a generator of rotation g is defined as","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_g(f)Q = -fraci2\n left fracdfleft(exp(tg) Qright)dt right_t=0","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Note that the exponential multiplies Q on the left โ€” hence the name. We will see below that this agrees with the usual definition of the angular-momentum from physics, except that in quantum physics a factor of hbar is usually included.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"So, for example, a rotation about the z axis has the quaternion z as its generator of rotation, and L_z defined in this way agrees with the usual angular-momentum operator L_z familiar from spherical-harmonic theory, and reduces to it when the function has spin weight 0, but also applies to functions of general spin weight. Similarly, we can compute L_x and L_y, and take appropriate combinations to find the usual raising and lowering (ladder) operators L_+ and L_-.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"In just the same way, we can define the right Lie derivative of a function f(Q) over the unit quaternions with respect to a generator of rotation g as","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"R_g(f)Q = -fraci2\n left fracdfleft(Q exp(tg)right)dt right_t=0","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Note that the exponential multiplies Q on the right โ€” hence the name.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"This operator is less common in physics, because it represents the dependence of the function on the choice of frame (or coordinate system), which is not usually of interest. Multiplication on the left represents a rotation of the physical system, while rotation on the right represents a rotation of the coordinate system. However, this dependence on coordinate system is precisely what defines the spin weight of a function, so this class of operators is relevant in discussions of spin-weighted spherical functions. In particular, the operators R_pm correspond (up to a sign) to the spin-raising and -lowering operators eth and bareth originally introduced by Newman and Penrose [7], as explained in greater detail by Boyle [1].","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Note that these definitions are extremely general, in that they can be used for any Lie group, and for any complex-valued function on that group. And in full generality, we have the useful properties of linearity:","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_smathbfa = sL_mathbfa\nqquad textand qquad\nR_smathbfa = sR_mathbfa","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"and","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_mathbfa+mathbfb = L_mathbfa + L_mathbfb\nqquad textand qquad\nR_mathbfa+mathbfb = R_mathbfa + R_mathbfb","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"for any scalar s and any elements of the Lie algebra mathbfa and mathbfb. In particular, if the Lie algebra has a basis mathbfe_(j), we use the shorthand L_j and R_j for L_mathbfe_(j) and R_mathbfe_(j), respectively, and we can expand any operator in terms of these basis operators:","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_mathbfa = sum_j a_j L_j\nqquad textand qquad\nR_mathbfa = sum_j a_j R_j","category":"page"},{"location":"operators/#Commutators","page":"Differential operators","title":"Commutators","text":"","category":"section"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"In general, for generators a and b, we have the commutator relations","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"left L_a L_b right = fraci2 L_ab\nqquad\nleft R_a R_b right = -fraci2 R_ab","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"where ab is the commutator of the two generators, which can be obtained directly as the commutator of the corresponding quaternions. Note the sign difference between these two equations. The factors of pm i2 are inherited directly from the definitions of L_g and R_g given above, but they appear there with the same sign. The sign difference between these two commutator equations results from the fact that the quaternions are multiplied in opposite orders in the two cases. It could be absorbed by defining the operators with opposite signs.[1] The arbitrary sign choices used above are purely for historical reasons.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Again, these results are valid for general (finite-dimensional) Lie groups, but a particularly interesting case is in application to the three-dimensional rotation group. In the following, we will apply our results to this group.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"The commutator relations for L are consistent โ€” except for the differing use of hbar โ€” with the usual relations from quantum mechanics:","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"left L_j L_k right = i hbar sum_l=1^3 varepsilon_jkl L_l","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Here, j, k, and l are indices that run from 1 to 3, and index the set of basis vectors (hatx haty hatz). If we represent an arbitrary basis vector as hate_j, then the quaternion commutator ab in the expression for L_a L_b becomes","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"hate_j hate_k = 2 sum_l=1^3 varepsilon_jkl hate_l","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Plugging this into the general expression L_a L_b = fraci2 L_ab, we obtain (up to the factor of hbar) the version frequently seen in quantum physics.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"[1]: In fact, we can define the left and right Lie derivative operators quite generally, for functions on any Lie group and for the corresponding Lie algebra. And in all cases (at least for finite-dimensional Lie algebras) we obtain the same commutator relations. The only potential difference is that it may not make sense to use the coefficient i2 in general; it was chosen here for consistency with the standard angular-momentum operators. If that coefficient is changed in the definitions of the Lie derivatives, the only change to the commutator relations would the substitution of that coefficient.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"The raising and lowering operators relative to L_z and R_z satisfy โ€” by definition of raising and lowering operators โ€” the relations","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_z L_pm = pm L_pm\nqquad\nR_z R_pm = pm R_pm","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"These allow us to solve โ€” up to an overall factor โ€” for those operators in terms of the basic generators (again, noting the sign difference):","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_pm = L_x pm i L_y\nqquad\nR_pm = R_x mp i R_y","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"(Interestingly, this procedure also shows that rasing and lowering operators can only exist if the factor in front of the derivatives in the definitions of L_g and R_g are pure imaginary numbers.) In particular, this results in the commutator relations","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_+ L_- = 2L_z\nqquad\nR_+ R_- = 2R_z","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Here, the signs are similar because the two sign differences noted above essentially cancel each other out.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"In the functions listed below, these operators are returned as matrices acting on vectors of mode weights. As such, we can actually evaluate these commutators as given to cross-validate the expressions and those functions.","category":"page"},{"location":"operators/#Transformations-of-functions-vs.-mode-weights","page":"Differential operators","title":"Transformations of functions vs. mode weights","text":"","category":"section"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"One important point to note is that mode weights transform \"contravariantly\" (very loosely speaking) relative to the spin-weighted spherical functions under some operators. For example, take the action of the L_+ operator, which acts on a SWSH as","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_+ left_sY_ellmright (R) = sqrt(ell-m)(ell+m+1) _sY_ellm+1(R)","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"We can use this to derive the mode weights of a general spin-weighted function f under the action of this operator:[2]","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"beginaligned\nleftL_+ fright_ellm\n=\nint leftL_+ f(R)right _sbarY_ellm(R) dR \n=\nint leftL_+ sum_ellmf_ellm _sY_ellm(R)right _sbarY_ellm(R) dR \n=\nint sum_ellm f_ellm leftL_+ _sY_ellm(R)right _sbarY_ellm(R) dR \n=\nsum_ellm f_ellm int leftL_+ _sY_ellm(R)right _sbarY_ellm(R) dR \n=\nsum_ellm f_ellm int leftsqrt(ell-m)(ell+m+1) _sY_ellm+1(R)right _sbarY_ellm(R) dR \n=\nsum_ellm f_ellm sqrt(ell-m)(ell+m+1) int _sY_ellm+1(R) _sbarY_ellm(R) dR \n=\nsum_ellm f_ellm sqrt(ell-m)(ell+m+1) delta_ellell delta_mm+1 \n=\nf_ellm-1 sqrt(ell-m+1)(ell+m)\nendaligned","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Note that this expression (and in particular its signs) more resembles the expression for L_- left_sY_ellmright than for L_+ left_sY_ellmright. Similar relations hold for the action of L_-.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"[2]: A technical note about the integrals above: the integrals should be taken over the appropriate space and with the appropriate weight such that the SWSHs are orthonormal. In general, this integral should be over mathrmSpin(3) and weighted by 12pi so that the result will be either 0 or 1; in general the SWSHs are not truly orthonormal when integrated over an S^2 subspace (nor even is the integral invariant). However, if we know that the spins are the same in both cases, it is possible to integrate over an S^2 subspace.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"However, it is important to note that the same \"contravariance\" is not present for the spin-raising and -lowering operators:","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"beginaligned\nlefteth fright_ellm\n=\nint lefteth f(R)right _s+1barY_ellm(R) dR \n=\nint lefteth sum_ellmf_ellm _sY_ellm(R)right _s+1barY_ellm(R) dR \n=\nsum_ellm f_ellm int lefteth _sY_ellm(R)right _s+1barY_ellm(R) dR \n=\nsum_ellm f_ellm sqrt(ell-s)(ell+s+1) int _s+1Y_ellm(R) _s+1barY_ellm(R) dR \n=\nsum_ellm f_ellm sqrt(ell-s)(ell+s+1) delta_ellell delta_mm \n=\nf_ellm sqrt(ell-s)(ell+s+1)\nendaligned","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Similarly bareth โ€” and R_pm of course โ€” obey this more \"covariant\" form of transformation.","category":"page"},{"location":"operators/#Docstrings","page":"Differential operators","title":"Docstrings","text":"","category":"section"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Modules = [SphericalFunctions]\nPages = [\"operators.jl\"]","category":"page"},{"location":"operators/#SphericalFunctions.Lz-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Lz","text":"Lz(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the angular-momentum operator associated with the z direction. This is the standard L_z operator, familiar from basic physics, extended to work with SWSHs. Note that this is the left Lie derivative; see Rz for the equivalent right Lie derivative. See the documentation or Boyle for more details.\n\nIn terms of the SWSHs, we can write the action of L_z as\n\nL_z _sY_ellm = m _sY_ellm\n\nSee also Lยฒ, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.Lยฒ-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Lยฒ","text":"Lยฒ(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the total angular-momentum operator from โ„“โ‚˜แตขโ‚™ up to โ„“โ‚˜โ‚โ‚“. If not present, โ„“โ‚˜แตขโ‚™ is assumed to be abs(s). The argument s is ignored; it is present only for consistency with other operators, and is assumed to be 0 if not present.\n\nThis is the standard Lยฒ operator, familiar from basic physics, extended to work with SWSHs. It is also known as the Casimir operator, and is equal to\n\nL^2 = L_x^2 + L_y^2 + L_z^2 = fracL_+L_- + L_-L_+ + 2L_zL_z2\n\nNote that these are the left Lie derivatives, but L^2 = R^2, where R is the right Lie derivative. See the documentation or Boyle for more details.\n\nIn terms of the SWSHs, we can write the action of L^2 as\n\nL^2 _sY_ellm = ell(ell+1) _sY_ellm\n\nSee also Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.Lโ‚Š-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Lโ‚Š","text":"Lโ‚Š(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the angular-momentum raising operator. This is the standard L_+ operator, familiar from basic physics, extended to work with SWSHs. Note that this is the left Lie derivative; see Rโ‚Š for the equivalent right Lie derivative. See the documentation or Boyle for more details.\n\nWe define L_+ to be the raising operator for the left Lie derivative with respect to rotation about z: L_z. By definition, this implies the commutator relation L_z L_+ = L_+, which allows us to derive L_+ = L_x + i L_y\n\nIn terms of the SWSHs, we can write the action of L_+ as\n\nL_+ _sY_ellm = sqrt(ell-m)(ell+m+1) _sY_ellm+1\n\nConsequently, the mode weights of a function are affected as\n\nleftL_+(f)right_sellm = sqrt(ell+m)(ell-m+1)leftfright_sellm-1\n\nSee also Lยฒ, Lz, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.Lโ‚‹-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Lโ‚‹","text":"Lโ‚‹(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the angular-momentum lowering operator. This is the standard L_- operator, familiar from basic physics, extended to work with SWSHs. Note that this is the left Lie derivative; see Rโ‚‹ for the equivalent right Lie derivative. See the documentation or Boyle for more details.\n\nWe define L_- to be the lowering operator for the left Lie derivative with respect to rotation about z: L_z. By definition, this implies the commutator relation L_z L_- = -L_-, which allows us to derive L_- = L_x - i L_y\n\nIn terms of the SWSHs, we can write the action of L_- as\n\nL_- _sY_ellm = sqrt(ell+m)(ell-m+1) _sY_ellm-1\n\nConsequently, the mode weights of a function are affected as\n\nleftL_-(f)right_sellm = sqrt(ell-m)(ell+m+1)leftfright_sellm+1\n\nSee also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.Rz-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Rz","text":"Rz(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the right angular-momentum operator associated with the z direction.\n\nThis is the R_z operator, much like the L_z operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. See Lz for the equivalent left Lie derivative. See the documentation or Boyle for more details.\n\nIn terms of the SWSHs, we can write the action of R_z as\n\nR_z _sY_ellm = -s _sY_ellm\n\nNote the unfortunate sign of s, which seems to be opposite to what we expect, and arises from the choice of definition of s in the original paper by Newman and Penrose.\n\nSee also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.Rยฒ-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Rยฒ","text":"Rยฒ(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the total angular-momentum operator from โ„“โ‚˜แตขโ‚™ up to โ„“โ‚˜โ‚โ‚“. If not present, โ„“โ‚˜แตขโ‚™ is assumed to be abs(s). The argument s is ignored; it is present only for consistency with other operators, and is assumed to be 0 if not present.\n\nThis is the R^2 operator, much like the L^2 operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. It is also known as the Casimir operator, and is equal to\n\nR^2 = R_x^2 + R_y^2 + R_z^2 = fracR_+R_- + R_-R_+ + 2R_zR_z2\n\nNote that these are the right Lie derivatives, but L^2 = R^2, where L is the left Lie derivative. See the documentation or Boyle for more details.\n\nIn terms of the SWSHs, we can write the action of R^2 as\n\nR^2 _sY_ellm = ell(ell+1) _sY_ellm\n\nSee also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.Rโ‚Š-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Rโ‚Š","text":"Rโ‚Š(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the right angular-momentum raising operator.\n\nThis is the R_+ operator, much like the L_+ operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. See Lโ‚Š for the equivalent left Lie derivative. See the documentation or Boyle for more details.\n\nWe define R_+ to be the raising operator for the right Lie derivative with respect to rotation about z: R_z. By definition, this implies the commutator relation R_z R_+ = R_+, which allows us to derive R_+ = R_x - i R_y\n\nIn terms of the SWSHs, we can write the action of R_+ as\n\nR_+ _sY_ellm = sqrt(ell+s)(ell-s+1) _s-1Y_ellm\n\nConsequently, the mode weights of a function are affected as\n\nleftR_+(f)right_sellm = sqrt(ell+s)(ell-s+1)leftfright_s-1ellm\n\nBecause of the unfortunate sign of s arising from the choice of definition of s in the original paper by Newman and Penrose, this is a lowering operator for s, though it really is a raising operator for R_z, and raises the eigenvalue of the corresponding Wigner matrix.\n\nSee also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚‹, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.Rโ‚‹-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Rโ‚‹","text":"Rโ‚‹(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the right angular-momentum lowering operator.\n\nThis is the R_- operator, much like the L_- operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. See Lโ‚‹ for the equivalent left Lie derivative. See the documentation or Boyle for more details.\n\nWe define R_- to be the raising operator for the right Lie derivative with respect to rotation about z: R_z. By definition, this implies the commutator relation R_z R_- = -R_-, which allows us to derive R_- = R_x + i R_y\n\nIn terms of the SWSHs, we can write the action of R_- as\n\nR_- _sY_ellm = sqrt(ell-s)(ell+s+1) _s+1Y_ellm\n\nConsequently, the mode weights of a function are affected as\n\nleftR_-(f)right_sellm = sqrt(ell-s)(ell+s+1)leftfright_s+1ellm\n\nBecause of the unfortunate sign of s arising from the choice of definition of s in the original paper by Newman and Penrose, this is a raising operator for s, though it really is a lowering operator for R_z, and lowers the eigenvalue of the corresponding Wigner matrix - though that raises the eigenvalue of the corresponding Wigner matrix.\n\nSee also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.รฐ-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.รฐ","text":"รฐ(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute coefficients for the spin-raising operator eth.\n\nThis operator was originally defined by Newman and Penrose, but is more completely defined by Boyle. It is identical to Rโ‚‹. Refer to that function's documentation for more details.\n\nBy definition, the spin-raising operator satisfies the commutator relation S eth = eth (where S is the spin operator, which just multiplies the function by its spin). In terms of the SWSHs, we can write the action of eth as\n\n eth _sY_ellm = sqrt(ell-s)(ell+s+1) _s+1Y_ellm\n\nConsequently, the mode weights of a function are affected as\n\nlefteth fright_sellm = sqrt(ell-s)(ell+s+1)leftfright_s+1ellm\n\nSee also รฐฬ„, Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.รฐฬ„-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.รฐฬ„","text":"รฐฬ„(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute coefficients for the spin-lowering operator bareth.\n\nThis operator was originally defined by Newman and Penrose, but is more completely defined by Boyle. It is opposite to Rโ‚Š โ€” meaning that bareth = -R. Refer to that function's documentation for more details.\n\nBy definition, the spin-lowering operator satisfies the commutator relation S bareth = -bareth (where S is the spin operator, which just multiplies the function by its spin). In terms of the SWSHs, we can write the action of bareth as\n\nbareth _sY_ellm = -sqrt(ell+s)(ell-s+1) _s-1Y_ellm\n\nConsequently, the mode weights of a function are affected as\n\nleftbareth fright_sellm\n= -sqrt(ell-s)(ell+s+1)leftfright_s+1ellm\n\nSee also รฐ, Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š.\n\n\n\n\n\n","category":"method"},{"location":"conventions/conventions/#Conventions","page":"Conventions","title":"Conventions","text":"","category":"section"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"In the following subsections, we work through all the conventions used in this package, starting from first principles to motivate the choices and ensure that each step is on firm footing. First, we can just list the most important conventions. Note that we will use Euler angles and spherical coordinates here. It is almost always a bad idea to use Euler angles in computing; quaternions are clearly the preferred representation for numerous reasons. However, Euler angles are important for (a) comparing to other sources, and (b) performing analytic integrations. These are the only two uses we will make of Euler angles.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Right-handed Cartesian coordinates (x y z) and unit basis vectors (๐ฑ ๐ฒ ๐ณ).\nSpherical coordinates (r theta phi) and unit basis vectors (๐ซ boldsymboltheta boldsymbolphi). The \"polar angle\" theta in 0 pi measures the angle between the specified direction and the positive ๐ณ axis. The \"azimuthal angle\" phi in 0 2pi) measures the angle between the projection of the specified direction onto the ๐ฑ-๐ฒ plane and the positive ๐ฑ axis, with the positive ๐ฒ axis corresponding to the positive angle phi = pi2.\nQuaternions ๐ = W + X๐ข + Y๐ฃ + Z๐ค, where ๐ข๐ฃ๐ค = -1. In software, this quaternion is represented by (W X Y Z). We will depict a three-dimensional vector ๐ฏ = v_x ๐ฑ + v_y ๐ฒ + v_z ๐ณ interchangeably as a quaternion v_x ๐ข + v_y ๐ฃ + v_z ๐ค.\nA rotation represented by the unit quaternion ๐‘ acts on a vector ๐ฏ as ๐‘ ๐ฏ ๐‘^-1.\nWhere relevant, rotations will be assumed to be right-handed, so that a quaternion characterizing the rotation through an angle vartheta about a unit vector ๐ฎ can be expressed as ๐‘ = exp(vartheta ๐ฎ2). Note that -๐‘ would deliver the same rotation, which is why the group of unit quaternions mathrmSpin(3) = mathrmSU(2) is a double cover of the group of rotations mathrmSO(3).\nEuler angles parametrize a unit quaternion as ๐‘ = exp(alpha ๐ค2) exp(beta ๐ฃ2) exp(gamma ๐ค2). The angles alpha and beta take values in 0 2pi). The angle beta takes values in 0 2pi to parametrize the group of unit quaternions mathrmSpin(3) = mathrmSU(2), or in 0 pi to parametrize the group of rotations mathrmSO(3).\nA point on the unit sphere with spherical coordinates (theta phi) can be represented by Euler angles (alpha beta gamma) = (phi theta 0). The rotation with these Euler angles takes the positive ๐ณ axis to the specified direction. In particular, any function of spherical coordinates can be promoted to a function on Euler angles using this identification.\nFor a complex-valued function f(๐‘), we define two operators, the left and right Lie derivatives:\nL_๐ฎ f(๐‘) = left-i fracddepsilonright_epsilon=0\nfleft(e^epsilon ๐ฎ2 ๐‘right)\nqquad textand qquad\nR_๐ฎ f(๐‘) = left-i fracddepsilonright_epsilon=0\nfleft(๐‘ e^epsilon ๐ฎ2right)\nwhere ๐ฎ can be any pure-vector quaternion. In particular, L represents the standard angular-momentum operators, and we can compute the expressions in Euler angles for the basis vectors:\nbeginaligned\nL_x = L_๐ข = -i left( sinalpha fracpartialpartialbeta + cosalpha cotbeta fracpartialpartialalpha right) \nL_y = L_๐ฃ = -i left( cosalpha fracpartialpartialbeta - sinalpha cotbeta fracpartialpartialalpha right) \nL_z = L_๐ค = -i fracpartialpartialalpha\nendaligned\nAngular-momentum operators defined in Lie terms, translated to Euler angles and spherical coordinates.\nSpherical harmonics\nWigner D-matrices\nSpin-weighted spherical harmonics","category":"page"},{"location":"conventions/conventions/#Three-dimensional-space","page":"Conventions","title":"Three-dimensional space","text":"","category":"section"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The space we are working in is naturally three-dimensional Euclidean space, so we start with a right-handed Cartesian coordinate system (x y z). These also give us the unit basis vectors (๐ฑ ๐ฒ ๐ณ). Note that these basis vectors are assumed to have unit norm, but we omit the hats just to keep the notation simple. Any vector in this space can be written as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"mathbfv = v_x mathbf๐ฑ + v_y mathbf๐ฒ + v_z mathbf๐ณ","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"in which case the Euclidean norm is given by","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":" mathbfv = sqrtv_x^2 + v_y^2 + v_z^2","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Equivalently, we can write the components of the Euclidean metric as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"g_ij = left( beginarrayccc\n 1 0 0 \n 0 1 0 \n 0 0 1\nendarray right)_ij","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Note that, because the points of the space are in one-to-one correspondence with the vectors, we will frequently use a vector to label a point in space.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"We will be working on the sphere, so it will be very convenient to use spherical coordinates (r theta phi). We choose the standard \"physics\" conventions for these, in which we relate to the Cartesian coordinates by","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\nr = sqrtx^2 + y^2 + z^2 in 0 infty) \ntheta = arccosleft(fraczrright) in 0 pi \nphi = arctanleft(fracyxright) in 0 2pi)\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"where we assume the arctan in the expression for phi is really the two-argument form that gives the correct quadrant. The inverse transformation is given by","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\nx = r sintheta cosphi \ny = r sintheta sinphi \nz = r costheta\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"We can use this to find the components of the metric in spherical coordinates:","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"g_ij\n= sum_ij fracpartial x^ipartial x^i fracpartial x^jpartial x^j g_ij\n= left( beginarrayccc\n 1 0 0 \n 0 r^2 0 \n 0 0 r^2 sin^2theta\nendarray right)_ij","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The unit coordinate vectors in spherical coordinates are then","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\nmathbf๐ซ = sintheta cosphi mathbf๐ฑ + sintheta sinphi mathbf๐ฒ + costheta mathbf๐ณ \nboldsymboltheta = costheta cosphi mathbf๐ฑ + costheta sinphi mathbf๐ฒ - sintheta mathbf๐ณ \nboldsymbolphi = -sinphi mathbf๐ฑ + cosphi mathbf๐ฒ\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"where, again, we omit the hats on the unit vectors to keep the notation simple.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"One seemingly obvious โ€” but extremely important โ€” fact is that the unit basis frame (๐ฑ ๐ฒ ๐ณ) can be rotated onto (boldsymboltheta boldsymbolphi mathbfr) by first rotating through the \"polar\" angle theta about the mathbfy axis, and then through the \"azimuthal\" angle phi about the mathbfz axis. This becomes important when we consider spin-weighted functions.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Integration in Cartesian coordinates is, of course, trivial as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"int_mathbbR^3 f d^3mathbfr = int_-infty^infty int_-infty^infty int_-infty^infty f dx dy dz","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"In spherical coordinates, the integrand involves the square-root of the determinant of the metric, so we have","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"int_mathbbR^3 f d^3mathbfr = int_0^infty int_0^pi int_0^2pi f r^2 sintheta dr dtheta dphi","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Restricting to the unit sphere, and normalizing so that the integral of 1 over the sphere is 1, we can simplify this to","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"int_S^2 f d^2Omega = frac14pi int_0^pi int_0^2pi f sintheta dtheta dphi","category":"page"},{"location":"conventions/conventions/#Four-dimensional-space:-Quaternions-and-rotations","page":"Conventions","title":"Four-dimensional space: Quaternions and rotations","text":"","category":"section"},{"location":"conventions/conventions/#Geometric-algebra","page":"Conventions","title":"Geometric algebra","text":"","category":"section"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Given the basis vectors (๐ฑ ๐ฒ ๐ณ) and the Euclidean norm, we can define the geometric algebra. The key feature is the geometric product, which is defined for any pair of vectors as ๐ฏ and ๐ฐ as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐ฏ ๐ฐ = ๐ฏ ๐ฐ + ๐ฏ ๐ฐ","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"where the dot product is the usual scalar product and the wedge product is the antisymmetric part of the tensor product โ€”ย acting just like the standard exterior product from the algebra of differential forms. The geometric product is linear, associative, distributive, and has the property that","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐ฏ๐ฏ = ๐ฏ ^2","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The most useful properties of the geometric product are that parallel vectors commute with each other, while orthogonal vectors anticommute. Since the geometric product is linear, the product of any two vectors can be decomposed into parallel and orthogonal parts.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The basis for this entire space is then the set","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"begingather\n๐Ÿ \n๐ฑ ๐ฒ ๐ณ\n๐ฑ๐ฒ ๐ฑ๐ณ ๐ฒ๐ณ \n๐ฑ๐ฒ๐ณ\nendgather","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The standard presentation of quaternions (including the confused historical development) uses different symbols for these last four basis elements:","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"begingather\n๐ข = ๐ณ๐ฒ = -๐ฒ๐ณ \n๐ฃ = ๐ฑ๐ณ = -๐ณ๐ฑ \n๐ค = ๐ฒ๐ฑ = -๐ฑ๐ฒ \n๐ˆ = ๐ฑ๐ฒ๐ณ\nendgather","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Note that each of these squares to -1. For example, recalling that orthogonal vectors anticommute, the product is associative, and the product of a vector with itself is just its squared norm, we have","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐ฑ๐ฒ๐ฑ๐ฒ = -๐ฑ๐ฒ๐ฒ๐ฑ = -๐ฑ(๐ฒ๐ฒ)๐ฑ = -๐ฑ๐ฑ = -1","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Any of these could act like the unit imaginary; ๐ฑ๐ฒ is probably the canonical choice.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐ˆ is sometimes called the pseudoscalar. Its inverse is ๐ˆ^-1 = ๐ณ๐ฒ๐ฑ = -๐ฑ๐ฒ๐ณ, which can also serve as something very much like the Hodge star operator,[1] mapping elements to their \"dual\" elements. In particular, we have","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\n๐ข = ๐ˆ^-1๐ฑ \n๐ฃ = ๐ˆ^-1๐ฒ \n๐ค = ๐ˆ^-1๐ณ\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"We will see that ๐ข generates right-handed rotations in the positive sense about ๐ฑ, ๐ฃ about ๐ฒ, and ๐ค about ๐ณ. Moreover, this mapping between (๐ฑ ๐ฒ ๐ณ) and (๐ข ๐ฃ ๐ค) is a vector-space isomorphism. In fact, the reader who is not familiar with geometric algebra but is familiar with quaternions may be able to read an expression like ๐ฃ ๐ฑ ๐ฃยน as if it is just an abuse of notation, and mentally replace ๐ฑ with ๐ข to read those symbols as a valid quaternion expression; both viewpoints are equally correct by the isomorphism.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"[1]: Note that quaternions will only be spanned by elements made from an even number of the basis vectors. It turns out that those with an odd number will produce reflections, rather than rotations, when acting on a vector โ€” as discussed below. This explains why quaternions are restricted to just those elements with an even number to represent rotations. For details see any geometric algebra text, like Doran and Lasenby.","category":"page"},{"location":"conventions/conventions/#Quaternions-and-Euler-angles","page":"Conventions","title":"Quaternions and Euler angles","text":"","category":"section"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Note that there are different conventions for the signs of the (๐ข ๐ฃ ๐ค) basis. Everyone agrees that ๐ขยฒ = ๐ฃยฒ = ๐คยฒ = -1, but we could easily flip the sign of any basis element, and these would still be satisfied. The identifications we chose above are made to ensure that ๐ข generates rotations about ๐ฑ, and so on, but even that depends on how we define quaternions as acting on vectors (to be discussed below). A different choice of the latter would result in all flipping the sign of all three basis elements, which is a convention that is commonly used โ€” though almost exclusively in aerospace. The key expressions that eliminate ambiguity are the multiplications","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\n๐ข ๐ฃ = ๐ค \n๐ฃ ๐ค = ๐ข \n๐ค ๐ข = ๐ฃ\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"We can also use these rules above to determine ๐ข๐ฃ๐ค = -๐Ÿ. All four of these equations have flipped signs in other conventions. See Sommer et al. for a discussion of the different conventions.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"We use coordinates (W X Y Z) on the space of quaternions, so that a quaternion would be written as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐ = W๐Ÿ + X๐ข + Y๐ฃ + Z๐ค","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"though we usually omit the ๐Ÿ. The space of all quaternions is thus four dimensional. The norm is just the standard Euclidean norm, so that the norm of a quaternion is","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":" ๐ = sqrtW^2 + X^2 + Y^2 + Z^2","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"An important operation is the conjugate, which is defined as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"overline๐ = W - X๐ข - Y๐ฃ - Z๐ค","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Note that the squared norm can be written as the quaternion times its conjugate. The inverse of a quaternion is thus just the conjugate divided by the squared norm:","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐^-1 = fracoverline๐๐overline๐ = fracoverline๐ ๐ ^2","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The other important operation is exponentiation. Since a scalar commutes with any quaternion, including a nonzero scalar component in the quaternion will simply multiply the result by the exponential of that scalar component. Moreover, we will not have any use for such an exponential, so we assume that the argument to the exponential function is a \"pure\" quaternion โ€” that is, one with zero scalar component. Moreover, we write it as a unit quaternion ๐ฎ times some real number sigma. In particular, note that ๐ฎ^2 = -1, so that it acts like the imaginary unit, which means we already know how to exponentiate it:","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"exp(๐ฎ sigma) = cossigma + ๐ฎ sinsigma","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Note that the inverse of the result can be obtained simply by negating the argument, as usual.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Much as with standard three-dimensional space, we could introduce a generalization of spherical coordinates, though we use a slight variant: extended Euler coordinates. We will see below how to interpret these as a series of rotations. For now, we simply state the relation:","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\nR = sqrtW^2 + X^2 + Y^2 + Z^2 in 0 infty) \nalpha = arctanfracZW + arctanfrac-XY in 0 2pi) \nbeta = 2arccossqrtfracW^2+Z^2W^2+X^2+Y^2+Z^2 in 0 2pi \ngamma = arctanfracZW - arctanfrac-XY in 0 2pi)\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"where we again assume the arctan in the expressions for alpha and gamma is really the two-argument form that gives the correct quadrant. Note that here, beta ranges up to 2pi rather than just pi, as in the standard Euler angles. This is because we are describing the space of quaternions, rather than just the space of rotations. If we restrict to R=1, we have exactly the group of unit quaternions mathrmSpin(3)=mathrmSU(2), which is a double cover of the rotation group mathrmSO(3). This extended range for beta is necessary to cover the entire space of quaternions; if we further restrict to 0 pi), we would only cover the space of rotations. This and the inclusion of R identify precisely how this coordinate system extends the standard Euler angles.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The inverse transformation is given by","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\n W = R cosfracฮฒ2 cosfracฮฑ+ฮณ2 \n X = -R sinfracฮฒ2 sinfracฮฑ-ฮณ2 \n Y = R sinfracฮฒ2 cosfracฮฑ-ฮณ2 \n Z = R cosfracฮฒ2 sinfracฮฑ+ฮณ2\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"As with the spherical coordinates, we can use this to find the components of the metric in our extended Euler coordinates:","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"g_ij\n= sum_ij fracpartial X^ipartial X^i fracpartial X^jpartial X^j g_ij\n= left( beginarraycccc\n 1 0 0 0 \n 0 fracR^24 0 fracR^2 cosbeta4 \n 0 0 fracR^24 0 \n 0 fracR^2 cosbeta4 0 fracR^24\nendarray right)_ij","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Again, integration involves a square-root of the determinant of the metric, which reduces to R^3 sinbeta 8. Note that โ€” unlike with standard spherical coordinates โ€” the absolute value is necessary because beta ranges over the entire interval 0 2pi. The integral over the entire space of quaternions is then","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"int_mathbbR^4 f d^4๐\n= int_-infty^infty int_-infty^infty int_-infty^infty int_-infty^infty f dW dX dY dZ\n= int_0^infty int_0^2pi int_0^2pi int_0^2pi f fracR^38 sin ฮฒ dR dฮฑ dฮฒ dฮณ","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Restricting to the unit sphere, and normalizing so that the integral of 1 over the sphere is 1, we can simplify this to","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"int_mathrmSpin(3) f d^3Omega\n= frac116pi^2 int_0^2pi int_0^2pi int_0^2pi f sin ฮฒ dฮฑ dฮฒ dฮณ","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Finally, restricting to the space of rotations, we can further simplify this to","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"int_mathrmSO(3) f d^3Omega\n= frac18pi^2 int_0^2pi int_0^pi int_0^2pi f sin ฮฒ dฮฑ dฮฒ dฮณ","category":"page"},{"location":"conventions/conventions/#Rotations","page":"Conventions","title":"Rotations","text":"","category":"section"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"We restrict to a unit quaternion ๐‘, for which W^2 + X^2 + Y^2 + Z^2 = 1. Given this constraint we can, without loss of generality, write the quaternion as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐‘\n= expleft(fracrho2 hatmathfrakrright)\n= cosfracrho2 + sinfracrho2 hatmathfrakr","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"where rho is an angle of rotation and hatmathfrakr is a unit \"pure-vector\" quaternion. We can multiply a vector ๐ฏ as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐‘ ๐ฏ ๐‘^-1","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Splitting ๐ฏ = ๐ฏ_ + ๐ฏ_ into components perpendicular and parallel to hatmathfrakr, we see that ๐ฏ_ commutes with ๐‘ and ๐‘^-1, while ๐ฏ_ anticommutes with hatmathfrakr. To find the full rotation, we expand the product:","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\n๐‘ ๐ฏ ๐‘^-1\n= ๐ฏ_\n + left(cosfracrho2 + sinfracrho2 hatmathfrakrright)\n ๐ฏ_\n left(cosfracrho2 - sinfracrho2 hatmathfrakrright) \n= ๐ฏ_\n + left(cosfracrho2 ๐ฏ_ + sinfracrho2 hatmathfrakr ๐ฏ_right)\n left(cosfracrho2 - sinfracrho2 hatmathfrakrright) \n= ๐ฏ_\n + cos^2fracrho2 ๐ฏ_ + sinfracrho2 cosfracrho2 hatmathfrakr ๐ฏ_\n - sinfracrho2 cosfracrho2 ๐ฏ_ hatmathfrakr - sin^2fracrho2 hatmathfrakr ๐ฏ_ hatmathfrakr \n= ๐ฏ_\n + cos^2fracrho2 ๐ฏ_ + sinfracrho2 cosfracrho2 hatmathfrakr ๐ฏ_ - sin^2fracrho2 ๐ฏ_ \n= ๐ฏ_\n + cosrho ๐ฏ_ + sinrho hatmathfrakrtimes ๐ฏ_\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The final expression shows that this is precisely what we expect when rotating ๐ฏ through an angle rho (in a positive, right-handed sense) about the axis hatmathfrakr.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Note that the presence of two factors of ๐‘ in the expression for rotating a vector explains two things. First, it explains why the angle of rotation is twice the angle of the quaternion: one factor of ๐‘ either commutes and cancels or anti-commutes and combines with the the other factor. Second, it explains why the quaternion group is a double cover of the rotation group: negating ๐‘ results in the same rotation. Thus, for any rotation, there are two (precisely opposite) quaternions that represent it.","category":"page"},{"location":"conventions/conventions/#Euler-angles-and-spherical-coordinates","page":"Conventions","title":"Euler angles and spherical coordinates","text":"","category":"section"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Now that we understand how rotations work, we can provide geometric intuition for the expressions given above for Euler angles. The Euler angles in our convention represent an initial rotation through gamma about the ๐ณ axis, followed by a rotation through beta about the ๐ฒ axis, and finally a rotation through alpha about the ๐ณ axis. Note that the axes are fixed, and not subject to any preceding rotations. More precisely, we can write the unit quaternion as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐‘ = expleft(fracalpha2 ๐คright)\n expleft(fracbeta2 ๐ฃright)\n expleft(fracgamma2 ๐คright)","category":"page"},{"location":"notes/sampling_theorems/#Sampling-theorems-and-transformations-of-spin-weighted-spherical-harmonics","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"","category":"section"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"McEwen and Wiaux [13] (MW) provide a very thorough review of the literature on sampling theorems related to spin-weighted spherical harmonics up to 2011. Reinecke and Seljebotn [3] (RS) outlined one of the more efficient and accurate implementations of spin-weighted spherical harmonic transforms (sSHT) currently available as libsharp, but their algorithm is 4Lยฒ, whereas McEwen and Wiaux's is2Lยฒ, while Elahi et al. [2] (EKKM) have obtained the optimal result that scales as Lยฒ.","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"The downside of the EKKM algorithm is that the ฮธ values at which to sample have to be obtained by iteratively minimizing the condition numbers of various matrices (which are involved in the computation itself). This expensive step only has to be performed once per choice of spin s and maximum โ„“ value L. Otherwise, the results of this algorithm seem to be relatively good โ€” at least for L up to 64. This does not compare favorably with the MW algorithm, which has slowly growing errors through L = 4096.","category":"page"},{"location":"notes/sampling_theorems/#EKKM-analysis","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"EKKM analysis","text":"","category":"section"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"The EKKM analysis looks like the following (with some notational changes). We begin by defining","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":" _stildef_theta(m) = int_0^2pi _sf(theta phi) e^-imphi dphi","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"We will denote the vector of these quantities for all values of theta as _stildemathbff_m. Inserting the _sY_ellm expansion for _sf(theta phi), and performing the integration using orthogonality of complex exponentials, we can find that","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":" _stildef_theta(m) = (-1)^s 2pi sum_ell=Delta^L sqrtfrac2ell+14pi d_m-s^ell(theta) _sf_ellm","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"Now, denoting the vector of _sf_ellm for all values of ell as _smathbff_m, we can write this as a matrix-vector equation:","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":" _stildemathbff_m = (-1)^s 2pi _smathbfd_m _smathbff_m","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"We are effectively measuring the _stildemathbff_m values, we can easily construct the _smathbfd_m matrix, and we are seeking the _smathbff_m values, so we can just invert this equation to solve for the latter.","category":"page"},{"location":"notes/sampling_theorems/#Discretizing-the-Fourier-transform","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Discretizing the Fourier transform","text":"","category":"section"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"Now, the only flaw in this analysis is that we have undersampled everywhere except ell = L, which means that the second equation (re-expressing the Fourier transforms as a sum using orthogonality of complex exponentials) isn't quite right; in general there is some folding due to aliasing of higher-frequency modes, so we need an additional sum over mm. Or perhaps more precisely, the first equation isn't actually what we implement. It should look more like this:","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":" _stildef_j(m) = sum_k=0^2j _sf(theta_j phi_k) e^-imphi_k Delta phi","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"where phi_k = frac2pi k2j+1, and Delta phi = frac2pi2j+1. (Recall the subtle notational distinction common in time-frequency analysis that tildes(t_j) = Delta t tildes_j, which would suggest we use _stildef_j(m) = Delta phi _stildef_jm.) Next, we can insert the expansion for _sf(theta phi):","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"beginaligned\n _stildef_j(m)\n = sum_k=0^2j sum_ellm _sf_ellm _sY_ellm(theta_j phi_k) e^-imphi_k Delta phi \n = sum_k=0^2j sum_ellm _sf_ellm (-1)^s sqrtfrac2ell+14pi d_ell^m-s(theta_j) e^i m phi_k e^-imphi_k frac2pi2j+1 \n = (-1)^s frac2pi2j+1 sum_ellm _sf_ellm sqrtfrac2ell+14pi d_ell^m-s(theta_j) sum_k=0^2je^i (m-m) phi_k\nendaligned","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"We can evaluate this last sum easily:","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":" sum_k=0^2je^i (m-m) phi_k = begincases\n 2j+1 m-m = n(2j+1) mathrmfor ninmathbbZ \n 0 mathrmotherwise\n endcases","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"This allows us to simplify as","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"beginaligned\n _stildef_j(m) = (-1)^s 2pi sum_ellm _sf_ellm sqrtfrac2ell+14pi d_ell^m-s(theta_j)\nendaligned","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"where m ranges over m + n(2j+1) for all nin mathbbZ such that m + n(2j+1) leq ell โ€”ย that is, all nin mathbbZ such that","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":" left lceil frac-ell-m2j+1 right rceil leq n leq left lfloor fracell-m2j+1 right rfloor","category":"page"},{"location":"notes/sampling_theorems/#Matrix-representation","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Matrix representation","text":"","category":"section"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"Usually, we would take the sum over ell ranging from mathrmmax(ms) to L, and the sum over m ranging over m + n(2j+1) for all nin mathbbZ such that m + n(2j+1) leq ell. However, we can also consider these sums to range over all possible values of ell m, and just set the coefficient to zero whenever these conditions are not satisfied. In that case, we can again think of this as a (much larger) vector-matrix equation reading","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":" _stildemathbff = (-1)^s 2pi _smathbfd _smathbff","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"where the index on _stildemathbff loops over j and m, the index on _smathbff loops over ell and m, and the indices on _smathbfd loop over each of those pairs.","category":"page"},{"location":"notes/sampling_theorems/#De-aliasing","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"De-aliasing","text":"","category":"section"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"While it is far simpler to simply invert the full _smathbfd matrix, its size scales as L^4, which means that it very quickly becomes impractical to store and manipulate the full matrix. In CMB astronomy, for example, it is not uncommon to use L into the tens of thousands, which would make the full matrix utterly impractical to use.","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"However, the matrix has a fairly sparse structure, with the number of nonzero elements scaling as L^3. More particularly, the sparsity has a fairly special structure, where the full matrix is mostly block diagonal, along with some sparse upper triangular elements. Of course, the goal is to solve the linear equation. For that, the first obvious choice is an LU decomposition. Unfortunately, the L and U components are not sparse. A second obvious choice is the QR decomposition, which is more tailored to the structure of this matrix โ€” the Q factor being essentially just the block diagonal, and the R factor being a somewhat less sparse upper triangle.","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"In principle, this alone could delay the impracticality threshold โ€” though still not enough for CMB astronomy. We can use the unusual structure to solve the linear equation in a more piecewise fashion, with fairly low memory overhead. Essentially, we start with the highest-k values, and solve for the corresponding highest-m values. Those harmonics will alias to other frequencies in theta_j rings with j k. But crucially, we know how they alias, and can simply remove them from the Fourier transforms of those rings. We then repeat, solving for the next-highest k values, and so on.","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"The following pseudo-code summarizes the analysis algorithm, modifying the input in place:","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"# Iterate over rings, doing Fourier decompositions on each\nfor j โˆˆ abs(s):โ„“โ‚˜โ‚โ‚“\n fft!(โ‚›f[j]) # Perform in-place FFT\n fftshift!(โ‚›f[j]) # Cycle order of FFT elements in place to match order of modes\n โ‚›f[j] *= 2ฯ€ / (2j+1) # Change normalization\nend\n\nfor m โˆˆ AlternatingCountdown(โ„“โ‚˜โ‚โ‚“) # Iterate over +m, then -m, down to m=0\n ฮ” = max(abs(s), abs(m))\n\n # Gather the `m` data from each ring into a temporary workspace\n for j โˆˆ ฮ”:โ„“โ‚˜โ‚โ‚“\n โ‚›fโ‚˜[j] = โ‚›f[Yindex(j, m, abs(s))]\n end\n\n # Solve for the mode weights from the Fourier components\n โ‚›fฬƒโ‚˜[ฮ”:โ„“โ‚˜โ‚โ‚“] = โ‚›ฮ›[m] \\ โ‚›fโ‚˜[ฮ”:โ„“โ‚˜โ‚โ‚“]\n\n # Distribute the data back into the output\n for โ„“ โˆˆ ฮ”:โ„“โ‚˜โ‚โ‚“\n โ‚›f[Yindex(โ„“, m, abs(s))] = โ‚›fฬƒโ‚˜[โ„“]\n end\n\n # De-alias Fourier components from rings with values of j < ฮ”\n for jโ€ฒ โˆˆ abs(s):m-1\n mโ€ฒ = mod(jโ€ฒ+m, 2jโ€ฒ+1)-jโ€ฒ # `m` aliases into `(jโ€ฒ, mโ€ฒ)`\n ฮฑ = 2ฯ€ * sum(\n ๐’ฏ.โ‚›fฬƒโ‚˜[โ„“] * โ‚›ฮปโ‚—โ‚˜\n for (โ„“, โ‚›ฮปโ‚—โ‚˜) โˆˆ zip(ฮ”:โ„“โ‚˜โ‚โ‚“, ฮป_iterator(๐’ฏ.ฮธ[jโ€ฒ], s, m))\n )\n โ‚›f[Yindex(jโ€ฒ, mโ€ฒ, abs(s))] -= ฮฑ\n end\n\nend","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"The following pseudo-code summarizes the synthesis algorithm, modifying the input in place:","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"for m โˆˆ AlternatingCountup(โ„“โ‚˜โ‚โ‚“) # Iterate over +m, then -m, up from m=0\n ฮ” = max(abs(s), abs(m))\n\n # Iterate over rings, combining contributions for this `m` value\n for j โˆˆ ฮ”:โ„“โ‚˜โ‚โ‚“\n # We will accumulate into ๐’ฏ.โ‚›fโ‚˜, and write it out at the end of the loop\n โ‚›fโ‚˜[j] = false\n\n # Direct (non-aliased) contributions from mโ€ฒ == m\n ฮป = ฮป_iterator(๐’ฏ.ฮธ[j], s, m)\n for (โ„“, โ‚›ฮปโ‚—โ‚˜) โˆˆ zip(ฮ”:โ„“โ‚˜โ‚โ‚“, ฮป)\n โ‚›fโ‚˜[j] += โ‚›fฬƒ[Yindex(โ„“, m, abs(s))] * โ‚›ฮปโ‚—โ‚˜\n end\n\n # Aliased contributions from |mโ€ฒ| > j > |m|\n for โ„“โ€ฒ โˆˆ j:โ„“โ‚˜โ‚โ‚“\n for n โˆˆ cld(-โ„“โ€ฒ-m, 2j+1):fld(โ„“โ€ฒ-m, 2j+1)\n mโ€ฒ = m + n*(2j+1)\n if abs(mโ€ฒ) > j\n โ‚›ฮปโ‚—โ€ฒโ‚˜โ€ฒ = โ‚›ฮ›[mโ€ฒ][j,โ„“โ€ฒ]\n ๐’ฏ.โ‚›fโ‚˜[j] += โ‚›fฬƒ[Yindex(โ„“โ€ฒ, mโ€ฒ, abs(s))] * โ‚›ฮปโ‚—โ€ฒโ‚˜โ€ฒ\n end\n end\n end\n\n end # j\n\n # Distribute the data back into the output\n @threads for j โˆˆ ฮ”:โ„“โ‚˜โ‚โ‚“\n โ‚›fฬƒ[Yindex(j, m, abs(s))] = ๐’ฏ.โ‚›fโ‚˜[j]\n end\n\nend # m\n\n# Iterate over rings, doing Fourier decompositions on each\nfor j โˆˆ abs(s):โ„“โ‚˜โ‚โ‚“\n ifftshift!(โ‚›fฬƒ[j]) # Cycle order of modes in place to match order of FFT elements\n bfft!(โ‚›fฬƒโฑผ[j]) # Perform in-place BFFT\nend","category":"page"},{"location":"notes/H_recursions/#Algorithm-for-computing-H","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"The H array, as given by Gumerov and Duraiswami [8], is related to Wigner's (small) d matrices โ€” which is itself related to the (big) mathfrakD matrices and the various spin-weighted spherical harmonics _sY_ellm โ€” via","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"d_ell^mm = epsilon_m epsilon_-m H_ell^mm","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"where","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"epsilon_k =\n begincases\n 1 kleq 0 \n (-1)^k k 0\n endcases","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"H has various advantages over d, including the fact that it can be efficiently and robustly valculated via recurrence relations, and the following symmetry relations:","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"beginaligned\n H^m m_n(ฮฒ) = H^m m_n(ฮฒ) \n H^m m_n(ฮฒ) = H^-m -m_n(ฮฒ) \n H^m m_n(ฮฒ) = (-1)^n+m+m H^-m m_n(ฯ€ - ฮฒ) \n H^m m_n(ฮฒ) = (-1)^m+m H^m m_n(-ฮฒ)\nendaligned","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Because of these symmetries, we only need to evaluate at most 1/4 of all the elements.","category":"page"},{"location":"notes/H_recursions/#Steps-to-compute-H","page":"Algorithm for computing H","title":"Steps to compute H","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"The following describes various details that are not spelled out correctly by Gumerov and Duraiswami [8]. All equation numbers refer to that paper.","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Because of the symmetries noted above, we only compute H^m m_n with m m โ€” roughly one quarter of all possible values. Furthermore, for computations of spin-weighted spherical harmonics of weight s, we only need to compute values with m s, which constitutes a dramatic savings when s โ„“โ‚˜โ‚โ‚“. The data are stored in the array Hwedge.","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"However, some parts of this calculation require calculating terms with m=n+1 โ€” whereas such elements of d and mathfrakD are considered zero. For this purpose, we need additional storage. Rather than allocating extra space, or requiring some additional workspace to be passed in, we can actually use parts of the input H data space for temporary storage while these extra terms are needed, which is before those parts of the storage are needed. Specifically, we need this additional storage for H^0 m_n_mathrmmax+1 with m in 0 n_mathrmmax+1, and we can use the storage destined for H^-1 m_n_mathrmmax with m in 1 n_mathrmmax. But this leaves two more indices, which we just store as individual variables โ€” Hฮฉ and Hฮจ โ€” representing the last and second-to-last of these additional elements stored.","category":"page"},{"location":"notes/H_recursions/#Step-1","page":"Algorithm for computing H","title":"Step 1","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Set H_0^00=1.","category":"page"},{"location":"notes/H_recursions/#Step-2","page":"Algorithm for computing H","title":"Step 2","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Compute values H^0m_n(ฮฒ) for m=0ldotsn and H^0m_n+1(ฮฒ) for m=0ldotsn+1. Using Eq. (32), we see that within Gumerov and Duraiswami's conventions","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"beginaligned\n H^0m_n(ฮฒ) = (-1)^m sqrtfrac(n-m)(n+m) P^m_n(cos ฮฒ) \n = frac1sqrtk_m (2n+1) P_nm(cos ฮฒ)\nendaligned","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Here, k_0=1 and k_m=2 for m0, and P is defined as","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":" P_nm = sqrtfrack_m(2n+1)(n-m)(n+m) P_nm","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Note that the factor of (-1)^m in the first equation above is different from the convention used here, and is related to the Condon-Shortley phase. Note that Gumerov and Duraiswami use the notation P^m_n, whereas we are using the notation P_nm โ€” which usually differ by a factor of (-1)^m.","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"We use the \"fully normalized\" associated Legendre functions (fnALF) P because, as explained by Xing et al. [12], it is possible to compute these values very efficiently and accurately, while also delaying the onset of overflow and underflow.","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"The algorithm Xing et al. describe as the best for computing P is due to Belikov (1991), and is given by them as","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"beginaligned\n P_00 = 1 \n P_10 = sqrt3 cos ฮฒ \n P_11 = sqrt3 sin ฮฒ \n P_n0 = a_n cos ฮฒ P_n-10 - b_n fracsin ฮฒ2 P_n-11 \n P_nm =\n c_nm cos ฮฒ P_n-1m\n - sin ฮฒ left d_nm P_n-1m+1 - e_nm P_n-1m-1 right\nendaligned","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"where the coefficients are given by","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"beginaligned\n a_n = sqrtfrac2n+12n-1 \n b_n = sqrtfrac2(n-1)(2n+1)n(2n-1) \n c_nm = frac1n sqrtfrac(n+m)(n-m)(2n+1)2n-1 \n d_nm = frac12n sqrtfrac(n-m)(n-m-1)(2n+1)2n-1 \n e_nm = frac12n sqrtfrac22-delta_0^m-1 sqrtfrac(n+m)(n+m-1)(2n+1)2n-1\nendaligned","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Now, we can directly obtain a recurrence relation for H^0m_n = P_nm sqrtk_m (2n+1) from those expressions:","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"beginaligned\n H^00_0 = 1 \n H^00_1 = cos ฮฒ \n H^01_1 = sqrt12 sin ฮฒ \n H^00_n = cos ฮฒ H^00_n-1 - b_n sin ฮฒ H^01_n-1 \n H^0m_n =\n c_nm cos ฮฒ H^0m_n-1\n - sin ฮฒ left d_nm H^0m+1_n-1 - e_nm H^0m-1_n-1 right\nendaligned","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"where the coefficients are given by","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"beginaligned\n b_n = sqrtfracn-1n \n c_nm = frac1n sqrt(n+m)(n-m) \n d_nm = frac12n sqrt(n-m)(n-m-1) \n e_nm = frac12n sqrt(n+m)(n+m-1)\nendaligned","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Note that the coefficients all simplified (in fact, a_n disappeared), without any increase in the complexity of the recurrence relations themselves. Rewriting Belikov's algorithm explicitly in terms of the H^0m_n also allows us to avoid an extra normalization step.","category":"page"},{"location":"notes/H_recursions/#Step-3","page":"Algorithm for computing H","title":"Step 3","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Compute H^1m_n(ฮฒ) for m=1ldotsn using relation (41). Symmetry and shift of the indices allow this relation to be written as","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"b^0_n+1 H^1 m_n\n = fracb^m1_n+1 (1cos ฮฒ)2 H^0 m+1_n+1\n fracb^ m1_n+1 (1+cos ฮฒ)2 H^0 m1_n+1\n a^m_n sin ฮฒ H^0 m_n+1","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Here the constants are defined by","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"a^m_n = sqrtfrac(n+m+1)(n-m+1) (2n+1)(2n+3)","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"b^m_n = mathrmsgn(m) sqrtfrac(n-m-1)(n-m) (2n-1)(2n+1)","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Note that all values are assumed to be zero whenever m n, we use mathrmsgn(0)=1 (unlike the common convention that mathrmsgn(0)=0), and we have a^m_n = a^-m_n. Also note that these coefficients only appear in this step, and because of how they appear (specifically, because b always appears with argument n+1), we can factor out the denominators in the definitions of the constants. We obtain this simplified formula","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"H^1 m_n\n = -frac1sqrtn(n+1) left\n fracbarb^m1_n+1 (1cos ฮฒ)2 H^0 m+1_n+1\n + fracbarb^ m1_n+1 (1+cos ฮฒ)2 H^0 m1_n+1\n + bara^m_n sin ฮฒ H^0 m_n+1\n right","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"with","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"bara^m_n = sqrt(n+m+1)(n-m+1)","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"barb^m_n+1 = sqrt(n-m)(n-m+1)","category":"page"},{"location":"notes/H_recursions/#Step-4","page":"Algorithm for computing H","title":"Step 4","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Recursively compute H^m+1 m_n(ฮฒ) for m=1ldotsn1, m=mn using relation (50) resolved with respect to H^m+1 m_n:","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"d^m_n H^m+1 m_n\n = d^m1_n H^m1 m_n\n d^m1_n H^m m1_n\n + d^m_n H^m m+1_n","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"(where the last term drops out for m=n). The constants are defined by","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"d^m_n = fracmathrmsgn(m)2 sqrt(n-m)(n+m+1)","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Note that we can drop the factor of 12, and for this case only the sign is always +1.","category":"page"},{"location":"notes/H_recursions/#Step-5","page":"Algorithm for computing H","title":"Step 5","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Recursively compute H^m1 m_n(ฮฒ) for m=0ldotsn+1, m=mldotsn using relation (50) resolved with respect to H^m1 m_n:","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"d^m1_n H^m1 m_n\n = d^m_n H^m+1 m_n\n + d^m1_n H^m m1_n\n d^m_n H^m m+1_n","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"(where the last term drops out for m=n).","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"NOTE: Although Gumerov and Duraiswami specify the loop over m to start at -1, I find it necessary to start at 0, or there will be missing information. This also requires setting the H^0 -1_n components (for all n) before beginning this loop.","category":"page"},{"location":"notes/H_recursions/#Pre-computing-constants-versus-computing-on-the-fly","page":"Algorithm for computing H","title":"Pre-computing constants versus computing on the fly","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Each of the constants a^m_n, b^m_n, and c^m_n involves divisions and square-roots, which can be very costly to compute. It can be advantageous to pre-compute the constants, and simply index the pre-computed arrays rather than re-computing them on each recursion.","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"If we include the cost of computing all these constants in a single call to the H recurrence, it can be much cheaper to compute each constant as needed within the algorithm, rather than computing them all at once at the beginning of the algorithm โ€” but only for very small computations, such as those involving n_mathrmmax 10. Beyond this, despite the storage penalties for all those constants, it turns out to be better to pre-compute them. However, it should be noted that the fractional cost of storing the constants is sim 3n_mathrmmax compared to just storing H itself, so this will never be a very significant amount of space.","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"On the other hand, if we can pre-compute the constants just once, and store them between multiple calls to the H recurrence, then it is always advantageous to do so โ€” typically by factors of 2 or 3 in speed. The only difficulty here is ensuring that each call to the recurrence has access to the constants, which can be a little awkward when using multiple processes and/or threads. However, it should be thread safe, since we only need to read those constants within the H recurrence. All in all, I conclude that it is probably not worth the effort to maintain separate versions of the recurrence for pre-computed and on-the-fly constants.","category":"page"},{"location":"#Introduction","page":"Introduction","title":"Introduction","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"This is a Julia package for evaluating and transforming Wigner's ๐”‡ matrices, and spin-weighted spherical harmonics _sY_ellm (which includes the ordinary scalar spherical harmonics). Because both ๐”‡ and the harmonics are most correctly considered functions on the rotation group ๐’๐Ž(3) โ€” or more generally, the spin group ๐’๐ฉ๐ข๐ง(3) that covers it โ€” these functions are evaluated directly in terms of quaternions. Concessions are also made for more standard forms of spherical coordinates and Euler angles.[1] Among other applications, those functions permit \"synthesis\" (evaluation of the spin-weighted spherical functions) of spin-weighted spherical harmonic coefficients on regular or distorted grids. This package also includes functions enabling efficient \"analysis\" (decomposition into mode coefficients) of functions evaluated on regular grids to high order and accuracy.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"These quantities are computed using recursion relations, which makes it possible to compute to very high โ„“ values. Unlike direct evaluation of individual elements, which would generally cause overflow or underflow beyond โ„“โ‰ˆ30 when using double precision, these recursion relations should be valid for far higher โ„“ values. More precisely, when using this package, Inf values appear starting at โ„“=128 for Float16, but I have not yet found any for values up to at least โ„“=1024 with Float32, and presumably far higher for Float64. BigFloat also works, and presumably will not overflow for any โ„“ value that could reasonably fit into computer memory โ€” though it is far slower. Also note that DoubleFloats will work, and achieve significantly greater accuracy (but no greater โ„“ range) than Float64. In all cases, results are typically accurate to roughly โ„“ times the precision of the input quaternion.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"The conventions for this package are mostly inherited from โ€” and are described in detail by โ€” its predecessors found here and here.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"Note that numerous other packages cover some of these use cases, including FastTransforms.jl, FastSphericalHarmonics.jl, WignerSymbols.jl, and WignerFamilies.jl. However, I need support for quaternions (via Quaternionic.jl) and for higher-precision numbers โ€” even at the cost of a very slight decrease in speed in some cases โ€” which are what this package provides.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"[1]: Euler angles are quite generally a very poor choice for computing with rotations. (The only context in which they may be preferred is when analytically integrating some analytically known functions.) Almost universally, it is best to use quaternions when computing with rotations. All the computations done within this package use quaternions; the user interfaces involving Euler angles essentially convert to/from quaternions. While the calculations needed for those conversions would still need to be done if this package used Euler angles internally โ€” meaning that this approach is as efficient as any โ€” that work can be avoided entirely if you work with quaternions directly.","category":"page"}] +[{"location":"references/#References","page":"References","title":"References","text":"","category":"section"},{"location":"references/","page":"References","title":"References","text":"The most important routine in this package is the computation of the ๐”‡ matrices โ€” or more specifically, of terms proportional to parts of the ๐”‡ matrices. This mostly follows the treatment of Gumerov and Duraiswami [8] (with minor modifications to account for errors in their presentation, as described here). To seed the recursions they present, we also need to calculate the associated Legendre functions. This is now done using the \"fully normalized column-wise recurrence formula\" (fnCWF) given by Eqs. (12)โ€”(14) of Xing et al. [12]. This improves significantly over the older implementation using the \"modified forward row method\" of Holmes and Featherstone [14], for which the results would fail to be finite starting at โ„“=22 for Float16, โ„“=183 for Float32, and โ„“=1474 for Float64. Another approach that was never precisely implemented in this package was due to Fukushima [15], who showed that using \"X-numbers\", wherein the exponent is stored as a separate integer, (implemented in this package) in the core of the recursion could increase the range to โ„“โ‰ˆ2ยณยฒ. Xing et al. showed that Fukushima's results exhibited increased error for certain angles, whereas their Eqs. (12)โ€”(14) could be used directly to obtain results with greater accuracy for those certain angles, and comparable accuracy for other angles.","category":"page"},{"location":"references/","page":"References","title":"References","text":"The other major functionality of this package is map2salm / salm2map, which decomposes function values on regular grids into mode weights (coefficients), and vice versa. The approach used here is taken from Reinecke and Seljebotn [3], with weights based on the method by Waldvogel [6]. However, this interface has been superseded by the SSHT object, which implements several approaches, including the Reinecke-Seljebotn-Waldvogel method, as well as the optimal-dimensionality method due to Elahi et al. [2], as well as a new unpublished optimal-dimensionality method I (Mike Boyle) created.","category":"page"},{"location":"references/#Bibliography","page":"References","title":"Bibliography","text":"","category":"section"},{"location":"references/","page":"References","title":"References","text":"M.ย Boyle. How should spin-weighted spherical functions be defined? Journalย ofย Mathematicalย Physics 57 (2016), arXiv:1604.08140 [gr-qc].\n\n\n\nU.ย Elahi, Z.ย Khalid, R.ย A.ย Kennedy and J.ย D.ย McEwen. An Optimal-Dimensionality Sampling for Spin-s Functions on the Sphere. IEEEย Signalย Processingย Letters 25, 1470โ€“1474 (2018), arXiv:1809.01321 [astro-ph.IM].\n\n\n\nM.ย Reinecke and D.ย S.ย Seljebotn. Libsharpโ€”spherical harmonic transforms revisited. Astronomyย &ย Astrophysics 554, A112 (2013), arXiv:1303.4945 [physics.comp-ph].\n\n\n\nE.ย B.ย Saff and A.ย B.ย Kuijlaars. Distributing many points on a sphere. Theย Mathematicalย Intelligencer 19, 5โ€“11 (1997).\n\n\n\nJ.ย S.ย Brauchart and P.ย J.ย Grabner. Distributing many points on spheres: Minimal energy and designs. Journalย ofย Complexity 31, 293โ€“326 (2015).\n\n\n\nJ.ย Waldvogel. Fast Construction of the Fejรฉr and Clenshawโ€“Curtis Quadrature Rules. BITย Numericalย Mathematics 46, 195โ€“202 (2006).\n\n\n\nE.ย T.ย Newman and R.ย Penrose. Note on the Bondi-Metzner-Sachs Group. Journalย ofย Mathematicalย Physics 7, 863โ€“870 (1966).\n\n\n\nN.ย A.ย Gumerov and R.ย Duraiswami. Recursive Computation of Spherical Harmonic Rotation Coefficients of Large Degree. In: Excursions in Harmonic Analysis, Volume 3 (Springer International Publishing, 2015); pp.ย 105โ€“141, arXiv:1403.7698 [math.NA].\n\n\n\nP.ย J.ย Kostelec and D.ย N.ย Rockmore. FFTs on the Rotation Group. Journalย ofย Fourierย Analysisย andย Applications 14, 145โ€“179 (2008).\n\n\n\nC.ย Doran and A.ย Lasenby. Geometric Algebra for Physicists (Cambridge University Press, Cambridge, 2003).\n\n\n\nH.ย Sommer, I.ย Gilitschenski, M.ย Bloesch, S.ย Weiss, R.ย Siegwart and J.ย Nieto. Why and How to Avoid the Flipped Quaternion Multiplication, arXiv:1801.07478ย cs, arXiv:1801.07478 [cs.RO].\n\n\n\nZ.ย Xing, S.ย Li, M.ย Tian, D.ย Fan and C.ย Zhang. Numerical experiments on column-wise recurrence formula to compute fully normalized associated Legendre functions of ultra-high degree and order. Journalย ofย Geodesy 94 (2019).\n\n\n\nJ.ย D.ย McEwen and Y.ย Wiaux. A Novel Sampling Theorem on the Sphere. IEEEย Transactionsย onย Signalย Processing 59, 5876โ€“5887 (2011), arXiv:1110.6298 [cs.IT].\n\n\n\nS.ย A.ย Holmes and W.ย E.ย Featherstone. A unified approach to the Clenshaw summation and the recursive computation of very high degree and order normalised associated Legendre functions. Journalย ofย Geodesy 76, 279โ€“299 (2002).\n\n\n\nT.ย Fukushima. Numerical computation of spherical harmonics of arbitrary degree and order by extending exponent of floating point numbers. Journalย ofย Geodesy 86, 271โ€“285 (2011).\n\n\n\nG.ย B.ย Folland. A Course in Abstract Harmonic Analysis. 2ย Edition (Chapman and Hall/CRC, New York, 2016).\n\n\n\nG.ย W.ย Hanson and A.ย B.ย Yakovlev. Operator Theory for Electromagnetics (Springer, New York, NY, 2002).\n\n\n\nE.ย U.ย Condon and G.ย H.ย Shortley. The Theory Of Atomic Spectra (Cambridge University Press, London, 1935).\n\n\n\nC.ย W.ย Ufford and G.ย H.ย Shortley. Atomic Eigenfunctions and Energies. Physicalย Review 42, 167โ€“175 (1932).\n\n\n\nJ.ย vanย Neerven. Functional Analysis. Cambridge Studies in Advanced Mathematics (Cambridge University Press, Cambridge, 2022).\n\n\n\nA.ย R.ย Edmonds. Angular Momentum in Quantum Mechanics (Princeton University Press, 2016).\n\n\n\nP.ย Ajith, M.ย Boyle, D.ย A.ย Brown, S.ย Fairhurst, M.ย Hannam, I.ย Hinder, S.ย Husa, B.ย Krishnan, R.ย A.ย Mercer, F.ย Ohme, C.ย D.ย Ott, J.ย S.ย Read, L.ย Santamaria and J.ย T.ย Whelan. Data formats for numerical relativity waves (2007), arXiv:0709.0093 [gr-qc].\n\n\n\nW.ย Fulton and J.ย Harris. Representation Theory. Vol.ย 129 of Graduate Texts in Mathematics (Springer, New York, NY, 2004).\n\n\n\nJ.ย N.ย Goldberg, A.ย J.ย Macfarlane, E.ย T.ย Newman, F.ย Rohrlich and E.ย C.ย Sudarshan. Spinโ€s Spherical Harmonics and รฐ. Journalย ofย Mathematicalย Physics 8, 2155โ€“2161 (1967).\n\n\n\nJ.ย J.ย Sakurai. Modern Quantum Mechanics, revisedย Edition (Addison Wesley, New York, 1994).\n\n\n\nK.ย S.ย Thorne. Multipole expansions of gravitational radiation. Reviewsย ofย Modernย Physics 52, 299 (1980).\n\n\n\nG.ย F.ย Torres Del Castillo. 3-D Spinors, Spin-Weighted Functions and their Applications. Vol.ย 52 no.ย 2 (Birkhรคuser, Boston, MA, 2003); p.ย 299.\n\n\n\nE.ย P.ย Wigner. Group Theory and Its Application to the Quantum Mechanics of Atomic Spectra (Academic Press, New York, NY, 1959).\n\n\n\n","category":"page"},{"location":"wigner_matrices/#Wigner's-๐”‡-and-d-matrices","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"","category":"section"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"Wigner's ๐”‡ matrices โ€” and to a lesser extent, the related d matrices โ€” are extremely important in the theory of rotations. Each element is, itself, a special function of the rotation group: in particular, an eigenfunction of the left- and right-Lie derivatives, and thus a spin-weighted spherical function. Collectively, they describe how spin-weighted spherical functions transform under rotation. But their accurate and efficient computation is surprisingly subtle. This package implements the current state-of-the-art techniques for their fast and accurate computation, based on the H recursion.","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"The actual computations can be done with the D_matrices function:","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"using Quaternionic\nusing SphericalFunctions\n\nR = randn(RotorF64)\nโ„“โ‚˜โ‚โ‚“ = 8\n๐”‡ = D_matrices(R, โ„“โ‚˜โ‚โ‚“)","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"However, the matrices can take up a lot of memory. So for maximum efficiency when calling this function repeatedly with different R values, it is best to pre-allocate the necessary memory with the D_prep function, and the pass that in as an argument to D_matrices!:","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"D_storage = D_prep(โ„“โ‚˜โ‚โ‚“)\n๐”‡ = D_matrices!(D_storage, R)","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"(Beware that, as noted in the documentation for D_matrices!, the output ๐”‡ is just a reference to part of the D_storage object, so you should not reuse D_storage until you have copied or otherwise finished using ๐”‡.)","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"The output ๐”‡ is a (linear!) vector of Complex numbers with the same base type as R. The ordering of the elements is described in the documentation for D_matrices. It is also possible to efficiently view slices of this vector as a series of individual matrices using a D_iterator:","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"for (โ„“, Dหก) in zip(0:โ„“โ‚˜โ‚โ‚“, D_iterator(๐”‡, โ„“โ‚˜โ‚โ‚“))\n # Do something with the matrix Dหก[โ„“+mโ€ฒ+1, โ„“+m+1]\nend","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"For the d matrices, we have almost the same interface, except that instead of the input quaternion R we only need the angle ฮฒ (or its complex angle expiฮฒ, which can be computed directly in some cases), and the output is real-valued:","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"using Quaternionic\nusing SphericalFunctions\n\nฮฒ = ฯ€ * rand(Float64)\nโ„“โ‚˜โ‚โ‚“ = 8\nd = d_matrices(ฮฒ, โ„“โ‚˜โ‚โ‚“)","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"Again, for repeated calls, it is best to pre-allocate storage:","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"d_storage = d_prep(โ„“โ‚˜โ‚โ‚“)\nd = d_matrices!(d_storage, ฮฒ)","category":"page"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"The output d is a vector of numbers of the same type as ฮฒ, ordered in the same way as the output of D_matrices. And similarly, we can iterate over the individual matrices using a d_iterator.","category":"page"},{"location":"wigner_matrices/#Docstrings","page":"Wigner's ๐”‡ and d matrices","title":"Docstrings","text":"","category":"section"},{"location":"wigner_matrices/","page":"Wigner's ๐”‡ and d matrices","title":"Wigner's ๐”‡ and d matrices","text":"D_matrices\nD_matrices!\nD_prep\nD_iterator\nd_matrices\nd_matrices!\nd_prep\nd_iterator","category":"page"},{"location":"wigner_matrices/#SphericalFunctions.D_matrices","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.D_matrices","text":"D_matrices(R, โ„“โ‚˜โ‚โ‚“)\nD_matrices(ฮฑ, ฮฒ, ฮณ, โ„“โ‚˜โ‚โ‚“)\n\nCompute Wigner's ๐”‡ matrices mathfrakD^(ell)_mm(beta) for all ell leq ell_mathrmmax.\n\nSee D_matrices! for details about the input and output values.\n\nThis function only appropriate when you need to evaluate the matrices for a single value of R or ฮฑ, ฮฒ, ฮณ because it allocates large arrays and performs many calculations that could be reused. If you need to evaluate the matrices for many values of R or ฮฑ, ฮฒ, ฮณ, you should pre-allocate the storage with D_prep, and then call D_matrices! with the result instead.\n\n\n\n\n\n","category":"function"},{"location":"wigner_matrices/#SphericalFunctions.D_matrices!","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.D_matrices!","text":"D_matrices!(D_storage, R)\nD_matrices!(D_storage, ฮฑ, ฮฒ, ฮณ)\nD_matrices!(D, R, โ„“โ‚˜โ‚โ‚“)\nD_matrices!(D, ฮฑ, ฮฒ, ฮณ, โ„“โ‚˜โ‚โ‚“)\n\nCompute Wigner's ๐”‡ matrices mathfrakD^(ell)_mm(beta) for all ell leq ell_mathrmmax.\n\nIn all cases, the result is returned in a 1-dimensional array ordered as\n\n[\n ๐”‡หกโ‚˜โ‚š,โ‚˜(R)\n for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“\n for mp โˆˆ -โ„“:โ„“\n for m โˆˆ -โ„“:โ„“\n]\n\nWhen the first argument is D, it will be modified, so it must be at least as large as that array. When the first argument is D_storage, it should be the quantity returned by D_prep, and the result will be written into the D field of that tuple. Both of these options โ€” especially the latter โ€” reduce the number of allocations needed on each call to the corresponding functions, which should increase the speed significantly. Note that the D or D_storage arguments must have types compatible with the type of R or ฮฑ, ฮฒ, ฮณ.\n\nwarn: Warn\nWhen using the D_storage argument (which is recommended), the returned quantity D will be an alias of D_storage[1]. If you want to retain that data after the next call to D_matrices!, you should copy it with copy(D).\n\nThe ฮฑ, ฮฒ, ฮณ arguments are Euler angles as described in the documentation of Quaternionic.from_euler_angles.\n\nSee also D_matrices for a simpler function call when you only need to evaluate the matrices for a single value of R or ฮฑ, ฮฒ, ฮณ.\n\nExamples\n\nusing Quaternionic, SphericalFunctions\nโ„“โ‚˜โ‚โ‚“ = 8\nT = Float64\nR = Rotor{T}(1, 2, 3, 4) # Will be normalized automatically\nD_storage = D_prep(โ„“โ‚˜โ‚โ‚“, T)\nD = D_matrices!(D_storage, R)\n\n\n\n\n\n","category":"function"},{"location":"wigner_matrices/#SphericalFunctions.D_prep","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.D_prep","text":"D_prep(โ„“โ‚˜โ‚โ‚“, [T=Float64])\n\nConstruct storage space and pre-compute recursion coefficients to compute Wigner's mathfrakD matrix in place.\n\nThis returns the D_storage arguments needed by D_matrices!.\n\n\n\n\n\n","category":"function"},{"location":"wigner_matrices/#SphericalFunctions.D_iterator","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.D_iterator","text":"D_iterator(D, โ„“โ‚˜โ‚โ‚“, [โ„“โ‚˜แตขโ‚™])\n\nConstruct an Iterator that returns sub-matrices of D, each of which consists of elements (โ„“-โ„“-โ„“) through (โ„“โ„“โ„“), for โ„“ from โ„“โ‚˜แตขโ‚™ through โ„“โ‚˜โ‚โ‚“. By default, โ„“โ‚˜แตขโ‚™ is 0.\n\ndanger: Inconsistent behavior\nThis iterator mistakenly returns the transpose of the result implied by this documentation. As a result, a warning is issued every time this function is called. Rather than actually fixing this bug in this minor/patch version โ€” which would be a breaking change โ€” this is a final release in this major version of the package to notify users of this function (and d_iterator) that there is a problem. The next major version of the package will likely change the actual behavior to the one implied by this docstring. To quiet these warnings, you can use Dit = with_logger(NullLogger()) do D_iterator(...) end.\n\nNote that the returned objects are views into the original D data โ€” meaning that you may alter their values.\n\nBecause the result is a matrix restricted to a particular โ„“ value, you can index the (โ„“ m m) element as [โ„“+mโ€ฒ+1, โ„“+m+1]. For example, you might use this as something like\n\nfor (โ„“, Dหก) in zip(โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“, D_iterator(D, โ„“โ‚˜โ‚โ‚“))\n for mโ€ฒ in -โ„“:โ„“\n for m in -โ„“:โ„“\n Dหก[โ„“+mโ€ฒ+1, โ„“+m+1] # ... do something with Dหก\n end\n end\nend\n\nAlso note that no bounds checking is done, either at instantiation time or during iteration. You are responsible for ensuring that the size of D and the values of โ„“โ‚˜โ‚โ‚“ and โ„“โ‚˜แตขโ‚™ make sense.\n\n\n\n\n\n","category":"type"},{"location":"wigner_matrices/#SphericalFunctions.d_matrices","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.d_matrices","text":"d_matrices(ฮฒ, โ„“โ‚˜โ‚โ‚“)\nd_matrices(expiฮฒ, โ„“โ‚˜โ‚โ‚“)\n\nCompute Wigner's d^(ell) matrices with elements d^(ell)_mm(beta) for all ell leq ell_mathrmmax. The d matrices are sometimes called the \"reduced\" Wigner matrices, in contrast to the full mathfrakD matrices.\n\nSee d_matrices! for details about the input and output values.\n\nThis function only appropriate when you need to evaluate the matrices for a single value of ฮฒ or expiฮฒ because it allocates large arrays and performs many calculations that could be reused. If you need to evaluate the matrices for many values of ฮฒ or expiฮฒ, you should pre-allocate the storage with d_prep, and then call d_matrices! with the result instead.\n\n\n\n\n\n","category":"function"},{"location":"wigner_matrices/#SphericalFunctions.d_matrices!","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.d_matrices!","text":"d_matrices!(d_storage, ฮฒ)\nd_matrices!(d_storage, expiฮฒ)\nd_matrices!(d, ฮฒ, โ„“โ‚˜โ‚โ‚“)\nd_matrices!(d, expiฮฒ, โ„“โ‚˜โ‚โ‚“)\n\nCompute Wigner's d^(ell) matrices with elements d^(ell)_mm(beta) for all ell leq ell_mathrmmax. The d matrices are sometimes called the \"reduced\" Wigner matrices, in contrast to the full mathfrakD matrices.\n\nIn all cases, the result is returned in a 1-dimensional array ordered as\n\n[\n dหกโ‚˜โ‚š,โ‚˜(ฮฒ)\n for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“\n for mp โˆˆ -โ„“:โ„“\n for m โˆˆ -โ„“:โ„“\n]\n\nWhen the first argument is d, it will be modified, so it must be at least as large as that array. When the first argument is d_storage, it should be the quantity returned by d_prep, and the result will be written into the d field of that tuple. Both of these options โ€” especially the latter โ€” reduce the number of allocations needed on each call to the corresponding functions, which should increase the speed significantly.\n\nwarn: Warn\nWhen using the d_storage argument (which is recommended), the returned quantity d will be an alias of d_storage[1]. If you want to retain that data after the next call to d_matrices!, you should copy it with copy(d).\n\nSee also d_matrices for a simpler function call when you only need to evaluate the matrices for a single value of ฮฒ or expiฮฒ.\n\nExamples\n\nusing SphericalFunctions\nโ„“โ‚˜โ‚โ‚“ = 8\nT = Float64\nฮฒ = T(1)/8\nd_storage = d_prep(โ„“โ‚˜โ‚โ‚“, T)\nd = d_matrices!(d_storage, ฮฒ)\n\n\n\n\n\n","category":"function"},{"location":"wigner_matrices/#SphericalFunctions.d_prep","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.d_prep","text":"d_prep(โ„“โ‚˜โ‚โ‚“, [T=Float64])\n\nConstruct space and pre-compute recursion coefficients to compute Wigner's d matrix in place.\n\nThis returns the d_storage arguments needed by d_matrices!.\n\n\n\n\n\n","category":"function"},{"location":"wigner_matrices/#SphericalFunctions.d_iterator","page":"Wigner's ๐”‡ and d matrices","title":"SphericalFunctions.d_iterator","text":"d_iterator(d, โ„“โ‚˜โ‚โ‚“, [โ„“โ‚˜แตขโ‚™])\n\nConstruct an Iterator that returns sub-matrices of d, each of which consists of elements (โ„“-โ„“-โ„“) through (โ„“โ„“โ„“), for โ„“ from โ„“โ‚˜แตขโ‚™ through โ„“โ‚˜โ‚โ‚“. By default, โ„“โ‚˜แตขโ‚™ is 0.\n\ndanger: Inconsistent behavior\nThis iterator mistakenly returns the transpose of the result implied by this documentation. As a result, a warning is issued every time this function is called. Rather than actually fixing this bug in this minor/patch version โ€” which would be a breaking change โ€” this is a final release in this major version of the package to notify users of this function (and D_iterator) that there is a problem. The next major version of the package will likely change the actual behavior to the one implied by this docstring. To quiet these warnings, you can use Dit = with_logger(NullLogger()) do D_iterator(...) end.\n\nNote that the returned objects are views into the original d data โ€” meaning that you may alter their values.\n\nBecause the result is a matrix restricted to a particular โ„“ value, you can index the (โ„“ m m) element as [โ„“+mโ€ฒ+1, โ„“+m+1]. For example, you might use this as something like\n\nfor (โ„“, dหก) in zip(โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“, d_iterator(d, โ„“โ‚˜โ‚โ‚“))\n for mโ€ฒ in -โ„“:โ„“\n for m in -โ„“:โ„“\n dหก[โ„“+mโ€ฒ+1, โ„“+m+1] # ... do something with dหก\n end\n end\nend\n\nAlso note that no bounds checking is done, either at instantiation time or during iteration. You are responsible for ensuring that the size of d and the values of โ„“โ‚˜โ‚โ‚“ and โ„“โ‚˜แตขโ‚™ make sense.\n\n\n\n\n\n","category":"type"},{"location":"conventions/comparisons/#Comparisons","page":"Comparisons","title":"Comparisons","text":"","category":"section"},{"location":"conventions/comparisons/","page":"Comparisons","title":"Comparisons","text":"Here, we compare our conventions to other sources, including references in the literature as well as other software that implements some of these. Each of these comparisons is also performed explicitly in this package's test suite.","category":"page"},{"location":"conventions/comparisons/","page":"Comparisons","title":"Comparisons","text":"Among the items that would be good to compare are the following, when actually used by any of these sources:","category":"page"},{"location":"conventions/comparisons/","page":"Comparisons","title":"Comparisons","text":"Quaternions\nOrder of components\nBasis\nOperation as rotations\nEuler angles\nSpherical coordinates\nSpherical harmonics\nCondon-Shortley phase\nFormula\nSpin-weighted spherical harmonics\nBehavior under rotation\nWigner D-matrices\nOrder of indices\nConjugation\nFunction of rotation or inverse rotation\nFormula","category":"page"},{"location":"conventions/comparisons/","page":"Comparisons","title":"Comparisons","text":"One major result of this is that almost everyone since 1935 has used the same exact expression for the (scalar) spherical harmonics.","category":"page"},{"location":"conventions/comparisons/#Condon-Shortley","page":"Comparisons","title":"Condon-Shortley","text":"","category":"section"},{"location":"conventions/comparisons/#Wigner","page":"Comparisons","title":"Wigner","text":"","category":"section"},{"location":"conventions/comparisons/#Newman-Penrose","page":"Comparisons","title":"Newman-Penrose","text":"","category":"section"},{"location":"conventions/comparisons/#Goldberg","page":"Comparisons","title":"Goldberg","text":"","category":"section"},{"location":"conventions/comparisons/#Wikipedia","page":"Comparisons","title":"Wikipedia","text":"","category":"section"},{"location":"conventions/comparisons/#Mathematica","page":"Comparisons","title":"Mathematica","text":"","category":"section"},{"location":"conventions/comparisons/#SymPy","page":"Comparisons","title":"SymPy","text":"","category":"section"},{"location":"conventions/comparisons/#Sakurai","page":"Comparisons","title":"Sakurai","text":"","category":"section"},{"location":"conventions/comparisons/#Thorne","page":"Comparisons","title":"Thorne","text":"","category":"section"},{"location":"conventions/comparisons/#Torres-del-Castillo","page":"Comparisons","title":"Torres del Castillo","text":"","category":"section"},{"location":"conventions/comparisons/#NINJA","page":"Comparisons","title":"NINJA","text":"","category":"section"},{"location":"conventions/comparisons/#LALSuite","page":"Comparisons","title":"LALSuite","text":"","category":"section"},{"location":"utilities/#Utilities","page":"Utilities","title":"Utilities","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"While not usually the star of the show, the following utilities can be quite helpful for actually using the rest of the code.","category":"page"},{"location":"utilities/#Complex-powers","page":"Utilities","title":"Complex powers","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"One common task we find when working with spherical functions is the computation of a range of integer powers of some complex number โ€” so much so that it can be best to pre-compute the powers and cache their values. While a naive approach is generally quite accurate, and reasonably fast, we can do a little better with a specialized routine.","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"Modules = [SphericalFunctions]\nPages = [\"complex_powers.jl\"]\nOrder = [:module, :type, :constant, :function, :macro]","category":"page"},{"location":"utilities/#SphericalFunctions.complex_powers!-Tuple{Any, Any}","page":"Utilities","title":"SphericalFunctions.complex_powers!","text":"complex_powers!(zpowers, z)\n\nCompute integer powers of z from z^0 through z^m, recursively, where m is one less than the length of the input zpowers vector.\n\nNote that z is assumed to be normalized, with complex amplitude approximately 1.\n\nSee also: complex_powers\n\n\n\n\n\n","category":"method"},{"location":"utilities/#SphericalFunctions.complex_powers-Tuple{Any, Int64}","page":"Utilities","title":"SphericalFunctions.complex_powers","text":"complex_powers(z, m)\n\nCompute integer powers of z from z^0 through z^m, recursively.\n\nNote that z is assumed to be normalized, with complex amplitude approximately 1.\n\nThis algorithm is mostly due to Stoer and Bulirsch in \"Introduction to Numerical Analysis\" (page 24) โ€” with a little help from de Moivre's formula, which is essentially exp(iฮธ)โฟ = exp(inฮธ), as well as my own alterations to deal with different behaviors in different quadrants.\n\nThere isn't usually a huge advantage to using this specialized function. If you just need a particular power, it will generally be far more efficient and just as accurate to compute either exp(iฮธ)โฟ or exp(inฮธ) explicitly. However, if you need all powers from 0 to m, this function is about 10 or 5 times faster than those options, respectively, for large m. Like those options, this function is numerically stable, in the sense that its errors are usually smaller than m times the error from machine-precision errors in the input argument โ€” or at worst about 50% larger, which occurs as the phase approaches multiples of ฯ€/2.\n\nSee also: complex_powers!\n\n\n\n\n\n","category":"method"},{"location":"utilities/#Sizes-of-and-indexing-into-๐”‡,-d,-and-Y-data","page":"Utilities","title":"Sizes of and indexing into ๐”‡, d, and Y data","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"By Y data, we mean anything indexed like Y_ell m modes; by D data, we mean anything indexed like Wigner's mathfrakD matrices, or special subsets of them, like the H matrices.","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"Modules = [SphericalFunctions]\nPages = [\"indexing.jl\", \"wigner_matrices/indexing.jl\", \"wigner_matrices/Hrecursions.jl\"]\nOrder = [:module, :type, :constant, :function, :macro]","category":"page"},{"location":"utilities/#SphericalFunctions.WignerDindex","page":"Utilities","title":"SphericalFunctions.WignerDindex","text":"WignerDindex(โ„“, mโ€ฒ, m, mโ€ฒโ‚˜โ‚โ‚“=โ„“)\n\nCompute index into Wigner ๐”‡ matrix\n\nSee also WignerDrange and WignerDsize.\n\nNotes\n\nThis assumes that the Wigner ๐”‡ matrix is arranged as\n\n[\n ๐”‡(โ„“, mโ€ฒ, m)\n for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“\n for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)\n for m โˆˆ -โ„“:โ„“\n]\n\n\n\n\n\n","category":"function"},{"location":"utilities/#SphericalFunctions.WignerDrange","page":"Utilities","title":"SphericalFunctions.WignerDrange","text":"WignerDrange(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)\n\nCreate an array of (โ„“, m', m) indices as in ๐”‡ array\n\nSee also WignerDsize and WignerDindex.\n\nNotes\n\nThis assumes that the Wigner ๐”‡ matrix is arranged as\n\n[\n ๐”‡(โ„“, mโ€ฒ, m)\n for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“\n for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)\n for m โˆˆ -โ„“:โ„“\n]\n\n\n\n\n\n","category":"function"},{"location":"utilities/#SphericalFunctions.WignerDsize-Tuple{Any}","page":"Utilities","title":"SphericalFunctions.WignerDsize","text":"WignerDsize(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)\n\nCompute total size of Wigner ๐”‡ matrix\n\nSee also WignerDrange and WignerDindex.\n\nNotes\n\nThis assumes that the Wigner ๐”‡ matrix is arranged as\n\n[\n ๐”‡(โ„“, mโ€ฒ, m)\n for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“\n for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)\n for m โˆˆ -โ„“:โ„“\n]\n\n\n\n\n\n","category":"method"},{"location":"utilities/#SphericalFunctions.WignerHindex","page":"Utilities","title":"SphericalFunctions.WignerHindex","text":"WignerHindex(โ„“, mโ€ฒ, m, mโ€ฒโ‚˜โ‚โ‚“)\n\nIndex to \"wedge\" arrays.\n\nSee also WignerHsize and WignerHrange.\n\nNotes\n\nHere, it is assumed that only data with mโ‰ฅ|m'| are stored, and only corresponding values are passed. We also assume |m|โ‰คโ„“ and |m'|โ‰คโ„“. Neither of these are checked. The wedge array that this function indexes is ordered as\n\n[\n H(โ„“, mโ€ฒ, m) for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“\n for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)\n for m โˆˆ abs(mโ€ฒ):โ„“\n]\n\n\n\n\n\n","category":"function"},{"location":"utilities/#SphericalFunctions.WignerHrange","page":"Utilities","title":"SphericalFunctions.WignerHrange","text":"WignerHrange(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)\n\nCreate an array of (โ„“, m', m) indices as in H array\n\nSee also WignerHsize and WignerHindex\n\nNotes\n\nHere, it is assumed that only data with mโ‰ฅ|m'| are stored, and only corresponding values are passed. We also assume |m|โ‰คโ„“ and |m'|โ‰คโ„“. Neither of these are checked. The wedge array that this function indexes is ordered as\n\n[\n H(โ„“, mโ€ฒ, m) for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“\n for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)\n for m โˆˆ abs(mโ€ฒ):โ„“\n]\n\n\n\n\n\n","category":"function"},{"location":"utilities/#SphericalFunctions.WignerHsize-Tuple{Any}","page":"Utilities","title":"SphericalFunctions.WignerHsize","text":"WignerHsize(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)\n\nTotal size of array of wedges of width mโ€ฒโ‚˜โ‚โ‚“ up to โ„“โ‚˜โ‚โ‚“. If mโ€ฒโ‚˜โ‚โ‚“ is not given, it defaults to โ„“โ‚˜โ‚โ‚“.\n\nSee also WignerHrange and WignerHindex.\n\nNotes\n\nHere, it is assumed that only data with mโ‰ฅ|mโ€ฒ| are stored, and only corresponding values are passed. We also assume |m|โ‰คโ„“ and |mโ€ฒ|โ‰คโ„“. Neither of these are checked. The wedge array that this function indexes is ordered as\n\n[\n H(โ„“, mโ€ฒ, m) for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“\n for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)\n for m โˆˆ abs(mโ€ฒ):โ„“\n]\n\n\n\n\n\n","category":"method"},{"location":"utilities/#SphericalFunctions.Yindex","page":"Utilities","title":"SphericalFunctions.Yindex","text":"Yindex(โ„“, m, โ„“โ‚˜แตขโ‚™=0)\n\nCompute index into array of mode weights\n\nParameters\n\nโ„“ : int Integer satisfying โ„“โ‚˜แตขโ‚™ <= โ„“ <= โ„“โ‚˜โ‚โ‚“ m : int Integer satisfying -โ„“ <= m <= โ„“ โ„“โ‚˜แตขโ‚™ : int, optional Integer satisfying 0 <= โ„“โ‚˜แตขโ‚™. Defaults to 0.\n\nReturns\n\ni : int Index of a particular element of the mode-weight array as described below\n\nSee Also\n\nYsize : Total size of array of mode weights Yrange : Array of (โ„“, m) indices corresponding to this array\n\nNotes\n\nThis assumes that the modes are arranged (with fixed s value) as\n\n[\n Y(s, โ„“, m)\n for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“\n for m โˆˆ -โ„“:โ„“\n]\n\n\n\n\n\n","category":"function"},{"location":"utilities/#SphericalFunctions.Yrange-Tuple{Any}","page":"Utilities","title":"SphericalFunctions.Yrange","text":"Yrange(โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“)\n\nCreate an array of (โ„“, m) indices as in Y array\n\nParameters\n\nโ„“โ‚˜แตขโ‚™ : int Integer satisfying 0 <= โ„“โ‚˜แตขโ‚™ <= โ„“โ‚˜โ‚โ‚“ โ„“โ‚˜โ‚โ‚“ : int Integer satisfying 0 <= โ„“โ‚˜แตขโ‚™ <= โ„“โ‚˜โ‚โ‚“\n\nReturns\n\ni : int Total size of array of mode weights arranged as described below\n\nSee Also\n\nYsize : Total size of array of mode weights Yindex : Index of a particular element of the mode weight array\n\nNotes\n\nThis assumes that the modes are arranged (with fixed s value) as\n\n[\n Y(s, โ„“, m)\n for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“\n for m โˆˆ -โ„“:โ„“\n]\n\n\n\n\n\n","category":"method"},{"location":"utilities/#SphericalFunctions.Ysize-Tuple{Any}","page":"Utilities","title":"SphericalFunctions.Ysize","text":"Ysize(โ„“โ‚˜โ‚โ‚“)\n\nCompute total size of array of mode weights\n\nSee Also\n\nYrange : Array of (โ„“, m) indices corresponding to this array Yindex : Index of a particular element of the mode weight array\n\nNotes\n\nThis assumes that the modes are arranged (with fixed s value) as\n\n[\n Y(s, โ„“, m)\n for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“\n for m โˆˆ -โ„“:โ„“\n]\n\n\n\n\n\n","category":"method"},{"location":"utilities/#SphericalFunctions._WignerHindex-NTuple{4, Any}","page":"Utilities","title":"SphericalFunctions._WignerHindex","text":"WignerHindex(โ„“, mโ€ฒ, m, mโ€ฒโ‚˜โ‚โ‚“)\n\nHelper function for WignerHindex, with more constraints.\n\nThis function assumes that m โ‰ฅ |mโ€ฒ|. The main WignerHindex function uses symmetries of the H array to account for cases that violate this assumption. (But note that both that function and this one assume that |m| โ‰ค โ„“ and |mโ€ฒ| โ‰ค โ„“.)\n\n\n\n\n\n","category":"method"},{"location":"utilities/#SphericalFunctions.deduce_limits","page":"Utilities","title":"SphericalFunctions.deduce_limits","text":"deduce_limits(ysize, [โ„“min])\n\nDeduce the value of (โ„“min, โ„“max) that produces Y arrays of the given size.\n\nIf โ„“min is not given, it is assumed to be 0. If it is set to nothing, the smallest possible value of โ„“min will be used. However, note that this is not a well-posed problem; multiple combinations of (โ„“min, โ„“max) can give rise to Y arrays of the same size.\n\nSee also Ysize\n\n\n\n\n\n","category":"function"},{"location":"utilities/#SphericalFunctions.phi_theta-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"Utilities","title":"SphericalFunctions.phi_theta","text":"phi_theta(Nฯ•, Nฮธ, [T=Float64])\n\nConstruct (phi, theta) grid in order expected by this package.\n\nSee also theta_phi for the opposite ordering.\n\n\n\n\n\n","category":"method"},{"location":"utilities/#SphericalFunctions.theta_phi-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"Utilities","title":"SphericalFunctions.theta_phi","text":"theta_phi(Nฮธ, Nฯ•, [T=Float64])\n\nConstruct (theta, phi) grid in spinsfast order.\n\nNote that this order is different from the one assumed by this package; use phi_theta for the opposite ordering.\n\n\n\n\n\n","category":"method"},{"location":"utilities/#Combinatorics","page":"Utilities","title":"Combinatorics","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"Spherical functions frequently involve binomial coefficients and similar terms, with arguments proportional to โ„“, which we aim to allow to be very large โ€” of order 1,000 or more. Unfortunately, due to combinatorical explosions, this is frequently infeasible with naive methods. Here, we collect any specialized methods that help us beat the limits.","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"Modules = [SphericalFunctions]\nPages = [\"utils.jl\"]","category":"page"},{"location":"utilities/#SphericalFunctions.sqrtbinomial-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"Utilities","title":"SphericalFunctions.sqrtbinomial","text":"sqrtbinomial(n, k, [T])\n\nEvaluate the square-root of the binomial coefficient binomial(n,k) for large coefficients.\n\nOrdinarily, when n and k are standard Int arguments, the built-in binomial function will overflow around n=66, because it results in Ints. We need much larger values. This function, which is based on a related one in SpecialFunctions.jl, returns reasonably accurate results up to n โ‰ˆ 1026 when k โ‰ˆ n/2 (which is the case of interest in many applications in this package).\n\nComputations are carried out (and returned) in type T, which defaults to Float64.\n\n\n\n\n\n","category":"method"},{"location":"conventions/outline/#Outline","page":"Outline","title":"Outline","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Three-dimensional Euclidean space\nCartesian coordinates (x y z) => โ„ยณ\nCartesian basis vectors (๐ฑ ๐ฒ ๐ณ)\nEuclidean norm => Euclidean metric\nSpherical coordinates\nSpecifically give transformation to/from (x y z)\nDerive metric in these coordinates from transformation\nIntegration / measure on two-sphere\nDerive as restriction of full metric, in both coordinate systems\nFour-dimensional Euclidean space\nEight-dimensional Clifford algebra over the tangent vector space Tโ„ยณ\nFour-dimensional even sub-algebra => โ„โด\nCoordinates (W X Y Z)\nBasis vectors (๐Ÿ ๐ข ๐ฃ ๐ค), but we usually just omit ๐Ÿ\nShow a few essential formulas establishing the product and its conventions\nUnit quaternions are isomorphic to mathbfSpin(3) = mathbfSU(2); double covers mathbfSO(3)\nBe explicit about the mapping between vector in โ„ยณ and quaternions\nShow how a unit quaternion can be used to rotate a vector\nSpherical coordinates (hyperspherical / Euler)\nSpecifically give transformation to/from (W X Y Z)\nDerive metric in these coordinates from transformation\nExpress unit quaternion in Euler angles\nIntegration / measure / Haar measure on three-sphere\nDerive as restriction of full metric, in both coordinate systems\nAngular momentum operators / functional analysis\nExpress angular momentum operators in terms of quaternion components\nExpress angular momentum operators in terms of Euler angles\nShow for both the three- and two-spheres\nShow how they act on functions on the three-sphere\nRepresentation theory / harmonic analysis\nRepresentations show up in Fourier analysis on groups\nPeter-Weyl theorem\nGeneralizes Fourier analysis to compact groups\nA basis of functions on the group is given by matrix elements of group representations\nRepresentation theory of mathbfSpin(3)\nShow how the Lie algebra is represented by the angular-momentum operators\nShow how the Lie group is represented by the Wigner D-matrices\nDemonstrate that mathfrakD is a representation\nDemonstrate its behavior under left and right rotation\nDemonstrate orthonormality\nRepresentation theory of mathbfSO(3)\nThere are several places in Folland (e.g., above corollary 5.48) where he mentions that representations of a quotient group are just representations that are trivial (evidently meaning mapping everything to the identity matrix) on the factor. I can't find anywhere that he explains this explicitly, but it seems easy enough to show. He might do it using characters.\nFor mathbfSpin(3) and mathbfSO(3), the factor group is just 1 -1. Presumably, every representation acting on 1 will give the identity matrix, so that's trivial. So we just need a criterion for when a representation is trivial on -1. Noting that exp(pi vecv) = -1 for any vecv, I think we can show that this requires m in mathbbZ.\nBasically, the point is that the representations of mathbfSO(3) are just the integer representations of mathbfSpin(3).\nRestrict to homogeneous space (Sยณ -> Sยฒ)\nThe circle group is a closed (normal?) subgroup of mathbfSpin(3), which we might implement as initial multiplication about a particular axis.\nIn Eq. (2.47) Folland (2016) defines a functional taking a function on the group to a function on the homogeneous space by integrating over the factor (the circle group). This gives you the spherical harmonics, but not the spin-weighted spherical harmonics โ€” because the spin-weighted spherical harmonics cannot be defined on the 2-sphere.\nSpin weight comes from Fourier analysis on the subgroup.\nRepresentation matrices transfer to the homogeneous space, with sparsity patterns","category":"page"},{"location":"conventions/outline/#Notes","page":"Outline","title":"Notes","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Spherical harmonics as functions on homogeneous space. https://www.youtube.com/watch?v=TnFvOa9v7do gives some nice discussion; maybe the paper has better references.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Theorem 2.16 of Hanson-Yakovlev says that an orthonormal basis of a product of L^2 spaces is given by the product of the orthonormal bases of the individual spaces. Furthermore, on page 354, they point out that (1sqrt2pi) e^imphi is an orthonormal basis of L^2(02pi), while the set 1c_nm P_n^m(costheta) is an orthonormal basis of L^2(0 pi) in the theta coordinate. Therefore, the product of these two sets is an orthonormal basis of the product space L^2left((02pi) times (0 pi)right), which forms a coordinate space for S^2. I would probably modify this to point out that (02pi) is really S^1, and then we could extend it to point out that you can throw on another factor of S^1 to cover S^3, which happens to give us the Wigner D-matrices.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"We first define the rotor that takes (hatx haty hatz) onto (hattheta hatphi hatr). Then, we can invert that, so that given a rotor that specifies such a rotation exactly, we can get the spherical coordinates โ€” or specifically sintheta, costheta, and exp(iphi).","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Then, with the universally agreed-upon Y as given in terms of spherical coordinates, we can rewrite it directly to work with quaternion components, and then it immediately applies to general rotations, which allows us to figure out where the s should go. That is, we can essentially derive _sY from the universal formula for Y.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Then, we can simply follow Wigner around Eq. (15.21) to derived a transformation law in the form","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"_sY_ellm(R_theta phi) = sum_m M_mm(R)\n_sY_ellm(R_theta phi)","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"for some matrix M. Note that I have written this as if the _sY functions are column vectors. The reason this happens is because I want to write R_theta phi = R R_theta phi, rather than swapping the order of the rotations on the right-hand side.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"The big problem here is that Wigner, in his Eq. (15.21) defines the transformation matrix as if the eigenfunctions formed a row vector instead of a column vector, which means that his matrix is transposed compared to what I want to write. I suppose maybe other authors then just consider the inverse rotation, so that they can work with the conjugate transpose, which is why we see the relative conjugate.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Since Y is universal, let's start with that as non-negotiable, and see if we can derive the relationship to mathfrakD.\nR_theta phi is a unit quaternion that rotates the point described by Cartesian coordinates (0,0,1) onto the point described by spherical coordinates (theta phi).\nJust textually, it makes the most sense to write\nR_theta phi = R R_theta phi\nfor some rotation R. Now, we just need to interpret R.\nAgain, just textually, it makes the most sense to write\nY_ellm(theta phi) = sum_m mathfrakD^(ell)_mm(R)\nY_ellm(theta phi)\nor, generalizing to spin-weighted spherical harmonics\n_sY_ellm(R_theta phi) = sum_m mathfrakD^(ell)_mm(R)\n_sY_ellm(R_theta phi)\nWe also have that mathfrakD obeys the representation property, so\nmathfrakD^(ell)_mm(R_theta phi)\n= sum_m mathfrakD^(ell)_mm(R)\nmathfrakD^(ell)_mm(R_theta phi)\nThere is no reason that I can see to introduce a conjugation\nThe fact that m appears on both sides of the equation means that it must correspond to s โ€” though we have to check the behavior under final rotation to determine the sign.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"_sY_ellm(R_theta phi)\npropto\nmathfrakD^(ell)_mpropto s(R_theta phi)","category":"page"},{"location":"conventions/outline/#collapsible-markdown?","page":"Outline","title":"collapsible markdown?","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"
CLICK ME","category":"page"},{"location":"conventions/outline/#yes,-even-hidden-code-blocks!","page":"Outline","title":"yes, even hidden code blocks!","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"println(\"hello world!\")","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"
","category":"page"},{"location":"conventions/outline/#More-notes","page":"Outline","title":"More notes","text":"","category":"section"},{"location":"conventions/outline/#Spherical-harmonics","page":"Outline","title":"Spherical harmonics","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Fortunately, there does not seem to be any disagreement in the physics literature about the definition of the spherical harmonics; everyone uses the Condon-Shortley convention. Or at least, they say they do. The problem arises when people define the spherical harmonics in terms of the Legendre polynomials, for which there is a sign ambiguity. Therefore, to ensure that we are using the same conventions, we need to go back to the original definition of the spherical harmonics by Condon and Shortley.","category":"page"},{"location":"conventions/outline/#Condon-Shortley-phase","page":"Outline","title":"Condon-Shortley phase","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"The Condon-Shortley phase convention is a choice of phase factors in the definition of the spherical harmonics that requires the coefficients in","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"L_pm ellmrangle = alpha^pm_ellm ell m pm 1rangle","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"to be real and positive. The reasoning behind this choice is explained more clearly in Section 2 of Ufford and Shortley (1932). As a more practical matter, the Condon-Shortley phase describes signs chosen in the expression for spherical harmonics. The key expression is Eq. (15) of section 4ยณ (page 52) of Condon-Shortley:","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Theta(ell m) = (-1)^ell sqrtfrac2ell+12 frac(ell+m)(ell-m)\nfrac12^ell ell frac1sin^mtheta\nfracd^ell-md(costheta)^ell-m sin^2elltheta","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"When multiplied by Eq. (5) Phi(m) = e^imphi sqrt2pi, this gives the spherical harmonic function. The right-hand side of the expression above is usually immediately replaced by a simpler expression using Legendre polynomials, but this just shifts sign ambiguity into the definition of the Legendre polynomials. Instead, we can expand the above expression directly for the first few ell values and/or use automatic differentiation to actually test their original expression as such against the function implemented in this package. The first few values are given in a footnote to Condon and Shortley's Eq. (15) (and have been verified separately by hand and by computation with SymPy):","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\nTheta(00) = sqrtfrac12 \nTheta(10) = sqrtfrac32 costheta \nTheta(1pm1) = mp sqrtfrac34 sintheta \nTheta(20) = sqrtfrac58 (2cos^2theta - sin^2theta) \nTheta(2pm1) = mp sqrtfrac154 costheta sintheta \nTheta(2pm2) = sqrtfrac1516 sin^2theta \nTheta(30) = sqrtfrac78 (2cos^3theta - 3costhetasin^2theta) \nTheta(3pm1) = mp sqrtfrac2132 (4cos^2thetasintheta - sin^3theta) \nTheta(3pm2) = sqrtfrac10516 costheta sin^2theta \nTheta(3pm3) = mp sqrtfrac3532 sin^3theta\nendaligned","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"These are tested, along with the results from automatic differentiation, every time this package is updated. The result is perfect agreement, so that we can definitively say that ***the spherical-harmonic functions provided by this package obey the Condon-Shortley phase convention.***","category":"page"},{"location":"conventions/outline/#Angular-momentum-operators","page":"Outline","title":"Angular-momentum operators","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"First, a couple points about -ihbar:\nThe finite transformations look like exp-i theta L_j, but the factor of i introduced here just cancels the one in the L_j, and the sign is just chosen to make the result consistent with our notion of active or passive transformations.\nAny factors of hbar are included purely for the sake of convenience.\nThe factor i comes from plain functional analysis: We need a self-adjoint operator, and partial_x by itself is anti-self-adjoint (as can be verified by evaluating on langle x x rangle = delta(x-x), which switches sign based on which is being differentiated). We want self-adjoint operators so that we get purely real eigenvalues. Van Neerven cites this in a more rigorous context in his Example (10.40) (page 331), with more explanation around Eq. (15.17) (page 592). The \"self-adjoint iff real eigenvalues\" condition is item (1) in his Corollary 9.18.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Wigner's ๐”‡ matrices are defined as matrix elements of a rotation in the basis of spherical harmonics. That rotation is defined in terms of the generators of rotation, which are expressed in terms of the angular-momentum operators. Therefore, to really understand conventions for the ๐”‡ matrices, we need to understand conventions for the angular-momentum operators.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"There is universal agreement that the angular momentum is defined as mathbfL = mathbfx times mathbfp, where mathbfx is the position vector and mathbfp is the momentum vector. In quantum mechanics, there is further agreement that the momentum operator becomes -ihbarnabla. Thus, in operator form, the angular momentum can be decomposed as","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\nL_x = -ihbar left( y fracpartialpartial z - z fracpartialpartial y right) \nL_y = -ihbar left( z fracpartialpartial x - x fracpartialpartial z right) \nL_z = -ihbar left( x fracpartialpartial y - y fracpartialpartial x right)\nendaligned","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"We can transform these to use spherical coordinates and obtain","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\nL_x = -ihbar left( sinphi fracpartialpartialtheta + cottheta cosphi fracpartialpartialphi right) \nL_y = -ihbar left( cosphi fracpartialpartialtheta - cottheta sinphi fracpartialpartialphi right) \nL_z = -ihbar fracpartialpartialphi\nendaligned","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"The conventions we choose must be chosen to agree with these โ€” modulo factors of hbar, which are nonstandard in mathematics. We will have to check this, and the Condon-Shortley requirement that when applied to spherical harmonics they produce real and positive coefficients.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"I defined these in Eqs. (42) and (43) of Boyle (2016) as","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\nL_j f(mathbfR) colonequals -z left fracpartialpartial theta\nfleft(e^theta mathbfe_j 2 mathbfR right) right_theta=0 \nK_j f(mathbfR) colonequals -z left fracpartialpartial theta\nfleft(mathbfR e^theta mathbfe_j 2right) right_theta=0\nendaligned","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"where mathbfe_j is the unit vector in the j direction. Surprisingly, I found that Edmonds expresses essentially the same thing in the equations following his Eq. (4.1.5).","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Condon and Shortley's Eq. (1) of section 4ยณ (page 50) defines","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"L_z = -i hbar fracpartialpartial phi","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"while Eq. (8) on the following page defines","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\nL_x + i L_y = hbar e^iphi left( fracpartialpartial theta + i cottheta fracpartialpartial phi right) \nL_x - i L_y = hbar e^-iphi left(-fracpartialpartial theta + i cottheta fracpartialpartial phi right)\nendaligned","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Note that one is not the conjugate of the other! This is because of the factors of -i in the definitions of L_x and L_y.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Edmonds gives the total angular-momentum operator for a rigid body in Eq. (2.2.2) as","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\nL_x = -ihbar left(-cos alpha cotbeta fracpartialpartialalpha - sinalpha fracpartialpartialbeta + fraccosalphasinbeta fracpartialpartialgamma right) \nL_y = -ihbar left(-sinalpha cotbeta fracpartialpartial alpha + cosalpha fracpartialpartialbeta + fracsinalphasinbeta fracpartialpartialgamma right) \nL_z = -ihbar fracpartialpartialalpha\nendaligned","category":"page"},{"location":"conventions/outline/#Wigner-๐”‡-and-d-matrices","page":"Outline","title":"Wigner ๐”‡ and d matrices","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Wigner's Eqs. (11.18) and (11.19) define the real orthogonal transformation mathbfR by","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"x_i = R_ij x_j","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"and the operator mathbfP_mathbfR to act on a function f such that","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"mathbfP_mathbfR f(x_1 ldots) = f(x_1 ldots)","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Then, his Eq. (15.5) presumably implies","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Y_ellm(vartheta varphi)\n= mathbfP_alpha beta gamma Y_ellm(vartheta varphi)\n= sum_m mathfrakD^(ell)(alpha beta gamma)_mm\n Y_ellm(vartheta varphi)","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"where alpha beta gamma takes (vartheta varphi) to (vartheta varphi). In any case, we can now leave behind this mathbfP notation and just look at the beginning and end of the equation above as the critical relationship in Wigner's notation.","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Eq. (44b) of Boyle (2016) says","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"L_pm mathfrakD^(ell)_mm(mathbfR)\n= sqrt(ell mp m)(ell pm m + 1) mathfrakD^(ell)_m pm 1 m(mathbfR)","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"while Eq. (21) relates the Wigner D-matrix to the spin-weighted spherical harmonics as","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"_sY_ellm(mathbfR)\n= (-1)^s sqrtfrac2ell+14pi mathfrakD^(ell)_m-s(mathbfR)","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Plugging the latter into the former, we get","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"L_pm _sY_ellm(mathbfR)\n= sqrt(ell mp m)(ell pm m + 1) _sY_ellm pm 1(mathbfR)","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"That is, in our conventions we have","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"alpha^pm_ellm = sqrt(ell mp m)(ell pm m + 1)","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"which is always real and positive, and thus consistent with the Condon-Shortley phase convention.","category":"page"},{"location":"conventions/outline/#Properties","page":"Outline","title":"Properties","text":"","category":"section"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"D^j_mm(alphabetagamma) = (-1)^m-m D^j_-m-m(alphabetagamma)^*\n(-1)^m-mD^j_mm(alphabetagamma)=D^j_mm(gammabetaalpha)\nd_mm^j=(-1)^m-md_mm^j=d_-m-m^j","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\nd_mm^j(pi) = (-1)^j-m delta_m-m 6pt\nd_mm^j(pi-beta) = (-1)^j+m d_m-m^j(beta)6pt\nd_mm^j(pi+beta) = (-1)^j-m d_m-m^j(beta)6pt\nd_mm^j(2pi+beta) = (-1)^2j d_mm^j(beta)6pt\nd_mm^j(-beta) = d_mm^j(beta) = (-1)^m-m d_mm^j(beta)\nendaligned","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"begingather\nR = cosepsilon + sinepsilon hatmathfrakr \nR๐ฏ = cosepsilon ๐ฏ + sinepsilon hatmathfrakr๐ฏ \nR๐ฏR^-1 = (๐ฏcosepsilon + sinepsilon hatmathfrakr๐ฏ)(cosepsilon - sinepsilon hatmathfrakr) \nR๐ฏR^-1 = ๐ฏcos^2epsilon + sin^2epsilon hatmathfrakr๐ฏhatmathfrakr^-1 + sinepsilon cosepsilon (hatmathfrakr๐ฏ - ๐ฏhatmathfrakr) \nR๐ฏR^-1 = begincases\n๐ฏ ๐ฏ hatmathfrakr = hatmathfrakr๐ฏ \n๐ฏ(cos^2epsilon - sin^2epsilon) + 2 sinepsilon cosepsilon frachatmathfrakr ๐ฏ2 ๐ฏ hatmathfrakr = -hatmathfrakr๐ฏ \nendcases \nR๐ฏR^-1 = begincases\n๐ฏ ๐ฏ hatmathfrakr = hatmathfrakr๐ฏ \ncos2epsilon ๐ฏ + sin2epsilon frachatmathfrakr ๐ฏ2 ๐ฏ hatmathfrakr = -hatmathfrakr๐ฏ \nendcases \nendgather","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"Using techniques from geometric algebra, we can easily prove that the result is another vector, so we can measure its (squared) norm just by multiplying it by itself:","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"beginaligned\n ๐‘ ๐ฏ ๐‘^-1 ^2\n= ๐‘ ๐ฏ ๐‘^-1 ๐‘ ๐ฏ ๐‘^-1 \n= ๐‘ ๐ฏ ๐ฏ ๐‘^-1 \n= ๐ฏ^2 ๐‘ ๐‘^-1 \n= ๐ฏ^2\nendaligned","category":"page"},{"location":"conventions/outline/","page":"Outline","title":"Outline","text":"That is, ๐ฏ = ๐‘ ๐ฏ ๐‘^-1 has the same norm as ๐ฏ, which means that ๐ฏ is a rotation of ๐ฏ. Given the constraint on the norm of ๐‘, we can rewrite it as","category":"page"},{"location":"functions/#Complete-function-list","page":"Complete function list","title":"Complete function list","text":"","category":"section"},{"location":"functions/","page":"Complete function list","title":"Complete function list","text":"The following list contains all documented functions inside the SphericalFunctions module.","category":"page"},{"location":"functions/","page":"Complete function list","title":"Complete function list","text":"Modules = [SphericalFunctions]","category":"page"},{"location":"transformations/#s-SHT-Transformations","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"","category":"section"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"One important capability of this package is the transformation between the two representations of a spin-weighted spherical function:","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"Values f of the function evaluated on a set of points or \"pixels\" in the domain of the function.\nValues fฬƒ of the mode weights (coefficients) of an expansion in the standard spin-weighted spherical-harmonic basis.","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"In the literature, the transformation f โ†ฆ fฬƒ is usually called \"analysis\" or map2salm, while the inverse transformation f โ†ฆ fฬƒ is called \"synthesis\" or salm2map. These are both referred to as spin-spherical-harmonic transforms, or s-SHTs.","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"To describe the values of a spin-s function up to some maximum angular resolution ell_mathrmmax, we need (ell_mathrmmax+1)^2 - s^2 mode weights. We assume throughout that the values fฬƒ are stored as","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"fฬƒ = [mode_weight(โ„“, m) for โ„“ โˆˆ abs(s):โ„“โ‚˜โ‚โ‚“ for m โˆˆ -โ„“:โ„“]","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"(Here, mode_weight is a made-up function intended to provide a schematic.) In particular, the m index varies most rapidly, and the ell index varies most slowly. Correspondingly, there must be at least (ell_mathrmmax+1)^2 - s^2 function values f. However, some s-SHT algorithms require more function values โ€” usually by a factor of 2 or 4 โ€” trading off between speed and memory usage.","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"The SSHT object implements these transformations, storing pre-computed constants and pre-allocated workspace for the transformations. The interface is designed to be similar to that of FFTW.jl, whereby an SSHT object ๐’ฏ can be used to perform the transformation as either","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"f = ๐’ฏ * fฬƒ","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"or","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"fฬƒ = ๐’ฏ \\ f","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"Currently, there are three algorithms implemented, each having different advantages and disadvantages:","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"The \"Direct\" algorithm (introduced here for the first time), which is the default, but should only be used up to ell_mathrmmax lesssim 50 because its intermediate storage requirements scale as ell_mathrmmax^4. This algorithm is the fastest for small ell_mathrmmax, it can be used with arbitrary (non-degenerate) pixelizations, and achieves optimal dimensionality.\nThe \"Minimal\" algorithm due to Elahi et al. [2], with some minor improvements. This algorithm is fast and โ€” as the name implies โ€” also achieves optimal dimensionality, and its storage scales as ell_mathrmmax^3. However, its pixelization is restricted, and its accuracy at very high ell_mathrmmax is not as good as the \"RS\" algorithm. The algorithm itself is not actually fully specified by Elahi et al., and leaves out some relatively simple improvements, so I have had to take some liberties with my interpretation.\nThe \"RS\" algorithm due to Reinecke and Seljebotn [3]. This forms the basis for the libsharp and ducc.sht packages. It requires pixelizations on \"iso-latitude rings\", and does not achieve optimal dimensionality. However, it is very fast, and its accuracy is excellent at extremely high ell_mathrmmax.","category":"page"},{"location":"transformations/#SSHT-objects","page":"s-SHT Transformations","title":"SSHT objects","text":"","category":"section"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"Modules = [SphericalFunctions]\nPages = [\"ssht.jl\", \"ssht/direct.jl\", \"ssht/minimal.jl\", \"ssht/rs.jl\"]","category":"page"},{"location":"transformations/#SphericalFunctions.SSHT","page":"s-SHT Transformations","title":"SphericalFunctions.SSHT","text":"Supertype of storage for spin-spherical-harmonic transforms\n\n\n\n\n\n","category":"type"},{"location":"transformations/#SphericalFunctions.SSHT-Tuple{Any, Any}","page":"s-SHT Transformations","title":"SphericalFunctions.SSHT","text":"SSHT(s, โ„“โ‚˜โ‚โ‚“; [method=\"Direct\"], [T=Float64], [kwargs...])\n\nConstruct an SSHT object to transform between spin-weighted spherical-harmonic mode weights and function values โ€” performing an s-SHT.\n\nThis object behaves similarly to an AbstractFFTs.Plan object โ€” specifically in the ability to use the semantics of algebra to perform transforms. For example, if the function values are stored as a vector f, the mode weights as fฬƒ, and the SSHT as ๐’ฏ, then we can compute the function values from the mode weights as\n\nf = ๐’ฏ * fฬƒ\n\nor solve for the mode weights from the function values as\n\nfฬƒ = ๐’ฏ \\ f\n\nThe first dimensions of fฬƒ must index the mode weights (as usual, for โ„“โˆˆabs(s):โ„“โ‚˜โ‚โ‚“ and mโˆˆ-โ„“:โ„“) and the first index of f must index the locations at which the function is evaluated. Any following dimensions will be broadcast over. Note that certain types will broadcast using Julia threads, while others will broadcast using BLAS threads. The relevant number of threads must be set appropriately.\n\nCertain SSHT types (currently, only Minimal and Direct) also have an option to always act in place โ€” meaning that they simply re-use the input storage, even when used in an expression like ๐’ฏ \\ f. The option must be passed as the inplace argument to the constructors, and is part of the type of the resulting object. Regardless of the value of that option, for those types where the option exists, it is also possible to use mul! and ldiv! from the LinearAlgebra package to force operation in place.\n\nNote that different algorithms require different \"pixelizations\", or sets of Rotors on which to evaluate the function. These can be obtained from the SSHT object using the pixels and rotors functions.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.pixels","page":"s-SHT Transformations","title":"SphericalFunctions.pixels","text":"pixels(๐’ฏ)\n\nReturn the spherical coordinates (ฮธ, ฯ•) on which the spin-weighted spherical harmonics are evaluated. See also rotors, which provides the actual Rotors on which they are evaluated.\n\n\n\n\n\n","category":"function"},{"location":"transformations/#SphericalFunctions.rotors","page":"s-SHT Transformations","title":"SphericalFunctions.rotors","text":"rotors(๐’ฏ)\n\nReturn the Rotors on which the spin-weighted spherical harmonics are evaluated. See also pixels, which provides the corresponding spherical coordinates.\n\n\n\n\n\n","category":"function"},{"location":"transformations/#SphericalFunctions.SSHTDirect","page":"s-SHT Transformations","title":"SphericalFunctions.SSHTDirect","text":"SSHTDirect(s, โ„“โ‚˜โ‚โ‚“; decomposition=LinearAlgebra.qr, T=Float64, Rฮธฯ•=golden_ratio_spiral_rotors(s, โ„“โ‚˜โ‚โ‚“, T), inplace=true)\n\nConstruct an s-SHT object that uses the \"Direct\" method; see โ‚›๐˜ for details about the method and optional arguments. Also see SSHT for general information about how to use these objects.\n\nBy default, this uses precisely optimal sampling โ€” meaning that the number of points on which the function is evaluated, represented by Rฮธฯ•, is equal to the number of modes. However, it is equally possible to evaluate on more points than there are modes. This can be useful, for example, when processing multiple fields with different spin weights; the function could be evaluated on points appropriate for the lowest value of s, and therefore could also be used to solve for fields of all other spin weights.\n\nNote that in-place operation is possible for this type when the length of the input Rฮธฯ• is equal to the number of modes given s and โ„“โ‚˜โ‚โ‚“ โ€” and is the default behavior when possible. See SSHT for description of in-place operation.\n\nThis method is typically better than other current implementations for โ„“โ‚˜โ‚โ‚“ 24, both in terms of speed and accuracy. However, this advantage quickly falls away. A warning will be issued if โ„“โ‚˜โ‚โ‚“ is greater than about 64, because this method is not likely to be the most efficient or most accurate choice.\n\n\n\n\n\n","category":"type"},{"location":"transformations/#SphericalFunctions.SSHTMinimal","page":"s-SHT Transformations","title":"SphericalFunctions.SSHTMinimal","text":"Storage for Minimal spin-spherical-harmonic transform\n\nThe Minimal algorithm was described by Elahi et al., and allows for the minimal number of function samples.\n\n\n\n\n\n","category":"type"},{"location":"transformations/#SphericalFunctions.SSHTMinimal-Union{Tuple{TT}, Tuple{Any, Any}} where TT","page":"s-SHT Transformations","title":"SphericalFunctions.SSHTMinimal","text":"SSHTMinimal(s, โ„“โ‚˜โ‚โ‚“; kwargs...)\n\nConstruct a SSHTMinimal object directly. This may also be achieved by calling the main SSHT function with the same keywords, along with method=\"Minimal\".\n\nThis object uses the algorithm described by Elahi et al.\n\nThe basic floating-point number type may be adjusted with the keyword argument T, which defaults to Float64.\n\nThe SSHs are evaluated on a series of \"rings\" at constant colatitude. Their locations are specified by the ฮธ keyword argument, which defaults to sorted_rings(s, โ„“โ‚˜โ‚โ‚“, T). The first element of ฮธ is the colatitude of the smallest ring (containing 2s+1 elements), and so on to the last element of ฮธ, which is the colatitude of the largest ring (containing 2โ„“โ‚˜โ‚โ‚“+1 elements).\n\nWhenever T is either Float64 or Float32, the keyword arguments plan_fft_flags and plan_fft_timelimit may also be useful for obtaining more efficient FFTs. They default to FFTW.ESTIMATE and Inf, respectively. They are passed to AbstractFFTs.plan_fft.\n\nNote that, because this algorithm achieves optimal dimensionality, the transformation will be performed in place by default. If this is not desired, pass the keyword argument inplace=false. This will cause the algorithm to copy the input and perform in-place transformation on that copy.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.SSHTRS","page":"s-SHT Transformations","title":"SphericalFunctions.SSHTRS","text":"Storage for spin-spherical-harmonic transform\n\nThe algorithm was described in by Reinecke and Seljebotn.\n\n\n\n\n\n","category":"type"},{"location":"transformations/#SphericalFunctions.SSHTRS-Union{Tuple{TT}, Tuple{Any, Any}} where TT","page":"s-SHT Transformations","title":"SphericalFunctions.SSHTRS","text":"SSHTRS(s, โ„“โ‚˜โ‚โ‚“; kwargs...)\n\nConstruct a SSHTRS object directly. This may also be achieved by calling the main SSHT function with the same keywords, along with method=\"RS\".\n\nThis object uses the algorithm described by Reinecke and Seljebotn.\n\nThe basic floating-point number type may be adjusted with the keyword argument T, which defaults to Float64.\n\nThe SSHs are evaluated on a series of \"rings\" at constant colatitude. Their locations are specified by the ฮธ keyword argument, which defaults to fejer1_rings(2โ„“โ‚˜โ‚โ‚“+1, T). If this is changed, the user should also provide the corresponding quadrature_weights argument โ€” the default being fejer1(length(ฮธ), T).\n\nOn each of these rings, an FFT is performed. To reach the band limit of m = โ„“โ‚˜โ‚โ‚“, the number of points along each ring must therefore be at least 2โ„“โ‚˜โ‚โ‚“+1, but may be greater. For example, if 2โ„“โ‚˜โ‚โ‚“+1 does not factorize neatly into a product of small primes, it may be preferable to use 2โ„“โ‚˜โ‚โ‚“+2 points along each ring. (In that case, whenever โ„“โ‚˜โ‚โ‚“ is 1 less than a power of 2, the number of points will be exactly a power of 2, which is usually particularly efficient.) The number of points on each ring can be modified independently, if given as a vector with the same length as ฮธ, or as a single number which is assumed to be the same for all rings.\n\nWhenever T is either Float64 or Float32, the keyword arguments plan_fft_flags and plan_fft_timelimit may also be useful for obtaining more efficient FFTs. They default to FFTW.ESTIMATE and Inf, respectively. They are passed to AbstractFFTs.plan_fft.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#Pixelizations","page":"s-SHT Transformations","title":"Pixelizations","text":"","category":"section"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"The algorithms implemented here require pixelizations. While the \"Direct\" algorithm can be used with arbitrary pixelizations, the \"Minimal\" and \"RS\" algorithms require more specific choices, as noted in their docstrings.","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"Typically, \"pixelization\" refers exclusively to a choice of points on the sphere ๐•Šยฒ at which to compute function values. Of course, as mentioned elsewhere, it is not technically possible to define spin-weighted functions as functions of a point on ๐•Šยฒ alone; we also need some sense of reference direction in the tangent space. Quite generally, we can define spin-weighted functions on the group ๐’๐Ž(3) or ๐’๐ฉ๐ข๐ง(3), so we will also refer to a choice of a set of points in ๐’๐ฉ๐ข๐ง(3) (which is essentially the group of unit quaternions) as a \"pixelization\". However, assuming spherical coordinates, a choice of coordinates on the sphere almost everywhere induces a choice of the reference direction in the tangent space, so it is almost possible to define pixelizations just in terms of points on ๐•Šยฒ. But using spherical coordinates is actually enough to fully specify the pixelization, because the degeneracies at the poles also allow us to define the reference direction.","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"In principle, we could be concerned about the choice of reference direction in the tangent space. That is, we might expect to care about pixelizations over ๐•Šยณ. However, we are dealing with spin-weighted functions, which are eigenfunctions of a final rotation about the reference direction. This means that once we choose any reference direction at each point, we know the function values for any other reference direction at those points. In particular, an important property of a pixelization is the condition number of the transformation matrix between the function values and the mode weights. If we rotate the reference direction at a single point, this is equivalent to multiplying the matrix by a diagonal matrix with entries of 1 everywhere except the entry corresponding to that point, where the entry is some complex phase. This does not change the condition number of the matrix, so we can ignore the choice of reference direction at every point. For other situations, where we might care about the choice of reference direction, it might be interesting to consider this work by Marc Alexa, and references therein.","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"Interesting discussions of various pixelizations and metrics can be found in Saff and Kuijlaars (1997) and Brauchart and Grabner (2015), as well as blog posts here and here. Note that the \"equal-area\" pixelizations of Healpix are very restrictiveโ€”only being available for very specific numbers of pointsโ€”and do not provide any obvious advantages over the more flexible pixelizations available here.","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"The various pixelizations may be computed as follows:","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"Modules = [SphericalFunctions]\nPages = [\"pixelizations.jl\"]","category":"page"},{"location":"transformations/#SphericalFunctions.clenshaw_curtis_rings-Union{Tuple{Any}, Tuple{T}, Tuple{Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.clenshaw_curtis_rings","text":"clenshaw_curtis_rings(N, [T=Float64])\n\nValues of the colatitude coordinate (ฮธ) appropriate for quadrature by the Clenshaw-Curtis rule, using weights provided by clenshaw_curtis.\n\nNote that the first argument to this function is N, rather than the โ„“โ‚˜โ‚โ‚“ used in some other functions. For spin-weighted spherical harmonics, you may want to use N=2โ„“โ‚˜โ‚โ‚“+1.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.fejer1_rings-Union{Tuple{Any}, Tuple{T}, Tuple{Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.fejer1_rings","text":"fejer1_rings(N, [T=Float64])\n\nValues of the colatitude coordinate (ฮธ) appropriate for quadrature by Fejรฉr's first rule, using weights provided by fejer1.\n\nNote that the first argument to this function is N, rather than the โ„“โ‚˜โ‚โ‚“ used in some other functions. For spin-weighted spherical harmonics, you may want to use N=2โ„“โ‚˜โ‚โ‚“+1.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.fejer2_rings-Union{Tuple{Any}, Tuple{T}, Tuple{Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.fejer2_rings","text":"fejer2_rings(N, [T=Float64])\n\nValues of the colatitude coordinate (ฮธ) appropriate for quadrature by Fejรฉr's second rule, using weights provided by fejer2.\n\nNote that the first argument to this function is N, rather than the โ„“โ‚˜โ‚โ‚“ used in some other functions. For spin-weighted spherical harmonics, you may want to use N=2โ„“โ‚˜โ‚โ‚“+1.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.golden_ratio_spiral_pixels-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.golden_ratio_spiral_pixels","text":"golden_ratio_spiral_pixels(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])\n\nCover the sphere ๐•Šยฒ with pixels generated by the golden-ratio spiral. Successive pixels are separated by the azimuthal angle ฮ”ฯ• = 2ฯ€(2-ฯ†), and are uniformly distributed in cos ฮธ.\n\nThis is also known as the \"Fibonacci sphere\" or \"Fibonacci lattice\".\n\nVisually, this is a very reasonable-looking pixelization, with fairly uniform distance between neighbors, and approximate isotropy. No two pixels will share the same values of either ฮธ or ฯ•. Also note that no point is present on either the North or South poles.\n\nThe returned quantity is a vector of 2-SVectors providing the spherical coordinates of each pixel. See also golden_ratio_spiral_rotors for the corresponding Rotors.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.golden_ratio_spiral_rotors-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.golden_ratio_spiral_rotors","text":"golden_ratio_spiral_rotors(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])\n\nCover the sphere ๐•Šยฒ with pixels generated by the golden-ratio spiral.\n\nSee golden_ratio_spiral_pixels for more detailed explanation. The quantity returned by this function is a vector of Rotors providing each pixel.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.sorted_ring_pixels-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.sorted_ring_pixels","text":"sorted_ring_pixels(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])\n\nCover the sphere ๐•Šยฒ with (โ„“โ‚˜โ‚โ‚“+1)ยฒ-sยฒ pixels distributed in rings provided by sorted_rings; see that function's documentation for more description.\n\nThe returned quantity is a vector of 2-SVectors containing the spherical coordinates of each pixel. See also sorted_ring_rotors for the corresponding Rotors.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.sorted_ring_rotors-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.sorted_ring_rotors","text":"sorted_ring_rotors(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])\n\nCover the sphere ๐•Šยฒ with (โ„“โ‚˜โ‚โ‚“+1)ยฒ-sยฒ pixels distributed in rings provided by sorted_rings; see that function's documentation for more description.\n\nThe returned quantity is a vector of Rotors. See also sorted_ring_rotors for the corresponding spherical coordinates.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.sorted_rings-Union{Tuple{T}, Tuple{Any, Any}, Tuple{Any, Any, Type{T}}} where T","page":"s-SHT Transformations","title":"SphericalFunctions.sorted_rings","text":"sorted_rings(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])\n\nCompute locations of a series of rings labelled by j sโ„“โ‚˜โ‚โ‚“ (analogous to โ„“), where each ring will contain k = 2j+1 (analogous to m) pixels distributed evenly around the ring. These rings are then sorted, so that the ring with the most pixels (j = โ„“โ‚˜โ‚โ‚“) is closest to the equator, and the next-largest ring is placed just above or below the equator (depending on the sign of s), the next just below or above, and so on. This is generally a fairly good first guess when minimizing the condition number of matrices used to solve for mode weights from function values. In particular, I use this to initialize the Minimal algorithm, which is then fed into an optimizer to fine-tune the positions of the rings.\n\nThis function does not provide the individual pixels; it just provides the colatitude values of the rings on which the pixels will be placed. The pixels themselves are provided by sorted_ring_pixels.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#Quadrature-weights","page":"s-SHT Transformations","title":"Quadrature weights","text":"","category":"section"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"The \"RS\" algorithm requires quadrature weights corresponding to the input pixelization. Though there is a working default choice, it is possible to use others. There are several that are currently implemented, along with their corresponding pixelizations:","category":"page"},{"location":"transformations/","page":"s-SHT Transformations","title":"s-SHT Transformations","text":"Modules = [SphericalFunctions]\nPages = [\"weights.jl\"]\nOrder = [:module, :type, :constant, :function, :macro]","category":"page"},{"location":"transformations/#SphericalFunctions.clenshaw_curtis-Union{Tuple{T}, Tuple{Any, Type{T}}} where T<:AbstractFloat","page":"s-SHT Transformations","title":"SphericalFunctions.clenshaw_curtis","text":"clenshaw_curtis(n, [T])\n\nCompute n weights for the Clenshaw-Curtis rule, corresponding to n evenly spaced nodes from 0 to ฯ€ inclusive. That is, the nodes are located at\n\ntheta_k = k fracpin-1 quad k=0 ldots n-1\n\nThis function uses Waldvogel's method.\n\nThe type T may be any AbstractFloat, but defaults to Float64.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.fejer1-Union{Tuple{Any}, Tuple{T}, Tuple{Any, Type{T}}} where T<:AbstractFloat","page":"s-SHT Transformations","title":"SphericalFunctions.fejer1","text":"fejer1(n, [T])\n\nCompute n weights for Fejรฉr's first rule, corresponding to n evenly spaced nodes from 0 to ฯ€ inclusive. That is, the nodes are located at\n\ntheta_k = k fracpin-1 quad k=0 ldots n-1\n\nThis function uses Waldvogel's method.\n\nThe type T may be any AbstractFloat, but defaults to Float64.\n\n\n\n\n\n","category":"method"},{"location":"transformations/#SphericalFunctions.fejer2-Union{Tuple{T}, Tuple{Any, Type{T}}} where T<:AbstractFloat","page":"s-SHT Transformations","title":"SphericalFunctions.fejer2","text":"fejer2(n, [T])\n\nCompute n weights for Fejรฉr's second rule, corresponding to n evenly spaced nodes between 0 and ฯ€ exclusive. That is, the nodes are located at\n\ntheta_k = k fracpin+1 quad k=1 ldots n\n\nThis function uses Waldvogel's method. However, contrary to Waldvogel's notation, this routine does not include the weight corresponding to the ฯ‘=0 or ฯ€ nodes, which both have weight 0.\n\nThe type T may be any AbstractFloat, but defaults to Float64.\n\n\n\n\n\n","category":"method"},{"location":"internal/#Internal-functions","page":"Internal functions","title":"Internal functions","text":"","category":"section"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"There are various functions that are only used internally, some of which are likely to be deprecated in the near future. These are documented here for completeness.","category":"page"},{"location":"internal/#H-recursion-and-ALFs","page":"Internal functions","title":"H recursion and ALFs","text":"","category":"section"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"The fundamental algorithm is the H recursion, which is the core computation needed for Wigner's d and ๐”‡ matrices, and the spin-weighted spherical harmonics _sY_ellm, as well as map2salm functions.","category":"page"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"Modules = [SphericalFunctions]\nPages = [\"Hrecursion.jl\"]","category":"page"},{"location":"internal/#SphericalFunctions.H!-Union{Tuple{T}, Tuple{AbstractVector, Complex{T}, Any, Any, Any}, Tuple{AbstractVector, Complex{T}, Vararg{Any, 4}}} where T<:Real","page":"Internal functions","title":"SphericalFunctions.H!","text":"H!(H, expiฮฒ, โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“, H_rec_coeffs)\nH!(H, expiฮฒ, โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“, H_rec_coeffs, Hindex)\n\nCompute the H matrix defined by Gumerov and Duraiswami [8].\n\nThis computation forms the basis for computing Wigner's d and ๐”‡ matrices via d_matrices! and D_matrices!, the spin-weighted spherical harmonics via sYlm_values!, and for transforming from values of spin-weighted spherical functions evaluated on a grid to the corresponding mode weights via map2salm.\n\nDue to symmetries, we only need to compute ~1/4 of the elements of this matrix, so only those elements with m m are computed. The relevant indices of the H vector are computed based on the Hindex function โ€” which defaults to WignerHindex, but could reasonably be WignerDindex if the input H vector contains all valid indices. However, it is assumed that the storage scheme used for H is such that the successive m values are located in successive elements.\n\nIf mโ‚˜โ‚โ‚“ โ„“โ‚˜โ‚โ‚“, we don't even need 1/4 of the elements, and only values with m mโ‚˜โ‚โ‚“ will be computed. This is particularly useful for computing spin-weighted spherical harmonics.\n\nNote that the recursion coefficients H_rec_coeffs should be the quantity returned by H_recursion_coefficients.\n\n\n\n\n\n","category":"method"},{"location":"internal/#SphericalFunctions.H_recursion_coefficients-Union{Tuple{T}, Tuple{Any, Type{T}}} where T<:Real","page":"Internal functions","title":"SphericalFunctions.H_recursion_coefficients","text":"H_recursion_coefficients(โ„“โ‚˜โ‚โ‚“, T)\n\nPre-compute constants used in Wigner H recursion.\n\n\n\n\n\n","category":"method"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"Internally, the H recursion relies on calculation of the Associated Legendre Functions (ALFs), which can also be called on their own:","category":"page"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"Modules = [SphericalFunctions]\nPages = [\"associated_legendre.jl\"]","category":"page"},{"location":"internal/#SphericalFunctions.ALFcompute!-Union{Tuple{T}, Tuple{Vector{T}, Complex{T}, Int64, ALFRecursionCoefficients{T}}} where T<:Real","page":"Internal functions","title":"SphericalFunctions.ALFcompute!","text":"ALFcompute(expiฮฒ, nmax)\nALFcompute!(Pฬ„, expiฮฒ, nmax)\nALFcompute(expiฮฒ, nmax, recursion_coefficients)\nALFcompute!(Pฬ„, expiฮฒ, nmax, recursion_coefficients)\n\nCompute the \"fully normalized\" Associated Legendre Functions up to some maximum n value nmax.\n\nThese functions can take a vector Pฬ„, to store the data, stored in order of increasing m most rapidly varying and then increasing n. If not supplied, Pฬ„ will be constructed for you and returned.\n\nThe optional recursion_coefficients argument must be an ALFRecursionCoefficients, which stores various constant coefficients used in the recursion. This object requires more than 3x the memory and more than 20x the time to compute a single Pฬ„ vector without this argument, but passing it will typically speed up the calculation of each Pฬ„ by a factor of 8x or so. Thus, if you expect to compute Pฬ„ more than a few times, it will take less time to pre-compute those factors, and pass them to this function.\n\nNote that the base real type will be inferred from the (complex) type of expiฮฒ. If present, the base types of Pฬ„ and recursion_coefficients must agree.\n\n\n\n\n\n","category":"method"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"The function _slambda_ellm is defined as essentially _sY_ell0, and is important internally for computing the ALFs. We have some important utilities for computing it:","category":"page"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"SphericalFunctions.ฮป_recursion_initialize\nSphericalFunctions.ฮป_iterator\nSphericalFunctions.AlternatingCountdown","category":"page"},{"location":"internal/#SphericalFunctions.ฮป_recursion_initialize","page":"Internal functions","title":"SphericalFunctions.ฮป_recursion_initialize","text":"ฮป_recursion_initialize(cosฮธ, sinยฝฮธ, cosยฝฮธ, s, โ„“, m)\n\nThis provides initial values for the recursion to find _slambda_ellm along indices of increasing ell, due to Kostelec & Rockmore Specifically, this function computes values with ell=m.\n\n_slambda_ellm(theta)\n = _sY_ellm(theta 0)\n = (-1)^m sqrtfrac2ell+14pi d^ell_-ms(theta)\n\n\n\n\n\n","category":"function"},{"location":"internal/#SphericalFunctions.ฮป_iterator","page":"Internal functions","title":"SphericalFunctions.ฮป_iterator","text":"ฮป_iterator(ฮธ, s, m)\n\nConstruct an object to iterate over โ‚›ฮปโ‚—โ‚˜ values.\n\nThe โ‚›ฮปโ‚—โ‚˜(ฮธ) function is defined as the spin-weighted spherical harmonic evaluated at spherical coordinates (ฮธ ฯ•), with ฯ•=0. In particular, note that it is real-valued. The return type is determined by the type of ฮธ (or more precisely, cosยฝฮธ).\n\nThis algorithm by Kostelec & Rockmore allows us to iterate over increasing โ„“ values, for given fixed s and m values.\n\nNote that this iteration has no inherent bound, so if you try to iterate over all values, you will end up in an infinite loop. Instead, you can zip this iterator with another:\n\nฮธ = 0.1\ns = -2\nm = 1\nฮป = ฮป_iterator(ฮธ, s, m)\nฮ” = max(abs(s), abs(m))\nfor (โ„“, โ‚›ฮปโ‚—โ‚˜) โˆˆ zip(ฮ”:ฮ”+5, ฮป)\n @show (โ„“, โ‚›ฮปโ‚—โ‚˜)\nend\n\nAlternatively, you could use Iterates.take(ฮป, 6), for example.\n\nNote that the iteration always begins with โ„“ = ฮ” = max(abs(s), abs(m)).\n\n\n\n\n\n","category":"type"},{"location":"internal/#SphericalFunctions.AlternatingCountdown","page":"Internal functions","title":"SphericalFunctions.AlternatingCountdown","text":"Simple iterator to count down to 0, with alternating signs\n\njulia> collect(AlternatingCountdown(5))\n11-element Vector{Int64}:\n 5\n -5\n 4\n -4\n 3\n -3\n 2\n -2\n 1\n -1\n 0\n\n\n\n\n\n","category":"type"},{"location":"internal/#โ‚›๐˜","page":"Internal functions","title":"โ‚›๐˜","text":"","category":"section"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"Various d, D, and sYlm functions are important in the main API. Their names and signatures have been tweaked from older versions of this package. The only one with remaining documentation is โ‚›๐˜, which could probably be replaced by sYlm_values, except that the default pixelization is golden_ratio_spiral_rotors, which makes it very convenient for interacting with SSHT.","category":"page"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"โ‚›๐˜","category":"page"},{"location":"internal/#SphericalFunctions.โ‚›๐˜","page":"Internal functions","title":"SphericalFunctions.โ‚›๐˜","text":"โ‚›๐˜(s, โ„“โ‚˜โ‚โ‚“, [T=Float64], [Rฮธฯ•=golden_ratio_spiral_rotors(s, โ„“โ‚˜โ‚โ‚“, T)])\n\nConstruct a matrix of โ‚›Yโ‚—โ‚˜(Rฮธฯ•) values for the input s and all nontrivial (ell m) up to โ„“โ‚˜โ‚โ‚“.\n\nThis is a fast and accurate method for mapping between the vector of spin-weighted spherical-harmonic mode weights โ‚›๐Ÿโ‚—โ‚˜ and the vector of function values on the sphere โ‚›๐Ÿโฑผโ‚–, as\n\nโ‚›๐Ÿโฑผโ‚– = โ‚›๐˜ โ‚›๐Ÿโ‚—โ‚˜\n\nwhere the right-hand side represents the matrix-vector product. As usual, we assume that the โ‚›๐Ÿโ‚—โ‚˜ modes are ordered by increasing m -โ„“โ„“, and โ„“ sโ„“โ‚˜โ‚โ‚“. The ordering of the โ‚›๐Ÿโฑผโ‚– values will be determined by the ordering of the argument Rฮธฯ•.\n\nNote that the number of modes need not be the same as the number of points on which the function is evaluated, which would imply that the output matrix is not square. To be able to invert the relationship, however, we need the number of points โ‚›๐Ÿโฑผโ‚– to be at least as large as the number of modes โ‚›๐Ÿโ‚—โ‚˜.\n\nNote that the usefulness of this approach is limited by the fact that the size of this matrix scales as โ„“โ‚˜โ‚โ‚“โด. As such, it is mostly useful only for โ„“โ‚˜โ‚โ‚“ of order dozens, rather than โ€” say โ€” the tens of thousands that CMB astronomy or lensing require, for example.\n\nDirect application and inversion of this matrix are used in the \"direct\" methods of s-SHT transformations. See SSHTDirect for details about the implementation.\n\n\n\n\n\n","category":"function"},{"location":"internal/#Transformation","page":"Internal functions","title":"Transformation","text":"","category":"section"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"The newer SSHT interface is more efficient for most purposes, but this package used to use functions named map2salm, which is still present, but may be deprecated.","category":"page"},{"location":"internal/","page":"Internal functions","title":"Internal functions","text":"Modules = [SphericalFunctions]\nPages = [\"map2salm.jl\"]","category":"page"},{"location":"internal/#SphericalFunctions.map2salm!-Union{Tuple{T}, Tuple{AbstractArray{Complex{T}}, AbstractArray{Complex{T}}, Int64, Int64}, Tuple{AbstractArray{Complex{T}}, AbstractArray{Complex{T}}, Int64, Int64, Any}} where T<:Real","page":"Internal functions","title":"SphericalFunctions.map2salm!","text":"map2salm!(salm, map, spin, โ„“max)\nmap2salm!(salm, map, plan)\n\nTransform map values sampled on the sphere to _sa_ell m modes in place.\n\nFor details, see map2salm.\n\n\n\n\n\n","category":"method"},{"location":"internal/#SphericalFunctions.map2salm-Union{Tuple{T}, Tuple{AbstractArray{Complex{T}}, Int64, Int64}, Tuple{AbstractArray{Complex{T}}, Int64, Int64, Any}} where T<:Real","page":"Internal functions","title":"SphericalFunctions.map2salm","text":"map2salm(map, spin, โ„“max)\nmap2salm(map, plan)\n\nTransform map values sampled on the sphere to _sa_ell m modes.\n\nThe map array should have size Nฯ† along its first dimension and Nฯ‘ along its second; any number of dimensions may follow. The spin must be entered explicitly, and โ„“max is the highest โ„“ value you want in the output.\n\nFor repeated applications of this function with different values of map, it is more efficient to pre-compute plan using plan_map2salm. These functions will create a new salm array on each call. To operate in place on a pre-allocated salm array, use map2salm!.\n\nThe core of this function follows the method described by Reinecke and Seljebotn.\n\n\n\n\n\n","category":"method"},{"location":"internal/#SphericalFunctions.plan_map2salm-Union{Tuple{T}, Tuple{AbstractArray{Complex{T}}, Int64, Int64}} where T<:Real","page":"Internal functions","title":"SphericalFunctions.plan_map2salm","text":"plan_map2salm(map, spin, โ„“max)\n\nPrecompute values to use in executing map2salm or map2salm!.\n\nThe arguments to this function exactly mirror those of the first form of map2salm, and all but the first argument in the first form of map2salm!. The plan returned by this function can be passed to the second forms of those functions to avoid some computation and allocation costs.\n\nNote that the plan object is not thread safe; a separate plan should be created for each thread that will use one, or locks should be used to ensure that a single plan is not used at the same time on different threads.\n\n\n\n\n\n","category":"method"},{"location":"sYlm/#{}_{s}Y_{\\ell,m}-functions","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"","category":"section"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"The spin-weighted spherical harmonics are an important set of functions defined on the rotation group ๐’๐Ž(3), or more generally, the spin group ๐’๐ฉ๐ข๐ง(3) that covers it. They are eigenfunctions of the left- and right-Lie derivatives, and are particularly useful in describing the angular dependence of polarized fields, like the electromagnetic field and gravitational-wave field. Originally introduced by Newman and Penrose [7], they are essentially components of Wigner's frakD matrices:","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"_sY_ellm(mathbfR)\n = (-1)^s sqrtfrac2ell+14pi frakD^(ell)_m -s(mathbfR)","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"As such, they can be computed using the same H recursion algorithm as the Wigner frakD^(ell)_m -s matrices. But because not all values of s in -ellell are used, we can be much more efficient in both storage and computation time.","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"The user interface is very similar to the one for Wigner's ๐”‡ and d matrices:","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"using Quaternionic\nusing SphericalFunctions\n\nR = randn(RotorF64)\nโ„“โ‚˜โ‚โ‚“ = 8\ns = -2\nY = sYlm_values(R, โ„“โ‚˜โ‚โ‚“, s)","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"Again, the results can take up a lot of memory, so for maximum efficiency when calling this function repeatedly with different R values, it is best to pre-allocate the necessary memory with the sYlm_prep function, and the pass that in as an argument to sYlm_values!:","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"Y_storage = sYlm_prep(โ„“โ‚˜โ‚โ‚“, s)\nY = sYlm_values!(Y_storage, R, s)","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"(Beware that, as noted in the documentation for sYlm_values!, the output Y is just a reference to part of the Y_storage object, so you should not reuse Y_storage until you have copied or otherwise finished using Y.)","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"The output Y is a single vector of Complex numbers with the same base type as R. The ordering of the elements is described in the documentation for sYlm_values!. It is also possible to efficiently view slices of this vector as a series of individual vectors using a sYlm_iterator:","category":"page"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"for (โ„“, Yหก) in zip(0:โ„“โ‚˜โ‚โ‚“, sYlm_iterator(Y, โ„“โ‚˜โ‚โ‚“))\n # Do something with the matrix Yหก[โ„“+mโ€ฒ+1, โ„“+m+1]\nend","category":"page"},{"location":"sYlm/#Docstrings","page":"_sY_ellm functions","title":"Docstrings","text":"","category":"section"},{"location":"sYlm/","page":"_sY_ellm functions","title":"_sY_ellm functions","text":"sYlm_values\nsYlm_values!\nsYlm_prep\nsYlm_iterator","category":"page"},{"location":"sYlm/#SphericalFunctions.sYlm_values","page":"_sY_ellm functions","title":"SphericalFunctions.sYlm_values","text":"sYlm_values(R, โ„“โ‚˜โ‚โ‚“, spin)\nsYlm_values(ฮธ, ฯ•, โ„“โ‚˜โ‚โ‚“, spin)\n\nCompute values of the spin-weighted spherical harmonic _sY_ell m(R) for all ell leq ell_mathrmmax.\n\nSee sYlm_values! for details about the input and output values.\n\nThis function only appropriate when you need to evaluate the _sY_ell m for a single value of R or ฮธ, ฯ• because it allocates large arrays and performs many calculations that could be reused. If you need to evaluate the matrices for many values of R or ฮธ, ฯ•, you should pre-allocate the storage with sYlm_prep, and then call sYlm_values! with the result instead.\n\n\n\n\n\n","category":"function"},{"location":"sYlm/#SphericalFunctions.sYlm_values!","page":"_sY_ellm functions","title":"SphericalFunctions.sYlm_values!","text":"sYlm_values!(sYlm_storage, R, spin)\nsYlm_values!(sYlm_storage, ฮธ, ฯ•, spin)\nsYlm_values!(sYlm, R, โ„“โ‚˜โ‚โ‚“, spin)\nsYlm_values!(sYlm, ฮธ, ฯ•, โ„“โ‚˜โ‚โ‚“, spin)\n\nCompute values of the spin-weighted spherical harmonic _sY_ell m(R) for all ell leq ell_mathrmmax.\n\nThe spherical harmonics of spin weight s are related to Wigner's mathfrakD matrix as\n\nbeginaligned\n_sY_ell m(R)\n = (-1)^s sqrtfrac2ell+14pi mathfrakD^(ell)_m -s(R) \n = (-1)^s sqrtfrac2ell+14pi barmathfrakD^(ell)_-s m(barR)\nendaligned\n\nIn all cases, the result is returned in a 1-dimensional array ordered as\n\n[\n โ‚›Yโ‚—โ‚˜(R)\n for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“\n for m โˆˆ -โ„“:โ„“\n]\n\nWhen the first argument is Y, it will be modified, so it must be at least as large as that array. When the first argument is sYlm_storage, it should be the quantity returned by sYlm_prep, and the result will be written into the Y field of that tuple. Both of these options โ€” especially the latter โ€” reduce the number of allocations needed on each call to the corresponding functions, which should increase the speed significantly. Note that the Y or sYlm_storage arguments must have types compatible with the type of R or ฮธ, ฯ•.\n\nwarn: Warn\nWhen using the sYlm_storage argument (which is recommended), the returned quantity sYlm will be an alias of sYlm_storage[1]. If you want to retain that data after the next call to sYlm_values!, you should copy it with copy(sYlm).\n\nThe ฮธ, ฯ• arguments are spherical coordinates as described in the documentation of Quaternionic.from_spherical_coordinates.\n\nSee also sYlm_values for a simpler function call when you only need to evaluate the _sY_ell m for a single value of R or ฮธ, ฯ•.\n\nExamples\n\nusing Quaternionic, SphericalFunctions\nspin = -2\nโ„“โ‚˜โ‚โ‚“ = 8\nT = Float64\nR = Rotor{T}(1, 2, 3, 4) # Will be normalized automatically\nsYlm_storage = sYlm_prep(โ„“โ‚˜โ‚โ‚“, spin, T)\nsYlm = sYlm_values!(sYlm_storage, R, spin)\n\n\n\n\n\n","category":"function"},{"location":"sYlm/#SphericalFunctions.sYlm_prep","page":"_sY_ellm functions","title":"SphericalFunctions.sYlm_prep","text":"sYlm_prep(โ„“โ‚˜โ‚โ‚“, sโ‚˜โ‚โ‚“, [T=Float64, [โ„“โ‚˜แตขโ‚™=0]])\n\nConstruct storage space and pre-compute recursion coefficients to compute spin-weighted spherical-harmonic values _sY_ell m in place.\n\nThis returns the sYlm_storage arguments needed by sYlm_values!.\n\nNote that the result of this function can be passed to sYlm_values!, even if the value of spin passed to that function is smaller (in absolute value) than the sโ‚˜โ‚โ‚“ passed to this function. That is, the sYlm_storage returned by this function can be used to compute _sY_ell m values for numerous values of the spin.\n\n\n\n\n\n","category":"function"},{"location":"sYlm/#SphericalFunctions.sYlm_iterator","page":"_sY_ellm functions","title":"SphericalFunctions.sYlm_iterator","text":"sYlm_iterator(Y, โ„“โ‚˜โ‚โ‚“, [โ„“โ‚˜แตขโ‚™, [iโ‚˜แตขโ‚™]])\n\nConstruct an Iterator that returns sub-vectors of Y, each of which consists of elements (โ„“-โ„“) through (โ„“โ„“), for โ„“ from โ„“โ‚˜แตขโ‚™ through โ„“โ‚˜โ‚โ‚“.\n\nNote that the returned objects are views into the original Y data โ€” meaning that you may alter their values.\n\nBecause the result is a vector restricted to a particular โ„“ value, you can index the (โ„“ m) element as [โ„“+m+1]. For example, you might use this as something like\n\nfor (โ„“, Yหก) in zip(โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“, sYlm_iterator(Y, โ„“โ‚˜โ‚โ‚“))\n for m in -โ„“:โ„“\n Yหก[โ„“+m+1] # ... do something with Yหก\n end\nend\n\nBy default, Y is assumed to contain all possible values, beginning with (0,0). However, if โ„“โ‚˜แตขโ‚™ is not 0, this can be ambiguous: do we mean that Y really starts with the (0,0) element and we are just asking to begin the iteration higher? Or do we mean that Y doesn't even contain data for lower โ„“ values? We can resolve this using iโ‚˜แตขโ‚™, which gives the index of โ„“โ‚˜แตขโ‚™ in Y. By default, we assume the first case, and set iโ‚˜แตขโ‚™=Ysize(โ„“โ‚˜แตขโ‚™-1)+1. However, if Y doesn't contain data below โ„“โ‚˜แตขโ‚™, we could use iโ‚˜แตขโ‚™=1 to indicate the index in Y at which to find (โ„“โ‚˜แตขโ‚™-โ„“โ‚˜แตขโ‚™).\n\nAlso note that no bounds checking is done, either at instantiation time or during iteration. You are responsible for ensuring that the size of Y and the values of โ„“โ‚˜โ‚โ‚“, โ„“โ‚˜แตขโ‚™, and iโ‚˜แตขโ‚™ make sense.\n\n\n\n\n\n","category":"type"},{"location":"operators/#Differential-operators","page":"Differential operators","title":"Differential operators","text":"","category":"section"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Spin-weighted spherical functions cannot be defined on the sphere S^2, but are well defined on the group mathrmSpin(3) cong mathrmSU(2) or the rotation group mathrmSO(3). (See Boyle [1] for the explanation.) However, this also allows us to define a variety of differential operators acting on these functions, relating to infinitesimal motions in these groups, acting either from the left or the right on their arguments. Right or left matters because the groups mentioned above are all non-commutative groups.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"In general, the left Lie derivative of a function f(Q) over the unit quaternions with respect to a generator of rotation g is defined as","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_g(f)Q = -fraci2\n left fracdfleft(exp(tg) Qright)dt right_t=0","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Note that the exponential multiplies Q on the left โ€” hence the name. We will see below that this agrees with the usual definition of the angular-momentum from physics, except that in quantum physics a factor of hbar is usually included.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"So, for example, a rotation about the z axis has the quaternion z as its generator of rotation, and L_z defined in this way agrees with the usual angular-momentum operator L_z familiar from spherical-harmonic theory, and reduces to it when the function has spin weight 0, but also applies to functions of general spin weight. Similarly, we can compute L_x and L_y, and take appropriate combinations to find the usual raising and lowering (ladder) operators L_+ and L_-.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"In just the same way, we can define the right Lie derivative of a function f(Q) over the unit quaternions with respect to a generator of rotation g as","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"R_g(f)Q = -fraci2\n left fracdfleft(Q exp(tg)right)dt right_t=0","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Note that the exponential multiplies Q on the right โ€” hence the name.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"This operator is less common in physics, because it represents the dependence of the function on the choice of frame (or coordinate system), which is not usually of interest. Multiplication on the left represents a rotation of the physical system, while rotation on the right represents a rotation of the coordinate system. However, this dependence on coordinate system is precisely what defines the spin weight of a function, so this class of operators is relevant in discussions of spin-weighted spherical functions. In particular, the operators R_pm correspond (up to a sign) to the spin-raising and -lowering operators eth and bareth originally introduced by Newman and Penrose [7], as explained in greater detail by Boyle [1].","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Note that these definitions are extremely general, in that they can be used for any Lie group, and for any complex-valued function on that group. And in full generality, we have the useful properties of linearity:","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_smathbfa = sL_mathbfa\nqquad textand qquad\nR_smathbfa = sR_mathbfa","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"and","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_mathbfa+mathbfb = L_mathbfa + L_mathbfb\nqquad textand qquad\nR_mathbfa+mathbfb = R_mathbfa + R_mathbfb","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"for any scalar s and any elements of the Lie algebra mathbfa and mathbfb. In particular, if the Lie algebra has a basis mathbfe_(j), we use the shorthand L_j and R_j for L_mathbfe_(j) and R_mathbfe_(j), respectively, and we can expand any operator in terms of these basis operators:","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_mathbfa = sum_j a_j L_j\nqquad textand qquad\nR_mathbfa = sum_j a_j R_j","category":"page"},{"location":"operators/#Commutators","page":"Differential operators","title":"Commutators","text":"","category":"section"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"In general, for generators a and b, we have the commutator relations","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"left L_a L_b right = fraci2 L_ab\nqquad\nleft R_a R_b right = -fraci2 R_ab","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"where ab is the commutator of the two generators, which can be obtained directly as the commutator of the corresponding quaternions. Note the sign difference between these two equations. The factors of pm i2 are inherited directly from the definitions of L_g and R_g given above, but they appear there with the same sign. The sign difference between these two commutator equations results from the fact that the quaternions are multiplied in opposite orders in the two cases. It could be absorbed by defining the operators with opposite signs.[1] The arbitrary sign choices used above are purely for historical reasons.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Again, these results are valid for general (finite-dimensional) Lie groups, but a particularly interesting case is in application to the three-dimensional rotation group. In the following, we will apply our results to this group.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"The commutator relations for L are consistent โ€” except for the differing use of hbar โ€” with the usual relations from quantum mechanics:","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"left L_j L_k right = i hbar sum_l=1^3 varepsilon_jkl L_l","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Here, j, k, and l are indices that run from 1 to 3, and index the set of basis vectors (hatx haty hatz). If we represent an arbitrary basis vector as hate_j, then the quaternion commutator ab in the expression for L_a L_b becomes","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"hate_j hate_k = 2 sum_l=1^3 varepsilon_jkl hate_l","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Plugging this into the general expression L_a L_b = fraci2 L_ab, we obtain (up to the factor of hbar) the version frequently seen in quantum physics.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"[1]: In fact, we can define the left and right Lie derivative operators quite generally, for functions on any Lie group and for the corresponding Lie algebra. And in all cases (at least for finite-dimensional Lie algebras) we obtain the same commutator relations. The only potential difference is that it may not make sense to use the coefficient i2 in general; it was chosen here for consistency with the standard angular-momentum operators. If that coefficient is changed in the definitions of the Lie derivatives, the only change to the commutator relations would the substitution of that coefficient.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"The raising and lowering operators relative to L_z and R_z satisfy โ€” by definition of raising and lowering operators โ€” the relations","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_z L_pm = pm L_pm\nqquad\nR_z R_pm = pm R_pm","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"These allow us to solve โ€” up to an overall factor โ€” for those operators in terms of the basic generators (again, noting the sign difference):","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_pm = L_x pm i L_y\nqquad\nR_pm = R_x mp i R_y","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"(Interestingly, this procedure also shows that rasing and lowering operators can only exist if the factor in front of the derivatives in the definitions of L_g and R_g are pure imaginary numbers.) In particular, this results in the commutator relations","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_+ L_- = 2L_z\nqquad\nR_+ R_- = 2R_z","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Here, the signs are similar because the two sign differences noted above essentially cancel each other out.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"In the functions listed below, these operators are returned as matrices acting on vectors of mode weights. As such, we can actually evaluate these commutators as given to cross-validate the expressions and those functions.","category":"page"},{"location":"operators/#Transformations-of-functions-vs.-mode-weights","page":"Differential operators","title":"Transformations of functions vs. mode weights","text":"","category":"section"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"One important point to note is that mode weights transform \"contravariantly\" (very loosely speaking) relative to the spin-weighted spherical functions under some operators. For example, take the action of the L_+ operator, which acts on a SWSH as","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"L_+ left_sY_ellmright (R) = sqrt(ell-m)(ell+m+1) _sY_ellm+1(R)","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"We can use this to derive the mode weights of a general spin-weighted function f under the action of this operator:[2]","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"beginaligned\nleftL_+ fright_ellm\n=\nint leftL_+ f(R)right _sbarY_ellm(R) dR \n=\nint leftL_+ sum_ellmf_ellm _sY_ellm(R)right _sbarY_ellm(R) dR \n=\nint sum_ellm f_ellm leftL_+ _sY_ellm(R)right _sbarY_ellm(R) dR \n=\nsum_ellm f_ellm int leftL_+ _sY_ellm(R)right _sbarY_ellm(R) dR \n=\nsum_ellm f_ellm int leftsqrt(ell-m)(ell+m+1) _sY_ellm+1(R)right _sbarY_ellm(R) dR \n=\nsum_ellm f_ellm sqrt(ell-m)(ell+m+1) int _sY_ellm+1(R) _sbarY_ellm(R) dR \n=\nsum_ellm f_ellm sqrt(ell-m)(ell+m+1) delta_ellell delta_mm+1 \n=\nf_ellm-1 sqrt(ell-m+1)(ell+m)\nendaligned","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Note that this expression (and in particular its signs) more resembles the expression for L_- left_sY_ellmright than for L_+ left_sY_ellmright. Similar relations hold for the action of L_-.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"[2]: A technical note about the integrals above: the integrals should be taken over the appropriate space and with the appropriate weight such that the SWSHs are orthonormal. In general, this integral should be over mathrmSpin(3) and weighted by 12pi so that the result will be either 0 or 1; in general the SWSHs are not truly orthonormal when integrated over an S^2 subspace (nor even is the integral invariant). However, if we know that the spins are the same in both cases, it is possible to integrate over an S^2 subspace.","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"However, it is important to note that the same \"contravariance\" is not present for the spin-raising and -lowering operators:","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"beginaligned\nlefteth fright_ellm\n=\nint lefteth f(R)right _s+1barY_ellm(R) dR \n=\nint lefteth sum_ellmf_ellm _sY_ellm(R)right _s+1barY_ellm(R) dR \n=\nsum_ellm f_ellm int lefteth _sY_ellm(R)right _s+1barY_ellm(R) dR \n=\nsum_ellm f_ellm sqrt(ell-s)(ell+s+1) int _s+1Y_ellm(R) _s+1barY_ellm(R) dR \n=\nsum_ellm f_ellm sqrt(ell-s)(ell+s+1) delta_ellell delta_mm \n=\nf_ellm sqrt(ell-s)(ell+s+1)\nendaligned","category":"page"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Similarly bareth โ€” and R_pm of course โ€” obey this more \"covariant\" form of transformation.","category":"page"},{"location":"operators/#Docstrings","page":"Differential operators","title":"Docstrings","text":"","category":"section"},{"location":"operators/","page":"Differential operators","title":"Differential operators","text":"Modules = [SphericalFunctions]\nPages = [\"operators.jl\"]","category":"page"},{"location":"operators/#SphericalFunctions.Lz-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Lz","text":"Lz(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the angular-momentum operator associated with the z direction. This is the standard L_z operator, familiar from basic physics, extended to work with SWSHs. Note that this is the left Lie derivative; see Rz for the equivalent right Lie derivative. See the documentation or Boyle for more details.\n\nIn terms of the SWSHs, we can write the action of L_z as\n\nL_z _sY_ellm = m _sY_ellm\n\nSee also Lยฒ, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.Lยฒ-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Lยฒ","text":"Lยฒ(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the total angular-momentum operator from โ„“โ‚˜แตขโ‚™ up to โ„“โ‚˜โ‚โ‚“. If not present, โ„“โ‚˜แตขโ‚™ is assumed to be abs(s). The argument s is ignored; it is present only for consistency with other operators, and is assumed to be 0 if not present.\n\nThis is the standard Lยฒ operator, familiar from basic physics, extended to work with SWSHs. It is also known as the Casimir operator, and is equal to\n\nL^2 = L_x^2 + L_y^2 + L_z^2 = fracL_+L_- + L_-L_+ + 2L_zL_z2\n\nNote that these are the left Lie derivatives, but L^2 = R^2, where R is the right Lie derivative. See the documentation or Boyle for more details.\n\nIn terms of the SWSHs, we can write the action of L^2 as\n\nL^2 _sY_ellm = ell(ell+1) _sY_ellm\n\nSee also Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.Lโ‚Š-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Lโ‚Š","text":"Lโ‚Š(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the angular-momentum raising operator. This is the standard L_+ operator, familiar from basic physics, extended to work with SWSHs. Note that this is the left Lie derivative; see Rโ‚Š for the equivalent right Lie derivative. See the documentation or Boyle for more details.\n\nWe define L_+ to be the raising operator for the left Lie derivative with respect to rotation about z: L_z. By definition, this implies the commutator relation L_z L_+ = L_+, which allows us to derive L_+ = L_x + i L_y\n\nIn terms of the SWSHs, we can write the action of L_+ as\n\nL_+ _sY_ellm = sqrt(ell-m)(ell+m+1) _sY_ellm+1\n\nConsequently, the mode weights of a function are affected as\n\nleftL_+(f)right_sellm = sqrt(ell+m)(ell-m+1)leftfright_sellm-1\n\nSee also Lยฒ, Lz, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.Lโ‚‹-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Lโ‚‹","text":"Lโ‚‹(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the angular-momentum lowering operator. This is the standard L_- operator, familiar from basic physics, extended to work with SWSHs. Note that this is the left Lie derivative; see Rโ‚‹ for the equivalent right Lie derivative. See the documentation or Boyle for more details.\n\nWe define L_- to be the lowering operator for the left Lie derivative with respect to rotation about z: L_z. By definition, this implies the commutator relation L_z L_- = -L_-, which allows us to derive L_- = L_x - i L_y\n\nIn terms of the SWSHs, we can write the action of L_- as\n\nL_- _sY_ellm = sqrt(ell+m)(ell-m+1) _sY_ellm-1\n\nConsequently, the mode weights of a function are affected as\n\nleftL_-(f)right_sellm = sqrt(ell-m)(ell+m+1)leftfright_sellm+1\n\nSee also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.Rz-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Rz","text":"Rz(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the right angular-momentum operator associated with the z direction.\n\nThis is the R_z operator, much like the L_z operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. See Lz for the equivalent left Lie derivative. See the documentation or Boyle for more details.\n\nIn terms of the SWSHs, we can write the action of R_z as\n\nR_z _sY_ellm = -s _sY_ellm\n\nNote the unfortunate sign of s, which seems to be opposite to what we expect, and arises from the choice of definition of s in the original paper by Newman and Penrose.\n\nSee also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.Rยฒ-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Rยฒ","text":"Rยฒ(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the total angular-momentum operator from โ„“โ‚˜แตขโ‚™ up to โ„“โ‚˜โ‚โ‚“. If not present, โ„“โ‚˜แตขโ‚™ is assumed to be abs(s). The argument s is ignored; it is present only for consistency with other operators, and is assumed to be 0 if not present.\n\nThis is the R^2 operator, much like the L^2 operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. It is also known as the Casimir operator, and is equal to\n\nR^2 = R_x^2 + R_y^2 + R_z^2 = fracR_+R_- + R_-R_+ + 2R_zR_z2\n\nNote that these are the right Lie derivatives, but L^2 = R^2, where L is the left Lie derivative. See the documentation or Boyle for more details.\n\nIn terms of the SWSHs, we can write the action of R^2 as\n\nR^2 _sY_ellm = ell(ell+1) _sY_ellm\n\nSee also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rz, Rโ‚Š, Rโ‚‹, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.Rโ‚Š-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Rโ‚Š","text":"Rโ‚Š(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the right angular-momentum raising operator.\n\nThis is the R_+ operator, much like the L_+ operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. See Lโ‚Š for the equivalent left Lie derivative. See the documentation or Boyle for more details.\n\nWe define R_+ to be the raising operator for the right Lie derivative with respect to rotation about z: R_z. By definition, this implies the commutator relation R_z R_+ = R_+, which allows us to derive R_+ = R_x - i R_y\n\nIn terms of the SWSHs, we can write the action of R_+ as\n\nR_+ _sY_ellm = sqrt(ell+s)(ell-s+1) _s-1Y_ellm\n\nConsequently, the mode weights of a function are affected as\n\nleftR_+(f)right_sellm = sqrt(ell+s)(ell-s+1)leftfright_s-1ellm\n\nBecause of the unfortunate sign of s arising from the choice of definition of s in the original paper by Newman and Penrose, this is a lowering operator for s, though it really is a raising operator for R_z, and raises the eigenvalue of the corresponding Wigner matrix.\n\nSee also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚‹, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.Rโ‚‹-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.Rโ‚‹","text":"Rโ‚‹(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute the right angular-momentum lowering operator.\n\nThis is the R_- operator, much like the L_- operator familiar from basic physics, but in terms of the right Lie derivative, and extended to work with SWSHs. See Lโ‚‹ for the equivalent left Lie derivative. See the documentation or Boyle for more details.\n\nWe define R_- to be the raising operator for the right Lie derivative with respect to rotation about z: R_z. By definition, this implies the commutator relation R_z R_- = -R_-, which allows us to derive R_- = R_x + i R_y\n\nIn terms of the SWSHs, we can write the action of R_- as\n\nR_- _sY_ellm = sqrt(ell-s)(ell+s+1) _s+1Y_ellm\n\nConsequently, the mode weights of a function are affected as\n\nleftR_-(f)right_sellm = sqrt(ell-s)(ell+s+1)leftfright_s+1ellm\n\nBecause of the unfortunate sign of s arising from the choice of definition of s in the original paper by Newman and Penrose, this is a raising operator for s, though it really is a lowering operator for R_z, and lowers the eigenvalue of the corresponding Wigner matrix - though that raises the eigenvalue of the corresponding Wigner matrix.\n\nSee also Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š, รฐ, รฐฬ„.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.รฐ-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.รฐ","text":"รฐ(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute coefficients for the spin-raising operator eth.\n\nThis operator was originally defined by Newman and Penrose, but is more completely defined by Boyle. It is identical to Rโ‚‹. Refer to that function's documentation for more details.\n\nBy definition, the spin-raising operator satisfies the commutator relation S eth = eth (where S is the spin operator, which just multiplies the function by its spin). In terms of the SWSHs, we can write the action of eth as\n\n eth _sY_ellm = sqrt(ell-s)(ell+s+1) _s+1Y_ellm\n\nConsequently, the mode weights of a function are affected as\n\nlefteth fright_sellm = sqrt(ell-s)(ell+s+1)leftfright_s+1ellm\n\nSee also รฐฬ„, Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š.\n\n\n\n\n\n","category":"method"},{"location":"operators/#SphericalFunctions.รฐฬ„-Union{Tuple{T}, Tuple{Any, Any, Any}, Tuple{Any, Any, Any, Type{T}}} where T","page":"Differential operators","title":"SphericalFunctions.รฐฬ„","text":"รฐฬ„(s, โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“, [T])\n\nCompute coefficients for the spin-lowering operator bareth.\n\nThis operator was originally defined by Newman and Penrose, but is more completely defined by Boyle. It is opposite to Rโ‚Š โ€” meaning that bareth = -R. Refer to that function's documentation for more details.\n\nBy definition, the spin-lowering operator satisfies the commutator relation S bareth = -bareth (where S is the spin operator, which just multiplies the function by its spin). In terms of the SWSHs, we can write the action of bareth as\n\nbareth _sY_ellm = -sqrt(ell+s)(ell-s+1) _s-1Y_ellm\n\nConsequently, the mode weights of a function are affected as\n\nleftbareth fright_sellm\n= -sqrt(ell-s)(ell+s+1)leftfright_s+1ellm\n\nSee also รฐ, Lยฒ, Lz, Lโ‚Š, Lโ‚‹, Rยฒ, Rz, Rโ‚Š.\n\n\n\n\n\n","category":"method"},{"location":"conventions/conventions/#Conventions","page":"Conventions","title":"Conventions","text":"","category":"section"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"In the following subsections, we work through all the conventions used in this package, starting from first principles to motivate the choices and ensure that each step is on firm footing. First, we can just list the most important conventions. Note that we will use Euler angles and spherical coordinates here. It is almost always a bad idea to use Euler angles in computing; quaternions are clearly the preferred representation for numerous reasons. However, Euler angles are important for (a) comparing to other sources, and (b) performing analytic integrations. These are the only two uses we will make of Euler angles.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Right-handed Cartesian coordinates (x y z) and unit basis vectors (๐ฑ ๐ฒ ๐ณ).\nSpherical coordinates (r theta phi) and unit basis vectors (๐ซ boldsymboltheta boldsymbolphi). The \"polar angle\" theta in 0 pi measures the angle between the specified direction and the positive ๐ณ axis. The \"azimuthal angle\" phi in 0 2pi) measures the angle between the projection of the specified direction onto the ๐ฑ-๐ฒ plane and the positive ๐ฑ axis, with the positive ๐ฒ axis corresponding to the positive angle phi = pi2.\nQuaternions ๐ = W + X๐ข + Y๐ฃ + Z๐ค, where ๐ข๐ฃ๐ค = -1. In software, this quaternion is represented by (W X Y Z). We will depict a three-dimensional vector ๐ฏ = v_x ๐ฑ + v_y ๐ฒ + v_z ๐ณ interchangeably as a quaternion v_x ๐ข + v_y ๐ฃ + v_z ๐ค.\nA rotation represented by the unit quaternion ๐‘ acts on a vector ๐ฏ as ๐‘ ๐ฏ ๐‘^-1.\nWhere relevant, rotations will be assumed to be right-handed, so that a quaternion characterizing the rotation through an angle vartheta about a unit vector ๐ฎ can be expressed as ๐‘ = exp(vartheta ๐ฎ2). Note that -๐‘ would deliver the same rotation, which is why the group of unit quaternions mathrmSpin(3) = mathrmSU(2) is a double cover of the group of rotations mathrmSO(3).\nEuler angles parametrize a unit quaternion as ๐‘ = exp(alpha ๐ค2) exp(beta ๐ฃ2) exp(gamma ๐ค2). The angles alpha and beta take values in 0 2pi). The angle beta takes values in 0 2pi to parametrize the group of unit quaternions mathrmSpin(3) = mathrmSU(2), or in 0 pi to parametrize the group of rotations mathrmSO(3).\nA point on the unit sphere with spherical coordinates (theta phi) can be represented by Euler angles (alpha beta gamma) = (phi theta 0). The rotation with these Euler angles takes the positive ๐ณ axis to the specified direction. In particular, any function of spherical coordinates can be promoted to a function on Euler angles using this identification.\nFor a complex-valued function f(๐‘), we define two operators, the left and right Lie derivatives:\nL_๐ฎ f(๐‘) = left-i fracddepsilonright_epsilon=0\nfleft(e^epsilon ๐ฎ2 ๐‘right)\nqquad textand qquad\nR_๐ฎ f(๐‘) = left-i fracddepsilonright_epsilon=0\nfleft(๐‘ e^epsilon ๐ฎ2right)\nwhere ๐ฎ can be any pure-vector quaternion. In particular, L represents the standard angular-momentum operators, and we can compute the expressions in Euler angles for the basis vectors:\nbeginaligned\n L_x = L_๐ข = -i left\n -fraccosalphatanbeta fracpartial partial alpha\n - sinalpha fracpartial partial beta\n +fraccosalphasinbeta fracpartial partial gamma\n right \n L_y = L_๐ฃ = -i left\n -fracsinalphatanbeta fracpartial partial alpha\n + cosalpha fracpartial partial beta\n +fracsinalphasinbeta fracpartial partial gamma\n right \n L_z = L_๐ค = -i fracpartial partial alpha \n K_x = K_๐ข = -i left\n -fraccosgammasinbeta fracpartial partial alpha\n +singamma fracpartial partial beta\n +fraccosgammatanbeta fracpartial partial gamma\n right \n K_y = K_๐ฃ = -i left\n fracsingammasinbeta fracpartial partial alpha\n +cosgamma fracpartial partial beta\n -fracsingammatanbeta fracpartial partial gamma\n right \n K_z = K_๐ค = -i fracpartial partial gamma\nendaligned\nWe can lift any function on S^2 to a function on S^3 โ€” or more precisely any function on spherical coordinates to a function on the space of Euler angles โ€” by the correspondence (theta phi) mapsto (alpha beta gamma) = (phi theta 0). We can then express the angular-momentum operators in their more common form, in terms of spherical coordinates:\nbeginaligned\n L_x = -i left\n -fraccosphitantheta fracpartial partial phi\n - sinphi fracpartial partial theta\n right \n L_y = -i left\n -fracsinphitantheta fracpartial partial phi\n + cosphi fracpartial partial theta\n right \n L_z = -i fracpartial partial phi\nendaligned\n(The R operators make less sense for a function of spherical coordinates.)\nSpherical harmonics\nWigner D-matrices\nSpin-weighted spherical harmonics","category":"page"},{"location":"conventions/conventions/#Three-dimensional-space","page":"Conventions","title":"Three-dimensional space","text":"","category":"section"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The space we are working in is naturally three-dimensional Euclidean space, so we start with a right-handed Cartesian coordinate system (x y z). These also give us the unit basis vectors (๐ฑ ๐ฒ ๐ณ). Note that these basis vectors are assumed to have unit norm, but we omit the hats just to keep the notation simple. Any vector in this space can be written as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"mathbfv = v_x mathbf๐ฑ + v_y mathbf๐ฒ + v_z mathbf๐ณ","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"in which case the Euclidean norm is given by","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":" mathbfv = sqrtv_x^2 + v_y^2 + v_z^2","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Equivalently, we can write the components of the Euclidean metric as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"g_ij = left( beginarrayccc\n 1 0 0 \n 0 1 0 \n 0 0 1\nendarray right)_ij","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Note that, because the points of the space are in one-to-one correspondence with the vectors, we will frequently use a vector to label a point in space.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"We will be working on the sphere, so it will be very convenient to use spherical coordinates (r theta phi). We choose the standard \"physics\" conventions for these, in which we relate to the Cartesian coordinates by","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\nr = sqrtx^2 + y^2 + z^2 in 0 infty) \ntheta = arccosleft(fraczrright) in 0 pi \nphi = arctanleft(fracyxright) in 0 2pi)\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"where we assume the arctan in the expression for phi is really the two-argument form that gives the correct quadrant. The inverse transformation is given by","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\nx = r sintheta cosphi \ny = r sintheta sinphi \nz = r costheta\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"We can use this to find the components of the metric in spherical coordinates:","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"g_ij\n= sum_ij fracpartial x^ipartial x^i fracpartial x^jpartial x^j g_ij\n= left( beginarrayccc\n 1 0 0 \n 0 r^2 0 \n 0 0 r^2 sin^2theta\nendarray right)_ij","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The unit coordinate vectors in spherical coordinates are then","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\nmathbf๐ซ = sintheta cosphi mathbf๐ฑ + sintheta sinphi mathbf๐ฒ + costheta mathbf๐ณ \nboldsymboltheta = costheta cosphi mathbf๐ฑ + costheta sinphi mathbf๐ฒ - sintheta mathbf๐ณ \nboldsymbolphi = -sinphi mathbf๐ฑ + cosphi mathbf๐ฒ\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"where, again, we omit the hats on the unit vectors to keep the notation simple.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"One seemingly obvious โ€” but extremely important โ€” fact is that the unit basis frame (๐ฑ ๐ฒ ๐ณ) can be rotated onto (boldsymboltheta boldsymbolphi mathbfr) by first rotating through the \"polar\" angle theta about the mathbfy axis, and then through the \"azimuthal\" angle phi about the mathbfz axis. This becomes important when we consider spin-weighted functions.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Integration in Cartesian coordinates is, of course, trivial as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"int_mathbbR^3 f d^3mathbfr = int_-infty^infty int_-infty^infty int_-infty^infty f dx dy dz","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"In spherical coordinates, the integrand involves the square-root of the determinant of the metric, so we have","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"int_mathbbR^3 f d^3mathbfr = int_0^infty int_0^pi int_0^2pi f r^2 sintheta dr dtheta dphi","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Restricting to the unit sphere, and normalizing so that the integral of 1 over the sphere is 1, we can simplify this to","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"int_S^2 f d^2Omega = frac14pi int_0^pi int_0^2pi f sintheta dtheta dphi","category":"page"},{"location":"conventions/conventions/#Four-dimensional-space:-Quaternions-and-rotations","page":"Conventions","title":"Four-dimensional space: Quaternions and rotations","text":"","category":"section"},{"location":"conventions/conventions/#Geometric-algebra","page":"Conventions","title":"Geometric algebra","text":"","category":"section"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Given the basis vectors (๐ฑ ๐ฒ ๐ณ) and the Euclidean norm, we can define the geometric algebra. The key feature is the geometric product, which is defined for any pair of vectors as ๐ฏ and ๐ฐ as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐ฏ ๐ฐ = ๐ฏ ๐ฐ + ๐ฏ ๐ฐ","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"where the dot product is the usual scalar product and the wedge product is the antisymmetric part of the tensor product โ€”ย acting just like the standard exterior product from the algebra of differential forms. The geometric product is linear, associative, distributive, and has the property that","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐ฏ๐ฏ = ๐ฏ ^2","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The most useful properties of the geometric product are that parallel vectors commute with each other, while orthogonal vectors anticommute. Since the geometric product is linear, the product of any two vectors can be decomposed into parallel and orthogonal parts.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The basis for this entire space is then the set","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"begingather\n๐Ÿ \n๐ฑ ๐ฒ ๐ณ\n๐ฑ๐ฒ ๐ฑ๐ณ ๐ฒ๐ณ \n๐ฑ๐ฒ๐ณ\nendgather","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The standard presentation of quaternions (including the confused historical development) uses different symbols for these last four basis elements:","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"begingather\n๐ข = ๐ณ๐ฒ = -๐ฒ๐ณ \n๐ฃ = ๐ฑ๐ณ = -๐ณ๐ฑ \n๐ค = ๐ฒ๐ฑ = -๐ฑ๐ฒ \n๐ˆ = ๐ฑ๐ฒ๐ณ\nendgather","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Note that each of these squares to -1. For example, recalling that orthogonal vectors anticommute, the product is associative, and the product of a vector with itself is just its squared norm, we have","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐ฑ๐ฒ๐ฑ๐ฒ = -๐ฑ๐ฒ๐ฒ๐ฑ = -๐ฑ(๐ฒ๐ฒ)๐ฑ = -๐ฑ๐ฑ = -1","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Any of these could act like the unit imaginary; ๐ฑ๐ฒ is probably the canonical choice.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐ˆ is sometimes called the pseudoscalar. Its inverse is ๐ˆ^-1 = ๐ณ๐ฒ๐ฑ = -๐ฑ๐ฒ๐ณ, which can also serve as something very much like the Hodge star operator,[1] mapping elements to their \"dual\" elements. In particular, we have","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\n๐ข = ๐ˆ^-1๐ฑ \n๐ฃ = ๐ˆ^-1๐ฒ \n๐ค = ๐ˆ^-1๐ณ\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"We will see that ๐ข generates right-handed rotations in the positive sense about ๐ฑ, ๐ฃ about ๐ฒ, and ๐ค about ๐ณ. Moreover, this mapping between (๐ฑ ๐ฒ ๐ณ) and (๐ข ๐ฃ ๐ค) is a vector-space isomorphism. In fact, the reader who is not familiar with geometric algebra but is familiar with quaternions may be able to read an expression like ๐ฃ ๐ฑ ๐ฃยน as if it is just an abuse of notation, and mentally replace ๐ฑ with ๐ข to read those symbols as a valid quaternion expression; both viewpoints are equally correct by the isomorphism.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"[1]: Note that quaternions will only be spanned by elements made from an even number of the basis vectors. It turns out that those with an odd number will produce reflections, rather than rotations, when acting on a vector โ€” as discussed below. This explains why quaternions are restricted to just those elements with an even number to represent rotations. For details see any geometric algebra text, like Doran and Lasenby.","category":"page"},{"location":"conventions/conventions/#Quaternions-and-Euler-angles","page":"Conventions","title":"Quaternions and Euler angles","text":"","category":"section"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Note that there are different conventions for the signs of the (๐ข ๐ฃ ๐ค) basis. Everyone agrees that ๐ขยฒ = ๐ฃยฒ = ๐คยฒ = -1, but we could easily flip the sign of any basis element, and these would still be satisfied. The identifications we chose above are made to ensure that ๐ข generates rotations about ๐ฑ, and so on, but even that depends on how we define quaternions as acting on vectors (to be discussed below). A different choice of the latter would result in all flipping the sign of all three basis elements, which is a convention that is commonly used โ€” though almost exclusively in aerospace. The key expressions that eliminate ambiguity are the multiplications","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\n๐ข ๐ฃ = ๐ค \n๐ฃ ๐ค = ๐ข \n๐ค ๐ข = ๐ฃ\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"We can also use these rules above to determine ๐ข๐ฃ๐ค = -๐Ÿ. All four of these equations have flipped signs in other conventions. See Sommer et al. for a discussion of the different conventions.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"We use coordinates (W X Y Z) on the space of quaternions, so that a quaternion would be written as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐ = W๐Ÿ + X๐ข + Y๐ฃ + Z๐ค","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"though we usually omit the ๐Ÿ. The space of all quaternions is thus four dimensional. The norm is just the standard Euclidean norm, so that the norm of a quaternion is","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":" ๐ = sqrtW^2 + X^2 + Y^2 + Z^2","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"An important operation is the conjugate, which is defined as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"overline๐ = W - X๐ข - Y๐ฃ - Z๐ค","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Note that the squared norm can be written as the quaternion times its conjugate. The inverse of a quaternion is thus just the conjugate divided by the squared norm:","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐^-1 = fracoverline๐๐overline๐ = fracoverline๐ ๐ ^2","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The other important operation is exponentiation. Since a scalar commutes with any quaternion, including a nonzero scalar component in the quaternion will simply multiply the result by the exponential of that scalar component. Moreover, we will not have any use for such an exponential, so we assume that the argument to the exponential function is a \"pure\" quaternion โ€” that is, one with zero scalar component. Moreover, we write it as a unit quaternion ๐ฎ times some real number sigma. In particular, note that ๐ฎ^2 = -1, so that it acts like the imaginary unit, which means we already know how to exponentiate it:","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"exp(๐ฎ sigma) = cossigma + ๐ฎ sinsigma","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Note that the inverse of the result can be obtained simply by negating the argument, as usual.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Much as with standard three-dimensional space, we could introduce a generalization of spherical coordinates, though we use a slight variant: extended Euler coordinates. We will see below how to interpret these as a series of rotations. For now, we simply state the relation:","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\nR = sqrtW^2 + X^2 + Y^2 + Z^2 in 0 infty) \nalpha = arctanfracZW + arctanfrac-XY in 0 2pi) \nbeta = 2arccossqrtfracW^2+Z^2W^2+X^2+Y^2+Z^2 in 0 2pi \ngamma = arctanfracZW - arctanfrac-XY in 0 2pi)\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"where we again assume the arctan in the expressions for alpha and gamma is really the two-argument form that gives the correct quadrant. Note that here, beta ranges up to 2pi rather than just pi, as in the standard Euler angles. This is because we are describing the space of quaternions, rather than just the space of rotations. If we restrict to R=1, we have exactly the group of unit quaternions mathrmSpin(3)=mathrmSU(2), which is a double cover of the rotation group mathrmSO(3). This extended range for beta is necessary to cover the entire space of quaternions; if we further restrict to 0 pi), we would only cover the space of rotations. This and the inclusion of R identify precisely how this coordinate system extends the standard Euler angles.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The inverse transformation is given by","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\n W = R cosfracฮฒ2 cosfracฮฑ+ฮณ2 \n X = -R sinfracฮฒ2 sinfracฮฑ-ฮณ2 \n Y = R sinfracฮฒ2 cosfracฮฑ-ฮณ2 \n Z = R cosfracฮฒ2 sinfracฮฑ+ฮณ2\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"As with the spherical coordinates, we can use this to find the components of the metric in our extended Euler coordinates:","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"g_ij\n= sum_ij fracpartial X^ipartial X^i fracpartial X^jpartial X^j g_ij\n= left( beginarraycccc\n 1 0 0 0 \n 0 fracR^24 0 fracR^2 cosbeta4 \n 0 0 fracR^24 0 \n 0 fracR^2 cosbeta4 0 fracR^24\nendarray right)_ij","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Again, integration involves a square-root of the determinant of the metric, which reduces to R^3 sinbeta 8. Note that โ€” unlike with standard spherical coordinates โ€” the absolute value is necessary because beta ranges over the entire interval 0 2pi. The integral over the entire space of quaternions is then","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"int_mathbbR^4 f d^4๐\n= int_-infty^infty int_-infty^infty int_-infty^infty int_-infty^infty f dW dX dY dZ\n= int_0^infty int_0^2pi int_0^2pi int_0^2pi f fracR^38 sin ฮฒ dR dฮฑ dฮฒ dฮณ","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Restricting to the unit sphere, and normalizing so that the integral of 1 over the sphere is 1, we can simplify this to","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"int_mathrmSpin(3) f d^3Omega\n= frac116pi^2 int_0^2pi int_0^2pi int_0^2pi f sin ฮฒ dฮฑ dฮฒ dฮณ","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Finally, restricting to the space of rotations, we can further simplify this to","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"int_mathrmSO(3) f d^3Omega\n= frac18pi^2 int_0^2pi int_0^pi int_0^2pi f sin ฮฒ dฮฑ dฮฒ dฮณ","category":"page"},{"location":"conventions/conventions/#Rotations","page":"Conventions","title":"Rotations","text":"","category":"section"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"We restrict to a unit quaternion ๐‘, for which W^2 + X^2 + Y^2 + Z^2 = 1. Given this constraint we can, without loss of generality, write the quaternion as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐‘\n= expleft(fracrho2 hatmathfrakrright)\n= cosfracrho2 + sinfracrho2 hatmathfrakr","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"where rho is an angle of rotation and hatmathfrakr is a unit \"pure-vector\" quaternion. We can multiply a vector ๐ฏ as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐‘ ๐ฏ ๐‘^-1","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Splitting ๐ฏ = ๐ฏ_ + ๐ฏ_ into components perpendicular and parallel to hatmathfrakr, we see that ๐ฏ_ commutes with ๐‘ and ๐‘^-1, while ๐ฏ_ anticommutes with hatmathfrakr. To find the full rotation, we expand the product:","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"beginaligned\n๐‘ ๐ฏ ๐‘^-1\n= ๐ฏ_\n + left(cosfracrho2 + sinfracrho2 hatmathfrakrright)\n ๐ฏ_\n left(cosfracrho2 - sinfracrho2 hatmathfrakrright) \n= ๐ฏ_\n + left(cosfracrho2 ๐ฏ_ + sinfracrho2 hatmathfrakr ๐ฏ_right)\n left(cosfracrho2 - sinfracrho2 hatmathfrakrright) \n= ๐ฏ_\n + cos^2fracrho2 ๐ฏ_ + sinfracrho2 cosfracrho2 hatmathfrakr ๐ฏ_\n - sinfracrho2 cosfracrho2 ๐ฏ_ hatmathfrakr - sin^2fracrho2 hatmathfrakr ๐ฏ_ hatmathfrakr \n= ๐ฏ_\n + cos^2fracrho2 ๐ฏ_ + sinfracrho2 cosfracrho2 hatmathfrakr ๐ฏ_ - sin^2fracrho2 ๐ฏ_ \n= ๐ฏ_\n + cosrho ๐ฏ_ + sinrho hatmathfrakrtimes ๐ฏ_\nendaligned","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The final expression shows that this is precisely what we expect when rotating ๐ฏ through an angle rho (in a positive, right-handed sense) about the axis hatmathfrakr.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Note that the presence of two factors of ๐‘ in the expression for rotating a vector explains two things. First, it explains why the angle of rotation is twice the angle of the quaternion: one factor of ๐‘ either commutes and cancels or anti-commutes and combines with the the other factor. Second, it explains why the quaternion group is a double cover of the rotation group: negating ๐‘ results in the same rotation. Thus, for any rotation, there are two (precisely opposite) quaternions that represent it.","category":"page"},{"location":"conventions/conventions/#Euler-angles-and-spherical-coordinates","page":"Conventions","title":"Euler angles and spherical coordinates","text":"","category":"section"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Now that we understand how rotations work, we can provide geometric intuition for the expressions given above for Euler angles. The Euler angles in our convention represent an initial rotation through gamma about the ๐ณ axis, followed by a rotation through beta about the ๐ฒ axis, and finally a rotation through alpha about the ๐ณ axis. Note that the axes are fixed, and not subject to any preceding rotations. More precisely, we can write the unit quaternion as","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"๐‘ = expleft(fracalpha2 ๐คright)\n expleft(fracbeta2 ๐ฃright)\n expleft(fracgamma2 ๐คright)","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"One of the more important interpretations of a rotor is considering what it does to the basis triad (๐ฑ ๐ฒ ๐ณ). In particular, the vector ๐ณ is rotated onto the point given by spherical coordinates (theta phi) = (beta alpha), while ๐ฑ and ๐ฒ are rotated into the plane spanned by the unit basis vectors boldsymboltheta and boldsymbolphi corresponding to that point. If gamma = 0 the rotation is precise, meaning that ๐ฑ is rotated onto boldsymboltheta and ๐ฒ onto boldsymbolphi; if gamma 0 then they are rotated within that plane by the angle gamma about the mathbfr axis. Thus, we identify the spherical coordinates (theta phi) with the Euler angles (alpha beta gamma) = (phi theta 0).","category":"page"},{"location":"conventions/conventions/#Rotation-and-angular-momentum-operators","page":"Conventions","title":"Rotation and angular-momentum operators","text":"","category":"section"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"We have defined the spaces mathrmSpin(3) = mathrmSU(2) (topologically S^3), mathrmSO(3) (topologically mathbbRP^3), and S^2. Specifically, we have constructed each of those spaces starting with Cartesian coordinates and the Euclidean norm on mathbbR^3, which naturally supplies coordinates on each of those spaces. We will define functions from these spaces (and their corresponding coordinates) to the complex numbers. However, to construct and classify those functions, we will need to define operators on them. We will start with operators transforming them by finite rotations, then differentiate those operators to get the angular-momentum operators.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"Start with finite rotations โ€” both left and right translations\nnote the signs; these give us the signs\nThen, we differentiate those finite rotations, generating rotation of a function by exponentiating a generator giving finite rotation; this lets us set some signs\nExpress angular momentum operators in terms of quaternion components\nBasic Lie definition\nProperties: form a Lie algebra with the commutator as the Lie bracket\n\nExpress angular momentum operators in terms of Euler angles\nWe just rewrite the R in the Lie definitions in terms of Euler angles, multiply by exp(theta2), rederive the new Euler angles from that result, and use the chain rule\nShow for both the three- and two-spheres\nShow how they act on functions on the three-sphere","category":"page"},{"location":"conventions/conventions/#Angular-momentum-operators-in-Euler-angles","page":"Conventions","title":"Angular-momentum operators in Euler angles","text":"","category":"section"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"The idea here is to express, e.g., e^theta mathbfe_i 2mathbfR_alpha beta gamma in quaternion components, then solve for the new Euler angles mathbfR_alpha beta gamma in terms of the quaternion components, where these new angles all depend on theta. We then use the chain rule to express partial_theta in terms of partial_alpha, etc., which become partial_alpha, etc., when theta=0.","category":"page"},{"location":"conventions/conventions/","page":"Conventions","title":"Conventions","text":"\nbeginalign\n L_i f(mathbfR)\n =\n left -mathbfz fracpartial partial theta f left( e^theta mathbfe_i 2 mathbfR_alpha beta gamma right) right_theta=0 \n =\n left -mathbfz fracpartial partial theta f left( mathbfR_alpha beta gamma right) right_theta=0 \n =\n left -mathbfz left fracpartial alpha partial thetafracpartial partial alpha + fracpartial beta partial thetafracpartial partial beta + fracpartial gamma partial thetafracpartial partial gamma right f left( mathbfR_alpha beta gamma right) right_theta=0 \n =\n -mathbfz left fracpartial alpha partial thetafracpartial partial alpha + fracpartial beta partial thetafracpartial partial beta + fracpartial gamma partial thetafracpartial partial gamma right_theta=0 f left( mathbfR_alpha beta gamma right) \n K_i f(mathbfR)\n =\n -mathbfz left fracpartial alpha partial thetafracpartial partial alpha + fracpartial beta partial thetafracpartial partial beta + fracpartial gamma partial thetafracpartial partial gamma right_theta=0 f left( mathbfR_alpha beta gamma right)\nendalign","category":"page"},{"location":"notes/sampling_theorems/#Sampling-theorems-and-transformations-of-spin-weighted-spherical-harmonics","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"","category":"section"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"McEwen and Wiaux [13] (MW) provide a very thorough review of the literature on sampling theorems related to spin-weighted spherical harmonics up to 2011. Reinecke and Seljebotn [3] (RS) outlined one of the more efficient and accurate implementations of spin-weighted spherical harmonic transforms (sSHT) currently available as libsharp, but their algorithm is 4Lยฒ, whereas McEwen and Wiaux's is2Lยฒ, while Elahi et al. [2] (EKKM) have obtained the optimal result that scales as Lยฒ.","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"The downside of the EKKM algorithm is that the ฮธ values at which to sample have to be obtained by iteratively minimizing the condition numbers of various matrices (which are involved in the computation itself). This expensive step only has to be performed once per choice of spin s and maximum โ„“ value L. Otherwise, the results of this algorithm seem to be relatively good โ€” at least for L up to 64. This does not compare favorably with the MW algorithm, which has slowly growing errors through L = 4096.","category":"page"},{"location":"notes/sampling_theorems/#EKKM-analysis","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"EKKM analysis","text":"","category":"section"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"The EKKM analysis looks like the following (with some notational changes). We begin by defining","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":" _stildef_theta(m) = int_0^2pi _sf(theta phi) e^-imphi dphi","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"We will denote the vector of these quantities for all values of theta as _stildemathbff_m. Inserting the _sY_ellm expansion for _sf(theta phi), and performing the integration using orthogonality of complex exponentials, we can find that","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":" _stildef_theta(m) = (-1)^s 2pi sum_ell=Delta^L sqrtfrac2ell+14pi d_m-s^ell(theta) _sf_ellm","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"Now, denoting the vector of _sf_ellm for all values of ell as _smathbff_m, we can write this as a matrix-vector equation:","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":" _stildemathbff_m = (-1)^s 2pi _smathbfd_m _smathbff_m","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"We are effectively measuring the _stildemathbff_m values, we can easily construct the _smathbfd_m matrix, and we are seeking the _smathbff_m values, so we can just invert this equation to solve for the latter.","category":"page"},{"location":"notes/sampling_theorems/#Discretizing-the-Fourier-transform","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Discretizing the Fourier transform","text":"","category":"section"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"Now, the only flaw in this analysis is that we have undersampled everywhere except ell = L, which means that the second equation (re-expressing the Fourier transforms as a sum using orthogonality of complex exponentials) isn't quite right; in general there is some folding due to aliasing of higher-frequency modes, so we need an additional sum over mm. Or perhaps more precisely, the first equation isn't actually what we implement. It should look more like this:","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":" _stildef_j(m) = sum_k=0^2j _sf(theta_j phi_k) e^-imphi_k Delta phi","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"where phi_k = frac2pi k2j+1, and Delta phi = frac2pi2j+1. (Recall the subtle notational distinction common in time-frequency analysis that tildes(t_j) = Delta t tildes_j, which would suggest we use _stildef_j(m) = Delta phi _stildef_jm.) Next, we can insert the expansion for _sf(theta phi):","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"beginaligned\n _stildef_j(m)\n = sum_k=0^2j sum_ellm _sf_ellm _sY_ellm(theta_j phi_k) e^-imphi_k Delta phi \n = sum_k=0^2j sum_ellm _sf_ellm (-1)^s sqrtfrac2ell+14pi d_ell^m-s(theta_j) e^i m phi_k e^-imphi_k frac2pi2j+1 \n = (-1)^s frac2pi2j+1 sum_ellm _sf_ellm sqrtfrac2ell+14pi d_ell^m-s(theta_j) sum_k=0^2je^i (m-m) phi_k\nendaligned","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"We can evaluate this last sum easily:","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":" sum_k=0^2je^i (m-m) phi_k = begincases\n 2j+1 m-m = n(2j+1) mathrmfor ninmathbbZ \n 0 mathrmotherwise\n endcases","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"This allows us to simplify as","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"beginaligned\n _stildef_j(m) = (-1)^s 2pi sum_ellm _sf_ellm sqrtfrac2ell+14pi d_ell^m-s(theta_j)\nendaligned","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"where m ranges over m + n(2j+1) for all nin mathbbZ such that m + n(2j+1) leq ell โ€”ย that is, all nin mathbbZ such that","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":" left lceil frac-ell-m2j+1 right rceil leq n leq left lfloor fracell-m2j+1 right rfloor","category":"page"},{"location":"notes/sampling_theorems/#Matrix-representation","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Matrix representation","text":"","category":"section"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"Usually, we would take the sum over ell ranging from mathrmmax(ms) to L, and the sum over m ranging over m + n(2j+1) for all nin mathbbZ such that m + n(2j+1) leq ell. However, we can also consider these sums to range over all possible values of ell m, and just set the coefficient to zero whenever these conditions are not satisfied. In that case, we can again think of this as a (much larger) vector-matrix equation reading","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":" _stildemathbff = (-1)^s 2pi _smathbfd _smathbff","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"where the index on _stildemathbff loops over j and m, the index on _smathbff loops over ell and m, and the indices on _smathbfd loop over each of those pairs.","category":"page"},{"location":"notes/sampling_theorems/#De-aliasing","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"De-aliasing","text":"","category":"section"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"While it is far simpler to simply invert the full _smathbfd matrix, its size scales as L^4, which means that it very quickly becomes impractical to store and manipulate the full matrix. In CMB astronomy, for example, it is not uncommon to use L into the tens of thousands, which would make the full matrix utterly impractical to use.","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"However, the matrix has a fairly sparse structure, with the number of nonzero elements scaling as L^3. More particularly, the sparsity has a fairly special structure, where the full matrix is mostly block diagonal, along with some sparse upper triangular elements. Of course, the goal is to solve the linear equation. For that, the first obvious choice is an LU decomposition. Unfortunately, the L and U components are not sparse. A second obvious choice is the QR decomposition, which is more tailored to the structure of this matrix โ€” the Q factor being essentially just the block diagonal, and the R factor being a somewhat less sparse upper triangle.","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"In principle, this alone could delay the impracticality threshold โ€” though still not enough for CMB astronomy. We can use the unusual structure to solve the linear equation in a more piecewise fashion, with fairly low memory overhead. Essentially, we start with the highest-k values, and solve for the corresponding highest-m values. Those harmonics will alias to other frequencies in theta_j rings with j k. But crucially, we know how they alias, and can simply remove them from the Fourier transforms of those rings. We then repeat, solving for the next-highest k values, and so on.","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"The following pseudo-code summarizes the analysis algorithm, modifying the input in place:","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"# Iterate over rings, doing Fourier decompositions on each\nfor j โˆˆ abs(s):โ„“โ‚˜โ‚โ‚“\n fft!(โ‚›f[j]) # Perform in-place FFT\n fftshift!(โ‚›f[j]) # Cycle order of FFT elements in place to match order of modes\n โ‚›f[j] *= 2ฯ€ / (2j+1) # Change normalization\nend\n\nfor m โˆˆ AlternatingCountdown(โ„“โ‚˜โ‚โ‚“) # Iterate over +m, then -m, down to m=0\n ฮ” = max(abs(s), abs(m))\n\n # Gather the `m` data from each ring into a temporary workspace\n for j โˆˆ ฮ”:โ„“โ‚˜โ‚โ‚“\n โ‚›fโ‚˜[j] = โ‚›f[Yindex(j, m, abs(s))]\n end\n\n # Solve for the mode weights from the Fourier components\n โ‚›fฬƒโ‚˜[ฮ”:โ„“โ‚˜โ‚โ‚“] = โ‚›ฮ›[m] \\ โ‚›fโ‚˜[ฮ”:โ„“โ‚˜โ‚โ‚“]\n\n # Distribute the data back into the output\n for โ„“ โˆˆ ฮ”:โ„“โ‚˜โ‚โ‚“\n โ‚›f[Yindex(โ„“, m, abs(s))] = โ‚›fฬƒโ‚˜[โ„“]\n end\n\n # De-alias Fourier components from rings with values of j < ฮ”\n for jโ€ฒ โˆˆ abs(s):m-1\n mโ€ฒ = mod(jโ€ฒ+m, 2jโ€ฒ+1)-jโ€ฒ # `m` aliases into `(jโ€ฒ, mโ€ฒ)`\n ฮฑ = 2ฯ€ * sum(\n ๐’ฏ.โ‚›fฬƒโ‚˜[โ„“] * โ‚›ฮปโ‚—โ‚˜\n for (โ„“, โ‚›ฮปโ‚—โ‚˜) โˆˆ zip(ฮ”:โ„“โ‚˜โ‚โ‚“, ฮป_iterator(๐’ฏ.ฮธ[jโ€ฒ], s, m))\n )\n โ‚›f[Yindex(jโ€ฒ, mโ€ฒ, abs(s))] -= ฮฑ\n end\n\nend","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"The following pseudo-code summarizes the synthesis algorithm, modifying the input in place:","category":"page"},{"location":"notes/sampling_theorems/","page":"Sampling theorems and transformations of spin-weighted spherical harmonics","title":"Sampling theorems and transformations of spin-weighted spherical harmonics","text":"for m โˆˆ AlternatingCountup(โ„“โ‚˜โ‚โ‚“) # Iterate over +m, then -m, up from m=0\n ฮ” = max(abs(s), abs(m))\n\n # Iterate over rings, combining contributions for this `m` value\n for j โˆˆ ฮ”:โ„“โ‚˜โ‚โ‚“\n # We will accumulate into ๐’ฏ.โ‚›fโ‚˜, and write it out at the end of the loop\n โ‚›fโ‚˜[j] = false\n\n # Direct (non-aliased) contributions from mโ€ฒ == m\n ฮป = ฮป_iterator(๐’ฏ.ฮธ[j], s, m)\n for (โ„“, โ‚›ฮปโ‚—โ‚˜) โˆˆ zip(ฮ”:โ„“โ‚˜โ‚โ‚“, ฮป)\n โ‚›fโ‚˜[j] += โ‚›fฬƒ[Yindex(โ„“, m, abs(s))] * โ‚›ฮปโ‚—โ‚˜\n end\n\n # Aliased contributions from |mโ€ฒ| > j > |m|\n for โ„“โ€ฒ โˆˆ j:โ„“โ‚˜โ‚โ‚“\n for n โˆˆ cld(-โ„“โ€ฒ-m, 2j+1):fld(โ„“โ€ฒ-m, 2j+1)\n mโ€ฒ = m + n*(2j+1)\n if abs(mโ€ฒ) > j\n โ‚›ฮปโ‚—โ€ฒโ‚˜โ€ฒ = โ‚›ฮ›[mโ€ฒ][j,โ„“โ€ฒ]\n ๐’ฏ.โ‚›fโ‚˜[j] += โ‚›fฬƒ[Yindex(โ„“โ€ฒ, mโ€ฒ, abs(s))] * โ‚›ฮปโ‚—โ€ฒโ‚˜โ€ฒ\n end\n end\n end\n\n end # j\n\n # Distribute the data back into the output\n @threads for j โˆˆ ฮ”:โ„“โ‚˜โ‚โ‚“\n โ‚›fฬƒ[Yindex(j, m, abs(s))] = ๐’ฏ.โ‚›fโ‚˜[j]\n end\n\nend # m\n\n# Iterate over rings, doing Fourier decompositions on each\nfor j โˆˆ abs(s):โ„“โ‚˜โ‚โ‚“\n ifftshift!(โ‚›fฬƒ[j]) # Cycle order of modes in place to match order of FFT elements\n bfft!(โ‚›fฬƒโฑผ[j]) # Perform in-place BFFT\nend","category":"page"},{"location":"notes/H_recursions/#Algorithm-for-computing-H","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"The H array, as given by Gumerov and Duraiswami [8], is related to Wigner's (small) d matrices โ€” which is itself related to the (big) mathfrakD matrices and the various spin-weighted spherical harmonics _sY_ellm โ€” via","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"d_ell^mm = epsilon_m epsilon_-m H_ell^mm","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"where","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"epsilon_k =\n begincases\n 1 kleq 0 \n (-1)^k k 0\n endcases","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"H has various advantages over d, including the fact that it can be efficiently and robustly valculated via recurrence relations, and the following symmetry relations:","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"beginaligned\n H^m m_n(ฮฒ) = H^m m_n(ฮฒ) \n H^m m_n(ฮฒ) = H^-m -m_n(ฮฒ) \n H^m m_n(ฮฒ) = (-1)^n+m+m H^-m m_n(ฯ€ - ฮฒ) \n H^m m_n(ฮฒ) = (-1)^m+m H^m m_n(-ฮฒ)\nendaligned","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Because of these symmetries, we only need to evaluate at most 1/4 of all the elements.","category":"page"},{"location":"notes/H_recursions/#Steps-to-compute-H","page":"Algorithm for computing H","title":"Steps to compute H","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"The following describes various details that are not spelled out correctly by Gumerov and Duraiswami [8]. All equation numbers refer to that paper.","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Because of the symmetries noted above, we only compute H^m m_n with m m โ€” roughly one quarter of all possible values. Furthermore, for computations of spin-weighted spherical harmonics of weight s, we only need to compute values with m s, which constitutes a dramatic savings when s โ„“โ‚˜โ‚โ‚“. The data are stored in the array Hwedge.","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"However, some parts of this calculation require calculating terms with m=n+1 โ€” whereas such elements of d and mathfrakD are considered zero. For this purpose, we need additional storage. Rather than allocating extra space, or requiring some additional workspace to be passed in, we can actually use parts of the input H data space for temporary storage while these extra terms are needed, which is before those parts of the storage are needed. Specifically, we need this additional storage for H^0 m_n_mathrmmax+1 with m in 0 n_mathrmmax+1, and we can use the storage destined for H^-1 m_n_mathrmmax with m in 1 n_mathrmmax. But this leaves two more indices, which we just store as individual variables โ€” Hฮฉ and Hฮจ โ€” representing the last and second-to-last of these additional elements stored.","category":"page"},{"location":"notes/H_recursions/#Step-1","page":"Algorithm for computing H","title":"Step 1","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Set H_0^00=1.","category":"page"},{"location":"notes/H_recursions/#Step-2","page":"Algorithm for computing H","title":"Step 2","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Compute values H^0m_n(ฮฒ) for m=0ldotsn and H^0m_n+1(ฮฒ) for m=0ldotsn+1. Using Eq. (32), we see that within Gumerov and Duraiswami's conventions","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"beginaligned\n H^0m_n(ฮฒ) = (-1)^m sqrtfrac(n-m)(n+m) P^m_n(cos ฮฒ) \n = frac1sqrtk_m (2n+1) P_nm(cos ฮฒ)\nendaligned","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Here, k_0=1 and k_m=2 for m0, and P is defined as","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":" P_nm = sqrtfrack_m(2n+1)(n-m)(n+m) P_nm","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Note that the factor of (-1)^m in the first equation above is different from the convention used here, and is related to the Condon-Shortley phase. Note that Gumerov and Duraiswami use the notation P^m_n, whereas we are using the notation P_nm โ€” which usually differ by a factor of (-1)^m.","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"We use the \"fully normalized\" associated Legendre functions (fnALF) P because, as explained by Xing et al. [12], it is possible to compute these values very efficiently and accurately, while also delaying the onset of overflow and underflow.","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"The algorithm Xing et al. describe as the best for computing P is due to Belikov (1991), and is given by them as","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"beginaligned\n P_00 = 1 \n P_10 = sqrt3 cos ฮฒ \n P_11 = sqrt3 sin ฮฒ \n P_n0 = a_n cos ฮฒ P_n-10 - b_n fracsin ฮฒ2 P_n-11 \n P_nm =\n c_nm cos ฮฒ P_n-1m\n - sin ฮฒ left d_nm P_n-1m+1 - e_nm P_n-1m-1 right\nendaligned","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"where the coefficients are given by","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"beginaligned\n a_n = sqrtfrac2n+12n-1 \n b_n = sqrtfrac2(n-1)(2n+1)n(2n-1) \n c_nm = frac1n sqrtfrac(n+m)(n-m)(2n+1)2n-1 \n d_nm = frac12n sqrtfrac(n-m)(n-m-1)(2n+1)2n-1 \n e_nm = frac12n sqrtfrac22-delta_0^m-1 sqrtfrac(n+m)(n+m-1)(2n+1)2n-1\nendaligned","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Now, we can directly obtain a recurrence relation for H^0m_n = P_nm sqrtk_m (2n+1) from those expressions:","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"beginaligned\n H^00_0 = 1 \n H^00_1 = cos ฮฒ \n H^01_1 = sqrt12 sin ฮฒ \n H^00_n = cos ฮฒ H^00_n-1 - b_n sin ฮฒ H^01_n-1 \n H^0m_n =\n c_nm cos ฮฒ H^0m_n-1\n - sin ฮฒ left d_nm H^0m+1_n-1 - e_nm H^0m-1_n-1 right\nendaligned","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"where the coefficients are given by","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"beginaligned\n b_n = sqrtfracn-1n \n c_nm = frac1n sqrt(n+m)(n-m) \n d_nm = frac12n sqrt(n-m)(n-m-1) \n e_nm = frac12n sqrt(n+m)(n+m-1)\nendaligned","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Note that the coefficients all simplified (in fact, a_n disappeared), without any increase in the complexity of the recurrence relations themselves. Rewriting Belikov's algorithm explicitly in terms of the H^0m_n also allows us to avoid an extra normalization step.","category":"page"},{"location":"notes/H_recursions/#Step-3","page":"Algorithm for computing H","title":"Step 3","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Compute H^1m_n(ฮฒ) for m=1ldotsn using relation (41). Symmetry and shift of the indices allow this relation to be written as","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"b^0_n+1 H^1 m_n\n = fracb^m1_n+1 (1cos ฮฒ)2 H^0 m+1_n+1\n fracb^ m1_n+1 (1+cos ฮฒ)2 H^0 m1_n+1\n a^m_n sin ฮฒ H^0 m_n+1","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Here the constants are defined by","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"a^m_n = sqrtfrac(n+m+1)(n-m+1) (2n+1)(2n+3)","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"b^m_n = mathrmsgn(m) sqrtfrac(n-m-1)(n-m) (2n-1)(2n+1)","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Note that all values are assumed to be zero whenever m n, we use mathrmsgn(0)=1 (unlike the common convention that mathrmsgn(0)=0), and we have a^m_n = a^-m_n. Also note that these coefficients only appear in this step, and because of how they appear (specifically, because b always appears with argument n+1), we can factor out the denominators in the definitions of the constants. We obtain this simplified formula","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"H^1 m_n\n = -frac1sqrtn(n+1) left\n fracbarb^m1_n+1 (1cos ฮฒ)2 H^0 m+1_n+1\n + fracbarb^ m1_n+1 (1+cos ฮฒ)2 H^0 m1_n+1\n + bara^m_n sin ฮฒ H^0 m_n+1\n right","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"with","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"bara^m_n = sqrt(n+m+1)(n-m+1)","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"barb^m_n+1 = sqrt(n-m)(n-m+1)","category":"page"},{"location":"notes/H_recursions/#Step-4","page":"Algorithm for computing H","title":"Step 4","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Recursively compute H^m+1 m_n(ฮฒ) for m=1ldotsn1, m=mn using relation (50) resolved with respect to H^m+1 m_n:","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"d^m_n H^m+1 m_n\n = d^m1_n H^m1 m_n\n d^m1_n H^m m1_n\n + d^m_n H^m m+1_n","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"(where the last term drops out for m=n). The constants are defined by","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"d^m_n = fracmathrmsgn(m)2 sqrt(n-m)(n+m+1)","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Note that we can drop the factor of 12, and for this case only the sign is always +1.","category":"page"},{"location":"notes/H_recursions/#Step-5","page":"Algorithm for computing H","title":"Step 5","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Recursively compute H^m1 m_n(ฮฒ) for m=0ldotsn+1, m=mldotsn using relation (50) resolved with respect to H^m1 m_n:","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"d^m1_n H^m1 m_n\n = d^m_n H^m+1 m_n\n + d^m1_n H^m m1_n\n d^m_n H^m m+1_n","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"(where the last term drops out for m=n).","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"NOTE: Although Gumerov and Duraiswami specify the loop over m to start at -1, I find it necessary to start at 0, or there will be missing information. This also requires setting the H^0 -1_n components (for all n) before beginning this loop.","category":"page"},{"location":"notes/H_recursions/#Pre-computing-constants-versus-computing-on-the-fly","page":"Algorithm for computing H","title":"Pre-computing constants versus computing on the fly","text":"","category":"section"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"Each of the constants a^m_n, b^m_n, and c^m_n involves divisions and square-roots, which can be very costly to compute. It can be advantageous to pre-compute the constants, and simply index the pre-computed arrays rather than re-computing them on each recursion.","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"If we include the cost of computing all these constants in a single call to the H recurrence, it can be much cheaper to compute each constant as needed within the algorithm, rather than computing them all at once at the beginning of the algorithm โ€” but only for very small computations, such as those involving n_mathrmmax 10. Beyond this, despite the storage penalties for all those constants, it turns out to be better to pre-compute them. However, it should be noted that the fractional cost of storing the constants is sim 3n_mathrmmax compared to just storing H itself, so this will never be a very significant amount of space.","category":"page"},{"location":"notes/H_recursions/","page":"Algorithm for computing H","title":"Algorithm for computing H","text":"On the other hand, if we can pre-compute the constants just once, and store them between multiple calls to the H recurrence, then it is always advantageous to do so โ€” typically by factors of 2 or 3 in speed. The only difficulty here is ensuring that each call to the recurrence has access to the constants, which can be a little awkward when using multiple processes and/or threads. However, it should be thread safe, since we only need to read those constants within the H recurrence. All in all, I conclude that it is probably not worth the effort to maintain separate versions of the recurrence for pre-computed and on-the-fly constants.","category":"page"},{"location":"#Introduction","page":"Introduction","title":"Introduction","text":"","category":"section"},{"location":"","page":"Introduction","title":"Introduction","text":"This is a Julia package for evaluating and transforming Wigner's ๐”‡ matrices, and spin-weighted spherical harmonics _sY_ellm (which includes the ordinary scalar spherical harmonics). Because both ๐”‡ and the harmonics are most correctly considered functions on the rotation group ๐’๐Ž(3) โ€” or more generally, the spin group ๐’๐ฉ๐ข๐ง(3) that covers it โ€” these functions are evaluated directly in terms of quaternions. Concessions are also made for more standard forms of spherical coordinates and Euler angles.[1] Among other applications, those functions permit \"synthesis\" (evaluation of the spin-weighted spherical functions) of spin-weighted spherical harmonic coefficients on regular or distorted grids. This package also includes functions enabling efficient \"analysis\" (decomposition into mode coefficients) of functions evaluated on regular grids to high order and accuracy.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"These quantities are computed using recursion relations, which makes it possible to compute to very high โ„“ values. Unlike direct evaluation of individual elements, which would generally cause overflow or underflow beyond โ„“โ‰ˆ30 when using double precision, these recursion relations should be valid for far higher โ„“ values. More precisely, when using this package, Inf values appear starting at โ„“=128 for Float16, but I have not yet found any for values up to at least โ„“=1024 with Float32, and presumably far higher for Float64. BigFloat also works, and presumably will not overflow for any โ„“ value that could reasonably fit into computer memory โ€” though it is far slower. Also note that DoubleFloats will work, and achieve significantly greater accuracy (but no greater โ„“ range) than Float64. In all cases, results are typically accurate to roughly โ„“ times the precision of the input quaternion.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"The conventions for this package are mostly inherited from โ€” and are described in detail by โ€” its predecessors found here and here.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"Note that numerous other packages cover some of these use cases, including FastTransforms.jl, FastSphericalHarmonics.jl, WignerSymbols.jl, and WignerFamilies.jl. However, I need support for quaternions (via Quaternionic.jl) and for higher-precision numbers โ€” even at the cost of a very slight decrease in speed in some cases โ€” which are what this package provides.","category":"page"},{"location":"","page":"Introduction","title":"Introduction","text":"[1]: Euler angles are quite generally a very poor choice for computing with rotations. (The only context in which they may be preferred is when analytically integrating some analytically known functions.) Almost universally, it is best to use quaternions when computing with rotations. All the computations done within this package use quaternions; the user interfaces involving Euler angles essentially convert to/from quaternions. While the calculations needed for those conversions would still need to be done if this package used Euler angles internally โ€” meaning that this approach is as efficient as any โ€” that work can be avoided entirely if you work with quaternions directly.","category":"page"}] } diff --git a/previews/PR49/transformations/index.html b/previews/PR49/transformations/index.html index e583aad..b04616d 100644 --- a/previews/PR49/transformations/index.html +++ b/previews/PR49/transformations/index.html @@ -1,2 +1,2 @@ -s-SHT Transformations ยท SphericalFunctions.jl

$s$-SHT Transformations

One important capability of this package is the transformation between the two representations of a spin-weighted spherical function:

  1. Values f of the function evaluated on a set of points or "pixels" in the domain of the function.
  2. Values fฬƒ of the mode weights (coefficients) of an expansion in the standard spin-weighted spherical-harmonic basis.

In the literature, the transformation f โ†ฆ fฬƒ is usually called "analysis" or map2salm, while the inverse transformation f โ†ฆ fฬƒ is called "synthesis" or salm2map. These are both referred to as spin-spherical-harmonic transforms, or $s$-SHTs.

To describe the values of a spin-$s$ function up to some maximum angular resolution $\ell_\mathrm{max}$, we need $(\ell_\mathrm{max}+1)^2 - s^2$ mode weights. We assume throughout that the values fฬƒ are stored as

fฬƒ = [mode_weight(โ„“, m) for โ„“ โˆˆ abs(s):โ„“โ‚˜โ‚โ‚“ for m โˆˆ -โ„“:โ„“]

(Here, mode_weight is a made-up function intended to provide a schematic.) In particular, the $m$ index varies most rapidly, and the $\ell$ index varies most slowly. Correspondingly, there must be at least $(\ell_\mathrm{max}+1)^2 - s^2$ function values f. However, some $s$-SHT algorithms require more function values โ€” usually by a factor of 2 or 4 โ€” trading off between speed and memory usage.

The SSHT object implements these transformations, storing pre-computed constants and pre-allocated workspace for the transformations. The interface is designed to be similar to that of FFTW.jl, whereby an SSHT object ๐’ฏ can be used to perform the transformation as either

f = ๐’ฏ * fฬƒ

or

fฬƒ = ๐’ฏ \ f

Currently, there are three algorithms implemented, each having different advantages and disadvantages:

  1. The "Direct" algorithm (introduced here for the first time), which is the default, but should only be used up to $\ell_\mathrm{max} \lesssim 50$ because its intermediate storage requirements scale as $\ell_\mathrm{max}^4$. This algorithm is the fastest for small $\ell_\mathrm{max}$, it can be used with arbitrary (non-degenerate) pixelizations, and achieves optimal dimensionality.
  2. The "Minimal" algorithm due to Elahi et al. [2], with some minor improvements. This algorithm is fast and โ€” as the name implies โ€” also achieves optimal dimensionality, and its storage scales as $\ell_\mathrm{max}^3$. However, its pixelization is restricted, and its accuracy at very high $\ell_\mathrm{max}$ is not as good as the "RS" algorithm. The algorithm itself is not actually fully specified by Elahi et al., and leaves out some relatively simple improvements, so I have had to take some liberties with my interpretation.
  3. The "RS" algorithm due to Reinecke and Seljebotn [3]. This forms the basis for the libsharp and ducc.sht packages. It requires pixelizations on "iso-latitude rings", and does not achieve optimal dimensionality. However, it is very fast, and its accuracy is excellent at extremely high $\ell_\mathrm{max}$.

SSHT objects

SphericalFunctions.SSHT โ€” Method
SSHT(s, โ„“โ‚˜โ‚โ‚“; [method="Direct"], [T=Float64], [kwargs...])

Construct an SSHT object to transform between spin-weighted spherical-harmonic mode weights and function values โ€” performing an $s$-SHT.

This object behaves similarly to an AbstractFFTs.Plan object โ€” specifically in the ability to use the semantics of algebra to perform transforms. For example, if the function values are stored as a vector f, the mode weights as fฬƒ, and the SSHT as ๐’ฏ, then we can compute the function values from the mode weights as

f = ๐’ฏ * fฬƒ

or solve for the mode weights from the function values as

fฬƒ = ๐’ฏ \ f

The first dimensions of fฬƒ must index the mode weights (as usual, for โ„“โˆˆabs(s):โ„“โ‚˜โ‚โ‚“ and mโˆˆ-โ„“:โ„“) and the first index of f must index the locations at which the function is evaluated. Any following dimensions will be broadcast over. Note that certain types will broadcast using Julia threads, while others will broadcast using BLAS threads. The relevant number of threads must be set appropriately.

Certain SSHT types (currently, only Minimal and Direct) also have an option to always act in place โ€” meaning that they simply re-use the input storage, even when used in an expression like ๐’ฏ \ f. The option must be passed as the inplace argument to the constructors, and is part of the type of the resulting object. Regardless of the value of that option, for those types where the option exists, it is also possible to use mul! and ldiv! from the LinearAlgebra package to force operation in place.

Note that different algorithms require different "pixelizations", or sets of Rotors on which to evaluate the function. These can be obtained from the SSHT object using the pixels and rotors functions.

source
SphericalFunctions.pixels โ€” Function
pixels(๐’ฏ)

Return the spherical coordinates (ฮธ, ฯ•) on which the spin-weighted spherical harmonics are evaluated. See also rotors, which provides the actual Rotors on which they are evaluated.

source
SphericalFunctions.rotors โ€” Function
rotors(๐’ฏ)

Return the Rotors on which the spin-weighted spherical harmonics are evaluated. See also pixels, which provides the corresponding spherical coordinates.

source
SphericalFunctions.SSHTDirect โ€” Type
SSHTDirect(s, โ„“โ‚˜โ‚โ‚“; decomposition=LinearAlgebra.qr, T=Float64, Rฮธฯ•=golden_ratio_spiral_rotors(s, โ„“โ‚˜โ‚โ‚“, T), inplace=true)

Construct an $s$-SHT object that uses the "Direct" method; see โ‚›๐˜ for details about the method and optional arguments. Also see SSHT for general information about how to use these objects.

By default, this uses precisely optimal sampling โ€” meaning that the number of points on which the function is evaluated, represented by Rฮธฯ•, is equal to the number of modes. However, it is equally possible to evaluate on more points than there are modes. This can be useful, for example, when processing multiple fields with different spin weights; the function could be evaluated on points appropriate for the lowest value of $|s|$, and therefore could also be used to solve for fields of all other spin weights.

Note that in-place operation is possible for this type when the length of the input Rฮธฯ• is equal to the number of modes given s and โ„“โ‚˜โ‚โ‚“ โ€” and is the default behavior when possible. See SSHT for description of in-place operation.

This method is typically better than other current implementations for $โ„“โ‚˜โ‚โ‚“ โ‰ฒ 24$, both in terms of speed and accuracy. However, this advantage quickly falls away. A warning will be issued if โ„“โ‚˜โ‚โ‚“ is greater than about 64, because this method is not likely to be the most efficient or most accurate choice.

source
SphericalFunctions.SSHTMinimal โ€” Method
SSHTMinimal(s, โ„“โ‚˜โ‚โ‚“; kwargs...)

Construct a SSHTMinimal object directly. This may also be achieved by calling the main SSHT function with the same keywords, along with method="Minimal".

This object uses the algorithm described by Elahi et al.

The basic floating-point number type may be adjusted with the keyword argument T, which defaults to Float64.

The SSHs are evaluated on a series of "rings" at constant colatitude. Their locations are specified by the ฮธ keyword argument, which defaults to sorted_rings(s, โ„“โ‚˜โ‚โ‚“, T). The first element of ฮธ is the colatitude of the smallest ring (containing $2s+1$ elements), and so on to the last element of ฮธ, which is the colatitude of the largest ring (containing $2โ„“โ‚˜โ‚โ‚“+1$ elements).

Whenever T is either Float64 or Float32, the keyword arguments plan_fft_flags and plan_fft_timelimit may also be useful for obtaining more efficient FFTs. They default to FFTW.ESTIMATE and Inf, respectively. They are passed to AbstractFFTs.plan_fft.

Note that, because this algorithm achieves optimal dimensionality, the transformation will be performed in place by default. If this is not desired, pass the keyword argument inplace=false. This will cause the algorithm to copy the input and perform in-place transformation on that copy.

source
SphericalFunctions.SSHTRS โ€” Method
SSHTRS(s, โ„“โ‚˜โ‚โ‚“; kwargs...)

Construct a SSHTRS object directly. This may also be achieved by calling the main SSHT function with the same keywords, along with method="RS".

This object uses the algorithm described by Reinecke and Seljebotn.

The basic floating-point number type may be adjusted with the keyword argument T, which defaults to Float64.

The SSHs are evaluated on a series of "rings" at constant colatitude. Their locations are specified by the ฮธ keyword argument, which defaults to fejer1_rings(2โ„“โ‚˜โ‚โ‚“+1, T). If this is changed, the user should also provide the corresponding quadrature_weights argument โ€” the default being fejer1(length(ฮธ), T).

On each of these rings, an FFT is performed. To reach the band limit of $m = ยฑ โ„“โ‚˜โ‚โ‚“$, the number of points along each ring must therefore be at least $2โ„“โ‚˜โ‚โ‚“+1$, but may be greater. For example, if $2โ„“โ‚˜โ‚โ‚“+1$ does not factorize neatly into a product of small primes, it may be preferable to use $2โ„“โ‚˜โ‚โ‚“+2$ points along each ring. (In that case, whenever โ„“โ‚˜โ‚โ‚“ is 1 less than a power of 2, the number of points will be exactly a power of 2, which is usually particularly efficient.) The number of points on each ring can be modified independently, if given as a vector with the same length as ฮธ, or as a single number which is assumed to be the same for all rings.

Whenever T is either Float64 or Float32, the keyword arguments plan_fft_flags and plan_fft_timelimit may also be useful for obtaining more efficient FFTs. They default to FFTW.ESTIMATE and Inf, respectively. They are passed to AbstractFFTs.plan_fft.

source

Pixelizations

The algorithms implemented here require pixelizations. While the "Direct" algorithm can be used with arbitrary pixelizations, the "Minimal" and "RS" algorithms require more specific choices, as noted in their docstrings.

Typically, "pixelization" refers exclusively to a choice of points on the sphere ๐•Šยฒ at which to compute function values. Of course, as mentioned elsewhere, it is not technically possible to define spin-weighted functions as functions of a point on ๐•Šยฒ alone; we also need some sense of reference direction in the tangent space. Quite generally, we can define spin-weighted functions on the group ๐’๐Ž(3) or ๐’๐ฉ๐ข๐ง(3), so we will also refer to a choice of a set of points in ๐’๐ฉ๐ข๐ง(3) (which is essentially the group of unit quaternions) as a "pixelization". However, assuming spherical coordinates, a choice of coordinates on the sphere almost everywhere induces a choice of the reference direction in the tangent space, so it is almost possible to define pixelizations just in terms of points on ๐•Šยฒ. But using spherical coordinates is actually enough to fully specify the pixelization, because the degeneracies at the poles also allow us to define the reference direction.

In principle, we could be concerned about the choice of reference direction in the tangent space. That is, we might expect to care about pixelizations over ๐•Šยณ. However, we are dealing with spin-weighted functions, which are eigenfunctions of a final rotation about the reference direction. This means that once we choose any reference direction at each point, we know the function values for any other reference direction at those points. In particular, an important property of a pixelization is the condition number of the transformation matrix between the function values and the mode weights. If we rotate the reference direction at a single point, this is equivalent to multiplying the matrix by a diagonal matrix with entries of 1 everywhere except the entry corresponding to that point, where the entry is some complex phase. This does not change the condition number of the matrix, so we can ignore the choice of reference direction at every point. For other situations, where we might care about the choice of reference direction, it might be interesting to consider this work by Marc Alexa, and references therein.

Interesting discussions of various pixelizations and metrics can be found in Saff and Kuijlaars (1997) and Brauchart and Grabner (2015), as well as blog posts here and here. Note that the "equal-area" pixelizations of Healpix are very restrictiveโ€”only being available for very specific numbers of pointsโ€”and do not provide any obvious advantages over the more flexible pixelizations available here.

The various pixelizations may be computed as follows:

SphericalFunctions.clenshaw_curtis_rings โ€” Method
clenshaw_curtis_rings(N, [T=Float64])

Values of the colatitude coordinate ($ฮธ$) appropriate for quadrature by the Clenshaw-Curtis rule, using weights provided by clenshaw_curtis.

Note that the first argument to this function is N, rather than the โ„“โ‚˜โ‚โ‚“ used in some other functions. For spin-weighted spherical harmonics, you may want to use N=2โ„“โ‚˜โ‚โ‚“+1.

source
SphericalFunctions.fejer1_rings โ€” Method
fejer1_rings(N, [T=Float64])

Values of the colatitude coordinate ($ฮธ$) appropriate for quadrature by Fejรฉr's first rule, using weights provided by fejer1.

Note that the first argument to this function is N, rather than the โ„“โ‚˜โ‚โ‚“ used in some other functions. For spin-weighted spherical harmonics, you may want to use N=2โ„“โ‚˜โ‚โ‚“+1.

source
SphericalFunctions.fejer2_rings โ€” Method
fejer2_rings(N, [T=Float64])

Values of the colatitude coordinate ($ฮธ$) appropriate for quadrature by Fejรฉr's second rule, using weights provided by fejer2.

Note that the first argument to this function is N, rather than the โ„“โ‚˜โ‚โ‚“ used in some other functions. For spin-weighted spherical harmonics, you may want to use N=2โ„“โ‚˜โ‚โ‚“+1.

source
SphericalFunctions.golden_ratio_spiral_pixels โ€” Method
golden_ratio_spiral_pixels(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])

Cover the sphere ๐•Šยฒ with pixels generated by the golden-ratio spiral. Successive pixels are separated by the azimuthal angle $ฮ”ฯ• = 2ฯ€(2-ฯ†)$, and are uniformly distributed in $\cos ฮธ$.

This is also known as the "Fibonacci sphere" or "Fibonacci lattice".

Visually, this is a very reasonable-looking pixelization, with fairly uniform distance between neighbors, and approximate isotropy. No two pixels will share the same values of either $ฮธ$ or $ฯ•$. Also note that no point is present on either the North or South poles.

The returned quantity is a vector of 2-SVectors providing the spherical coordinates of each pixel. See also golden_ratio_spiral_rotors for the corresponding Rotors.

source
SphericalFunctions.sorted_ring_pixels โ€” Method
sorted_ring_pixels(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])

Cover the sphere ๐•Šยฒ with $(โ„“โ‚˜โ‚โ‚“+1)ยฒ-sยฒ$ pixels distributed in rings provided by sorted_rings; see that function's documentation for more description.

The returned quantity is a vector of 2-SVectors containing the spherical coordinates of each pixel. See also sorted_ring_rotors for the corresponding Rotors.

source
SphericalFunctions.sorted_ring_rotors โ€” Method
sorted_ring_rotors(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])

Cover the sphere ๐•Šยฒ with $(โ„“โ‚˜โ‚โ‚“+1)ยฒ-sยฒ$ pixels distributed in rings provided by sorted_rings; see that function's documentation for more description.

The returned quantity is a vector of Rotors. See also sorted_ring_rotors for the corresponding spherical coordinates.

source
SphericalFunctions.sorted_rings โ€” Method
sorted_rings(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])

Compute locations of a series of rings labelled by $j โˆˆ |s|:โ„“โ‚˜โ‚โ‚“$ (analogous to $โ„“$), where each ring will contain $k = 2j+1$ (analogous to $m$) pixels distributed evenly around the ring. These rings are then sorted, so that the ring with the most pixels ($j = โ„“โ‚˜โ‚โ‚“$) is closest to the equator, and the next-largest ring is placed just above or below the equator (depending on the sign of $s$), the next just below or above, and so on. This is generally a fairly good first guess when minimizing the condition number of matrices used to solve for mode weights from function values. In particular, I use this to initialize the Minimal algorithm, which is then fed into an optimizer to fine-tune the positions of the rings.

This function does not provide the individual pixels; it just provides the colatitude values of the rings on which the pixels will be placed. The pixels themselves are provided by sorted_ring_pixels.

source

Quadrature weights

The "RS" algorithm requires quadrature weights corresponding to the input pixelization. Though there is a working default choice, it is possible to use others. There are several that are currently implemented, along with their corresponding pixelizations:

SphericalFunctions.clenshaw_curtis โ€” Method
clenshaw_curtis(n, [T])

Compute n weights for the Clenshaw-Curtis rule, corresponding to n evenly spaced nodes from 0 to ฯ€ inclusive. That is, the nodes are located at

\[\theta_k = k \frac{\pi}{n-1} \quad k=0, \ldots, n-1.\]

This function uses Waldvogel's method.

The type T may be any AbstractFloat, but defaults to Float64.

source
SphericalFunctions.fejer1 โ€” Method
fejer1(n, [T])

Compute n weights for Fejรฉr's first rule, corresponding to n evenly spaced nodes from 0 to ฯ€ inclusive. That is, the nodes are located at

\[\theta_k = k \frac{\pi}{n-1} \quad k=0, \ldots, n-1.\]

This function uses Waldvogel's method.

The type T may be any AbstractFloat, but defaults to Float64.

source
SphericalFunctions.fejer2 โ€” Method
fejer2(n, [T])

Compute n weights for Fejรฉr's second rule, corresponding to n evenly spaced nodes between 0 and ฯ€ exclusive. That is, the nodes are located at

\[\theta_k = k \frac{\pi}{n+1} \quad k=1, \ldots, n.\]

This function uses Waldvogel's method. However, contrary to Waldvogel's notation, this routine does not include the weight corresponding to the ฯ‘=0 or ฯ€ nodes, which both have weight 0.

The type T may be any AbstractFloat, but defaults to Float64.

source
+s-SHT Transformations ยท SphericalFunctions.jl

$s$-SHT Transformations

One important capability of this package is the transformation between the two representations of a spin-weighted spherical function:

  1. Values f of the function evaluated on a set of points or "pixels" in the domain of the function.
  2. Values fฬƒ of the mode weights (coefficients) of an expansion in the standard spin-weighted spherical-harmonic basis.

In the literature, the transformation f โ†ฆ fฬƒ is usually called "analysis" or map2salm, while the inverse transformation f โ†ฆ fฬƒ is called "synthesis" or salm2map. These are both referred to as spin-spherical-harmonic transforms, or $s$-SHTs.

To describe the values of a spin-$s$ function up to some maximum angular resolution $\ell_\mathrm{max}$, we need $(\ell_\mathrm{max}+1)^2 - s^2$ mode weights. We assume throughout that the values fฬƒ are stored as

fฬƒ = [mode_weight(โ„“, m) for โ„“ โˆˆ abs(s):โ„“โ‚˜โ‚โ‚“ for m โˆˆ -โ„“:โ„“]

(Here, mode_weight is a made-up function intended to provide a schematic.) In particular, the $m$ index varies most rapidly, and the $\ell$ index varies most slowly. Correspondingly, there must be at least $(\ell_\mathrm{max}+1)^2 - s^2$ function values f. However, some $s$-SHT algorithms require more function values โ€” usually by a factor of 2 or 4 โ€” trading off between speed and memory usage.

The SSHT object implements these transformations, storing pre-computed constants and pre-allocated workspace for the transformations. The interface is designed to be similar to that of FFTW.jl, whereby an SSHT object ๐’ฏ can be used to perform the transformation as either

f = ๐’ฏ * fฬƒ

or

fฬƒ = ๐’ฏ \ f

Currently, there are three algorithms implemented, each having different advantages and disadvantages:

  1. The "Direct" algorithm (introduced here for the first time), which is the default, but should only be used up to $\ell_\mathrm{max} \lesssim 50$ because its intermediate storage requirements scale as $\ell_\mathrm{max}^4$. This algorithm is the fastest for small $\ell_\mathrm{max}$, it can be used with arbitrary (non-degenerate) pixelizations, and achieves optimal dimensionality.
  2. The "Minimal" algorithm due to Elahi et al. [2], with some minor improvements. This algorithm is fast and โ€” as the name implies โ€” also achieves optimal dimensionality, and its storage scales as $\ell_\mathrm{max}^3$. However, its pixelization is restricted, and its accuracy at very high $\ell_\mathrm{max}$ is not as good as the "RS" algorithm. The algorithm itself is not actually fully specified by Elahi et al., and leaves out some relatively simple improvements, so I have had to take some liberties with my interpretation.
  3. The "RS" algorithm due to Reinecke and Seljebotn [3]. This forms the basis for the libsharp and ducc.sht packages. It requires pixelizations on "iso-latitude rings", and does not achieve optimal dimensionality. However, it is very fast, and its accuracy is excellent at extremely high $\ell_\mathrm{max}$.

SSHT objects

SphericalFunctions.SSHT โ€” Method
SSHT(s, โ„“โ‚˜โ‚โ‚“; [method="Direct"], [T=Float64], [kwargs...])

Construct an SSHT object to transform between spin-weighted spherical-harmonic mode weights and function values โ€” performing an $s$-SHT.

This object behaves similarly to an AbstractFFTs.Plan object โ€” specifically in the ability to use the semantics of algebra to perform transforms. For example, if the function values are stored as a vector f, the mode weights as fฬƒ, and the SSHT as ๐’ฏ, then we can compute the function values from the mode weights as

f = ๐’ฏ * fฬƒ

or solve for the mode weights from the function values as

fฬƒ = ๐’ฏ \ f

The first dimensions of fฬƒ must index the mode weights (as usual, for โ„“โˆˆabs(s):โ„“โ‚˜โ‚โ‚“ and mโˆˆ-โ„“:โ„“) and the first index of f must index the locations at which the function is evaluated. Any following dimensions will be broadcast over. Note that certain types will broadcast using Julia threads, while others will broadcast using BLAS threads. The relevant number of threads must be set appropriately.

Certain SSHT types (currently, only Minimal and Direct) also have an option to always act in place โ€” meaning that they simply re-use the input storage, even when used in an expression like ๐’ฏ \ f. The option must be passed as the inplace argument to the constructors, and is part of the type of the resulting object. Regardless of the value of that option, for those types where the option exists, it is also possible to use mul! and ldiv! from the LinearAlgebra package to force operation in place.

Note that different algorithms require different "pixelizations", or sets of Rotors on which to evaluate the function. These can be obtained from the SSHT object using the pixels and rotors functions.

source
SphericalFunctions.pixels โ€” Function
pixels(๐’ฏ)

Return the spherical coordinates (ฮธ, ฯ•) on which the spin-weighted spherical harmonics are evaluated. See also rotors, which provides the actual Rotors on which they are evaluated.

source
SphericalFunctions.rotors โ€” Function
rotors(๐’ฏ)

Return the Rotors on which the spin-weighted spherical harmonics are evaluated. See also pixels, which provides the corresponding spherical coordinates.

source
SphericalFunctions.SSHTDirect โ€” Type
SSHTDirect(s, โ„“โ‚˜โ‚โ‚“; decomposition=LinearAlgebra.qr, T=Float64, Rฮธฯ•=golden_ratio_spiral_rotors(s, โ„“โ‚˜โ‚โ‚“, T), inplace=true)

Construct an $s$-SHT object that uses the "Direct" method; see โ‚›๐˜ for details about the method and optional arguments. Also see SSHT for general information about how to use these objects.

By default, this uses precisely optimal sampling โ€” meaning that the number of points on which the function is evaluated, represented by Rฮธฯ•, is equal to the number of modes. However, it is equally possible to evaluate on more points than there are modes. This can be useful, for example, when processing multiple fields with different spin weights; the function could be evaluated on points appropriate for the lowest value of $|s|$, and therefore could also be used to solve for fields of all other spin weights.

Note that in-place operation is possible for this type when the length of the input Rฮธฯ• is equal to the number of modes given s and โ„“โ‚˜โ‚โ‚“ โ€” and is the default behavior when possible. See SSHT for description of in-place operation.

This method is typically better than other current implementations for $โ„“โ‚˜โ‚โ‚“ โ‰ฒ 24$, both in terms of speed and accuracy. However, this advantage quickly falls away. A warning will be issued if โ„“โ‚˜โ‚โ‚“ is greater than about 64, because this method is not likely to be the most efficient or most accurate choice.

source
SphericalFunctions.SSHTMinimal โ€” Method
SSHTMinimal(s, โ„“โ‚˜โ‚โ‚“; kwargs...)

Construct a SSHTMinimal object directly. This may also be achieved by calling the main SSHT function with the same keywords, along with method="Minimal".

This object uses the algorithm described by Elahi et al.

The basic floating-point number type may be adjusted with the keyword argument T, which defaults to Float64.

The SSHs are evaluated on a series of "rings" at constant colatitude. Their locations are specified by the ฮธ keyword argument, which defaults to sorted_rings(s, โ„“โ‚˜โ‚โ‚“, T). The first element of ฮธ is the colatitude of the smallest ring (containing $2s+1$ elements), and so on to the last element of ฮธ, which is the colatitude of the largest ring (containing $2โ„“โ‚˜โ‚โ‚“+1$ elements).

Whenever T is either Float64 or Float32, the keyword arguments plan_fft_flags and plan_fft_timelimit may also be useful for obtaining more efficient FFTs. They default to FFTW.ESTIMATE and Inf, respectively. They are passed to AbstractFFTs.plan_fft.

Note that, because this algorithm achieves optimal dimensionality, the transformation will be performed in place by default. If this is not desired, pass the keyword argument inplace=false. This will cause the algorithm to copy the input and perform in-place transformation on that copy.

source
SphericalFunctions.SSHTRS โ€” Method
SSHTRS(s, โ„“โ‚˜โ‚โ‚“; kwargs...)

Construct a SSHTRS object directly. This may also be achieved by calling the main SSHT function with the same keywords, along with method="RS".

This object uses the algorithm described by Reinecke and Seljebotn.

The basic floating-point number type may be adjusted with the keyword argument T, which defaults to Float64.

The SSHs are evaluated on a series of "rings" at constant colatitude. Their locations are specified by the ฮธ keyword argument, which defaults to fejer1_rings(2โ„“โ‚˜โ‚โ‚“+1, T). If this is changed, the user should also provide the corresponding quadrature_weights argument โ€” the default being fejer1(length(ฮธ), T).

On each of these rings, an FFT is performed. To reach the band limit of $m = ยฑ โ„“โ‚˜โ‚โ‚“$, the number of points along each ring must therefore be at least $2โ„“โ‚˜โ‚โ‚“+1$, but may be greater. For example, if $2โ„“โ‚˜โ‚โ‚“+1$ does not factorize neatly into a product of small primes, it may be preferable to use $2โ„“โ‚˜โ‚โ‚“+2$ points along each ring. (In that case, whenever โ„“โ‚˜โ‚โ‚“ is 1 less than a power of 2, the number of points will be exactly a power of 2, which is usually particularly efficient.) The number of points on each ring can be modified independently, if given as a vector with the same length as ฮธ, or as a single number which is assumed to be the same for all rings.

Whenever T is either Float64 or Float32, the keyword arguments plan_fft_flags and plan_fft_timelimit may also be useful for obtaining more efficient FFTs. They default to FFTW.ESTIMATE and Inf, respectively. They are passed to AbstractFFTs.plan_fft.

source

Pixelizations

The algorithms implemented here require pixelizations. While the "Direct" algorithm can be used with arbitrary pixelizations, the "Minimal" and "RS" algorithms require more specific choices, as noted in their docstrings.

Typically, "pixelization" refers exclusively to a choice of points on the sphere ๐•Šยฒ at which to compute function values. Of course, as mentioned elsewhere, it is not technically possible to define spin-weighted functions as functions of a point on ๐•Šยฒ alone; we also need some sense of reference direction in the tangent space. Quite generally, we can define spin-weighted functions on the group ๐’๐Ž(3) or ๐’๐ฉ๐ข๐ง(3), so we will also refer to a choice of a set of points in ๐’๐ฉ๐ข๐ง(3) (which is essentially the group of unit quaternions) as a "pixelization". However, assuming spherical coordinates, a choice of coordinates on the sphere almost everywhere induces a choice of the reference direction in the tangent space, so it is almost possible to define pixelizations just in terms of points on ๐•Šยฒ. But using spherical coordinates is actually enough to fully specify the pixelization, because the degeneracies at the poles also allow us to define the reference direction.

In principle, we could be concerned about the choice of reference direction in the tangent space. That is, we might expect to care about pixelizations over ๐•Šยณ. However, we are dealing with spin-weighted functions, which are eigenfunctions of a final rotation about the reference direction. This means that once we choose any reference direction at each point, we know the function values for any other reference direction at those points. In particular, an important property of a pixelization is the condition number of the transformation matrix between the function values and the mode weights. If we rotate the reference direction at a single point, this is equivalent to multiplying the matrix by a diagonal matrix with entries of 1 everywhere except the entry corresponding to that point, where the entry is some complex phase. This does not change the condition number of the matrix, so we can ignore the choice of reference direction at every point. For other situations, where we might care about the choice of reference direction, it might be interesting to consider this work by Marc Alexa, and references therein.

Interesting discussions of various pixelizations and metrics can be found in Saff and Kuijlaars (1997) and Brauchart and Grabner (2015), as well as blog posts here and here. Note that the "equal-area" pixelizations of Healpix are very restrictiveโ€”only being available for very specific numbers of pointsโ€”and do not provide any obvious advantages over the more flexible pixelizations available here.

The various pixelizations may be computed as follows:

SphericalFunctions.clenshaw_curtis_rings โ€” Method
clenshaw_curtis_rings(N, [T=Float64])

Values of the colatitude coordinate ($ฮธ$) appropriate for quadrature by the Clenshaw-Curtis rule, using weights provided by clenshaw_curtis.

Note that the first argument to this function is N, rather than the โ„“โ‚˜โ‚โ‚“ used in some other functions. For spin-weighted spherical harmonics, you may want to use N=2โ„“โ‚˜โ‚โ‚“+1.

source
SphericalFunctions.fejer1_rings โ€” Method
fejer1_rings(N, [T=Float64])

Values of the colatitude coordinate ($ฮธ$) appropriate for quadrature by Fejรฉr's first rule, using weights provided by fejer1.

Note that the first argument to this function is N, rather than the โ„“โ‚˜โ‚โ‚“ used in some other functions. For spin-weighted spherical harmonics, you may want to use N=2โ„“โ‚˜โ‚โ‚“+1.

source
SphericalFunctions.fejer2_rings โ€” Method
fejer2_rings(N, [T=Float64])

Values of the colatitude coordinate ($ฮธ$) appropriate for quadrature by Fejรฉr's second rule, using weights provided by fejer2.

Note that the first argument to this function is N, rather than the โ„“โ‚˜โ‚โ‚“ used in some other functions. For spin-weighted spherical harmonics, you may want to use N=2โ„“โ‚˜โ‚โ‚“+1.

source
SphericalFunctions.golden_ratio_spiral_pixels โ€” Method
golden_ratio_spiral_pixels(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])

Cover the sphere ๐•Šยฒ with pixels generated by the golden-ratio spiral. Successive pixels are separated by the azimuthal angle $ฮ”ฯ• = 2ฯ€(2-ฯ†)$, and are uniformly distributed in $\cos ฮธ$.

This is also known as the "Fibonacci sphere" or "Fibonacci lattice".

Visually, this is a very reasonable-looking pixelization, with fairly uniform distance between neighbors, and approximate isotropy. No two pixels will share the same values of either $ฮธ$ or $ฯ•$. Also note that no point is present on either the North or South poles.

The returned quantity is a vector of 2-SVectors providing the spherical coordinates of each pixel. See also golden_ratio_spiral_rotors for the corresponding Rotors.

source
SphericalFunctions.sorted_ring_pixels โ€” Method
sorted_ring_pixels(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])

Cover the sphere ๐•Šยฒ with $(โ„“โ‚˜โ‚โ‚“+1)ยฒ-sยฒ$ pixels distributed in rings provided by sorted_rings; see that function's documentation for more description.

The returned quantity is a vector of 2-SVectors containing the spherical coordinates of each pixel. See also sorted_ring_rotors for the corresponding Rotors.

source
SphericalFunctions.sorted_ring_rotors โ€” Method
sorted_ring_rotors(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])

Cover the sphere ๐•Šยฒ with $(โ„“โ‚˜โ‚โ‚“+1)ยฒ-sยฒ$ pixels distributed in rings provided by sorted_rings; see that function's documentation for more description.

The returned quantity is a vector of Rotors. See also sorted_ring_rotors for the corresponding spherical coordinates.

source
SphericalFunctions.sorted_rings โ€” Method
sorted_rings(s, โ„“โ‚˜โ‚โ‚“, [T=Float64])

Compute locations of a series of rings labelled by $j โˆˆ |s|:โ„“โ‚˜โ‚โ‚“$ (analogous to $โ„“$), where each ring will contain $k = 2j+1$ (analogous to $m$) pixels distributed evenly around the ring. These rings are then sorted, so that the ring with the most pixels ($j = โ„“โ‚˜โ‚โ‚“$) is closest to the equator, and the next-largest ring is placed just above or below the equator (depending on the sign of $s$), the next just below or above, and so on. This is generally a fairly good first guess when minimizing the condition number of matrices used to solve for mode weights from function values. In particular, I use this to initialize the Minimal algorithm, which is then fed into an optimizer to fine-tune the positions of the rings.

This function does not provide the individual pixels; it just provides the colatitude values of the rings on which the pixels will be placed. The pixels themselves are provided by sorted_ring_pixels.

source

Quadrature weights

The "RS" algorithm requires quadrature weights corresponding to the input pixelization. Though there is a working default choice, it is possible to use others. There are several that are currently implemented, along with their corresponding pixelizations:

SphericalFunctions.clenshaw_curtis โ€” Method
clenshaw_curtis(n, [T])

Compute n weights for the Clenshaw-Curtis rule, corresponding to n evenly spaced nodes from 0 to ฯ€ inclusive. That is, the nodes are located at

\[\theta_k = k \frac{\pi}{n-1} \quad k=0, \ldots, n-1.\]

This function uses Waldvogel's method.

The type T may be any AbstractFloat, but defaults to Float64.

source
SphericalFunctions.fejer1 โ€” Method
fejer1(n, [T])

Compute n weights for Fejรฉr's first rule, corresponding to n evenly spaced nodes from 0 to ฯ€ inclusive. That is, the nodes are located at

\[\theta_k = k \frac{\pi}{n-1} \quad k=0, \ldots, n-1.\]

This function uses Waldvogel's method.

The type T may be any AbstractFloat, but defaults to Float64.

source
SphericalFunctions.fejer2 โ€” Method
fejer2(n, [T])

Compute n weights for Fejรฉr's second rule, corresponding to n evenly spaced nodes between 0 and ฯ€ exclusive. That is, the nodes are located at

\[\theta_k = k \frac{\pi}{n+1} \quad k=1, \ldots, n.\]

This function uses Waldvogel's method. However, contrary to Waldvogel's notation, this routine does not include the weight corresponding to the ฯ‘=0 or ฯ€ nodes, which both have weight 0.

The type T may be any AbstractFloat, but defaults to Float64.

source
diff --git a/previews/PR49/utilities/index.html b/previews/PR49/utilities/index.html index 88a61f0..cc215bd 100644 --- a/previews/PR49/utilities/index.html +++ b/previews/PR49/utilities/index.html @@ -1,41 +1,41 @@ -Utilities ยท SphericalFunctions.jl

Utilities

While not usually the star of the show, the following utilities can be quite helpful for actually using the rest of the code.

Complex powers

One common task we find when working with spherical functions is the computation of a range of integer powers of some complex number โ€” so much so that it can be best to pre-compute the powers and cache their values. While a naive approach is generally quite accurate, and reasonably fast, we can do a little better with a specialized routine.

SphericalFunctions.complex_powers! โ€” Method
complex_powers!(zpowers, z)

Compute integer powers of z from z^0 through z^m, recursively, where m is one less than the length of the input zpowers vector.

Note that z is assumed to be normalized, with complex amplitude approximately 1.

See also: complex_powers

source
SphericalFunctions.complex_powers โ€” Method
complex_powers(z, m)

Compute integer powers of z from z^0 through z^m, recursively.

Note that z is assumed to be normalized, with complex amplitude approximately 1.

This algorithm is mostly due to Stoer and Bulirsch in "Introduction to Numerical Analysis" (page 24) โ€” with a little help from de Moivre's formula, which is essentially exp(iฮธ)โฟ = exp(inฮธ), as well as my own alterations to deal with different behaviors in different quadrants.

There isn't usually a huge advantage to using this specialized function. If you just need a particular power, it will generally be far more efficient and just as accurate to compute either exp(iฮธ)โฟ or exp(inฮธ) explicitly. However, if you need all powers from 0 to m, this function is about 10 or 5 times faster than those options, respectively, for large m. Like those options, this function is numerically stable, in the sense that its errors are usually smaller than m times the error from machine-precision errors in the input argument โ€” or at worst about 50% larger, which occurs as the phase approaches multiples of ฯ€/2.

See also: complex_powers!

source

Sizes of and indexing into $๐”‡$, $d$, and $Y$ data

By $Y$ data, we mean anything indexed like $Y_{\ell, m}$ modes; by $D$ data, we mean anything indexed like Wigner's $\mathfrak{D}$ matrices, or special subsets of them, like the $H$ matrices.

SphericalFunctions.WignerDindex โ€” Function
WignerDindex(โ„“, mโ€ฒ, m, mโ€ฒโ‚˜โ‚โ‚“=โ„“)

Compute index into Wigner ๐”‡ matrix

See also WignerDrange and WignerDsize.

Notes

This assumes that the Wigner ๐”‡ matrix is arranged as

[
+Utilities ยท SphericalFunctions.jl

Utilities

While not usually the star of the show, the following utilities can be quite helpful for actually using the rest of the code.

Complex powers

One common task we find when working with spherical functions is the computation of a range of integer powers of some complex number โ€” so much so that it can be best to pre-compute the powers and cache their values. While a naive approach is generally quite accurate, and reasonably fast, we can do a little better with a specialized routine.

SphericalFunctions.complex_powers! โ€” Method
complex_powers!(zpowers, z)

Compute integer powers of z from z^0 through z^m, recursively, where m is one less than the length of the input zpowers vector.

Note that z is assumed to be normalized, with complex amplitude approximately 1.

See also: complex_powers

source
SphericalFunctions.complex_powers โ€” Method
complex_powers(z, m)

Compute integer powers of z from z^0 through z^m, recursively.

Note that z is assumed to be normalized, with complex amplitude approximately 1.

This algorithm is mostly due to Stoer and Bulirsch in "Introduction to Numerical Analysis" (page 24) โ€” with a little help from de Moivre's formula, which is essentially exp(iฮธ)โฟ = exp(inฮธ), as well as my own alterations to deal with different behaviors in different quadrants.

There isn't usually a huge advantage to using this specialized function. If you just need a particular power, it will generally be far more efficient and just as accurate to compute either exp(iฮธ)โฟ or exp(inฮธ) explicitly. However, if you need all powers from 0 to m, this function is about 10 or 5 times faster than those options, respectively, for large m. Like those options, this function is numerically stable, in the sense that its errors are usually smaller than m times the error from machine-precision errors in the input argument โ€” or at worst about 50% larger, which occurs as the phase approaches multiples of ฯ€/2.

See also: complex_powers!

source

Sizes of and indexing into $๐”‡$, $d$, and $Y$ data

By $Y$ data, we mean anything indexed like $Y_{\ell, m}$ modes; by $D$ data, we mean anything indexed like Wigner's $\mathfrak{D}$ matrices, or special subsets of them, like the $H$ matrices.

SphericalFunctions.WignerDindex โ€” Function
WignerDindex(โ„“, mโ€ฒ, m, mโ€ฒโ‚˜โ‚โ‚“=โ„“)

Compute index into Wigner ๐”‡ matrix

See also WignerDrange and WignerDsize.

Notes

This assumes that the Wigner ๐”‡ matrix is arranged as

[
     ๐”‡(โ„“, mโ€ฒ, m)
     for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“
     for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)
     for m โˆˆ -โ„“:โ„“
-]
source
SphericalFunctions.WignerDrange โ€” Function
WignerDrange(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)

Create an array of (โ„“, m', m) indices as in ๐”‡ array

See also WignerDsize and WignerDindex.

Notes

This assumes that the Wigner ๐”‡ matrix is arranged as

[
+]
source
SphericalFunctions.WignerDrange โ€” Function
WignerDrange(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)

Create an array of (โ„“, m', m) indices as in ๐”‡ array

See also WignerDsize and WignerDindex.

Notes

This assumes that the Wigner ๐”‡ matrix is arranged as

[
     ๐”‡(โ„“, mโ€ฒ, m)
     for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“
     for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)
     for m โˆˆ -โ„“:โ„“
-]
source
SphericalFunctions.WignerDsize โ€” Method
WignerDsize(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)

Compute total size of Wigner ๐”‡ matrix

See also WignerDrange and WignerDindex.

Notes

This assumes that the Wigner ๐”‡ matrix is arranged as

[
+]
source
SphericalFunctions.WignerDsize โ€” Method
WignerDsize(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)

Compute total size of Wigner ๐”‡ matrix

See also WignerDrange and WignerDindex.

Notes

This assumes that the Wigner ๐”‡ matrix is arranged as

[
     ๐”‡(โ„“, mโ€ฒ, m)
     for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“
     for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)
     for m โˆˆ -โ„“:โ„“
-]
source
SphericalFunctions.WignerHindex โ€” Function
WignerHindex(โ„“, mโ€ฒ, m, mโ€ฒโ‚˜โ‚โ‚“)

Index to "wedge" arrays.

See also WignerHsize and WignerHrange.

Notes

Here, it is assumed that only data with mโ‰ฅ|m'| are stored, and only corresponding values are passed. We also assume |m|โ‰คโ„“ and |m'|โ‰คโ„“. Neither of these are checked. The wedge array that this function indexes is ordered as

[
+]
source
SphericalFunctions.WignerHindex โ€” Function
WignerHindex(โ„“, mโ€ฒ, m, mโ€ฒโ‚˜โ‚โ‚“)

Index to "wedge" arrays.

See also WignerHsize and WignerHrange.

Notes

Here, it is assumed that only data with mโ‰ฅ|m'| are stored, and only corresponding values are passed. We also assume |m|โ‰คโ„“ and |m'|โ‰คโ„“. Neither of these are checked. The wedge array that this function indexes is ordered as

[
     H(โ„“, mโ€ฒ, m) for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“
     for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)
     for m โˆˆ abs(mโ€ฒ):โ„“
-]
source
SphericalFunctions.WignerHrange โ€” Function
WignerHrange(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)

Create an array of (โ„“, m', m) indices as in H array

See also WignerHsize and WignerHindex

Notes

Here, it is assumed that only data with mโ‰ฅ|m'| are stored, and only corresponding values are passed. We also assume |m|โ‰คโ„“ and |m'|โ‰คโ„“. Neither of these are checked. The wedge array that this function indexes is ordered as

[
+]
source
SphericalFunctions.WignerHrange โ€” Function
WignerHrange(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)

Create an array of (โ„“, m', m) indices as in H array

See also WignerHsize and WignerHindex

Notes

Here, it is assumed that only data with mโ‰ฅ|m'| are stored, and only corresponding values are passed. We also assume |m|โ‰คโ„“ and |m'|โ‰คโ„“. Neither of these are checked. The wedge array that this function indexes is ordered as

[
     H(โ„“, mโ€ฒ, m) for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“
     for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)
     for m โˆˆ abs(mโ€ฒ):โ„“
-]
source
SphericalFunctions.WignerHsize โ€” Method
WignerHsize(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)

Total size of array of wedges of width mโ€ฒโ‚˜โ‚โ‚“ up to โ„“โ‚˜โ‚โ‚“. If mโ€ฒโ‚˜โ‚โ‚“ is not given, it defaults to โ„“โ‚˜โ‚โ‚“.

See also WignerHrange and WignerHindex.

Notes

Here, it is assumed that only data with mโ‰ฅ|mโ€ฒ| are stored, and only corresponding values are passed. We also assume |m|โ‰คโ„“ and |mโ€ฒ|โ‰คโ„“. Neither of these are checked. The wedge array that this function indexes is ordered as

[
+]
source
SphericalFunctions.WignerHsize โ€” Method
WignerHsize(โ„“โ‚˜โ‚โ‚“, mโ€ฒโ‚˜โ‚โ‚“=โ„“โ‚˜โ‚โ‚“)

Total size of array of wedges of width mโ€ฒโ‚˜โ‚โ‚“ up to โ„“โ‚˜โ‚โ‚“. If mโ€ฒโ‚˜โ‚โ‚“ is not given, it defaults to โ„“โ‚˜โ‚โ‚“.

See also WignerHrange and WignerHindex.

Notes

Here, it is assumed that only data with mโ‰ฅ|mโ€ฒ| are stored, and only corresponding values are passed. We also assume |m|โ‰คโ„“ and |mโ€ฒ|โ‰คโ„“. Neither of these are checked. The wedge array that this function indexes is ordered as

[
     H(โ„“, mโ€ฒ, m) for โ„“ โˆˆ 0:โ„“โ‚˜โ‚โ‚“
     for mโ€ฒ โˆˆ -min(โ„“, mโ€ฒโ‚˜โ‚โ‚“):min(โ„“, mโ€ฒโ‚˜โ‚โ‚“)
     for m โˆˆ abs(mโ€ฒ):โ„“
-]
source
SphericalFunctions.Yindex โ€” Function
Yindex(โ„“, m, โ„“โ‚˜แตขโ‚™=0)

Compute index into array of mode weights

Parameters

โ„“ : int Integer satisfying โ„“โ‚˜แตขโ‚™ <= โ„“ <= โ„“โ‚˜โ‚โ‚“ m : int Integer satisfying -โ„“ <= m <= โ„“ โ„“โ‚˜แตขโ‚™ : int, optional Integer satisfying 0 <= โ„“โ‚˜แตขโ‚™. Defaults to 0.

Returns

i : int Index of a particular element of the mode-weight array as described below

See Also

Ysize : Total size of array of mode weights Yrange : Array of (โ„“, m) indices corresponding to this array

Notes

This assumes that the modes are arranged (with fixed s value) as

[
+]
source
SphericalFunctions.Yindex โ€” Function
Yindex(โ„“, m, โ„“โ‚˜แตขโ‚™=0)

Compute index into array of mode weights

Parameters

โ„“ : int Integer satisfying โ„“โ‚˜แตขโ‚™ <= โ„“ <= โ„“โ‚˜โ‚โ‚“ m : int Integer satisfying -โ„“ <= m <= โ„“ โ„“โ‚˜แตขโ‚™ : int, optional Integer satisfying 0 <= โ„“โ‚˜แตขโ‚™. Defaults to 0.

Returns

i : int Index of a particular element of the mode-weight array as described below

See Also

Ysize : Total size of array of mode weights Yrange : Array of (โ„“, m) indices corresponding to this array

Notes

This assumes that the modes are arranged (with fixed s value) as

[
     Y(s, โ„“, m)
     for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“
     for m โˆˆ -โ„“:โ„“
-]
source
SphericalFunctions.Yrange โ€” Method
Yrange(โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“)

Create an array of (โ„“, m) indices as in Y array

Parameters

โ„“โ‚˜แตขโ‚™ : int Integer satisfying 0 <= โ„“โ‚˜แตขโ‚™ <= โ„“โ‚˜โ‚โ‚“ โ„“โ‚˜โ‚โ‚“ : int Integer satisfying 0 <= โ„“โ‚˜แตขโ‚™ <= โ„“โ‚˜โ‚โ‚“

Returns

i : int Total size of array of mode weights arranged as described below

See Also

Ysize : Total size of array of mode weights Yindex : Index of a particular element of the mode weight array

Notes

This assumes that the modes are arranged (with fixed s value) as

[
+]
source
SphericalFunctions.Yrange โ€” Method
Yrange(โ„“โ‚˜แตขโ‚™, โ„“โ‚˜โ‚โ‚“)

Create an array of (โ„“, m) indices as in Y array

Parameters

โ„“โ‚˜แตขโ‚™ : int Integer satisfying 0 <= โ„“โ‚˜แตขโ‚™ <= โ„“โ‚˜โ‚โ‚“ โ„“โ‚˜โ‚โ‚“ : int Integer satisfying 0 <= โ„“โ‚˜แตขโ‚™ <= โ„“โ‚˜โ‚โ‚“

Returns

i : int Total size of array of mode weights arranged as described below

See Also

Ysize : Total size of array of mode weights Yindex : Index of a particular element of the mode weight array

Notes

This assumes that the modes are arranged (with fixed s value) as

[
     Y(s, โ„“, m)
     for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“
     for m โˆˆ -โ„“:โ„“
-]
source
SphericalFunctions.Ysize โ€” Method
Ysize(โ„“โ‚˜โ‚โ‚“)

Compute total size of array of mode weights

See Also

Yrange : Array of (โ„“, m) indices corresponding to this array Yindex : Index of a particular element of the mode weight array

Notes

This assumes that the modes are arranged (with fixed s value) as

[
+]
source
SphericalFunctions.Ysize โ€” Method
Ysize(โ„“โ‚˜โ‚โ‚“)

Compute total size of array of mode weights

See Also

Yrange : Array of (โ„“, m) indices corresponding to this array Yindex : Index of a particular element of the mode weight array

Notes

This assumes that the modes are arranged (with fixed s value) as

[
     Y(s, โ„“, m)
     for โ„“ โˆˆ โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“
     for m โˆˆ -โ„“:โ„“
-]
source
SphericalFunctions._WignerHindex โ€” Method

WignerHindex(โ„“, mโ€ฒ, m, mโ€ฒโ‚˜โ‚โ‚“)

Helper function for WignerHindex, with more constraints.

This function assumes that m โ‰ฅ |mโ€ฒ|. The main WignerHindex function uses symmetries of the H array to account for cases that violate this assumption. (But note that both that function and this one assume that |m| โ‰ค โ„“ and |mโ€ฒ| โ‰ค โ„“.)

source
SphericalFunctions.deduce_limits โ€” Function
deduce_limits(ysize, [โ„“min])

Deduce the value of (โ„“min, โ„“max) that produces $Y$ arrays of the given size.

If โ„“min is not given, it is assumed to be 0. If it is set to nothing, the smallest possible value of โ„“min will be used. However, note that this is not a well-posed problem; multiple combinations of (โ„“min, โ„“max) can give rise to $Y$ arrays of the same size.

See also Ysize

source
SphericalFunctions.theta_phi โ€” Method
theta_phi(Nฮธ, Nฯ•, [T=Float64])

Construct (theta, phi) grid in spinsfast order.

Note that this order is different from the one assumed by this package; use phi_theta for the opposite ordering.

source

Combinatorics

Spherical functions frequently involve binomial coefficients and similar terms, with arguments proportional to $โ„“$, which we aim to allow to be very large โ€” of order 1,000 or more. Unfortunately, due to combinatorical explosions, this is frequently infeasible with naive methods. Here, we collect any specialized methods that help us beat the limits.

SphericalFunctions.sqrtbinomial โ€” Method
sqrtbinomial(n, k, [T])

Evaluate the square-root of the binomial coefficient binomial(n,k) for large coefficients.

Ordinarily, when n and k are standard Int arguments, the built-in binomial function will overflow around n=66, because it results in Ints. We need much larger values. This function, which is based on a related one in SpecialFunctions.jl, returns reasonably accurate results up to n โ‰ˆ 1026 when k โ‰ˆ n/2 (which is the case of interest in many applications in this package).

Computations are carried out (and returned) in type T, which defaults to Float64.

source
+]
source
SphericalFunctions._WignerHindex โ€” Method

WignerHindex(โ„“, mโ€ฒ, m, mโ€ฒโ‚˜โ‚โ‚“)

Helper function for WignerHindex, with more constraints.

This function assumes that m โ‰ฅ |mโ€ฒ|. The main WignerHindex function uses symmetries of the H array to account for cases that violate this assumption. (But note that both that function and this one assume that |m| โ‰ค โ„“ and |mโ€ฒ| โ‰ค โ„“.)

source
SphericalFunctions.deduce_limits โ€” Function
deduce_limits(ysize, [โ„“min])

Deduce the value of (โ„“min, โ„“max) that produces $Y$ arrays of the given size.

If โ„“min is not given, it is assumed to be 0. If it is set to nothing, the smallest possible value of โ„“min will be used. However, note that this is not a well-posed problem; multiple combinations of (โ„“min, โ„“max) can give rise to $Y$ arrays of the same size.

See also Ysize

source
SphericalFunctions.theta_phi โ€” Method
theta_phi(Nฮธ, Nฯ•, [T=Float64])

Construct (theta, phi) grid in spinsfast order.

Note that this order is different from the one assumed by this package; use phi_theta for the opposite ordering.

source

Combinatorics

Spherical functions frequently involve binomial coefficients and similar terms, with arguments proportional to $โ„“$, which we aim to allow to be very large โ€” of order 1,000 or more. Unfortunately, due to combinatorical explosions, this is frequently infeasible with naive methods. Here, we collect any specialized methods that help us beat the limits.

SphericalFunctions.sqrtbinomial โ€” Method
sqrtbinomial(n, k, [T])

Evaluate the square-root of the binomial coefficient binomial(n,k) for large coefficients.

Ordinarily, when n and k are standard Int arguments, the built-in binomial function will overflow around n=66, because it results in Ints. We need much larger values. This function, which is based on a related one in SpecialFunctions.jl, returns reasonably accurate results up to n โ‰ˆ 1026 when k โ‰ˆ n/2 (which is the case of interest in many applications in this package).

Computations are carried out (and returned) in type T, which defaults to Float64.

source
diff --git a/previews/PR49/wigner_matrices/index.html b/previews/PR49/wigner_matrices/index.html index 1eb399e..ed8b648 100644 --- a/previews/PR49/wigner_matrices/index.html +++ b/previews/PR49/wigner_matrices/index.html @@ -14,7 +14,7 @@ โ„“โ‚˜โ‚โ‚“ = 8 d = d_matrices(ฮฒ, โ„“โ‚˜โ‚โ‚“)

Again, for repeated calls, it is best to pre-allocate storage:

d_storage = d_prep(โ„“โ‚˜โ‚โ‚“)
 d = d_matrices!(d_storage, ฮฒ)

The output d is a vector of numbers of the same type as ฮฒ, ordered in the same way as the output of D_matrices. And similarly, we can iterate over the individual matrices using a d_iterator.

Docstrings

SphericalFunctions.D_matrices โ€” Function
D_matrices(R, โ„“โ‚˜โ‚โ‚“)
-D_matrices(ฮฑ, ฮฒ, ฮณ, โ„“โ‚˜โ‚โ‚“)

Compute Wigner's ๐”‡ matrices $\mathfrak{D}^{(\ell)}_{m',m}(\beta)$ for all $\ell \leq \ell_\mathrm{max}$.

See D_matrices! for details about the input and output values.

This function only appropriate when you need to evaluate the matrices for a single value of R or ฮฑ, ฮฒ, ฮณ because it allocates large arrays and performs many calculations that could be reused. If you need to evaluate the matrices for many values of R or ฮฑ, ฮฒ, ฮณ, you should pre-allocate the storage with D_prep, and then call D_matrices! with the result instead.

source
SphericalFunctions.D_matrices! โ€” Function
D_matrices!(D_storage, R)
+D_matrices(ฮฑ, ฮฒ, ฮณ, โ„“โ‚˜โ‚โ‚“)

Compute Wigner's ๐”‡ matrices $\mathfrak{D}^{(\ell)}_{m',m}(\beta)$ for all $\ell \leq \ell_\mathrm{max}$.

See D_matrices! for details about the input and output values.

This function only appropriate when you need to evaluate the matrices for a single value of R or ฮฑ, ฮฒ, ฮณ because it allocates large arrays and performs many calculations that could be reused. If you need to evaluate the matrices for many values of R or ฮฑ, ฮฒ, ฮณ, you should pre-allocate the storage with D_prep, and then call D_matrices! with the result instead.

source
SphericalFunctions.D_matrices! โ€” Function
D_matrices!(D_storage, R)
 D_matrices!(D_storage, ฮฑ, ฮฒ, ฮณ)
 D_matrices!(D, R, โ„“โ‚˜โ‚โ‚“)
 D_matrices!(D, ฮฑ, ฮฒ, ฮณ, โ„“โ‚˜โ‚โ‚“)

Compute Wigner's ๐”‡ matrices $\mathfrak{D}^{(\ell)}_{m',m}(\beta)$ for all $\ell \leq \ell_\mathrm{max}$.

In all cases, the result is returned in a 1-dimensional array ordered as

[
@@ -27,14 +27,14 @@
 T = Float64
 R = Rotor{T}(1, 2, 3, 4)  # Will be normalized automatically
 D_storage = D_prep(โ„“โ‚˜โ‚โ‚“, T)
-D = D_matrices!(D_storage, R)
source
SphericalFunctions.D_prep โ€” Function
D_prep(โ„“โ‚˜โ‚โ‚“, [T=Float64])

Construct storage space and pre-compute recursion coefficients to compute Wigner's $\mathfrak{D}$ matrix in place.

This returns the D_storage arguments needed by D_matrices!.

source
SphericalFunctions.D_iterator โ€” Type
D_iterator(D, โ„“โ‚˜โ‚โ‚“, [โ„“โ‚˜แตขโ‚™])

Construct an Iterator that returns sub-matrices of D, each of which consists of elements $(โ„“,-โ„“,-โ„“)$ through $(โ„“,โ„“,โ„“)$, for $โ„“$ from โ„“โ‚˜แตขโ‚™ through โ„“โ‚˜โ‚โ‚“. By default, โ„“โ‚˜แตขโ‚™ is 0.

Inconsistent behavior

This iterator mistakenly returns the transpose of the result implied by this documentation. As a result, a warning is issued every time this function is called. Rather than actually fixing this bug in this minor/patch version โ€” which would be a breaking change โ€” this is a final release in this major version of the package to notify users of this function (and d_iterator) that there is a problem. The next major version of the package will likely change the actual behavior to the one implied by this docstring. To quiet these warnings, you can use Dit = with_logger(NullLogger()) do D_iterator(...) end.

Note that the returned objects are views into the original D data โ€” meaning that you may alter their values.

Because the result is a matrix restricted to a particular $โ„“$ value, you can index the $(โ„“, mโ€ฒ, m)$ element as [โ„“+mโ€ฒ+1, โ„“+m+1]. For example, you might use this as something like

for (โ„“, Dหก) in zip(โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“, D_iterator(D, โ„“โ‚˜โ‚โ‚“))
+D = D_matrices!(D_storage, R)
source
SphericalFunctions.D_prep โ€” Function
D_prep(โ„“โ‚˜โ‚โ‚“, [T=Float64])

Construct storage space and pre-compute recursion coefficients to compute Wigner's $\mathfrak{D}$ matrix in place.

This returns the D_storage arguments needed by D_matrices!.

source
SphericalFunctions.D_iterator โ€” Type
D_iterator(D, โ„“โ‚˜โ‚โ‚“, [โ„“โ‚˜แตขโ‚™])

Construct an Iterator that returns sub-matrices of D, each of which consists of elements $(โ„“,-โ„“,-โ„“)$ through $(โ„“,โ„“,โ„“)$, for $โ„“$ from โ„“โ‚˜แตขโ‚™ through โ„“โ‚˜โ‚โ‚“. By default, โ„“โ‚˜แตขโ‚™ is 0.

Inconsistent behavior

This iterator mistakenly returns the transpose of the result implied by this documentation. As a result, a warning is issued every time this function is called. Rather than actually fixing this bug in this minor/patch version โ€” which would be a breaking change โ€” this is a final release in this major version of the package to notify users of this function (and d_iterator) that there is a problem. The next major version of the package will likely change the actual behavior to the one implied by this docstring. To quiet these warnings, you can use Dit = with_logger(NullLogger()) do D_iterator(...) end.

Note that the returned objects are views into the original D data โ€” meaning that you may alter their values.

Because the result is a matrix restricted to a particular $โ„“$ value, you can index the $(โ„“, mโ€ฒ, m)$ element as [โ„“+mโ€ฒ+1, โ„“+m+1]. For example, you might use this as something like

for (โ„“, Dหก) in zip(โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“, D_iterator(D, โ„“โ‚˜โ‚โ‚“))
     for mโ€ฒ in -โ„“:โ„“
         for m in -โ„“:โ„“
             Dหก[โ„“+mโ€ฒ+1, โ„“+m+1]  # ... do something with Dหก
         end
     end
-end

Also note that no bounds checking is done, either at instantiation time or during iteration. You are responsible for ensuring that the size of D and the values of โ„“โ‚˜โ‚โ‚“ and โ„“โ‚˜แตขโ‚™ make sense.

source
SphericalFunctions.d_matrices โ€” Function
d_matrices(ฮฒ, โ„“โ‚˜โ‚โ‚“)
-d_matrices(expiฮฒ, โ„“โ‚˜โ‚โ‚“)

Compute Wigner's $d^{(\ell)}$ matrices with elements $d^{(\ell)}_{m',m}(\beta)$ for all $\ell \leq \ell_\mathrm{max}$. The $d$ matrices are sometimes called the "reduced" Wigner matrices, in contrast to the full $\mathfrak{D}$ matrices.

See d_matrices! for details about the input and output values.

This function only appropriate when you need to evaluate the matrices for a single value of ฮฒ or expiฮฒ because it allocates large arrays and performs many calculations that could be reused. If you need to evaluate the matrices for many values of ฮฒ or expiฮฒ, you should pre-allocate the storage with d_prep, and then call d_matrices! with the result instead.

source
SphericalFunctions.d_matrices! โ€” Function
d_matrices!(d_storage, ฮฒ)
+end

Also note that no bounds checking is done, either at instantiation time or during iteration. You are responsible for ensuring that the size of D and the values of โ„“โ‚˜โ‚โ‚“ and โ„“โ‚˜แตขโ‚™ make sense.

source
SphericalFunctions.d_matrices โ€” Function
d_matrices(ฮฒ, โ„“โ‚˜โ‚โ‚“)
+d_matrices(expiฮฒ, โ„“โ‚˜โ‚โ‚“)

Compute Wigner's $d^{(\ell)}$ matrices with elements $d^{(\ell)}_{m',m}(\beta)$ for all $\ell \leq \ell_\mathrm{max}$. The $d$ matrices are sometimes called the "reduced" Wigner matrices, in contrast to the full $\mathfrak{D}$ matrices.

See d_matrices! for details about the input and output values.

This function only appropriate when you need to evaluate the matrices for a single value of ฮฒ or expiฮฒ because it allocates large arrays and performs many calculations that could be reused. If you need to evaluate the matrices for many values of ฮฒ or expiฮฒ, you should pre-allocate the storage with d_prep, and then call d_matrices! with the result instead.

source
SphericalFunctions.d_matrices! โ€” Function
d_matrices!(d_storage, ฮฒ)
 d_matrices!(d_storage, expiฮฒ)
 d_matrices!(d, ฮฒ, โ„“โ‚˜โ‚โ‚“)
 d_matrices!(d, expiฮฒ, โ„“โ‚˜โ‚โ‚“)

Compute Wigner's $d^{(\ell)}$ matrices with elements $d^{(\ell)}_{m',m}(\beta)$ for all $\ell \leq \ell_\mathrm{max}$. The $d$ matrices are sometimes called the "reduced" Wigner matrices, in contrast to the full $\mathfrak{D}$ matrices.

In all cases, the result is returned in a 1-dimensional array ordered as

[
@@ -47,10 +47,10 @@
 T = Float64
 ฮฒ = T(1)/8
 d_storage = d_prep(โ„“โ‚˜โ‚โ‚“, T)
-d = d_matrices!(d_storage, ฮฒ)
source
SphericalFunctions.d_prep โ€” Function
d_prep(โ„“โ‚˜โ‚โ‚“, [T=Float64])

Construct space and pre-compute recursion coefficients to compute Wigner's $d$ matrix in place.

This returns the d_storage arguments needed by d_matrices!.

source
SphericalFunctions.d_iterator โ€” Type
d_iterator(d, โ„“โ‚˜โ‚โ‚“, [โ„“โ‚˜แตขโ‚™])

Construct an Iterator that returns sub-matrices of d, each of which consists of elements $(โ„“,-โ„“,-โ„“)$ through $(โ„“,โ„“,โ„“)$, for $โ„“$ from โ„“โ‚˜แตขโ‚™ through โ„“โ‚˜โ‚โ‚“. By default, โ„“โ‚˜แตขโ‚™ is 0.

Inconsistent behavior

This iterator mistakenly returns the transpose of the result implied by this documentation. As a result, a warning is issued every time this function is called. Rather than actually fixing this bug in this minor/patch version โ€” which would be a breaking change โ€” this is a final release in this major version of the package to notify users of this function (and D_iterator) that there is a problem. The next major version of the package will likely change the actual behavior to the one implied by this docstring. To quiet these warnings, you can use Dit = with_logger(NullLogger()) do D_iterator(...) end.

Note that the returned objects are views into the original d data โ€” meaning that you may alter their values.

Because the result is a matrix restricted to a particular $โ„“$ value, you can index the $(โ„“, mโ€ฒ, m)$ element as [โ„“+mโ€ฒ+1, โ„“+m+1]. For example, you might use this as something like

for (โ„“, dหก) in zip(โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“, d_iterator(d, โ„“โ‚˜โ‚โ‚“))
+d = d_matrices!(d_storage, ฮฒ)
source
SphericalFunctions.d_prep โ€” Function
d_prep(โ„“โ‚˜โ‚โ‚“, [T=Float64])

Construct space and pre-compute recursion coefficients to compute Wigner's $d$ matrix in place.

This returns the d_storage arguments needed by d_matrices!.

source
SphericalFunctions.d_iterator โ€” Type
d_iterator(d, โ„“โ‚˜โ‚โ‚“, [โ„“โ‚˜แตขโ‚™])

Construct an Iterator that returns sub-matrices of d, each of which consists of elements $(โ„“,-โ„“,-โ„“)$ through $(โ„“,โ„“,โ„“)$, for $โ„“$ from โ„“โ‚˜แตขโ‚™ through โ„“โ‚˜โ‚โ‚“. By default, โ„“โ‚˜แตขโ‚™ is 0.

Inconsistent behavior

This iterator mistakenly returns the transpose of the result implied by this documentation. As a result, a warning is issued every time this function is called. Rather than actually fixing this bug in this minor/patch version โ€” which would be a breaking change โ€” this is a final release in this major version of the package to notify users of this function (and D_iterator) that there is a problem. The next major version of the package will likely change the actual behavior to the one implied by this docstring. To quiet these warnings, you can use Dit = with_logger(NullLogger()) do D_iterator(...) end.

Note that the returned objects are views into the original d data โ€” meaning that you may alter their values.

Because the result is a matrix restricted to a particular $โ„“$ value, you can index the $(โ„“, mโ€ฒ, m)$ element as [โ„“+mโ€ฒ+1, โ„“+m+1]. For example, you might use this as something like

for (โ„“, dหก) in zip(โ„“โ‚˜แตขโ‚™:โ„“โ‚˜โ‚โ‚“, d_iterator(d, โ„“โ‚˜โ‚โ‚“))
     for mโ€ฒ in -โ„“:โ„“
         for m in -โ„“:โ„“
             dหก[โ„“+mโ€ฒ+1, โ„“+m+1]  # ... do something with dหก
         end
     end
-end

Also note that no bounds checking is done, either at instantiation time or during iteration. You are responsible for ensuring that the size of d and the values of โ„“โ‚˜โ‚โ‚“ and โ„“โ‚˜แตขโ‚™ make sense.

source
+end

Also note that no bounds checking is done, either at instantiation time or during iteration. You are responsible for ensuring that the size of d and the values of โ„“โ‚˜โ‚โ‚“ and โ„“โ‚˜แตขโ‚™ make sense.

source