145 const Crystal& crystal_structure,
146 const std::vector<SymmetryOperation>& symmetry_operations,
147 const std::vector<HubbardManifoldLayout>& layouts,
148 std::vector<std::vector<std::vector<Complex>>>& occupation_matrices) {
149 int number_of_operations =
static_cast<int>(symmetry_operations.size());
150 if (number_of_operations <= 1 || layouts.empty())
158 std::vector<int> distinct_angular_momenta;
159 for (
const auto& layout : layouts) {
160 if (std::find(distinct_angular_momenta.begin(),
161 distinct_angular_momenta.end(),
162 layout.angular_momentum) == distinct_angular_momenta.end())
163 distinct_angular_momenta.push_back(layout.angular_momentum);
165 std::vector<std::vector<std::vector<Real>>> rotation_matrices(number_of_operations);
166 for (
int operation_index = 0; operation_index < number_of_operations; operation_index++) {
169 rotation_matrices[operation_index].resize(distinct_angular_momenta.size());
170 for (
size_t slot = 0; slot < distinct_angular_momenta.size(); slot++)
171 rotation_matrices[operation_index][slot] =
175 auto find_manifold = [&](
int atom_index,
int angular_momentum) {
176 for (
size_t index = 0; index < layouts.size(); index++)
177 if (layouts[index].atom_index == atom_index &&
178 layouts[index].angular_momentum == angular_momentum)
179 return static_cast<int>(index);
183 auto original = occupation_matrices;
185 for (
size_t manifold_index = 0; manifold_index < layouts.size(); manifold_index++) {
186 const auto& layout = layouts[manifold_index];
187 int manifold_size = layout.manifold_size;
188 size_t rotation_slot =
static_cast<size_t>(std::find(distinct_angular_momenta.begin(),
189 distinct_angular_momenta.end(),
190 layout.angular_momentum) -
191 distinct_angular_momenta.begin());
193 for (
size_t spin_index = 0; spin_index < occupation_matrices[manifold_index].size();
195 std::vector<Complex> averaged(
static_cast<size_t>(manifold_size) * manifold_size,
197 int contributing_operations = 0;
199 for (
int operation_index = 0; operation_index < number_of_operations;
201 const auto& operation = symmetry_operations[operation_index];
202 if (layout.atom_index >=
static_cast<int>(operation.atom_map.size()))
204 int image_atom = operation.atom_map[layout.atom_index];
205 int image_manifold = find_manifold(image_atom, layout.angular_momentum);
206 if (image_manifold < 0)
209 const auto& rotation = rotation_matrices[operation_index][rotation_slot];
210 const auto& source = original[image_manifold][spin_index];
213 for (
int m = 0; m < manifold_size; m++) {
214 for (
int m_prime = 0; m_prime < manifold_size; m_prime++) {
216 for (
int p = 0; p < manifold_size; p++) {
217 Real left = rotation[
static_cast<size_t>(p) * manifold_size + m];
220 for (
int q = 0; q < manifold_size; q++) {
222 rotation[
static_cast<size_t>(q) * manifold_size + m_prime];
225 accumulated += left * right *
226 source[
static_cast<size_t>(p) * manifold_size + q];
229 averaged[
static_cast<size_t>(m) * manifold_size + m_prime] += accumulated;
232 contributing_operations++;
235 if (contributing_operations == 0)
237 for (
auto& element : averaged)
238 element /=
static_cast<Real>(contributing_operations);
239 occupation_matrices[manifold_index][spin_index] = averaged;