2. Conventions

2.1. Doubled Quantum Numbers

Most public functions accept angular momenta and projections as doubled integers:

\[\texttt{two\_j}=2j, \qquad \texttt{two\_m}=2m.\]

Thus two_j = 1 means \(j=1/2\), two_j = 2 means \(j=1\), and two_m = -3 means \(m=-3/2\). Public parameter names use the two_ prefix whenever this convention applies.

The complete compiled example is:

 1// SPDX-License-Identifier: MIT
 2
 3/**
 4 * @file doubled_spin.cpp
 5 * @brief Example of the doubled-spin input convention.
 6 */
 7
 8#include <cmath>
 9#include <iostream>
10
11#include <wigner/wigner.hpp>
12
13namespace
14{
15    void print_spin_label(const char* name, int two_value)
16    {
17        std::cout << name << " = " << two_value << " means ";
18        if ((two_value & 1) == 0)
19        {
20            std::cout << two_value / 2;
21        }
22        else
23        {
24            std::cout << two_value << "/2";
25        }
26        std::cout << '\n';
27    }
28}
29
30int main()
31{
32    std::cout << "Doubled-spin convention examples\n";
33    print_spin_label("two_j", 1);
34    print_spin_label("two_m", -1);
35    print_spin_label("two_j", 2);
36    print_spin_label("two_m", 0);
37    std::cout << '\n';
38
39    const double three_j = wigner::wigner_3j(1, 1, 0, 1, -1, 0);
40    const double cg = wigner::clebsch_gordan(1, 1, 1, -1, 0, 0);
41
42    std::cout << "wigner_3j(1, 1, 0, 1, -1, 0) = " << three_j << '\n';
43    std::cout << "clebsch_gordan(1, 1, 1, -1, 0, 0) = " << cg << '\n';
44
45    const double expected = 1.0 / std::sqrt(2.0);
46    const bool values_match =
47        std::abs(three_j - expected) < 1.0e-12 &&
48        std::abs(cg - expected) < 1.0e-12;
49    return values_match ? 0 : 1;
50}

For a valid state, two_j is non-negative, abs(two_m) <= two_j, and two_j and two_m have the same parity. The helper valid_spin_state checks all three conditions.

2.2. Orbital Exceptions

gaunt and spherical_harmonic use ordinary integer l and m. These APIs describe orbital spherical harmonics, for which half-integer angular momentum is not meaningful. Angles are always expressed in radians.

2.3. Phase and Normalization

The package follows the Condon-Shortley convention used by Varshalovich and Edmonds. In particular,

\[\begin{split}\langle j_1m_1,j_2m_2\mid jm\rangle =(-1)^{j_1-j_2+m}\sqrt{2j+1} \begin{pmatrix} j_1&j_2&j\\m_1&m_2&-m \end{pmatrix}.\end{split}\]

The Racah-W convention is

\[\begin{split}W(abcd;ef)=(-1)^{a+b+c+d} \left\{\begin{matrix}a&b&e\\d&c&f\end{matrix}\right\}.\end{split}\]

The default three-body recoupling coefficient transforms ((j1 j2)j12, j3)J to (j1, (j2 j3)j23)J and is

\[\begin{split}(-1)^{j_1+j_2+j_3+J} \sqrt{(2j_{12}+1)(2j_{23}+1)} \left\{\begin{matrix} j_1&j_2&j_{12}\\j_3&J&j_{23} \end{matrix}\right\}.\end{split}\]

These definitions matter whenever values are compared with tables or another software package. A disagreement by a sign can indicate a convention mismatch rather than a numerical failure.

2.4. Rotations

wigner_D uses the Euler-angle factorization

\[D^j_{mn}(\alpha,\beta,\gamma) =e^{-im\alpha}d^j_{mn}(\beta)e^{-in\gamma}.\]

The reduced matrix d is real in this convention. The full matrix is complex. Euler angles are accepted as double values in radians.

2.5. Invalid Inputs and Mathematical Zeros

Public numerical functions are noexcept. A tuple that fails its spin, projection-sum, or triangle selection rules returns zero. This behavior is convenient during matrix assembly because a forbidden coupling contributes no matrix element and does not require an exception path.

Zero is not, however, a validity flag. An admissible coefficient can vanish mathematically. Use valid_spin_state, triangle_condition, and the allowed-coupling helpers when code must distinguish a forbidden tuple from an allowed zero.

2.6. Argument Order

Positional overloads follow the array displayed in each API’s documentation. The 3j, 6j, and 9j APIs also accept named argument structs. The struct form is preferable when a value is stored, passed between algorithms, or assembled from a channel label because each member keeps its role visible.

The first- and second-kind 12j functions accept only their corresponding argument structs. Their ring ordering is documented with the declarations in the API Reference chapter.