pairinteraction
A Rydberg Interaction Calculator
wigner.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2024 Pairinteraction Developers
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
4#pragma once
5
8
9#include <cassert>
10#include <cmath>
11#include <complex>
12#include <limits>
13#include <stdexcept>
14#include <type_traits>
15
17
18namespace {
19
20template <typename Real>
21inline constexpr Real PI = 3.141592653589793238462643383279502884;
22
23template <typename Real>
24inline Real wigner_uppercase_d_matrix_pi_half(Real f, Real m_initial, Real m_final) {
25 static_assert(std::is_floating_point_v<Real>);
26 assert(2 * f == std::floor(2 * f) && f >= 0);
27 assert(2 * m_initial == std::floor(2 * m_initial) && m_initial >= -f && m_initial <= f);
28 assert(2 * m_final == std::floor(2 * m_final) && m_final >= -f && m_final <= f);
29
30 Real result = 0;
31 for (int k = std::max(0, static_cast<int>(m_final - m_initial));
32 k <= f + std::min(m_final, -m_initial); ++k) {
33 result += std::pow(-1, k) * maths::binomial_coefficient(f + m_final, static_cast<Real>(k)) *
34 maths::binomial_coefficient(f - m_final, k + m_initial - m_final);
35 }
36 result *= std::pow(-1, m_initial - m_final) / std::pow(2, f) *
37 std::sqrt(maths::factorial(f + m_initial) * maths::factorial(f - m_initial) /
38 (maths::factorial(f + m_final) * maths::factorial(f - m_final)));
39 return result;
40}
41
42} // namespace
43
44template <typename Scalar>
46 typename traits::NumTraits<Scalar>::real_t m_initial,
47 typename traits::NumTraits<Scalar>::real_t m_final,
50 typename traits::NumTraits<Scalar>::real_t gamma) {
52 assert(2 * f == std::floor(2 * f) && f >= 0);
53 assert(2 * m_initial == std::floor(2 * m_initial) && m_initial >= -f && m_initial <= f);
54 assert(2 * m_final == std::floor(2 * m_final) && m_final >= -f && m_final <= f);
55
56 auto precision =
57 10 * std::numeric_limits<typename traits::NumTraits<Scalar>::real_t>::epsilon();
58
60 return Scalar(std::cos(-m_initial * alpha), std::sin(-m_initial * alpha)) *
61 wigner_uppercase_d_matrix<typename traits::NumTraits<Scalar>::real_t>(
62 f, m_initial, m_final, 0, beta, 0) *
63 Scalar(std::cos(-m_final * gamma), std::sin(-m_final * gamma));
64 } else {
65 if (std::abs(std::remainder(m_initial * alpha,
66 PI<typename traits::NumTraits<Scalar>::real_t>)) > precision) {
67 throw std::invalid_argument(
68 "The scalar type must be complex if m_initial*alpha is not a multiple of pi");
69 }
70 if (std::abs(std::remainder(m_final * gamma,
71 PI<typename traits::NumTraits<Scalar>::real_t>)) > precision) {
72 throw std::invalid_argument(
73 "The scalar type must be complex if m_final*gamma is not a multiple of pi");
74 }
75 std::complex<Scalar> result = 0;
76 for (typename traits::NumTraits<Scalar>::real_t m = -f;
77 m <= f; // NOSONAR m is precisely representable
78 ++m) {
79 result += wigner_uppercase_d_matrix_pi_half(f, m_initial, m) *
80 std::complex<typename traits::NumTraits<Scalar>::real_t>(std::cos(-m * beta),
81 std::sin(-m * beta)) *
82 wigner_uppercase_d_matrix_pi_half(f, m, -m_final);
83 }
84 result *= std::pow(std::complex<typename traits::NumTraits<Scalar>::real_t>(0, 1),
85 2 * f - m_initial - m_final) *
86 static_cast<typename traits::NumTraits<Scalar>::real_t>(std::pow(-1, 2 * m_initial));
87 return result.real();
88 }
89}
90
91} // namespace pairinteraction::wigner
Real binomial_coefficient(Real n, Real k)
Definition: maths.hpp:12
Real factorial(Real n)
Definition: maths.hpp:32
Scalar wigner_uppercase_d_matrix(typename traits::NumTraits< Scalar >::real_t f, typename traits::NumTraits< Scalar >::real_t m_initial, typename traits::NumTraits< Scalar >::real_t m_final, typename traits::NumTraits< Scalar >::real_t alpha, typename traits::NumTraits< Scalar >::real_t beta, typename traits::NumTraits< Scalar >::real_t gamma)
Definition: wigner.hpp:45
Helper struct to extract types from a numerical type.
Definition: traits.hpp:35