Loading...
Searching...
No Matches
init.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * PlanewaveKohnShamQuantumSystem — planewave quantum system.
5 *
6 * Stores the electronic quantum states (wavefunction + eigenvalue + occupation)
7 * for all k-point states and bands in a planewave representation.
8 *
9 * Inheritance chain:
10 * KohnShamQuantumSystem (L2: Crystal, spin)
11 * └─ PlanewaveKohnShamQuantumSystem (this: kpoints, basis, quantum states)
12 * └─ NormConservingPlanewaveKohnShamQuantumSystem (NC pseudopotentials)
13 * └─ UltrasoftPlanewaveKohnShamQuantumSystem (augmentation)
14 */
15
16#include <algorithm>
17#include <cmath>
18#include <vector>
19
27
28namespace q3 {
29
30/**
31 * Planewave representation of the electronic quantum system.
32 *
33 * Stores an array of PlanewaveKohnShamQuantumState indexed as
34 * [kpoint_state_index * number_of_bands + band_index].
35 */
36class PlanewaveKohnShamQuantumSystem : public KohnShamQuantumSystem<PlanewaveKohnShamQuantumState> {
37 public:
39 ~PlanewaveKohnShamQuantumSystem() override = default;
40
42 const PlanewaveBasis& basis,
44 int number_of_spin_components_value,
47 , basis_(&basis)
50 this->number_of_spin_components = number_of_spin_components_value;
51 }
52
53 // ─── System parameters ─────────────────────────────────────
54 [[nodiscard]] int number_of_bands() const {
55 return number_of_bands_;
56 }
57 [[nodiscard]] int number_of_kpoint_states() const {
58 if (!kpoint_grid_)
59 return 0;
61 }
62 [[nodiscard]] Real number_of_electrons() const {
64 }
65 [[nodiscard]] Real spin_degeneracy() const {
66 return (number_of_spin_components == 1) ? 2.0 : 1.0;
67 }
68
69 /// Return a snapshot of the current occupation configuration.
70 [[nodiscard]] Occupation occupation_configuration() const {
71 Occupation occupation;
73 occupation.spin_degeneracy = spin_degeneracy();
76 return occupation;
77 }
78
79 // ─── K-point grid ──────────────────────────────────────────
80 [[nodiscard]] const KPointsGrid& kpoint_grid() const {
81 return *kpoint_grid_;
82 }
83
84 // ─── Basis ─────────────────────────────────────────────────
85 [[nodiscard]] const PlanewaveBasis& basis() const {
86 return *basis_;
87 }
88
89 // ─── Per-state access ──────────────────────────────────────
90 [[nodiscard]] const PlanewaveKohnShamQuantumState& quantum_state(int kpoint_state_index,
91 int band_index) const {
92 return this->quantum_states_[kpoint_state_index * number_of_bands_ + band_index];
93 }
94 PlanewaveKohnShamQuantumState& quantum_state(int kpoint_state_index, int band_index) {
95 return this->quantum_states_[kpoint_state_index * number_of_bands_ + band_index];
96 }
97
98 // ─── Wavefunction access ───────────────────────────────────
99 [[nodiscard]] Complex wavefunction(int kpoint_index, int band_index, int g_vector_index) const {
100 return this->quantum_states_[kpoint_index * number_of_bands_ + band_index]
101 .wavefunction.values()[g_vector_index];
102 }
103
104 /**
105 * Get raw coefficient data for a specific (kpoint_state, band).
106 */
107 Complex* wavefunction_band_data(int kpoint_state_index, int band_index) {
108 return this->quantum_states_[kpoint_state_index * number_of_bands_ + band_index]
109 .wavefunction.coefficient_data();
110 }
111 [[nodiscard]] const Complex* wavefunction_band_data(int kpoint_state_index,
112 int band_index) const {
113 return this->quantum_states_[kpoint_state_index * number_of_bands_ + band_index]
114 .wavefunction.coefficient_data();
115 }
116
117 // ─── Eigenvalue access ─────────────────────────────────────
118 [[nodiscard]] Real eigenvalue(int kpoint_state_index, int band_index) const {
119 return this->quantum_states_[kpoint_state_index * number_of_bands_ + band_index].eigenvalue;
120 }
121 void set_eigenvalue(int kpoint_state_index, int band_index, Real value) {
122 this->quantum_states_[kpoint_state_index * number_of_bands_ + band_index].eigenvalue =
123 value;
124 }
125
126 // ─── Occupation access ─────────────────────────────────────
127 [[nodiscard]] Real occupation_by_kpoint_state_index_and_band_index(int kpoint_state_index,
128 int band_index) const {
130 return this->quantum_states_[kpoint_state_index * number_of_bands_ + band_index]
131 .occupation;
132 }
133 // Default: fixed occupations
134 int occupied = number_of_occupied_bands_per_spin();
135 return (band_index < occupied) ? 1.0 : 0.0;
136 }
137
138 void set_occupation(int kpoint_state_index, int band_index, Real value) {
141 // Initialize all states with fixed occupations (done in the loop below).
142 int occupied = number_of_occupied_bands_per_spin();
143 int total_states = number_of_kpoint_states();
144 for (int state_index = 0; state_index < total_states; state_index++) {
145 for (int band_init_index = 0; band_init_index < number_of_bands_;
146 band_init_index++) {
147 this->quantum_states_[state_index * number_of_bands_ + band_init_index]
148 .occupation = (band_init_index < occupied) ? 1.0 : 0.0;
149 }
150 }
151 }
152 this->quantum_states_[kpoint_state_index * number_of_bands_ + band_index].occupation =
153 value;
154 }
155
156 [[nodiscard]] int number_of_occupied_bands_per_spin() const {
157 /**
158 * Each spin channel holds N/2 electrons: 2 per band when unpolarized
159 * (spin_degeneracy 2), 1 per band in LSDA where the two channels are
160 * separate k-point states. Fixed occupations therefore describe a
161 * zero-total-moment configuration; magnetized systems need smearing
162 * (per-channel electron counts then come from the common Fermi level).
163 */
164 return static_cast<int>(number_of_electrons_ / 2.0 + 0.5);
165 }
166
167 // ─── Bulk eigenvalue/occupation access (for compatibility) ──
168 /**
169 * Copy all eigenvalues into a Matrix<Real>.
170 */
171 [[nodiscard]] Matrix<Real> eigenvalues_matrix() const {
172 int total_kpoint_states = number_of_kpoint_states();
173 Matrix<Real> result(total_kpoint_states, number_of_bands_, 0.0);
174 for (int kpoint_state_index = 0; kpoint_state_index < total_kpoint_states;
175 kpoint_state_index++) {
176 for (int band_index = 0; band_index < number_of_bands_; band_index++) {
177 result(kpoint_state_index, band_index) =
178 this->quantum_states_[kpoint_state_index * number_of_bands_ + band_index]
179 .eigenvalue;
180 }
181 }
182 return result;
183 }
184
185 /**
186 * Set all eigenvalues from a Matrix<Real>.
187 */
188 void set_eigenvalues_from_matrix(const Matrix<Real>& eigenvalues) {
189 int total_kpoint_states = number_of_kpoint_states();
190 for (int kpoint_state_index = 0; kpoint_state_index < total_kpoint_states;
191 kpoint_state_index++) {
192 for (int band_index = 0; band_index < number_of_bands_; band_index++) {
193 this->quantum_states_[kpoint_state_index * number_of_bands_ + band_index]
194 .eigenvalue = eigenvalues(kpoint_state_index, band_index);
195 }
196 }
197 }
198
199 // ─── Fermi energy ──────────────────────────────────────────
200 [[nodiscard]] Real fermi_energy() const {
201 return fermi_energy_;
202 }
203 void set_fermi_energy(Real value) {
204 fermi_energy_ = value;
205 }
206
207 // ─── Convenience setters for initialization ────────────────
208 void set_number_of_bands(int value) {
209 number_of_bands_ = value;
210 }
212 number_of_electrons_ = value;
213 }
218 basis_ = basis;
219 }
220
221 /**
222 * Copy all electronic state data from another PlanewaveKohnShamQuantumSystem.
223 *
224 * Used to populate the owned quantum_system_snapshot_ in
225 * NormConservingPlanewaveKohnShamSCFState at convergence. Copies wavefunction coefficients,
226 * eigenvalues, occupations, Fermi energy, spin configuration, and the k-point grid /
227 * basis pointers needed to interpret them. Does NOT touch PP-specific data — that must
228 * already be set up by the factory on the destination.
229 */
230 void
232 const KPointsGrid* saved_grid = kpoint_grid_;
233 const PlanewaveBasis* saved_basis = basis_;
234
236
237 const auto& planewave_source = static_cast<const PlanewaveKohnShamQuantumSystem&>(source);
238 number_of_bands_ = planewave_source.number_of_bands_;
239 number_of_electrons_ = planewave_source.number_of_electrons_;
240 fermi_energy_ = planewave_source.fermi_energy_;
241 is_fractionally_occupied_ = planewave_source.is_fractionally_occupied_;
242 number_of_spin_components = planewave_source.number_of_spin_components;
243
244 if (saved_grid != nullptr) {
245 kpoint_grid_ = saved_grid;
246 } else {
247 kpoint_grid_ = planewave_source.kpoint_grid_;
248 }
249 if (saved_basis != nullptr) {
250 basis_ = saved_basis;
251 } else {
252 basis_ = planewave_source.basis_;
253 }
254 }
255
256 /**
257 * Allocate quantum states using per-k-point PW counts from the basis.
258 * Creates number_of_kpoint_states * number_of_bands states, each with
259 * its wavefunction sized to the appropriate number of plane waves.
260 */
261 void allocate_electronic_states(const std::vector<int>& number_of_plane_waves_per_kpoint) {
262 int total_kpoint_states = number_of_kpoint_states();
263 int number_of_kpoints = kpoint_grid_->number_of_kpoints();
264 this->quantum_states_.resize(total_kpoint_states * number_of_bands_);
265
266 for (int kpoint_state_index = 0; kpoint_state_index < total_kpoint_states;
267 kpoint_state_index++) {
268 int kpoint_index = kpoint_state_index % number_of_kpoints;
269 int number_of_plane_waves = number_of_plane_waves_per_kpoint[kpoint_index];
270 for (int band_index = 0; band_index < number_of_bands_; band_index++) {
271 auto& state =
272 this->quantum_states_[kpoint_state_index * number_of_bands_ + band_index];
273 state.wavefunction.resize(number_of_plane_waves);
274 state.eigenvalue = 0.0;
275 state.occupation = 0.0;
276 }
277 }
278 }
279
280 /**
281 * Number of plane waves for a given k-point state.
282 */
283 [[nodiscard]] int number_of_plane_waves_for_kpoint_state(int kpoint_state_index) const {
284 return this->quantum_states_[kpoint_state_index * number_of_bands_]
285 .wavefunction.number_of_plane_waves();
286 }
287
288 protected:
289 const KPointsGrid* kpoint_grid_ = nullptr;
290 const PlanewaveBasis* basis_ = nullptr;
295};
296
297} // namespace q3
int number_of_kpoints() const
void copy_quantum_states_from(const QuantumSystem< PlanewaveKohnShamQuantumState > &source) override
Definition init.hpp:231
~PlanewaveKohnShamQuantumSystem() override=default
const KPointsGrid & kpoint_grid() const
Definition init.hpp:80
void set_number_of_electrons(Real value)
Definition init.hpp:211
const KPointsGrid * kpoint_grid_
Definition init.hpp:289
const PlanewaveBasis & basis() const
Definition init.hpp:85
PlanewaveKohnShamQuantumSystem(const KPointsGrid &kpoint_grid, const PlanewaveBasis &basis, int number_of_bands, int number_of_spin_components_value, Real number_of_electrons)
Definition init.hpp:41
PlanewaveKohnShamQuantumState & quantum_state(int kpoint_state_index, int band_index)
Definition init.hpp:94
const PlanewaveBasis * basis_
Definition init.hpp:290
Complex wavefunction(int kpoint_index, int band_index, int g_vector_index) const
Definition init.hpp:99
void set_occupation(int kpoint_state_index, int band_index, Real value)
Definition init.hpp:138
Matrix< Real > eigenvalues_matrix() const
Definition init.hpp:171
Occupation occupation_configuration() const
Return a snapshot of the current occupation configuration.
Definition init.hpp:70
void set_eigenvalue(int kpoint_state_index, int band_index, Real value)
Definition init.hpp:121
void set_eigenvalues_from_matrix(const Matrix< Real > &eigenvalues)
Definition init.hpp:188
void set_number_of_bands(int value)
Definition init.hpp:208
Real occupation_by_kpoint_state_index_and_band_index(int kpoint_state_index, int band_index) const
Definition init.hpp:127
void set_kpoint_grid(const KPointsGrid *kpoint_grid)
Definition init.hpp:214
void allocate_electronic_states(const std::vector< int > &number_of_plane_waves_per_kpoint)
Definition init.hpp:261
int number_of_plane_waves_for_kpoint_state(int kpoint_state_index) const
Definition init.hpp:283
int number_of_occupied_bands_per_spin() const
Definition init.hpp:156
const PlanewaveKohnShamQuantumState & quantum_state(int kpoint_state_index, int band_index) const
Definition init.hpp:90
void set_basis(const PlanewaveBasis *basis)
Definition init.hpp:217
Real eigenvalue(int kpoint_state_index, int band_index) const
Definition init.hpp:118
Complex * wavefunction_band_data(int kpoint_state_index, int band_index)
Definition init.hpp:107
void set_fermi_energy(Real value)
Definition init.hpp:203
const Complex * wavefunction_band_data(int kpoint_state_index, int band_index) const
Definition init.hpp:111
std::vector< QuantumStateType > quantum_states_
virtual void copy_quantum_states_from(const QuantumSystem< QuantumStateType > &source)
double Real
std::complex< double > Complex
Electronic occupation configuration for a quantum system.
Real spin_degeneracy
Spin degeneracy factor (2.0 for unpolarized, 1.0 for spin-polarized).
bool is_smeared
Whether smearing is active (fractional occupations).
Real number_of_electrons
Total number of electrons.
int occupied_bands_per_spin
Number of occupied bands per spin channel.