Loading...
Searching...
No Matches
kpoint_states.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * A planewave run's per-k-point results in global order.
5 *
6 * Under k-point pools each pool's iterator holds only its own k-point states,
7 * so eigenvalues, occupations, weights and coordinates read straight off it
8 * describe a fraction of the grid, in pool-local order. Everything that reports
9 * them goes through here, which gathers one contribution per pool through the
10 * execution policy; a serial policy hands the local data back unchanged.
11 * Shared rather than repeated per flavor: the non-self-consistent flavor read
12 * its eigenvalues straight off the iterator while it ran only serially, and
13 * that copy would have reported one pool's k-points under MPI.
14 */
15
16#include <cstddef>
17#include <vector>
18
19#include "generated/esse/properties/non_scalar/eigenvalues_at_kpoints.hpp"
21
22namespace q3 {
23
24/**
25 * ESSE's eigenvalues_at_kpoints record for the whole run: every k-point state,
26 * with its coordinates (crystal), weight, eigenvalues and occupations. Q3
27 * stores one spin channel per state (a spin-polarized run's states are its
28 * k-points twice over, spin up first), so each entry holds one unlabelled
29 * channel.
30 *
31 * Collective under MPI: every rank must call it.
32 */
33[[nodiscard]] inline generated::EigenvaluesAtKpoints assemble_global_eigenvalues_at_kpoints(
35 const auto& eigenvalue_matrix = iterator.eigenvalues();
36 int local_number_of_kpoint_states = eigenvalue_matrix.rows();
37 int number_of_bands = eigenvalue_matrix.cols();
38 /**
39 * kpoint_grid() holds one entry per PHYSICAL k-point; eigenvalue_matrix /
40 * occupation() are indexed by k-point STATE (physical kpoint * spin, see
41 * build_global_kpoint_grid_from_input / accumulator.hpp for the same
42 * convention) -- for a spin-polarized run number_of_kpoints above is the
43 * state count, so kpoint_grid() lookups need the physical index instead.
44 */
45 int local_number_of_physical_kpoints = iterator.kpoint_grid().number_of_kpoints();
46 int number_of_spin_components = iterator.quantum_system().number_of_spin_components;
47 int number_of_values_per_state = 2 * number_of_bands + 4;
48 std::vector<Real> local_state_data(static_cast<std::size_t>(local_number_of_kpoint_states) *
49 number_of_values_per_state);
50 for (int kpoint_index_state = 0; kpoint_index_state < local_number_of_kpoint_states;
51 ++kpoint_index_state) {
52 int local_physical_kpoint_index = kpoint_index_state % local_number_of_physical_kpoints;
53 std::size_t state_offset =
54 static_cast<std::size_t>(kpoint_index_state) * number_of_values_per_state;
55 for (int band_index = 0; band_index < number_of_bands; band_index++) {
56 local_state_data[state_offset + band_index] =
57 eigenvalue_matrix(kpoint_index_state, band_index);
58 local_state_data[state_offset + number_of_bands + band_index] =
59 iterator.occupation(kpoint_index_state, band_index);
60 }
61 const auto& kpoint = iterator.kpoint_grid()[local_physical_kpoint_index];
62 local_state_data[state_offset + 2 * number_of_bands] = kpoint.weight;
63 local_state_data[state_offset + 2 * number_of_bands + 1] = kpoint.coordinates.x;
64 local_state_data[state_offset + 2 * number_of_bands + 2] = kpoint.coordinates.y;
65 local_state_data[state_offset + 2 * number_of_bands + 3] = kpoint.coordinates.z;
66 }
67
68 std::vector<Real> global_state_data =
70 local_state_data,
71 local_number_of_physical_kpoints,
72 number_of_spin_components,
73 number_of_values_per_state);
74 int global_number_of_kpoint_states =
75 static_cast<int>(global_state_data.size()) / number_of_values_per_state;
76 generated::EigenvaluesAtKpoints eigenvalues;
77 eigenvalues.name = generated::EigenvaluesAtKpointsNameEnum::EIGENVALUES_AT_KPOINTS;
78 eigenvalues.units = generated::EigenvaluesAtKpointsUnitsEnum::RY;
79 for (int kpoint_index_state = 0; kpoint_index_state < global_number_of_kpoint_states;
80 ++kpoint_index_state) {
81 const auto state =
82 global_state_data.begin() +
83 static_cast<std::ptrdiff_t>(kpoint_index_state) * number_of_values_per_state;
84 generated::EigenvaluesAtKpointsBandEnergies channel;
85 channel.energies.assign(state, state + number_of_bands);
86 channel.occupations =
87 std::vector<double>(state + number_of_bands, state + 2 * number_of_bands);
88 generated::EigenvaluesAtKpointsEigenvaluesAtKPoint kpoint;
89 kpoint.weight = state[2 * number_of_bands];
90 kpoint.kpoint =
91 std::vector<double>(state + 2 * number_of_bands + 1, state + 2 * number_of_bands + 4);
92 kpoint.eigenvalues = {channel};
93 eigenvalues.values.push_back(kpoint);
94 }
95 return eigenvalues;
96}
97
98/**
99 * Gather per-k-point-state blocks of `values_per_state` reals into global
100 * order, as assemble_global_eigenvalues_at_kpoints() does for the eigenvalues.
101 *
102 * `local_blocks` holds one block per local k-point state, spin-major over the
103 * pool's physical k-points. Collective under MPI.
104 */
105inline std::vector<std::vector<Real>>
107 const std::vector<std::vector<Real>>& local_blocks,
108 int values_per_state) {
109 const int local_number_of_physical_kpoints = iterator.kpoint_grid().number_of_kpoints();
110 const int number_of_spin_components = iterator.quantum_system().number_of_spin_components;
111 std::vector<Real> local_data;
112 local_data.reserve(local_blocks.size() * static_cast<std::size_t>(values_per_state));
113 for (const auto& block : local_blocks) {
114 local_data.insert(local_data.end(), block.begin(), block.end());
115 }
116 const std::vector<Real> global_data =
118 local_data,
119 local_number_of_physical_kpoints,
120 number_of_spin_components,
121 values_per_state);
122 std::vector<std::vector<Real>> global_blocks(global_data.size() / values_per_state);
123 for (std::size_t state_index = 0; state_index < global_blocks.size(); ++state_index) {
124 global_blocks[state_index].assign(
125 global_data.begin() + static_cast<std::ptrdiff_t>(state_index * values_per_state),
126 global_data.begin() +
127 static_cast<std::ptrdiff_t>((state_index + 1) * values_per_state));
128 }
129 return global_blocks;
130}
131
132} // namespace q3
int number_of_kpoints() const
size_t rows() const
Definition matrix.hpp:62
const PlanewaveKohnShamQuantumSystem & quantum_system() const
Definition init.hpp:223
const KPointsGrid & kpoint_grid() const
Definition init.hpp:209
Matrix< Real > eigenvalues() const
Definition init.hpp:237
const execution::PlanewaveExecutionPolicy & execution_policy() const
Definition init.hpp:119
Real occupation(int kpoint_index, int band_index) const
Definition init.hpp:272
virtual std::vector< Real > assemble_global_kpoint_state_data(const std::vector< Real > &local_data, int local_number_of_physical_kpoints, int number_of_spin_components, int number_of_values_per_state) const =0
generated::EigenvaluesAtKpoints assemble_global_eigenvalues_at_kpoints(const PlanewavePseudopotentialKohnShamSCFIterator &iterator)
std::vector< std::vector< Real > > assemble_global_kpoint_state_blocks(const PlanewavePseudopotentialKohnShamSCFIterator &iterator, const std::vector< std::vector< Real > > &local_blocks, int values_per_state)