Quantum 3xplorer (Q3)
An AI-native quantum simulation engine
Loading...
Searching...
No Matches
harmonic_rotation.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * How real spherical harmonics, and the crystal's symmetry operations, turn
5 * into the matrices that rotate an on-site quantity's angular indices.
6 *
7 * Two consumers share this: the DFT+U occupation matrix
8 * (`effective_potential/internal/hubbard/symmetrization.hpp`) and the PAW
9 * on-site occupations (`occupation_symmetrization.hpp` beside this file).
10 * Both average an atom-resolved, angular-indexed array over the point group,
11 * and both need the same two ingredients — D^l(R) and the Cartesian form of a
12 * fractional-coordinate operation — so they are defined once here rather than
13 * in whichever module happened to need them first.
14 */
15
16#include <vector>
17
23
24namespace q3 {
25
26/**
27 * D^l(R): how the real spherical harmonics of degree `l` mix under a Cartesian
28 * rotation.
29 *
30 * D_mm'(R) = ∫ dΩ Y_lm(R r̂) Y_lm'(r̂)
31 *
32 * so that Y_lm(R r̂) = Σ_m' D_mm'(R) Y_lm'(r̂). The integrand is a product of
33 * two degree-l harmonics, so a grid exact to degree 2l integrates it exactly;
34 * `build_angular_grid` is constructed on that contract and the PAW one-center
35 * engine relies on the same property.
36 *
37 * Rows and columns are indexed by position in `harmonic_order_sequence(l)`,
38 * which is the order both the Hubbard manifolds and the expanded projector
39 * channels are laid out in.
40 *
41 * Improper operations (det R = −1) need no special handling: a degree-l real
42 * harmonic has parity (−1)^l, and evaluating at the rotated direction carries
43 * that automatically.
44 */
45[[nodiscard]] inline std::vector<Real>
46build_real_harmonic_rotation_matrix(int angular_momentum, const Matrix3x3& cartesian_rotation) {
47 int manifold_size = 2 * angular_momentum + 1;
48 std::vector<Real> rotation_matrix(static_cast<size_t>(manifold_size) * manifold_size, 0.0);
49
50 auto angular_grid = paw_one_center::build_angular_grid(2 * angular_momentum);
51 const auto& orders = harmonic_order_sequence(angular_momentum);
52
53 for (const auto& point : angular_grid) {
54 Vector3D direction{point.x, point.y, point.z};
55 Vector3D rotated{0.0, 0.0, 0.0};
56 for (int row = 0; row < 3; row++)
57 for (int column = 0; column < 3; column++)
58 rotated[row] += cartesian_rotation[row][column] * direction[column];
59
60 for (int m = 0; m < manifold_size; m++) {
61 Real rotated_harmonic =
62 compute_real_spherical_harmonic(angular_momentum, orders[m], rotated);
63 for (int m_prime = 0; m_prime < manifold_size; m_prime++) {
64 Real harmonic =
65 compute_real_spherical_harmonic(angular_momentum, orders[m_prime], direction);
66 rotation_matrix[static_cast<size_t>(m) * manifold_size + m_prime] +=
67 point.weight * rotated_harmonic * harmonic;
68 }
69 }
70 }
71 return rotation_matrix;
72}
73
74/**
75 * The Cartesian rotation of a symmetry operation stored in crystal coordinates.
76 *
77 * `SymmetryOperation::rotation` acts on fractional coordinates, so it has to be
78 * conjugated by the lattice before it can rotate a direction in space:
79 * R_cart = A ᵀ · S · (A ᵀ)^{-1} with A the matrix of lattice vectors as rows.
80 * The reciprocal lattice supplies the inverse directly, since
81 * (Aᵀ)^{-1} = B / 2π with B the reciprocal vectors as rows.
82 */
83[[nodiscard]] inline Matrix3x3 cartesian_rotation_of(const Crystal& crystal_structure,
84 const SymmetryOperation& operation) {
85 const Matrix3x3& direct = crystal_structure.lattice_vectors();
86 const Matrix3x3& reciprocal = crystal_structure.reciprocal_lattice_vectors();
87
88 Matrix3x3 cartesian{};
89 for (int row = 0; row < 3; row++) {
90 for (int column = 0; column < 3; column++) {
91 Real accumulated = 0.0;
92 for (int first = 0; first < 3; first++)
93 for (int second = 0; second < 3; second++)
94 accumulated += direct[first][row] *
95 static_cast<Real>(operation.rotation[first][second]) *
96 reciprocal[second][column];
97 cartesian[row][column] = accumulated;
98 }
99 }
100 return cartesian;
101}
102
103} // namespace q3
const Matrix3x3 & reciprocal_lattice_vectors() const
Definition crystal.hpp:205
const Matrix3x3 & lattice_vectors() const
Definition crystal.hpp:202
std::vector< AngularPoint > build_angular_grid(int maximum_angular_momentum)
double Real
Real compute_real_spherical_harmonic(int degree, int order, const Vector3D &direction)
Definition harmonics.hpp:85
Matrix3x3 cartesian_rotation_of(const Crystal &crystal_structure, const SymmetryOperation &operation)
std::vector< Real > build_real_harmonic_rotation_matrix(int angular_momentum, const Matrix3x3 &cartesian_rotation)
std::vector< int > harmonic_order_sequence(int degree)
Definition harmonics.hpp:40
3×3 matrix stored row-major: row i = mat[i]
std::array< std::array< int, 3 >, 3 > rotation
Definition operation.hpp:27