Loading...
Searching...
No Matches
init.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * PlanewavePseudopotentialKohnShamSCFIterator — concrete pseudopotential SCF (layers 3–4).
5 *
6 * Extends the abstract PlanewaveKohnShamSCFIterator with the pseudopotential
7 * ionic world: the local ionic potential, partial-core charge, KB projectors,
8 * and the initial charge density / wavefunction setup from atomic superpositions.
9 *
10 * This class implements the norm-conserving pseudopotential case. Ultrasoft-only
11 * machinery (smooth pre-augmentation density, projector overlap coefficients,
12 * augmentation charges, the effective D-matrix) lives in
13 * UltrasoftPlanewavePseudopotentialKohnShamSCFIterator, leaving room for a
14 * future PAW sibling.
15 */
16
17#include <algorithm>
18#include <cmath>
19#include <cstdint>
20#include <filesystem>
21#include <limits>
22#include <memory>
23#include <optional>
24#include <stdexcept>
25#include <string>
26#include <system_error>
27#include <unordered_map>
28#include <vector>
29
31#include "io/logger.hpp"
35
56
57namespace q3 {
58
60 public:
64
65 /// Transfer ownership of a PseudopotentialSet into this iterator.
67 owned_pseudopotential_set_ = std::move(pseudopotential_set);
68 pseudopotential_set_ = &owned_pseudopotential_set_.value();
69 }
70
71 [[nodiscard]] const NormConservingPlanewaveKohnShamEnergies& energies() const override {
72 return energies_;
73 }
77
78 /**
79 * Assemble and return a snapshot of the converged SCF state.
80 *
81 * The ultrasoft subclass overrides this to inject the effective D-matrix into the snapshot.
82 */
86 data.converged = is_converged();
88 /**
89 * Share the existing quantum system snapshot instead of creating a new one.
90 * The PP basis (beta tables, local potential, core charge) is expensive to
91 * initialize, and we only need a read-only view for forces/stress/IO.
92 */
94 data.quantum_system_snapshot_->copy_quantum_states_from(quantum_system_);
104 data.kpoint_grid = &kpoint_grid();
109 return data;
110 }
111
112 /**
113 * Write binary checkpoint files (charge density, wavefunctions, and effective potential).
114 *
115 * Writes:
116 * - charge-density.dat — QE-compatible Fortran binary charge density
117 * - wfc*.dat — QE-compatible Fortran binary wavefunctions per k-point
118 * - effective-potential.q3cp — Q3-native v3 binary with V_eff in real space and,
119 * for PAW, the on-site occupations ρ_ij
120 *
121 * The effective-potential file enables NSCF calculations to load V_eff directly
122 * instead of reconstructing it from charge density + input parameters, and to
123 * build a PAW dataset's one-centre term of D from the converged ρ_ij.
124 *
125 * Under k-point pools of one rank each, every rank writes the wfc*.dat files
126 * of its own k-points, and the root writes the rest. Those it can write
127 * alone: the density, the potential built from it and the PAW ρ_ij are
128 * reduced across pools, so every rank already holds them whole. Only the
129 * eigenvalues are per pool, and are gathered first. The result is the same
130 * directory a serial run writes, which a serial NSCF restores.
131 *
132 * Collective: every rank must call this.
133 */
134 void write_checkpoints(const std::string& output_directory,
135 const std::string& prefix) const override {
137 if (execution_policy_->is_root()) {
138 log::warn("Checkpoint output is not supported when ranks share a k-point pool: "
139 "they split each k-point's plane-wave coefficients and the density "
140 "grid between them, and the checkpoint writers have no gather for "
141 "either. No checkpoint directory was created; results output is "
142 "unaffected. Give every rank its own pool, as the automatic MPI "
143 "topology does, to write one.");
144 }
145 return;
146 }
147 auto scf_state = result();
148 const Matrix<Real> eigenvalues_of_every_kpoint = global_eigenvalues();
149 std::string save_directory = output_directory + "/" + prefix + ".save";
150 /**
151 * Every rank creates the directory it writes into rather than waiting
152 * on the root. Ranks may race to create it, so success is judged by the
153 * directory existing afterwards, not by which call made it.
154 */
155 std::error_code directory_error;
156 std::filesystem::create_directories(save_directory, directory_error);
157 if (!std::filesystem::is_directory(save_directory)) {
158 throw std::runtime_error("Cannot create the checkpoint directory '" + save_directory +
159 "': " + directory_error.message());
160 }
161
162 auto wavefunctions_checkpoint = create_wavefunction_checkpoint(scf_state);
163 wavefunctions_checkpoint->write_to_file(save_directory);
164
165 if (!execution_policy_->is_root()) {
166 return;
167 }
169 log::info(" Each of the {} k-point pools wrote the wavefunctions of its own "
170 "k-points, {} in all",
172 eigenvalues_of_every_kpoint.rows() / number_of_spin_components());
173 }
174
175 auto charge_density_checkpoint = create_charge_density_checkpoint(scf_state);
176 charge_density_checkpoint->write_to_file(save_directory + "/charge-density.dat");
177
178 /**
179 * Write the effective potential (V_Hxc + V_loc) to the Q3-native
180 * checkpoint, along with how the run that produced it ended.
181 *
182 * The header fields are not decoration. A checkpoint travels away from
183 * the run that wrote it -- to an NSCF job, to a restart, to a third
184 * party verifying a published calculation -- and a reader has no other
185 * way to learn whether the density it holds converged, or what energy
186 * it converged to. Leaving them zero makes the file assert that it came
187 * from an unconverged run at zero energy, which is worse than saying
188 * nothing.
189 */
190 KohnShamQuantumSystemSnapshot effective_potential_snapshot;
191 effective_potential_snapshot.iteration = iteration();
192 effective_potential_snapshot.number_of_spin_components = number_of_spin_components();
193 effective_potential_snapshot.number_of_kpoint_states =
194 static_cast<int>(eigenvalues_of_every_kpoint.rows());
195 effective_potential_snapshot.number_of_bands =
196 static_cast<int>(eigenvalues_of_every_kpoint.cols());
197 effective_potential_snapshot.total_energy = total_energy();
198 effective_potential_snapshot.converged = is_converged();
199 effective_potential_snapshot.eigenvalues = eigenvalues_of_every_kpoint;
200 effective_potential_snapshot.charge_density_real = charge_density_real_;
201 effective_potential_snapshot.effective_potential_real = real_space_potential_;
202 effective_potential_snapshot.one_center_occupations = one_center_occupations();
203
204 Q3PlanewaveKohnShamQuantumSystemCheckpoint effective_potential_checkpoint;
205 effective_potential_checkpoint.save(save_directory + "/effective-potential.q3cp",
206 effective_potential_snapshot,
207 /*save_wavefunctions=*/false);
208 }
209
210 // ─── Pseudopotential accessors ───────────────────────────────────
211
212 /**
213 * Tr[n] per Hubbard manifold, per spin, from the converged occupation
214 * matrices -- the diagnostic the DFT+U line prints, in full precision and
215 * indexed the same way as the manifolds the SCF state carries.
216 *
217 * Empty when the run has no Hubbard manifolds.
218 */
219 [[nodiscard]] const std::vector<std::vector<Real>>& hubbard_occupation_traces() const {
221 }
222
223 /**
224 * Access the pseudopotential set by const reference.
225 */
226 [[nodiscard]] const PseudopotentialSet& pseudopotential_set() const {
227 return *pseudopotential_set_;
228 }
229
230 /**
231 * Access the pseudopotential quantum-system snapshot built during initialization.
232 */
237
238 /**
239 * Give the snapshot the electronic state the iterator currently holds.
240 *
241 * The snapshot is the only object carrying the pseudopotential data --
242 * beta tables, augmentation, the ultrasoft basis -- because the factory
243 * built it as the right subclass. `quantum_system_` is a by-value member
244 * of the base type and carries the wavefunctions and eigenvalues. Anything
245 * needing both at once (a Wannier capture on an ultrasoft or PAW dataset)
246 * has to bring them together first, which `result()` also does when it
247 * assembles the state to hand back.
248 *
249 * Copies electronic state only; the pseudopotential data on the snapshot
250 * is untouched.
251 */
253 quantum_system_snapshot_->copy_quantum_states_from(quantum_system_);
254 }
255
256 /**
257 * Overlap coefficients ⟨β_i|ψ_nk⟩ at convergence.
258 *
259 * Returns an empty matrix for norm-conserving calculations.
260 * The ultrasoft iterator overrides this to return the accumulated coefficients.
261 */
262 [[nodiscard]] virtual const Matrix<Real>& projector_overlap_coefficients() const {
263 static const Matrix<Real> empty_matrix{};
264 return empty_matrix;
265 }
266
267 /**
268 * The on-site occupations ρ_ij per spin channel, which the checkpoint
269 * stores: what D's one-centre term is built from. Empty wherever D has no
270 * such term; the PAW iterator overrides this.
271 */
272 [[nodiscard]] virtual std::vector<Matrix<Real>> one_center_occupations() const {
273 return {};
274 }
275
276 /**
277 * Whether a non-self-consistent pass must be handed those occupations
278 * before it diagonalizes -- true exactly where D carries a one-centre term.
279 */
280 [[nodiscard]] virtual bool requires_one_center_occupations() const {
281 return false;
282 }
283
284 /**
285 * Hand over ρ_ij from a checkpoint, so D's one-centre term is built from the
286 * converged occupations before the first Hamiltonian and stays so for the
287 * whole run. Call after construction and before run(), like
288 * load_effective_potential(). Nothing to do where D has no such term.
289 */
291 [[maybe_unused]] const std::vector<Matrix<Real>>& occupations_by_spin) {}
292
293 /**
294 * Set the diagonalizer tolerance directly, bypassing the adaptive SCF scheme.
295 *
296 * Intended for use by the NSCF flavor, which runs only a single diagonalization
297 * pass. The SCF adaptive scheme always starts at the loose initial threshold
298 * (1e-2 Ry) on iteration 1, which is far too loose for a fixed-potential NSCF
299 * calculation and causes Davidson to converge to wrong conduction-band eigenvalues
300 * at special high-symmetry k-points.
301 *
302 * This method may be called before run() when the diagonalizer_ is not yet
303 * constructed. The requested tolerance is stored as a pending override and
304 * applied on the first call to set_diagonalization_tolerance() inside run().
305 */
307 nscf_override_tolerance_ = tolerance;
308 }
309
310 /**
311 * Allow a fixed-potential pass enough Davidson iterations to converge every band.
312 *
313 * Pending, like the tolerance above, until the diagonalizer exists. Also
314 * turns on the report of any k-point whose solve still ends with bands
315 * unconverged, since a single pass has no later iteration to finish them.
316 */
317 void set_diagonalizer_maximum_iterations_for_nscf(int maximum_iterations) {
318 nscf_override_maximum_iterations_ = maximum_iterations;
319 }
320
321 /**
322 * Vxc(G) of a given valence density alone -- without the nonlinear core
323 * correction's core charge, which the Hamiltonian's own Vxc includes.
324 *
325 * For the mean-field export, whose VXC and vxc.dat need Vxc of the
326 * converged SCF density: a GW self-energy is built from the valence
327 * electrons, so the Vxc it replaces is the valence one. pw2bgw computes its
328 * VXC and vxc.dat the same way unless told otherwise, and its manual warns
329 * that keeping the core charge "will produce incorrect results"
330 * (`vxc_zero_rho_core`, default .TRUE., INPUT_pw2bgw). Measured on silicon
331 * with an NLCC dataset at 25 Ry: with the core charge, V_xc(G = 0) was
332 * -0.6750 Ry against pw2bgw's -0.6524 Ry. The base calculator is the one
333 * that adds no core charge (see
334 * NormConservingPlanewaveEffectivePotentialCalculator); without NLCC the
335 * two coincide. Touches none of the iterator's own potentials or energies.
336 */
337 [[nodiscard]] std::vector<Complex> valence_exchange_correlation_potential_g_of(
338 const std::vector<std::vector<Real>>& charge_density_real) {
339 PlanewaveEffectivePotentialCalculator valence_calculator(
341 return valence_calculator
344 }
345
346 /**
347 * Offer the bands a previous geometry saved in `save_directory` as this
348 * run's starting wavefunctions, as pw.x's next ionic step starts from the
349 * last one's. Each k-point whose wfc<k>.dat fits this run's basis starts
350 * from those bands, passed through the same Rayleigh-Ritz step as the
351 * atomic guess, so they are re-orthonormalized in this geometry's overlap
352 * and given eigenvalues before the eigensolver sees them. Any other k-point
353 * falls back to the atomic + random guess. Only the starting point changes,
354 * never what the SCF converges to.
355 */
356 void offer_starting_wavefunctions(std::string save_directory) {
357 starting_wavefunction_directory_ = std::move(save_directory);
358 }
359
360 protected:
361 // ─── Pseudopotential config ──────────────────────────────────────
363 std::string calculation_ = "self_consistent_field";
364 // Per-species initial magnetization (see KohnShamSCFIteratorConfig).
365 std::vector<Real> starting_magnetization_;
366 std::vector<Real> atomic_starting_magnetization_; // per atom; empty = per species
367 std::vector<std::pair<std::string, Vector3D>> band_path_;
369
370 // ─── Pseudopotential fields ──────────────────────────────────────
372 std::shared_ptr<NormConservingPlanewaveKohnShamQuantumSystem> quantum_system_snapshot_;
373
374 private:
375 /**
376 * Optional owned PseudopotentialSet — used when the factory constructs the
377 * iterator from InputData (the iterator owns the set rather than borrowing it).
378 */
379 std::optional<PseudopotentialSet> owned_pseudopotential_set_;
380 /// Set once the geometry-dependent D3(BJ) dispersion energy has been computed.
381 bool dispersion_energy_computed_ = false;
382 /// Persistent effective potential calculator (caches real-space core charge density).
383 std::unique_ptr<NormConservingPlanewaveEffectivePotentialCalculator>
384 effective_potential_calculator_;
385 /// Set by offer_starting_wavefunctions(): where a previous geometry left its wfc<k>.dat.
386 std::string starting_wavefunction_directory_;
387
388 public:
389 /**
390 * The projector cache is the SCF's too: the forces and stress build their
391 * own. The applicator holds pointers into it, so its view is cleared first
392 * and the storage freed after; the cache refills on demand.
393 */
394 void release_scf_workspace() override {
396 if (diagonalizer_) {
397 for (int kpoint_index = 0;
398 kpoint_index < static_cast<int>(cached_kleinman_bylander_projectors_.size());
399 ++kpoint_index) {
400 diagonalizer_->set_cached_projectors(kpoint_index, nullptr);
401 }
402 }
403 std::vector<q3::Matrix<Complex>>().swap(cached_kleinman_bylander_projectors_);
404 }
405
406 protected:
407 /// Cached KB projectors per k-point (reused by the projector overlap accumulation).
408 std::vector<q3::Matrix<Complex>> cached_kleinman_bylander_projectors_;
409
410 /// DFT+U (Hubbard): resolved atom/shell manifolds; empty means no correction is active.
411 std::vector<HubbardManifold> hubbard_manifolds_;
412 /**
413 * Tr[n] for each manifold and spin channel, as of the last SCF step that
414 * built the occupation matrices. Indexed [manifold][spin], parallel to
415 * hubbard_manifolds_; empty when no correction is active.
416 */
417 std::vector<std::vector<Real>> hubbard_occupation_traces_;
418 /**
419 * Cached Hubbard atomic-orbital projectors per k-point, all manifolds' orbitals
420 * concatenated in hubbard_manifolds_ order (geometry-only, set once at setup).
421 */
422 std::vector<q3::Matrix<Complex>> cached_hubbard_projectors_;
423 /**
424 * The cell's symmetry operations, built once.
425 *
426 * Only DFT+U needs them at this level, and only per SCF step, so they are
427 * cached lazily rather than computed in `initialize()` where every run
428 * would pay for them.
429 */
430 [[nodiscard]] const std::vector<SymmetryOperation>& cached_symmetry_operations() const {
435 }
437 }
438 mutable std::vector<SymmetryOperation> cached_symmetry_operations_;
439 mutable bool symmetry_operations_cached_{false};
440
441 /// Σ_σ Tr[V_U^σ n^σ]; see `hubbard_potential_energy()`.
443 /**
444 * Dense block-diagonal Hubbard D-matrix per spin channel (column-major, refreshed
445 * once per SCF iteration in construct_density_from_states()).
446 */
447 std::vector<std::vector<Complex>> hubbard_d_matrix_per_spin_;
449 /**
450 * ‖n_fresh − n_damped‖² — how far the freshly accumulated occupation
451 * matrix is from the damped one driving V_U, *not* the step actually
452 * taken (which is this scaled by the damping factor). The distinction
453 * matters because this is the quantity gating SCF exit. Same
454 * squared-magnitude convention `density_residual_` uses. Updated by
455 * `accumulate_hubbard_occupation_and_potential()`; consulted by
456 * `is_iteration_converged()`. A large sentinel (never a false "converged")
457 * until the damping cache has been through at least one real blend.
458 */
459 Real hubbard_occupation_residual_{std::numeric_limits<Real>::max()};
460 /// Owns the damping/Anderson state; see HubbardOccupationMixer.
462 /**
463 * Iterations of occupation seeding still owed. Starts at
464 * 1 + `hubbard_fixed_occupation_iterations`: the first application is the
465 * starting guess, any further ones hold that guess in place while the
466 * wavefunctions adapt to it.
467 */
469
470 // ─── KohnShamSCFIterator hooks ────────────────────────────────────
471
473 /**
474 * Read pseudopotential config before calling parent (which reads PW config).
475 * Skip fields already set by owned-data setters (InputData factory path).
476 */
477 if (config().pseudopotential_set != nullptr) {
479 }
483 bool any_nonzero_magnetization = false;
484 for (const auto* magnetizations :
486 for (Real magnetization : *magnetizations) {
487 if (magnetization < -1.0 || magnetization > 1.0)
488 throw std::runtime_error(
489 "starting_magnetization values must be in [-1, 1], got " +
490 std::to_string(magnetization));
491 if (magnetization != 0.0)
492 any_nonzero_magnetization = true;
493 }
494 /**
495 * Fixed occupations fill N/2 electrons per spin channel, so the TOTAL
496 * moment is pinned to zero regardless of the starting magnetization
497 * (QE rejects this input combination outright; see
498 * number_of_occupied_bands_per_spin). Warn rather than silently
499 * discarding the user's requested moment.
500 */
501 if (config().number_of_spin_components == 2 && any_nonzero_magnetization &&
502 config().smearing == "none") {
503 log::warn("LSDA with fixed occupations pins the total moment to zero; the "
504 "requested starting_magnetization can only seed a local (e.g. AFM) "
505 "spin arrangement. Use smearing to allow a net moment.");
506 }
509
511 }
512
518 } else {
519 log::info(" The saved starting density does not fit this run's grid; "
520 "starting from overlapping atoms instead");
522 }
523 }
527 } else {
529 }
530 }
531
532 /**
533 * Resolve DFT+U (Hubbard) manifolds and cache their atomic-orbital projectors, once,
534 * for the whole SCF run (geometry-only, like KB projectors). No-op if config().hubbard
535 * is empty. The one remaining scope gate is the Davidson diagonalizer.
536 *
537 * hubbard_projector_type selects "atomic" (raw pseudo-atomic orbitals, the default) or
538 * "ortho-atomic" (the full system-wide atomic-orbital set Lowdin-orthogonalized jointly
539 * before the manifold's columns are selected out -- see the call site below).
540 * HubbardForceCalculator carries the ortho-atomic gradient for norm-conserving datasets,
541 * including the term from every other orbital's own position-dependence through the joint
542 * S^-1/2 transform.
543 */
545 if (config().hubbard.empty()) {
546 return;
547 }
548 if (diagonalization_method_ != "davidson") {
549 throw std::runtime_error(
550 "DFT+U (hubbard) requires diagonalization: davidson (the direct diagonalizer "
551 "does not go through the Hamiltonian applicator this feature hooks into)");
552 }
553 if (config().hubbard_projector_type != "atomic" &&
554 config().hubbard_projector_type != "ortho-atomic") {
555 throw std::runtime_error("DFT+U: unrecognized hubbard_projector_type '" +
556 config().hubbard_projector_type +
557 "' (expected 'atomic' or 'ortho-atomic')");
558 }
559
560 auto orbital_labels = enumerate_atomic_orbitals(
562 quantum_system_snapshot_->pseudopotential_basis().pseudopotential_set());
564 resolve_hubbard_manifolds(crystal_structure(), orbital_labels, config().hubbard);
565
566 /**
567 * Occupation seeding directives are validated here, where the
568 * manifolds are known, so a typo'd species or an impossible spin dies
569 * at setup with a named cause instead of surfacing as a silently
570 * unseeded run converging into the wrong minimum -- the exact failure
571 * mode seeding exists to prevent.
572 */
573 for (const auto& directive : config().hubbard_starting_eigenvalues) {
574 if (directive.spin_index >= number_of_spin_components())
575 throw std::runtime_error(
576 "hubbard starting eigenvalue for species '" + directive.species_symbol +
577 "' addresses spin channel " + std::to_string(directive.spin_index + 1) +
578 " but the calculation has " + std::to_string(number_of_spin_components()) +
579 " spin component(s)");
580 bool species_has_manifold =
581 std::any_of(hubbard_manifolds_.begin(),
582 hubbard_manifolds_.end(),
583 [&](const HubbardManifold& manifold) {
584 return crystal_structure().element(manifold.atom_index) ==
585 directive.species_symbol;
586 });
587 if (!species_has_manifold)
588 throw std::runtime_error("hubbard starting eigenvalue names species '" +
589 directive.species_symbol +
590 "', which has no Hubbard manifold");
591 }
594 ? 0
595 : 1 + std::max(0, config().hubbard_fixed_occupation_iterations);
596
598 for (const auto& manifold : hubbard_manifolds_) {
599 total_hubbard_orbitals_ += static_cast<int>(manifold.orbital_indices.size());
600 }
601
604 std::vector<Complex>(static_cast<size_t>(total_hubbard_orbitals_) *
606 Complex(0.0, 0.0)));
607
608 constexpr Real q_spacing = 0.01;
609 constexpr int number_of_q_points = 900;
610 auto atomic_wavefunction_table = tabulate_atomic_wavefunctions_in_q_space(
611 quantum_system_snapshot_->pseudopotential_basis().pseudopotential_set(),
612 crystal_structure().cell_volume(),
613 q_spacing,
614 number_of_q_points);
615
616 int number_of_kpoints = kpoint_grid().number_of_kpoints();
617 cached_hubbard_projectors_.resize(number_of_kpoints);
618 for (int kpoint_index = 0; kpoint_index < number_of_kpoints; ++kpoint_index) {
619 std::vector<std::vector<Complex>> all_atomic_orbitals;
621 kpoint_index,
622 number_of_plane_waves(kpoint_index),
623 g_vector_indices(kpoint_index),
625 kpoint_grid(),
627 quantum_system_snapshot_->pseudopotential_basis().pseudopotential_set(),
628 atomic_wavefunction_table,
629 q_spacing,
630 number_of_q_points,
631 all_atomic_orbitals);
632
633 int plane_waves_at_kpoint = number_of_plane_waves(kpoint_index);
634 int number_of_atomic_orbitals = static_cast<int>(all_atomic_orbitals.size());
635 std::unique_ptr<OverlapOperator> overlap_operator;
636 q3::Matrix<Complex> kleinman_bylander_projectors;
637 if (quantum_system_snapshot_->has_ultrasoft()) {
638 const auto& pseudopotential_basis =
639 quantum_system_snapshot_->pseudopotential_basis();
641 kpoint_grid()[kpoint_index].coordinates,
644 pseudopotential_basis.pseudopotential_set(),
645 pseudopotential_basis.beta_function_table(),
646 g_vector_indices(kpoint_index),
647 plane_waves_at_kpoint,
648 pseudopotential_basis.total_number_of_projectors(),
649 kleinman_bylander_projectors);
650 overlap_operator = create_overlap_operator(crystal_structure(),
652 kleinman_bylander_projectors,
654 }
655
656 /**
657 * ortho-atomic: Lowdin-orthogonalize the FULL system-wide atomic-orbital set
658 * (all atoms, all shells) jointly -- matching QE's convention, which
659 * orthogonalizes the system-wide atomic-orbital set first -- before
660 * selecting out the Hubbard manifold's columns below. This must operate on the
661 * whole set, not a per-manifold subset: a manifold-only Lowdin transform would
662 * be a materially different (non-standard) definition.
663 */
664 if (config().hubbard_projector_type == "ortho-atomic") {
665 std::vector<Complex> packed_atomic_orbitals(
666 static_cast<size_t>(plane_waves_at_kpoint) * number_of_atomic_orbitals);
667 for (int orbital_index = 0; orbital_index < number_of_atomic_orbitals;
668 orbital_index++) {
669 std::copy(all_atomic_orbitals[static_cast<size_t>(orbital_index)].begin(),
670 all_atomic_orbitals[static_cast<size_t>(orbital_index)].end(),
671 packed_atomic_orbitals.begin() +
672 static_cast<size_t>(orbital_index) * plane_waves_at_kpoint);
673 }
674
675 /**
676 * Ultrasoft and PAW ortho-atomic projectors use the generalized
677 * <phi_i|S|phi_j> metric. Apply the same production overlap operator used
678 * by Davidson so its beta-projector ordering, q matrix, Gamma completion,
679 * and band-group reduction cannot drift from the eigenproblem definition.
680 */
681 std::vector<Complex> overlap_applied_atomic_orbitals;
682 const Complex* metric_right_orbitals = packed_atomic_orbitals.data();
683 if (overlap_operator != nullptr) {
684 overlap_applied_atomic_orbitals.resize(packed_atomic_orbitals.size());
685 overlap_operator->apply_batch(plane_waves_at_kpoint,
686 number_of_atomic_orbitals,
687 packed_atomic_orbitals.data(),
688 overlap_applied_atomic_orbitals.data());
689 metric_right_orbitals = overlap_applied_atomic_orbitals.data();
690 }
691
692 std::vector<Complex> atomic_orbital_overlap;
693 compute_hubbard_projector_overlaps(plane_waves_at_kpoint,
694 number_of_atomic_orbitals,
695 number_of_atomic_orbitals,
696 packed_atomic_orbitals.data(),
697 metric_right_orbitals,
698 atomic_orbital_overlap);
699 /**
700 * The Lowdin metric is itself a physical G-space overlap. Gamma-only storage
701 * contains one member of each +/-G pair, so diagonalizing the raw half-sphere
702 * sum would define a different projector from the explicit full-sphere run.
703 * Complete the metric before the band-group reduction and eigendecomposition,
704 * using the same overlap rule as the Hubbard occupation path below.
705 */
708 plane_waves_at_kpoint,
709 number_of_atomic_orbitals,
710 number_of_atomic_orbitals,
711 packed_atomic_orbitals.data(),
712 metric_right_orbitals,
714 g_vector_indices(kpoint_index),
715 plane_waves_at_kpoint),
716 /*band_functions_carry_g_component=*/false,
717 atomic_orbital_overlap);
718 }
720 atomic_orbital_overlap.data(), static_cast<int>(atomic_orbital_overlap.size()));
721 lowdin_orthogonalize_orbitals(all_atomic_orbitals,
722 std::move(atomic_orbital_overlap));
723 }
724
726 number_of_plane_waves(kpoint_index));
727 int row_index = 0;
728 for (const auto& manifold : hubbard_manifolds_) {
729 for (int orbital_index : manifold.orbital_indices) {
730 for (int g_index = 0; g_index < number_of_plane_waves(kpoint_index);
731 ++g_index) {
732 cached_hubbard_projectors_[kpoint_index][row_index][g_index] =
733 all_atomic_orbitals[static_cast<size_t>(orbital_index)]
734 [static_cast<size_t>(g_index)];
735 }
736 row_index++;
737 }
738 }
739 /**
740 * For ultrasoft and PAW the Hubbard occupations are defined with
741 * the all-electron inner product, <phi_m|S|psi>, not <phi_m|psi>:
742 * the pseudo orbital misses the on-site charge the augmentation
743 * carries, which for a 3d manifold is most of it.
744 *
745 * Rather than thread S through the occupation matrix, the
746 * Hamiltonian term and the projector overlaps separately, S is
747 * applied once here to the cached projectors. S is Hermitian, so
748 * <S phi_m|psi> = <phi_m|S|psi>, and every consumer downstream —
749 * the occupation matrix, the applicator's |phi> V <phi| term —
750 * becomes correct with no further change.
751 */
752 if (overlap_operator != nullptr) {
753 std::vector<Complex> overlap_applied_hubbard_projectors(
754 static_cast<size_t>(plane_waves_at_kpoint) * total_hubbard_orbitals_);
755 overlap_operator->apply_batch(plane_waves_at_kpoint,
757 cached_hubbard_projectors_[kpoint_index].data(),
758 overlap_applied_hubbard_projectors.data());
759 std::copy(overlap_applied_hubbard_projectors.begin(),
760 overlap_applied_hubbard_projectors.end(),
761 cached_hubbard_projectors_[kpoint_index].data());
762 }
763
764 diagonalizer_->set_cached_hubbard_projectors(kpoint_index,
765 &cached_hubbard_projectors_[kpoint_index]);
766 }
767
768 log::info(" DFT+U (Hubbard): {} manifold(s), {} total orbital(s), {} projectors",
769 hubbard_manifolds_.size(),
771 config().hubbard_projector_type);
772 }
773
778
779 int number_of_kpoints = kpoint_grid().number_of_kpoints();
780 cached_kleinman_bylander_projectors_.resize(number_of_kpoints);
781 for (int kpoint_index = 0; kpoint_index < number_of_kpoints; ++kpoint_index) {
783 kpoint_grid()[kpoint_index].coordinates,
786 quantum_system_snapshot_->pseudopotential_basis().pseudopotential_set(),
787 quantum_system_snapshot_->pseudopotential_basis().beta_function_table(),
788 g_vector_indices(kpoint_index),
789 number_of_plane_waves(kpoint_index),
790 quantum_system_snapshot_->pseudopotential_basis().total_number_of_projectors(),
792 diagonalizer_->set_cached_projectors(
793 kpoint_index, &cached_kleinman_bylander_projectors_[kpoint_index]);
794 }
795 return;
796 }
797
798 auto timer_0 = std::chrono::high_resolution_clock::now();
799 NormConservingPlanewaveWavefunctionInitializer atomic_wavefunction_initializer;
800 atomic_wavefunction_initializer.initialize_interpolation_table(
801 quantum_system_snapshot_->pseudopotential_basis().pseudopotential_set(),
802 crystal_structure().cell_volume());
803 int number_of_atomic_wavefunctions = count_atomic_orbitals(
805 quantum_system_snapshot_->pseudopotential_basis().pseudopotential_set());
806 log_pseudopotential_summary(number_of_atomic_wavefunctions);
807 report_memory_estimate(number_of_atomic_wavefunctions);
808
809 auto timer_1 = std::chrono::high_resolution_clock::now();
812 auto timer_2 = std::chrono::high_resolution_clock::now();
813 ProfilingCounters::instance().log_resident_checkpoint("potential + hamiltonian");
814
815 int number_of_kpoints = kpoint_grid().number_of_kpoints();
816
817 // Pre-compute KB projectors for each k-point (needed for initial density construction)
818 cached_kleinman_bylander_projectors_.resize(number_of_kpoints);
819 for (int kpoint_index = 0; kpoint_index < number_of_kpoints; ++kpoint_index) {
821 kpoint_grid()[kpoint_index].coordinates,
824 quantum_system_snapshot_->pseudopotential_basis().pseudopotential_set(),
825 quantum_system_snapshot_->pseudopotential_basis().beta_function_table(),
826 g_vector_indices(kpoint_index),
827 number_of_plane_waves(kpoint_index),
828 quantum_system_snapshot_->pseudopotential_basis().total_number_of_projectors(),
830 // Wire the cached projectors to the diagonalizer to avoid recomputation
831 diagonalizer_->set_cached_projectors(
832 kpoint_index, &cached_kleinman_bylander_projectors_[kpoint_index]);
833 }
834 auto timer_3 = std::chrono::high_resolution_clock::now();
836
837 /**
838 * The starting-guess Hamiltonian multiplies by the local potential on the
839 * wavefunction grid, pre-scaled by 1/N the way the Hamiltonian
840 * application holds it: restricted from the density grid through G space,
841 * completed within the pool, transformed back. The initializer took that
842 * conversion out of its own hands when the grids were first distributed,
843 * and this call went on passing the density-grid potential unconverted --
844 * read on the wrong grid, N times too large and different on every
845 * topology. Wherever there were more atomic orbitals than bands, the bands
846 * kept were chosen with it.
847 */
848 int total_smooth_points = planewave_basis_.fft_wave().total_grid_points();
849 std::vector<std::vector<Real>> starting_guess_potential(
850 static_cast<std::size_t>(number_of_spin_components()));
851 for (int spin_index = 0; spin_index < number_of_spin_components(); ++spin_index) {
852 auto smooth_potential_g = compute_smooth_grid_potential_from_dense(
854 execution_policy_->reduce_group_distributed_result(smooth_potential_g.data(),
855 total_smooth_points);
856 auto& potential = starting_guess_potential[static_cast<std::size_t>(spin_index)];
857 potential = inverse_fft_smooth_potential(smooth_potential_g, planewave_basis_);
858 Real inverse_smooth_points = 1.0 / total_smooth_points;
859 for (auto& value : potential) {
860 value *= inverse_smooth_points;
861 }
862 }
863
864 int number_of_kpoint_states = number_of_kpoints * number_of_spin_components();
865
866 /**
867 * A previous geometry's bands, when offered, replace the atomic guess
868 * as the starting set the Rayleigh-Ritz step below rotates. The
869 * checkpoint writer stores one spin channel only, so a spin-polarized
870 * run keeps the atomic guess.
871 */
872 const bool reuse_saved_wavefunctions =
873 !starting_wavefunction_directory_.empty() && number_of_spin_components() == 1;
874 if (!starting_wavefunction_directory_.empty() && !reuse_saved_wavefunctions) {
875 log::info(" Saved bands at '{}' not reused: the checkpoint holds one spin "
876 "channel and this run has {}",
877 starting_wavefunction_directory_,
879 }
880 int kpoint_states_from_saved_bands = 0;
881
882 double atomic_wfc_ms = 0.0;
883 double rotate_ms = 0.0;
884 for (int kpoint_index_state = 0; kpoint_index_state < number_of_kpoint_states;
885 ++kpoint_index_state) {
886 int spin_index = kpoint_index_state / number_of_kpoints;
887 int kpoint_index = kpoint_index_state % number_of_kpoints;
888
889 auto timer_awfc_start = std::chrono::high_resolution_clock::now();
890 // The starting set: saved bands when they fit, else atomic orbitals + random.
891 std::vector<std::vector<Complex>> atomic_wavefunctions;
892 if (reuse_saved_wavefunctions &&
893 take_saved_starting_wavefunctions(kpoint_index, atomic_wavefunctions)) {
894 ++kpoint_states_from_saved_bands;
895 } else {
896 atomic_wavefunction_initializer.compute_atomic_wavefunctions(
897 kpoint_index,
898 number_of_plane_waves(kpoint_index),
900 g_vector_indices(kpoint_index),
902 kpoint_grid(),
904 quantum_system_snapshot_->pseudopotential_basis().pseudopotential_set(),
905 atomic_wavefunctions);
906 }
907 auto timer_awfc_end = std::chrono::high_resolution_clock::now();
908 atomic_wfc_ms +=
909 std::chrono::duration<double, std::milli>(timer_awfc_end - timer_awfc_start)
910 .count();
912
913 atomic_wavefunction_initializer.rotate_wavefunctions(
914 kpoint_index,
915 kpoint_index_state,
916 number_of_plane_waves(kpoint_index),
918 g_vector_indices(kpoint_index),
919 kinetic_energy_squared()[kpoint_index],
920 starting_guess_potential[static_cast<std::size_t>(spin_index)],
922 kpoint_grid(),
926 atomic_wavefunctions,
929 auto timer_rotate_end = std::chrono::high_resolution_clock::now();
930 rotate_ms +=
931 std::chrono::duration<double, std::milli>(timer_rotate_end - timer_awfc_end)
932 .count();
934 }
935 auto timer_4 = std::chrono::high_resolution_clock::now();
936 if (reuse_saved_wavefunctions) {
937 // Counted once per pool: reduce_scalar runs across pools.
938 Real reused_states = kpoint_states_from_saved_bands;
939 Real all_states = number_of_kpoint_states;
940 execution_policy_->reduce_scalar(reused_states);
941 execution_policy_->reduce_scalar(all_states);
942 log::info(" Starting wavefunctions = saved bands at {} of {} k-point(s) from "
943 "'{}'",
944 std::lround(reused_states),
945 std::lround(all_states),
946 starting_wavefunction_directory_);
947 }
950
951 log::debug(" wfc_init breakdown:");
952 log::debug(" interp_table+count: {:.1f} ms",
953 std::chrono::duration<double, std::milli>(timer_1 - timer_0).count());
954 log::debug(" effective_potential: {:.1f} ms",
955 std::chrono::duration<double, std::milli>(timer_2 - timer_1).count());
956 log::debug(" kb_projectors: {:.1f} ms",
957 std::chrono::duration<double, std::milli>(timer_3 - timer_2).count());
958 log::debug(" atomic_wfc_gen: {:.1f} ms", atomic_wfc_ms);
959 log::debug(" rotate_wfc: {:.1f} ms", rotate_ms);
960 log::debug(" atomic_wfc+rotate: {:.1f} ms",
961 std::chrono::duration<double, std::milli>(timer_4 - timer_3).count());
962 }
963
965 diagonalizer_->set_first_iteration(iteration_ == 1);
966
967 int number_of_kpoints = kpoint_grid().number_of_kpoints();
968 int number_of_kpoint_states = number_of_kpoints * number_of_spin_components();
969
970 // Wire or pre-compute KB projectors for each k-point (reused by ρ_ij accumulation)
972 cached_kleinman_bylander_projectors_.resize(number_of_kpoints);
973 for (int kpoint_index = 0; kpoint_index < number_of_kpoints; ++kpoint_index) {
975 kpoint_grid()[kpoint_index].coordinates,
978 quantum_system_snapshot_->pseudopotential_basis().pseudopotential_set(),
979 quantum_system_snapshot_->pseudopotential_basis().beta_function_table(),
980 g_vector_indices(kpoint_index),
981 number_of_plane_waves(kpoint_index),
982 quantum_system_snapshot_->pseudopotential_basis().total_number_of_projectors(),
984 diagonalizer_->set_cached_projectors(
985 kpoint_index, &cached_kleinman_bylander_projectors_[kpoint_index]);
986 }
987 } else {
988 for (int kpoint_index = 0; kpoint_index < number_of_kpoints; ++kpoint_index) {
989 diagonalizer_->set_cached_projectors(
990 kpoint_index, &cached_kleinman_bylander_projectors_[kpoint_index]);
991 }
992 }
993
994 /**
995 * ── Forward pass: solve k-points 0, 1, 2, ..., N-1 ──
996 * Each k-point's converged wavefunctions seed the next k-point.
997 * At band-path segment boundaries (high-symmetry points where the path
998 * direction changes), propagation is skipped to avoid biasing the Davidson
999 * solver with wavefunctions from the wrong symmetry direction.
1000 */
1001 for (int kpoint_index_state = 0; kpoint_index_state < number_of_kpoint_states;
1002 ++kpoint_index_state) {
1003 int spin_index = kpoint_index_state / number_of_kpoints;
1004 int kpoint_index = kpoint_index_state % number_of_kpoints;
1005 // Invalidate cache when the spin channel (and thus potential) changes
1006 if (kpoint_index == 0) {
1007 diagonalizer_->invalidate_smooth_potential_cache();
1008 if (!hubbard_manifolds_.empty()) {
1009 diagonalizer_->set_hubbard_d_matrix(&hubbard_d_matrix_per_spin_[spin_index]);
1010 }
1011 }
1012 diagonalizer_->solve(kpoint_index_state,
1013 kpoint_index,
1014 number_of_plane_waves(kpoint_index),
1016 g_vector_indices(kpoint_index),
1017 kinetic_energy_squared()[kpoint_index],
1018 real_space_potential_[spin_index],
1020 kpoint_grid(),
1024 report_unconverged_solve(kpoint_index_state);
1025
1026 /**
1027 * Propagate converged wavefunctions to the next k-point, unless we
1028 * are at a segment boundary where the path direction changes.
1029 *
1030 * HARD RULE: Propagation by direct coefficient copying is only valid if
1031 * the G-vector bases are identical. In Q3, k-points have different G-spheres
1032 * and sortings. Direct propagation destroys the good starting guess from
1033 * the previous SCF iteration. Disable for SCF.
1034 */
1035 bool is_scf = (calculation_ == "scf" || calculation_ == "self_consistent_field");
1036 if (!is_scf && !is_at_band_path_segment_boundary(kpoint_index)) {
1038 }
1039 }
1040
1041 /**
1042 * ── Backward fix: re-solve edge k-points using neighbor seeds ──
1043 * This is only relevant for band-path calculations to fix symmetry-breaking
1044 * at segment boundaries. Skip for SCF.
1045 */
1046 if (calculation_ != "scf" && calculation_ != "self_consistent_field") {
1048 }
1049 }
1050
1055
1056 /**
1057 * The base check alone lets a DFT+U run exit while the (now damped, see
1058 * `previous_hubbard_occupation_matrices_`) occupation matrix is still
1059 * visibly moving iteration to iteration: the density can be
1060 * self-consistent while V_U, built from a still-relaxing n, is not.
1061 * `hubbard_occupation_residual_` is updated for *this* iteration inside
1062 * `construct_density_from_states()`, which `perform_iteration()` always
1063 * runs before this is checked (`SCFIterator::iterate()`), so it is never
1064 * stale by an iteration. The `hubbard_manifolds_.empty()` short-circuit
1065 * means non-Hubbard runs never consult the residual at all, so its
1066 * "unconverged" default (see the member doc) never matters for them.
1067 *
1068 * `occupation_matrices` going into the damping step is already pool- and
1069 * band-reduced (`accumulate_hubbard_occupation_and_potential`'s own MPI
1070 * reduction, upstream of the damping block), and `mixing_beta_` is the
1071 * same scalar on every rank, so `hubbard_occupation_residual_` is
1072 * deterministic pure arithmetic on already-rank-consistent inputs —
1073 * unlike `density_residual_`, it needs no `reduce_scalar_max` of its own
1074 * (see that residual's docstring for why *it* needs one: per-rank FFTW
1075 * plan noise, which nothing in the damping step re-introduces).
1076 */
1082
1083 /**
1084 * Recompute the DFT+U occupation matrix from this iteration's converged wavefunctions,
1085 * then the Dudarev energy and D-matrix for each spin channel. Called once per SCF
1086 * iteration (after all k-points/spins are solved), mirroring
1087 * UltrasoftPlanewavePseudopotentialKohnShamSCFIterator::accumulate_projector_overlaps()'s
1088 * k-point-state loop and pool-reduction pattern. No-op if hubbard_manifolds_ is empty.
1089 */
1091 if (hubbard_manifolds_.empty()) {
1092 return;
1093 }
1094
1095 int number_of_kpoints = kpoint_grid().number_of_kpoints();
1096 int number_of_kpoint_states = number_of_kpoints * number_of_spin_components();
1097 size_t number_of_manifolds = hubbard_manifolds_.size();
1098
1099 std::vector<int> manifold_row_offsets(number_of_manifolds);
1100 int total_hubbard_orbitals = 0;
1101 {
1102 int offset = 0;
1103 for (size_t manifold_index = 0; manifold_index < number_of_manifolds;
1104 ++manifold_index) {
1105 manifold_row_offsets[manifold_index] = offset;
1106 offset +=
1107 static_cast<int>(hubbard_manifolds_[manifold_index].orbital_indices.size());
1108 }
1109 total_hubbard_orbitals = offset;
1110 }
1111
1112 // occupation_matrices[manifold_index][spin_index] = row-major manifold_size^2.
1113 std::vector<std::vector<std::vector<Complex>>> occupation_matrices(number_of_manifolds);
1114 for (size_t manifold_index = 0; manifold_index < number_of_manifolds; ++manifold_index) {
1115 int manifold_size =
1116 static_cast<int>(hubbard_manifolds_[manifold_index].orbital_indices.size());
1117 occupation_matrices[manifold_index].assign(
1119 std::vector<Complex>(static_cast<size_t>(manifold_size) * manifold_size,
1120 Complex(0.0, 0.0)));
1121 }
1122
1123 for (int kpoint_index_state = 0; kpoint_index_state < number_of_kpoint_states;
1124 ++kpoint_index_state) {
1125 int spin_index = kpoint_index_state / number_of_kpoints;
1126 int kpoint_index = kpoint_index_state % number_of_kpoints;
1127 Real kpoint_weight = kpoint_grid()[kpoint_index].weight;
1128 int plane_waves_at_kpoint = number_of_plane_waves(kpoint_index);
1129 const auto& hubbard_projectors = cached_hubbard_projectors_[kpoint_index];
1130
1131 std::vector<Real> band_occupations(number_of_bands_);
1132 for (int band_index = 0; band_index < number_of_bands_; ++band_index) {
1133 band_occupations[band_index] =
1135 kpoint_index_state, band_index);
1136 }
1137
1138 /**
1139 * All <phi_j|psi_b> for this k-point in one ZGEMM -- see
1140 * compute_hubbard_projector_overlaps()'s docstring for why this is batched over
1141 * every Hubbard orbital rather than looped per manifold. Only occupied bands are
1142 * contracted, as the scalar loop this replaced also skipped the rest.
1143 */
1144 std::vector<int> occupied_band_indices;
1145 for (int band_index = 0; band_index < number_of_bands_; ++band_index) {
1146 if (band_occupations[band_index] >= math::tolerances::occupation_threshold) {
1147 occupied_band_indices.push_back(band_index);
1148 }
1149 }
1150 int number_of_occupied_bands = static_cast<int>(occupied_band_indices.size());
1151
1152 std::vector<Complex> packed_projectors(static_cast<size_t>(plane_waves_at_kpoint) *
1153 total_hubbard_orbitals);
1154 for (int orbital_index = 0; orbital_index < total_hubbard_orbitals; ++orbital_index) {
1155 const Complex* projector = hubbard_projectors[orbital_index];
1156 std::copy(projector,
1157 projector + plane_waves_at_kpoint,
1158 packed_projectors.begin() +
1159 static_cast<size_t>(orbital_index) * plane_waves_at_kpoint);
1160 }
1161
1162 std::vector<Complex> occupied_wavefunctions(static_cast<size_t>(plane_waves_at_kpoint) *
1163 number_of_occupied_bands);
1164 for (int occupied_band_index = 0; occupied_band_index < number_of_occupied_bands;
1165 ++occupied_band_index) {
1166 int band_index = occupied_band_indices[occupied_band_index];
1167 size_t offset = static_cast<size_t>(occupied_band_index) * plane_waves_at_kpoint;
1168 for (int g_index = 0; g_index < plane_waves_at_kpoint; ++g_index) {
1169 occupied_wavefunctions[offset + g_index] =
1170 quantum_system_.wavefunction(kpoint_index_state, band_index, g_index);
1171 }
1172 }
1173
1174 std::vector<Complex> batched_overlaps;
1175 compute_hubbard_projector_overlaps(plane_waves_at_kpoint,
1176 total_hubbard_orbitals,
1177 number_of_occupied_bands,
1178 packed_projectors.data(),
1179 occupied_wavefunctions.data(),
1180 batched_overlaps);
1181
1182 /**
1183 * Gamma-only sums over half the G sphere, so <phi_m|psi> comes out
1184 * at half its full-sphere value plus an Im-Im cross term. Completing
1185 * it here rather than inside the occupation kernel keeps n_mm' =
1186 * conj(O_m) O_m' exactly as written, and makes n real symmetric --
1187 * which in turn makes the Dudarev D matrix real, so the Hamiltonian
1188 * term it feeds preserves the half sphere's reality condition.
1189 */
1192 plane_waves_at_kpoint,
1193 total_hubbard_orbitals,
1194 number_of_occupied_bands,
1195 packed_projectors.data(),
1196 occupied_wavefunctions.data(),
1198 planewave_basis_, g_vector_indices(kpoint_index), plane_waves_at_kpoint),
1199 /*band_functions_carry_g_component=*/false,
1200 batched_overlaps);
1201 }
1202
1203 for (size_t manifold_index = 0; manifold_index < number_of_manifolds;
1204 ++manifold_index) {
1205 int manifold_size =
1206 static_cast<int>(hubbard_manifolds_[manifold_index].orbital_indices.size());
1207 int row_offset = manifold_row_offsets[manifold_index];
1208
1209 /**
1210 * Scatter this manifold's row block; unoccupied bands stay zero, exactly as
1211 * the scalar loop's `continue` left them.
1212 */
1213 Matrix<Complex> overlaps(static_cast<size_t>(number_of_bands_),
1214 static_cast<size_t>(manifold_size));
1215 for (int occupied_band_index = 0; occupied_band_index < number_of_occupied_bands;
1216 ++occupied_band_index) {
1217 size_t band_index =
1218 static_cast<size_t>(occupied_band_indices[occupied_band_index]);
1219 size_t column_offset =
1220 static_cast<size_t>(occupied_band_index) * total_hubbard_orbitals;
1221 for (int m = 0; m < manifold_size; ++m) {
1222 overlaps(band_index, static_cast<size_t>(m)) =
1223 batched_overlaps[column_offset + static_cast<size_t>(row_offset) +
1224 static_cast<size_t>(m)];
1225 }
1226 }
1227 /**
1228 * Under MPI band-parallelism (G-vector distribution within a k-point pool),
1229 * each rank's g_index loop above only covers its LOCAL plane-wave subset, so
1230 * overlaps here is only a partial <phi_m|psi> sum -- reduce across the
1231 * band-parallel group before use, mirroring the applicator's identical
1232 * <phi_m|psi> reduction for the H|psi> Hubbard term
1233 * (hamiltonian_applicator/serial.hpp's reduce_within_group(hubbard_overlaps, ...)).
1234 * A no-op when band_size == 1 (serial ExecutionPolicy's reduce_within_group()).
1235 */
1237 number_of_bands_ * manifold_size);
1240 manifold_size,
1241 overlaps,
1242 band_occupations,
1243 kpoint_weight,
1244 occupation_matrices[manifold_index][spin_index]);
1245 }
1246 }
1247
1248 /**
1249 * Each pool computed the occupation matrix only for its subset of k-points.
1250 * Flatten (Complex has no reduce_vector overload) -> reduce across pools -> unflatten.
1251 */
1252 std::vector<Real> flat_buffer;
1253 for (const auto& per_spin_matrices : occupation_matrices) {
1254 for (const auto& matrix : per_spin_matrices) {
1255 for (const auto& element : matrix) {
1256 flat_buffer.push_back(element.real());
1257 flat_buffer.push_back(element.imag());
1258 }
1259 }
1260 }
1261 execution_policy_->reduce_vector(flat_buffer);
1262 {
1263 size_t flat_index = 0;
1264 for (auto& per_spin_matrices : occupation_matrices) {
1265 for (auto& matrix : per_spin_matrices) {
1266 for (auto& element : matrix) {
1267 element = Complex(flat_buffer[flat_index], flat_buffer[flat_index + 1]);
1268 flat_index += 2;
1269 }
1270 }
1271 }
1272 }
1273
1274 /**
1275 * Restore the symmetry the IBZ sum does not carry: time reversal, then
1276 * the spatial operations.
1277 *
1278 * `n` has angular indices, so a weighted irreducible-wedge sum does not
1279 * reproduce the full-zone result the way an invariant scalar does — the
1280 * trace comes out right and the structure does not. Averaging over the
1281 * group is what QE does too; without it silicon's 3p
1282 * manifold, which symmetry forces to be isotropic, came out anisotropic
1283 * enough to move E_U from 0.1918 to 0.1204 Ry.
1284 *
1285 * The wedge was reduced by the spatial operations *and* time reversal,
1286 * so both have to come back; the first call is the Θ half and is
1287 * described where it is defined. It is a separate call rather than
1288 * another operation inside the group loop because Θ is antiunitary — it
1289 * conjugates `n` instead of rotating its indices, and no real D(R) can
1290 * express that. The two commute (a real D preserves realness), so the
1291 * order is only a matter of which one gets to run on the smaller job.
1292 *
1293 * Must run after both reductions: the matrix has to be complete before
1294 * it is averaged.
1295 *
1296 * Unconditional, with no "was symmetry used?" flag to thread through:
1297 * a full-zone sum already produces an invariant matrix, and averaging
1298 * an invariant over the group returns it unchanged. Gamma-only is the
1299 * one exclusion for the spatial half — its half-sphere basis breaks the
1300 * point group by construction, the same reason the density symmetrizer
1301 * stands down there. Θ needs no such exclusion: a Γ-only `n` is real
1302 * already.
1303 */
1306 std::vector<HubbardManifoldLayout> layouts;
1307 layouts.reserve(number_of_manifolds);
1308 for (const auto& manifold : hubbard_manifolds_)
1309 layouts.push_back({manifold.atom_index,
1310 manifold.angular_momentum,
1311 static_cast<int>(manifold.orbital_indices.size())});
1313 crystal_structure(), cached_symmetry_operations(), layouts, occupation_matrices);
1314 }
1315
1316 /**
1317 * First iteration only, after the matrix is complete (reduced and
1318 * symmetrized) and before anything reads it: replace the named
1319 * eigenvalues. The damping cache bootstraps from these seeded
1320 * matrices below, and the first Hubbard potential is built from
1321 * them, which is the entire mechanism -- V_U starts in the wanted
1322 * basin and self-consistency takes over from there.
1323 *
1324 * The user value is per-spin ([0, 1]); the raw matrix carries the
1325 * k-weight spin factor, so scale by spin_degeneracy() on the way in
1326 * (a factor of 1 for a spin-polarized run).
1327 */
1329 bool seeding_already_reported =
1331 1 + std::max(0, config().hubbard_fixed_occupation_iterations);
1332 for (size_t manifold_index = 0; manifold_index < number_of_manifolds;
1333 ++manifold_index) {
1334 const auto& manifold = hubbard_manifolds_[manifold_index];
1335 int manifold_size = static_cast<int>(manifold.orbital_indices.size());
1336 const std::string& atom_species = crystal_structure().element(manifold.atom_index);
1337 for (const auto& directive : config().hubbard_starting_eigenvalues) {
1338 if (directive.species_symbol != atom_species)
1339 continue;
1340 if (directive.eigenvalue_index >= manifold_size)
1341 throw std::runtime_error("hubbard starting eigenvalue " +
1342 std::to_string(directive.eigenvalue_index + 1) +
1343 " for species '" + directive.species_symbol +
1344 "' exceeds the manifold size " +
1345 std::to_string(manifold_size));
1347 occupation_matrices[manifold_index]
1348 [static_cast<size_t>(directive.spin_index)],
1349 manifold_size,
1350 directive.eigenvalue_index,
1351 directive.target_occupation * spin_degeneracy());
1352 if (!seeding_already_reported)
1353 log::info(" DFT+U: seeding atom {} spin {} eigenvalue {} -> {:.4f}",
1354 manifold.atom_index + 1,
1355 directive.spin_index + 1,
1356 directive.eigenvalue_index + 1,
1357 directive.target_occupation);
1358 }
1359 }
1361 }
1362
1363 /**
1364 * Tr[n] per manifold, per spin — the first thing to look at when a
1365 * DFT+U result looks wrong.
1366 *
1367 * It is the number of electrons the manifold's projectors actually see,
1368 * so it says immediately whether the projection is capturing the shell.
1369 * For ultrasoft and PAW that depends on the overlap operator: the
1370 * pseudo orbital alone misses the on-site charge the augmentation
1371 * carries. Measured on fcc nickel with a PAW dataset: Tr[n] = 8.83
1372 * with the overlap operator and 2.71 without it, so the bare pseudo
1373 * projection sees under a third of the d shell. Logged rather than left
1374 * to a debugger, because the failure it diagnoses is a converged,
1375 * plausible, wrong answer.
1376 */
1377 hubbard_occupation_traces_.assign(number_of_manifolds, {});
1378 for (size_t manifold_index = 0; manifold_index < number_of_manifolds; ++manifold_index) {
1379 int manifold_size =
1380 static_cast<int>(hubbard_manifolds_[manifold_index].orbital_indices.size());
1381 std::string traces;
1382 for (int spin_index = 0; spin_index < number_of_spin_components(); ++spin_index) {
1383 Real trace = 0.0;
1384 for (int m = 0; m < manifold_size; m++)
1385 trace += occupation_matrices[manifold_index][spin_index]
1386 [static_cast<size_t>(m) * manifold_size + m]
1387 .real();
1388 traces += fmt::format("{}{:.4f}", spin_index == 0 ? "" : " / ", trace);
1389 /**
1390 * Kept at full precision alongside the four-decimal line, and
1391 * recorded here rather than recomputed for the results file, so
1392 * the two can never name different numbers -- the same reason
1393 * the SCF history is recorded where its line is printed.
1394 */
1395 hubbard_occupation_traces_[manifold_index].push_back(trace);
1396 }
1397 log::info(" DFT+U: atom {} Tr[n] = {}",
1398 hubbard_manifolds_[manifold_index].atom_index + 1,
1399 traces);
1400 }
1401
1402 /**
1403 * Damp the occupation matrix before it drives V_U. The mixer decides
1404 * whether damping is warranted at all and whether to accelerate; see
1405 * `HubbardOccupationMixer` for why each of those is conditional.
1406 */
1407 bool damping_was_active = hubbard_occupation_mixer_.damping_active();
1408 const auto& damped_occupation_matrices = hubbard_occupation_mixer_.blend(
1409 occupation_matrices, mixing_beta_, convergence_threshold_);
1411 if (!damping_was_active && hubbard_occupation_mixer_.damping_active())
1412 log::info(" DFT+U: occupation matrix is not converging monotonically; "
1413 "damping it at mixing_beta from here");
1414
1415 /**
1416 * Dudarev energy + per-spin D-matrix, assembled into the block-diagonal buffers
1417 * the applicator expects (column-major, one buffer per spin).
1418 *
1419 * Normalization: kpoint_grid() weights already carry the spin factor (they sum
1420 * to 2 for spin-unpolarized runs, matching the electron-counting convention
1421 * documented in fermi_energy/planewave/init.hpp), so the n_mm' accumulated above
1422 * has eigenvalues up to spin_degeneracy(), not the [0,1] the Dudarev formula
1423 * (E_U = (U/2) Tr[n(1-n)]) is defined for. Rescale n by 1/spin_degeneracy() before
1424 * the formula, then scale the resulting per-channel energy back up by
1425 * spin_degeneracy() -- physically, an unpolarized run has two identical,
1426 * degenerate spin channels each contributing this same per-spin energy. The
1427 * D-matrix is used as computed (already expressed per spin channel, matching how
1428 * it is applied to a single, spin-independent wavefunction solve at nspin=1).
1429 */
1430 Real spin_degeneracy_factor = spin_degeneracy();
1431 Real total_hubbard_energy = 0.0;
1432 Real total_hubbard_potential_energy = 0.0;
1433 for (auto& buffer : hubbard_d_matrix_per_spin_) {
1434 std::fill(buffer.begin(), buffer.end(), Complex(0.0, 0.0));
1435 }
1436 for (size_t manifold_index = 0; manifold_index < number_of_manifolds; ++manifold_index) {
1437 int manifold_size =
1438 static_cast<int>(hubbard_manifolds_[manifold_index].orbital_indices.size());
1439 int row_offset = manifold_row_offsets[manifold_index];
1440 Real u_rydberg = hubbard_manifolds_[manifold_index].u_rydberg;
1441 for (int spin_index = 0; spin_index < number_of_spin_components(); ++spin_index) {
1442 /**
1443 * A scaled copy, not a reference: this is the mixer's retained
1444 * damped state, carried into the *next* iteration, and it must
1445 * survive this rescale untouched.
1446 */
1447 auto raw_occupation_matrix = damped_occupation_matrices[manifold_index][spin_index];
1448 for (auto& element : raw_occupation_matrix) {
1449 element /= spin_degeneracy_factor;
1450 }
1452 manifold_size, u_rydberg, raw_occupation_matrix);
1453 total_hubbard_energy += result.energy * spin_degeneracy_factor;
1454
1455 /**
1456 * Tr[V_U n] for this manifold and channel, accumulated from the
1457 * same matrices the energy used so the two cannot drift apart.
1458 * `compute_double_counting_correction()` subtracts it; see the
1459 * note there for why it is mandatory.
1460 *
1461 * V is indexed (m, m') and pairs with n_{m'm} — the transpose
1462 * convention `compute_hubbard_energy_and_potential` already
1463 * documents for the D matrix itself.
1464 */
1465 Real manifold_potential_energy = 0.0;
1466 for (int m = 0; m < manifold_size; ++m) {
1467 for (int m_prime = 0; m_prime < manifold_size; ++m_prime) {
1468 manifold_potential_energy +=
1469 (result.d_matrix[static_cast<size_t>(m * manifold_size + m_prime)] *
1470 raw_occupation_matrix[static_cast<size_t>(m_prime * manifold_size +
1471 m)])
1472 .real();
1473 }
1474 }
1475 total_hubbard_potential_energy +=
1476 manifold_potential_energy * spin_degeneracy_factor;
1477
1478 auto& combined_buffer = hubbard_d_matrix_per_spin_[spin_index];
1479 for (int m = 0; m < manifold_size; ++m) {
1480 for (int m_prime = 0; m_prime < manifold_size; ++m_prime) {
1481 int global_row = row_offset + m;
1482 int global_column = row_offset + m_prime;
1483 // Column-major, matching the applicator's BLAS "N","N" GEMM convention.
1484 combined_buffer[static_cast<size_t>(global_row) +
1485 static_cast<size_t>(global_column) *
1487 result.d_matrix[static_cast<size_t>(m * manifold_size + m_prime)];
1488 }
1489 }
1490 }
1491 }
1492 /**
1493 * A spin-unpolarized calculation double-counts each manifold's occupation across
1494 * the (non-existent) second spin channel; number_of_spin_components() == 1 already
1495 * accounts for this since the loop above only ran once per manifold in that case.
1496 */
1497 energies_mutable().hubbard_energy = total_hubbard_energy;
1498 hubbard_potential_energy_ = total_hubbard_potential_energy;
1499 }
1500
1501 /**
1502 * The base correction, plus DFT+U's own.
1503 *
1504 * Structurally identical to what the PAW iterator does for its one-center
1505 * term: a potential that entered the band energy has to be removed from it
1506 * here, and the corresponding energy is added back separately. The two
1507 * additions compose — a PAW + DFT+U run subtracts both.
1508 */
1511 hubbard_potential_energy();
1512 }
1513
1514 /**
1515 * Σ_σ Tr[V_U^σ n^σ] — the DFT+U potential's own contribution to the band
1516 * energy, which the double-counting correction has to remove.
1517 *
1518 * The Hubbard potential is applied inside the Hamiltonian, so every
1519 * eigenvalue already contains it. Adding E_U on top without removing
1520 * Tr[V_U n] counts the on-site interaction twice, and because
1521 * Tr[V_U n] = U(½Tr n − Tr n²) is *negative* for a partially filled shell,
1522 * the error lowers the total energy — which is how this presented:
1523 * switching U on made Q3's energy fall by ~1 Ry where E_U is positive
1524 * definite and QE's rises. The PAW one-center term has exactly this
1525 * counterpart and always did (`compute_double_counting_correction()` in the PAW iterator);
1526 * DFT+U simply never grew one.
1527 */
1528 [[nodiscard]] Real hubbard_potential_energy() const {
1529 return hubbard_potential_energy_;
1530 }
1531
1532 /**
1533 * Copy converged wavefunctions from the current k-point to the next k-point's
1534 * slot in quantum_system_, providing a physically motivated initial guess for
1535 * the Davidson solver.
1536 *
1537 * When the two k-points have different numbers of plane waves (due to the
1538 * |k+G|² cutoff sphere varying with k), the coefficients are truncated or
1539 * zero-padded. This is valid because G-vectors are sorted by kinetic energy,
1540 * so the leading coefficients correspond to the most important basis functions.
1541 */
1542 void propagate_wavefunctions_to_next_kpoint(int current_kpoint_state_index,
1543 int total_kpoint_states) {
1544 int next_kpoint_state_index = current_kpoint_state_index + 1;
1545 if (next_kpoint_state_index >= total_kpoint_states) {
1546 return;
1547 }
1548
1549 int number_of_kpoints = kpoint_grid().number_of_kpoints();
1550 int current_kpoint_index = current_kpoint_state_index % number_of_kpoints;
1551 int next_kpoint_index = next_kpoint_state_index % number_of_kpoints;
1552
1553 // Only propagate within the same spin channel (don't cross spin boundaries)
1554 int current_spin_index = current_kpoint_state_index / number_of_kpoints;
1555 int next_spin_index = next_kpoint_state_index / number_of_kpoints;
1556 if (current_spin_index != next_spin_index) {
1557 return;
1558 }
1559
1560 int source_number_of_plane_waves = number_of_plane_waves(current_kpoint_index);
1561 int target_number_of_plane_waves = number_of_plane_waves(next_kpoint_index);
1562 int coefficients_to_copy =
1563 std::min(source_number_of_plane_waves, target_number_of_plane_waves);
1564
1565 for (int band_index = 0; band_index < number_of_bands_; ++band_index) {
1566 const Complex* source_band_data =
1567 quantum_system_.wavefunction_band_data(current_kpoint_state_index, band_index);
1568 Complex* target_band_data =
1569 quantum_system_.wavefunction_band_data(next_kpoint_state_index, band_index);
1570
1571 // Copy the shared leading coefficients
1572 std::copy(source_band_data, source_band_data + coefficients_to_copy, target_band_data);
1573
1574 // Zero-pad if the target has more plane waves than the source
1575 if (target_number_of_plane_waves > source_number_of_plane_waves) {
1576 std::fill(target_band_data + coefficients_to_copy,
1577 target_band_data + target_number_of_plane_waves,
1578 Complex(0.0, 0.0));
1579 }
1580
1581 // Also propagate the eigenvalue as a starting estimate
1582 quantum_system_.set_eigenvalue(
1583 next_kpoint_state_index,
1584 band_index,
1585 quantum_system_.eigenvalue(current_kpoint_state_index, band_index));
1586 }
1587 }
1588
1589 /**
1590 * Copy converged wavefunctions from one k-point state to another (backward direction).
1591 *
1592 * Unlike propagate_wavefunctions_to_next_kpoint which only moves forward,
1593 * this copies from any source to any target state index. Used to seed
1594 * k[0] from k[1]'s converged wavefunctions after the forward pass.
1595 */
1596 void propagate_wavefunctions_backward(int source_kpoint_state_index,
1597 int target_kpoint_state_index) {
1598 int number_of_kpoints = kpoint_grid().number_of_kpoints();
1599 int source_kpoint_index = source_kpoint_state_index % number_of_kpoints;
1600 int target_kpoint_index = target_kpoint_state_index % number_of_kpoints;
1601
1602 int source_number_of_plane_waves = number_of_plane_waves(source_kpoint_index);
1603 int target_number_of_plane_waves = number_of_plane_waves(target_kpoint_index);
1604 int coefficients_to_copy =
1605 std::min(source_number_of_plane_waves, target_number_of_plane_waves);
1606
1607 for (int band_index = 0; band_index < number_of_bands_; ++band_index) {
1608 const Complex* source_band_data =
1609 quantum_system_.wavefunction_band_data(source_kpoint_state_index, band_index);
1610 Complex* target_band_data =
1611 quantum_system_.wavefunction_band_data(target_kpoint_state_index, band_index);
1612
1613 std::copy(source_band_data, source_band_data + coefficients_to_copy, target_band_data);
1614
1615 if (target_number_of_plane_waves > source_number_of_plane_waves) {
1616 std::fill(target_band_data + coefficients_to_copy,
1617 target_band_data + target_number_of_plane_waves,
1618 Complex(0.0, 0.0));
1619 }
1620
1621 quantum_system_.set_eigenvalue(
1622 target_kpoint_state_index,
1623 band_index,
1624 quantum_system_.eigenvalue(source_kpoint_state_index, band_index));
1625 }
1626 }
1627
1628 /**
1629 * Check whether a k-point index falls on a band-path segment boundary.
1630 *
1631 * Segment boundaries are the high-symmetry points where the path direction
1632 * changes (e.g., G, X, W, K in a G→X→W→K→G→L path). At these points,
1633 * the eigenstates may reorder between segments, so forward propagation of
1634 * wavefunctions across the boundary would bias the Davidson solver toward
1635 * eigenstates from the wrong symmetry direction.
1636 *
1637 * Returns false for SCF calculations (no band path defined) and for the
1638 * endpoint of the last segment (which has no following segment to pollute).
1639 */
1640 [[nodiscard]] bool is_at_band_path_segment_boundary(int kpoint_index) const {
1641 if (band_path_.empty() || band_path_points_per_segment_ <= 0) {
1642 return false;
1643 }
1644 int number_of_segments = static_cast<int>(band_path_.size()) - 1;
1645 if (number_of_segments <= 0) {
1646 return false;
1647 }
1648 /**
1649 * The last k-point (endpoint of the final segment) is not a boundary
1650 * because there is no following segment.
1651 */
1652 int last_kpoint_index = number_of_segments * band_path_points_per_segment_;
1653 if (kpoint_index >= last_kpoint_index) {
1654 return false;
1655 }
1656 // Boundaries are at multiples of points_per_segment: 0, PPS, 2*PPS, ...
1657 return (kpoint_index % band_path_points_per_segment_) == 0;
1658 }
1659
1660 /**
1661 * Re-solve edge k-points that lacked proper propagation seeds.
1662 *
1663 * After the forward pass, two types of k-points may have suboptimal
1664 * eigenvalues for high conduction bands:
1665 *
1666 * (a) k[0] — the very first k-point, solved with only atomic-orbital
1667 * seeds because no predecessor exists.
1668 *
1669 * (b) The first k-point of each new segment after a direction change —
1670 * these were solved without propagation seeds because we intentionally
1671 * skipped propagation across the segment boundary.
1672 *
1673 * For each such edge, we propagate backwards from a correctly converged
1674 * neighbor (2 steps into the segment) and re-solve. The neighbor at
1675 * offset +2 was itself seeded by propagation within the segment (from
1676 * offset +1) and so has correct eigenstates for this path direction.
1677 */
1679 int number_of_kpoint_states) {
1680 if (number_of_kpoints <= 2) {
1681 return;
1682 }
1683
1684 /**
1685 * Collect all k-point indices that need re-solving.
1686 * Always include k[0]. If a band path is defined, also include
1687 * the first k-point of each segment after the first.
1688 */
1689 std::vector<int> edge_kpoint_indices;
1690 edge_kpoint_indices.push_back(0);
1691
1692 if (!band_path_.empty() && band_path_points_per_segment_ > 0) {
1693 int number_of_segments = static_cast<int>(band_path_.size()) - 1;
1694 for (int segment_index = 1; segment_index < number_of_segments; ++segment_index) {
1695 int boundary_kpoint_index = segment_index * band_path_points_per_segment_;
1696 if (boundary_kpoint_index < number_of_kpoints) {
1697 edge_kpoint_indices.push_back(boundary_kpoint_index);
1698 }
1699 }
1700 }
1701
1702 /**
1703 * Number of k-points to re-solve at each edge (the boundary itself
1704 * plus this many into the segment). More points improves accuracy for
1705 * high conduction bands at the cost of extra diagonalizations.
1706 */
1707 const int backward_sweep_depth = 5;
1708
1709 for (int spin_index = 0; spin_index < number_of_spin_components(); ++spin_index) {
1710 for (int edge_kpoint_index : edge_kpoint_indices) {
1711 /**
1712 * Find the seed: the first k-point beyond the sweep region that
1713 * was correctly solved during the forward pass.
1714 */
1715 int sweep_end =
1716 std::min(edge_kpoint_index + backward_sweep_depth, number_of_kpoints - 1);
1717 int seed_kpoint_index = std::min(sweep_end + 1, number_of_kpoints - 1);
1718
1719 /**
1720 * Sweep backwards from the seed toward the edge point.
1721 * Each re-solved k-point then serves as the seed for the next.
1722 */
1723 for (int target_kpoint_index = sweep_end; target_kpoint_index >= edge_kpoint_index;
1724 --target_kpoint_index) {
1725
1726 int source_state_index = spin_index * number_of_kpoints + seed_kpoint_index;
1727 int target_state_index = spin_index * number_of_kpoints + target_kpoint_index;
1728
1729 propagate_wavefunctions_backward(source_state_index, target_state_index);
1730
1731 diagonalizer_->solve(target_state_index,
1732 target_kpoint_index,
1733 number_of_plane_waves(target_kpoint_index),
1734 number_of_bands_,
1735 g_vector_indices(target_kpoint_index),
1736 kinetic_energy_squared()[target_kpoint_index],
1737 real_space_potential_[spin_index],
1738 crystal_structure(),
1739 kpoint_grid(),
1740 planewave_basis_,
1741 *quantum_system_snapshot_,
1742 quantum_system_);
1743 report_unconverged_solve(target_state_index);
1744
1745 // The just-solved point becomes the seed for the next iteration
1746 seed_kpoint_index = target_kpoint_index;
1747 }
1748 }
1749 }
1750 }
1751
1752 /**
1753 * Warn when a non-self-consistent solve kept bands short of the tolerance.
1754 *
1755 * A self-consistent run finishes them on its next iteration, so only the
1756 * NSCF pass reports: its eigenvectors are the answer, and a model built on
1757 * them (a band structure, a Wannier capture) inherits the error silently.
1758 */
1759 void report_unconverged_solve(int kpoint_index_state) const {
1760 if (!report_unconverged_bands_) {
1761 return;
1762 }
1763 int unconverged = diagonalizer_->number_of_unconverged_bands();
1764 if (unconverged > 0) {
1765 log::warn("NSCF: k-point state {} kept {} of {} bands unconverged after the "
1766 "Davidson iteration cap; its eigenvalues and eigenvectors are not "
1767 "converged to the requested tolerance",
1768 kpoint_index_state,
1769 unconverged,
1770 number_of_bands_);
1771 }
1772 }
1773
1774 // ─── Ionic / external world ──────────────────────────────────────
1775 [[nodiscard]] const std::vector<Complex>& local_ionic_potential_g() const override {
1776 return quantum_system_snapshot_->pseudopotential_basis().total_local_potential_g();
1777 }
1778 [[nodiscard]] const std::vector<Complex>& core_charge_density_g() const override {
1779 return quantum_system_snapshot_->pseudopotential_basis().core_charge_density_reciprocal();
1780 }
1781
1782 // ─── Effective potential ─────────────────────────────────────────
1784 if (planewave_energies().ewald_energy < math::tolerances::numerical_zero_threshold) {
1785 energies_.ewald_energy = compute_ewald(crystal_structure(), planewave_basis_);
1786 }
1787 /**
1788 * Dispersion depends only on the (fixed) geometry, so compute it once
1789 * per iterator lifetime. An explicit flag — not a zero-energy sentinel —
1790 * marks it done: a legitimately zero dispersion energy must not trigger
1791 * recomputation, and a stale nonzero value must not survive a rebuild.
1792 * The factory resolves the configured scheme ("none" contributes an
1793 * exact zero), so no per-scheme branching happens here.
1794 */
1795 if (!dispersion_energy_computed_) {
1796 energies_.van_der_waals_energy =
1797 create_dispersion_calculator(config().dispersion_correction, crystal_structure())
1798 ->compute_energy();
1799 dispersion_energy_computed_ = true;
1800 }
1801
1802 EffectivePotentialResult effective_potential = effective_potential_calculator().compute(
1803 charge_density_real_, number_of_spin_components(), local_ionic_potential_g());
1804
1805 charge_density_g_ = std::move(effective_potential.charge_density_g);
1806 real_space_potential_ = std::move(effective_potential.real_space_potential);
1807 total_potential_g_ = std::move(effective_potential.total_potential_g);
1808 total_potential_g_by_spin_ = std::move(effective_potential.total_potential_g_by_spin);
1809 exchange_correlation_potential_g_ =
1810 std::move(effective_potential.exchange_correlation_potential_g);
1811 energies_.hartree_energy = effective_potential.hartree_energy;
1812 energies_.exchange_correlation_energy = effective_potential.exchange_correlation_energy;
1814 effective_potential.exchange_correlation_potential_energy;
1815
1816 // Cache the real-space ionic local potential on first call (constant during SCF).
1817 if (cached_local_ionic_potential_real_.empty()) {
1818 planewave_basis_.rho_g_to_r(local_ionic_potential_g(),
1819 cached_local_ionic_potential_real_);
1820 }
1821 }
1822
1823 /**
1824 * The effective potential calculator, created on first use and kept, since it
1825 * caches the real-space core charge density.
1826 */
1828 if (!effective_potential_calculator_) {
1829 effective_potential_calculator_ =
1830 std::make_unique<NormConservingPlanewaveEffectivePotentialCalculator>(
1831 planewave_basis_,
1832 crystal_structure(),
1833 *exchange_correlation_,
1834 *execution_policy_,
1835 quantum_system_snapshot_->pseudopotential_basis()
1836 .core_charge_density_reciprocal());
1837 }
1838 return *effective_potential_calculator_;
1839 }
1840
1841 // ─── Pseudopotential setup helpers ───────────────────────────────
1843 quantum_system_snapshot_ =
1845 crystal_structure(), planewave_basis_, pseudopotential_set());
1846 }
1847
1848 /**
1849 * Estimate this rank's footprint from the dimensions setup has settled.
1850 *
1851 * Called once, from the same place the pseudopotential summary is printed,
1852 * because the projector count is the last of its inputs to exist.
1853 */
1854 void report_memory_estimate(int number_of_atomic_wavefunctions) const {
1856 inputs.number_of_bands = number_of_bands_;
1857 const auto& plane_waves_per_kpoint = planewave_basis_.kpoint_number_of_plane_waves();
1859 plane_waves_per_kpoint.empty()
1860 ? 0
1861 : *std::max_element(plane_waves_per_kpoint.begin(), plane_waves_per_kpoint.end());
1862 inputs.number_of_g_vectors = planewave_basis_.number_of_g_vectors();
1863 inputs.number_of_projectors =
1864 quantum_system_snapshot_->pseudopotential_basis().total_number_of_projectors();
1865 inputs.number_of_atomic_orbitals = number_of_atomic_wavefunctions;
1866 inputs.number_of_atoms = crystal_structure().number_of_atoms();
1867 inputs.number_of_spin_components = number_of_spin_components();
1868 inputs.local_number_of_kpoint_states = number_of_kpoint_states();
1869 inputs.mixing_history_depth = mixing_history_size_;
1870 inputs.fft_rho_grid_points = planewave_basis_.fft_rho().total_grid_points();
1871 inputs.fft_wave_grid_points = planewave_basis_.fft_wave().total_grid_points();
1872 inputs.overlap_is_identity = !quantum_system_snapshot_->has_ultrasoft();
1873 inputs.diagonalizer_is_davidson = diagonalization_method_ == "davidson";
1874 inputs.davidson_basis_expansion_factor = config().davidson_basis_expansion_factor;
1877 }
1878
1879 /**
1880 * The saved bands of one local k-point as this run's starting set, decided
1881 * the same way on every rank of the pool: the Rayleigh-Ritz step that
1882 * follows sums its subspace matrices across the pool, so its ranks must
1883 * agree on how many starting vectors there are. False, and the set left
1884 * alone, when any rank of the pool cannot use its share of the file.
1885 */
1887 int kpoint_index, std::vector<std::vector<Complex>>& starting_wavefunctions) const {
1888 std::vector<std::vector<Complex>> saved_bands = read_saved_bands(kpoint_index);
1889 Real ranks_without_saved_bands = saved_bands.empty() ? 1.0 : 0.0;
1890 execution_policy_->reduce_within_pool_scalar(ranks_without_saved_bands);
1891 if (ranks_without_saved_bands > 0.0) {
1892 return false;
1893 }
1894 starting_wavefunctions = std::move(saved_bands);
1895 return true;
1896 }
1897
1898 /**
1899 * The first number_of_bands_ bands of wfc<global k + 1>.dat in the offered
1900 * directory, on this rank's plane waves, matched by Miller index. Empty
1901 * when the file is missing or unreadable, or was written for a different
1902 * basis: another gamma treatment, cell or k-point (a vc-relax step moves
1903 * the cell), fewer bands, or a plane wave of this rank's it does not hold.
1904 *
1905 * Files are matched by k-point index, and the k-point checked. Within a
1906 * relaxation the symmetry is held fixed, so the irreducible k-points and
1907 * their order are the same from step to step; a geometry whose symmetry
1908 * changes them starts the k-points that moved from the atomic guess.
1909 */
1910 [[nodiscard]] std::vector<std::vector<Complex>> read_saved_bands(int kpoint_index) const {
1911 const int global_kpoint_index = execution_policy_->global_kpoint_index(kpoint_index);
1912 const std::string path = starting_wavefunction_directory_ + "/wfc" +
1913 std::to_string(global_kpoint_index + 1) + ".dat";
1914 std::error_code exists_error;
1915 if (!std::filesystem::exists(path, exists_error)) {
1916 return {};
1917 }
1919 try {
1920 reader.read(path);
1921 } catch (const std::exception& error) {
1922 log::debug(" Saved bands not used: {}", error.what());
1923 return {};
1924 }
1925 if (reader.number_of_bands() < number_of_bands_ ||
1926 reader.is_gamma_only() != planewave_basis_.is_gamma_only()) {
1927 return {};
1928 }
1929
1930 // The writer's own quantities, so an unchanged cell and k-point match exactly.
1931 const Matrix3x3 reciprocal_vectors_bohr = crystal_structure().reciprocal_vectors_bohr();
1932 const auto& kpoint = kpoint_grid()[kpoint_index];
1933 constexpr Real tolerance_inverse_bohr = 1.0e-10;
1934 for (int dimension = 0; dimension < 3; dimension++) {
1935 const Real kpoint_cartesian =
1936 kpoint.coordinates.x * reciprocal_vectors_bohr[0][dimension] +
1937 kpoint.coordinates.y * reciprocal_vectors_bohr[1][dimension] +
1938 kpoint.coordinates.z * reciprocal_vectors_bohr[2][dimension];
1939 if (std::abs(reader.kpoint_coordinates()[dimension] - kpoint_cartesian) >
1940 tolerance_inverse_bohr) {
1941 return {};
1942 }
1943 for (int vector_index = 0; vector_index < 3; vector_index++) {
1944 if (std::abs(reader.reciprocal_lattice_vectors()[vector_index][dimension] -
1945 reciprocal_vectors_bohr[vector_index][dimension]) >
1946 tolerance_inverse_bohr) {
1947 return {};
1948 }
1949 }
1950 }
1951
1952 // Miller indices are bounded by the cutoff sphere; 2^20 per axis is far beyond any grid.
1953 auto miller_key = [](std::int64_t h, std::int64_t k, std::int64_t l) {
1954 constexpr std::int64_t offset = 1 << 20;
1955 constexpr std::int64_t span = 1 << 21;
1956 return ((h + offset) * span + (k + offset)) * span + (l + offset);
1957 };
1958 const auto& saved_millers = reader.miller_indices();
1959 std::unordered_map<std::int64_t, int> saved_position;
1960 saved_position.reserve(saved_millers.size());
1961 for (int position = 0; position < static_cast<int>(saved_millers.size()); position++) {
1962 saved_position.emplace(miller_key(saved_millers[position].x,
1963 saved_millers[position].y,
1964 saved_millers[position].z),
1965 position);
1966 }
1967 const auto& g_vectors = planewave_basis_.g_vectors();
1968 const auto& local_g_indices = g_vector_indices(kpoint_index);
1969 const int local_plane_waves = number_of_plane_waves(kpoint_index);
1970 std::vector<int> source_position(static_cast<std::size_t>(local_plane_waves));
1971 for (int plane_wave = 0; plane_wave < local_plane_waves; plane_wave++) {
1972 const auto& miller = g_vectors[local_g_indices[plane_wave]].miller;
1973 const auto found = saved_position.find(
1974 miller_key(std::lround(miller.x), std::lround(miller.y), std::lround(miller.z)));
1975 if (found == saved_position.end()) {
1976 return {};
1977 }
1978 source_position[static_cast<std::size_t>(plane_wave)] = found->second;
1979 }
1980
1981 std::vector<std::vector<Complex>> bands(
1982 static_cast<std::size_t>(number_of_bands_),
1983 std::vector<Complex>(static_cast<std::size_t>(local_plane_waves)));
1984 for (int band = 0; band < number_of_bands_; band++) {
1985 const auto& coefficients = reader.band_coefficients(band);
1986 for (int plane_wave = 0; plane_wave < local_plane_waves; plane_wave++) {
1987 bands[band][plane_wave] = coefficients[source_position[plane_wave]];
1988 }
1989 }
1990 return bands;
1991 }
1992
1993 void log_pseudopotential_summary(int number_of_atomic_wavefunctions) const {
1994 log::info(" number of KB projectors = {}",
1995 quantum_system_snapshot_->pseudopotential_basis().total_number_of_projectors());
1996 log::info(" Starting wavefunctions = {} atomic wfcs",
1997 number_of_atomic_wavefunctions);
1998 }
1999
2000 /**
2001 * Per-species initial magnetization, normalized to the species count.
2002 *
2003 * An EMPTY config vector means the input gave no starting_magnetization at
2004 * all; every species then defaults to constants::default_starting_magnetization
2005 * so a spin-polarized run can break spin symmetry. Explicit values — including
2006 * explicit zeros — are honored as given.
2007 */
2008 std::vector<Real> effective_species_magnetizations() const {
2009 std::vector<Real> species_magnetization(crystal_structure().number_of_species(), 0.0);
2010 if (starting_magnetization_.empty()) {
2011 species_magnetization.assign(species_magnetization.size(),
2013 return species_magnetization;
2014 }
2015 for (size_t species_index = 0; species_index < starting_magnetization_.size() &&
2016 species_index < species_magnetization.size();
2017 ++species_index) {
2018 species_magnetization[species_index] = starting_magnetization_[species_index];
2019 }
2020 return species_magnetization;
2021 }
2022
2024 int number_of_g_vectors = planewave_basis_.number_of_g_vectors();
2025 Real cell_volume = crystal_structure().cell_volume();
2026 bool spin_polarized = number_of_spin_components() == 2;
2027
2028 std::vector<Real> species_magnetization;
2029 std::vector<Complex> magnetization_density_g;
2030 if (spin_polarized) {
2031 species_magnetization = effective_species_magnetizations();
2032 magnetization_density_g.assign(number_of_g_vectors, Complex(0.0, 0.0));
2033 if (!atomic_starting_magnetization_.empty() &&
2034 static_cast<int>(atomic_starting_magnetization_.size()) !=
2035 crystal_structure().number_of_atoms())
2036 throw std::runtime_error("atomic_starting_magnetization lists " +
2037 std::to_string(atomic_starting_magnetization_.size()) +
2038 " values but the cell has " +
2039 std::to_string(crystal_structure().number_of_atoms()) +
2040 " atoms");
2041 }
2042
2043 charge_density_g_.resize(number_of_g_vectors, Complex(0.0, 0.0));
2044 for (int g_vector_index = 0; g_vector_index < number_of_g_vectors; ++g_vector_index) {
2045 for (int atom_index = 0; atom_index < crystal_structure().number_of_atoms();
2046 ++atom_index) {
2047 int species_type = crystal_structure().species_type_index(atom_index);
2048 Vector3D position =
2049 crystal_structure().convert_from_crystal_to_cartesian(atom_index);
2050 const auto& g_vector = planewave_basis_.g_vectors()[g_vector_index];
2051 Real phase = constants::two_pi * g_vector.g_cart.dot(position);
2052 Complex structure_factor = compute_phase_factor(phase);
2053 Complex atomic_contribution =
2054 quantum_system_snapshot_->pseudopotential_basis().atomic_charge_density_g(
2055 species_type)[g_vector_index] *
2056 structure_factor / cell_volume;
2057 charge_density_g_[g_vector_index] += atomic_contribution;
2058 if (spin_polarized) {
2059 /**
2060 * Magnetization density m(G): each atom contributes its starting
2061 * magnetization -- its own when given per atom, else its species'
2062 * -- times its atomic charge density.
2063 */
2064 Real atom_magnetization = atomic_starting_magnetization_.empty()
2065 ? species_magnetization[species_type]
2066 : atomic_starting_magnetization_[atom_index];
2067 magnetization_density_g[g_vector_index] +=
2068 atom_magnetization * atomic_contribution;
2069 }
2070 }
2071 }
2072
2073 Real total_starting_charge = charge_density_g_[0].real() * cell_volume;
2074 if (std::abs(total_starting_charge) > math::tolerances::zero_vector_magnitude_threshold) {
2075 Real scaling_factor = number_of_electrons_ / total_starting_charge;
2076 for (int g_vector_index = 0; g_vector_index < number_of_g_vectors; ++g_vector_index) {
2077 charge_density_g_[g_vector_index] *= scaling_factor;
2078 if (spin_polarized)
2079 magnetization_density_g[g_vector_index] *= scaling_factor;
2080 }
2081 }
2082
2083 int local_grid_points = planewave_basis_.fft_rho().local_grid_points();
2084 charge_density_real_.resize(number_of_spin_components());
2085
2086 if (!spin_polarized) {
2087 planewave_basis_.rho_g_to_r(charge_density_g_, charge_density_real_[0]);
2088 on_charge_density_initialized();
2089 return;
2090 }
2091
2092 // ρ↑ = (ρ + m)/2, ρ↓ = (ρ − m)/2 pointwise in real space.
2093 std::vector<Real> total_charge_density_real;
2094 std::vector<Real> magnetization_density_real;
2095 planewave_basis_.rho_g_to_r(charge_density_g_, total_charge_density_real);
2096 planewave_basis_.rho_g_to_r(magnetization_density_g, magnetization_density_real);
2097
2098 charge_density_real_[0].resize(local_grid_points);
2099 charge_density_real_[1].resize(local_grid_points);
2100 for (int grid_index = 0; grid_index < local_grid_points; ++grid_index) {
2101 charge_density_real_[0][grid_index] = 0.5 * (total_charge_density_real[grid_index] +
2102 magnetization_density_real[grid_index]);
2103 charge_density_real_[1][grid_index] = 0.5 * (total_charge_density_real[grid_index] -
2104 magnetization_density_real[grid_index]);
2105 }
2106 on_charge_density_initialized();
2107 }
2108};
2109
2110} // namespace q3
const std::string & element(int atom_index) const
Definition crystal.hpp:346
virtual int total_grid_points() const =0
Real residual() const
||n_fresh - n_damped||^2 from the last blend; huge until one has run.
const HubbardOccupationMatrices & blend(const HubbardOccupationMatrices &fresh, Real mixing_beta, Real convergence_threshold)
bool damping_active() const
Whether non-monotone progress has switched damping on for this run.
int number_of_kpoints() const
virtual void prepare_hamiltonian()
Definition init.hpp:585
const KohnShamSCFIteratorConfig & config() const
Definition init.hpp:256
const std::vector< Real > & charge_density_real() const
Definition init.hpp:197
Real total_energy() const override
Definition init.hpp:187
std::unique_ptr< XCFunctional > exchange_correlation_
Definition init.hpp:286
std::vector< Complex > total_potential_g_
Definition init.hpp:263
Crystal & crystal_structure() const
Definition init.hpp:219
bool has_preloaded_charge_density_
Definition init.hpp:282
std::vector< std::vector< Real > > charge_density_real_
Definition init.hpp:261
const std::vector< Complex > & exchange_correlation_potential_g() const
Definition init.hpp:212
std::vector< Complex > charge_density_g_
Definition init.hpp:260
const XCFunctional & exchange_correlation() const
Definition init.hpp:190
std::vector< std::vector< Real > > real_space_potential_
Definition init.hpp:262
bool preloaded_charge_density_is_a_starting_guess_
Set by offer_starting_charge_density(): a density that need not fit.
Definition init.hpp:284
std::vector< std::vector< Complex > > total_potential_g_by_spin_
Definition init.hpp:274
size_t rows() const
Definition matrix.hpp:62
T * data()
Returns the underlying flat data pointer.
Definition matrix.hpp:75
size_t cols() const
Definition matrix.hpp:65
void compute_atomic_wavefunctions(int kpoint_index, int number_of_plane_waves, int number_of_bands, const std::vector< int > &g_vector_indices, const Crystal &crystal_structure, const KPointsGrid &kpoint_grid, const PlanewaveBasis &planewave_basis, const PseudopotentialSet &pseudopotential_set, std::vector< std::vector< Complex > > &atomic_wavefunctions)
void initialize_interpolation_table(const PseudopotentialSet &pseudopotential_set, Real cell_volume)
void rotate_wavefunctions(int kpoint_index, int kpoint_index_state, int number_of_plane_waves, int number_of_bands, const std::vector< int > &g_vector_indices, const std::vector< Real > &kinetic_energy_squared, const std::vector< Real > &smooth_potential, const Crystal &crystal_structure, const KPointsGrid &kpoint_grid, const PlanewaveBasis &planewave_basis, const execution::PlanewaveExecutionPolicy &execution_policy, const NormConservingPlanewaveKohnShamQuantumSystem &pseudopotential_quantum_system, const std::vector< std::vector< Complex > > &atomic_wavefunctions, PlanewaveKohnShamQuantumSystem &quantum_system, const Matrix< Complex > &precomputed_kleinman_bylander_potential)
FFTGrid & fft_wave()
Definition init.hpp:292
bool is_gamma_only() const
Definition init.hpp:157
EffectivePotentialResult compute(const std::vector< std::vector< Real > > &charge_density_real, int number_of_spin_components, const std::vector< Complex > &local_ionic_potential_g) const
Definition init.hpp:52
Complex wavefunction(int kpoint_index, int band_index, int g_vector_index) const
Definition init.hpp:99
Real occupation_by_kpoint_state_index_and_band_index(int kpoint_state_index, int band_index) const
Definition init.hpp:127
const std::vector< std::vector< int > > & g_vector_indices() const
Definition init.hpp:280
const std::optional< Magnetization > & magnetization() const
Definition init.hpp:355
PlanewaveBasis planewave_basis_
Definition init.hpp:389
const KPointsGrid & kpoint_grid() const
Definition init.hpp:209
virtual void release_scf_workspace()
Definition init.hpp:109
std::string diagonalization_method_
Definition init.hpp:367
int number_of_kpoint_states() const override
Definition init.hpp:329
PlanewaveKohnShamQuantumSystem quantum_system_
Definition init.hpp:390
const execution::PlanewaveExecutionPolicy & execution_policy() const
Definition init.hpp:119
const std::vector< std::vector< Real > > & kinetic_energy_squared() const
Definition init.hpp:287
Real compute_double_counting_correction() const override
Definition init.hpp:925
void construct_density_from_states() override
Definition init.hpp:768
void scale_loaded_charge_density_to_electron_count()
Rescale the loaded density so it integrates to this system's electron count.
Definition init.hpp:168
std::unique_ptr< PlanewaveDiagonalizer > diagonalizer_
Definition init.hpp:395
virtual void on_charge_density_initialized()
Definition init.hpp:1159
const std::vector< int > & number_of_plane_waves() const
Definition init.hpp:294
std::optional< int > nscf_override_maximum_iterations_
Definition init.hpp:433
std::optional< Real > nscf_override_tolerance_
Definition init.hpp:427
Matrix< Real > global_eigenvalues() const
Definition init.hpp:248
bool loaded_charge_density_fits_grid() const
Definition init.hpp:153
void update_effective_potential() override
Definition init.hpp:666
void initialize_representation() override
Definition init.hpp:452
execution::PlanewaveExecutionPolicy * execution_policy_
Definition init.hpp:373
static void report_memory_estimate(const PlanewaveMemoryEstimate &estimate)
Definition reporter.hpp:143
void report_unconverged_solve(int kpoint_index_state) const
Definition init.hpp:1759
bool is_at_band_path_segment_boundary(int kpoint_index) const
Definition init.hpp:1640
void fix_edge_kpoints_with_backward_propagation(int number_of_kpoints, int number_of_kpoint_states)
Definition init.hpp:1678
std::shared_ptr< NormConservingPlanewaveKohnShamQuantumSystem > quantum_system_snapshot_
Definition init.hpp:372
virtual std::vector< Matrix< Real > > one_center_occupations() const
Definition init.hpp:272
std::vector< std::vector< Complex > > read_saved_bands(int kpoint_index) const
Definition init.hpp:1910
std::vector< Real > atomic_starting_magnetization_
Definition init.hpp:366
PlanewavePseudopotentialKohnShamSCFIterator(KohnShamSCFIteratorConfig config)
Definition init.hpp:61
NormConservingPlanewaveKohnShamEnergies energies_
Definition init.hpp:371
bool take_saved_starting_wavefunctions(int kpoint_index, std::vector< std::vector< Complex > > &starting_wavefunctions) const
Definition init.hpp:1886
virtual const Matrix< Real > & projector_overlap_coefficients() const
Definition init.hpp:262
void log_pseudopotential_summary(int number_of_atomic_wavefunctions) const
Definition init.hpp:1993
std::vector< q3::Matrix< Complex > > cached_kleinman_bylander_projectors_
Cached KB projectors per k-point (reused by the projector overlap accumulation).
Definition init.hpp:408
NormConservingPlanewaveEffectivePotentialCalculator & effective_potential_calculator()
Definition init.hpp:1827
NormConservingPlanewaveKohnShamEnergies & energies_mutable() override
Definition init.hpp:74
void set_diagonalizer_tolerance_for_nscf(Real tolerance)
Definition init.hpp:306
const NormConservingPlanewaveKohnShamQuantumSystem & norm_conserving_quantum_system() const
Definition init.hpp:234
void propagate_wavefunctions_to_next_kpoint(int current_kpoint_state_index, int total_kpoint_states)
Definition init.hpp:1542
const std::vector< SymmetryOperation > & cached_symmetry_operations() const
Definition init.hpp:430
std::vector< HubbardManifold > hubbard_manifolds_
DFT+U (Hubbard): resolved atom/shell manifolds; empty means no correction is active.
Definition init.hpp:411
std::vector< q3::Matrix< Complex > > cached_hubbard_projectors_
Definition init.hpp:422
Real compute_double_counting_correction() const override
Definition init.hpp:1509
std::vector< std::pair< std::string, Vector3D > > band_path_
Definition init.hpp:367
void set_diagonalizer_maximum_iterations_for_nscf(int maximum_iterations)
Definition init.hpp:317
const std::vector< Complex > & local_ionic_potential_g() const override
Definition init.hpp:1775
HubbardOccupationMixer hubbard_occupation_mixer_
Owns the damping/Anderson state; see HubbardOccupationMixer.
Definition init.hpp:461
virtual bool requires_one_center_occupations() const
Definition init.hpp:280
const PseudopotentialSet & pseudopotential_set() const
Definition init.hpp:226
const NormConservingPlanewaveKohnShamEnergies & energies() const override
Definition init.hpp:71
std::vector< std::vector< Real > > hubbard_occupation_traces_
Definition init.hpp:417
void set_owned_pseudopotential_set(PseudopotentialSet pseudopotential_set)
Transfer ownership of a PseudopotentialSet into this iterator.
Definition init.hpp:66
void report_memory_estimate(int number_of_atomic_wavefunctions) const
Definition init.hpp:1854
const std::vector< Complex > & core_charge_density_g() const override
Definition init.hpp:1778
const std::vector< std::vector< Real > > & hubbard_occupation_traces() const
Definition init.hpp:219
Real hubbard_potential_energy_
Σ_σ Tr[V_U^σ n^σ]; see hubbard_potential_energy().
Definition init.hpp:442
std::vector< Complex > valence_exchange_correlation_potential_g_of(const std::vector< std::vector< Real > > &charge_density_real)
Definition init.hpp:337
~PlanewavePseudopotentialKohnShamSCFIterator() override=default
std::vector< std::vector< Complex > > hubbard_d_matrix_per_spin_
Definition init.hpp:447
std::vector< SymmetryOperation > cached_symmetry_operations_
Definition init.hpp:438
virtual void load_one_center_occupations(const std::vector< Matrix< Real > > &occupations_by_spin)
Definition init.hpp:290
void offer_starting_wavefunctions(std::string save_directory)
Definition init.hpp:356
const PseudopotentialSet * pseudopotential_set_
Definition init.hpp:362
void propagate_wavefunctions_backward(int source_kpoint_state_index, int target_kpoint_state_index)
Definition init.hpp:1596
void write_checkpoints(const std::string &output_directory, const std::string &prefix) const override
Definition init.hpp:134
NormConservingPlanewaveKohnShamSCFState result() const override
Definition init.hpp:83
std::vector< Real > effective_species_magnetizations() const
Definition init.hpp:2008
bool save(const std::string &filename, const KohnShamQuantumSystemSnapshot &snapshot, bool save_wavefunctions=false) const override
Definition q3.hpp:32
const std::vector< Complex > & band_coefficients(int band_index) const
Coefficients of one band, parallel to miller_indices().
const Vector3D & kpoint_coordinates() const
Cartesian coordinates, in 1/bohr, of the k-point this file belongs to.
const std::vector< IntegerVector3D > & miller_indices() const
void read(const std::string &path)
Read path, replacing whatever this reader held; throws on a malformed file.
Definition qe_reader.hpp:35
const Matrix3x3 & reciprocal_lattice_vectors() const
const QuantumSystem< QuantumStateType > * preloaded_quantum_system_
Real convergence_threshold_
Definition init.hpp:104
int iteration() const
Definition init.hpp:39
virtual bool is_iteration_converged() const =0
int number_of_spin_components() const
Definition init.hpp:45
bool is_converged() const
Definition init.hpp:42
static std::vector< SymmetryOperation > get_symmetry_operations(const Crystal &crystal, Real symmetry_precision=math::tolerances::default_symmetry_precision)
Definition symmetry.hpp:484
virtual void reduce_group_distributed_result(ComplexValue *, int) const
Definition init.hpp:215
virtual bool is_root() const =0
virtual void reduce_within_group(ComplexValue *data, int number_of_elements) const =0
virtual void reduce_vector(std::vector< Real > &values) const =0
virtual bool each_process_owns_whole_kpoints() const =0
virtual int number_of_pools() const =0
virtual void reduce_scalar(Real &value) const =0
constexpr Real two_pi
Definition constants.hpp:25
constexpr Real default_starting_magnetization
Definition constants.hpp:43
void debug(spdlog::format_string_t< Args... > fmt, Args &&... args)
Definition logger.hpp:179
void warn(spdlog::format_string_t< Args... > fmt, Args &&... args)
Definition logger.hpp:187
void info(spdlog::format_string_t< Args... > fmt, Args &&... args)
Definition logger.hpp:183
void trace(spdlog::format_string_t< Args... > fmt, Args &&... args)
Definition logger.hpp:174
constexpr double numerical_zero_threshold
constexpr double zero_vector_magnitude_threshold
constexpr double occupation_threshold
void accumulate_hubbard_occupation_matrix(int number_of_bands, int manifold_size, const Matrix< Complex > &overlaps, const std::vector< Real > &band_occupations, Real kpoint_weight, std::vector< Complex > &occupation_matrix)
Definition hubbard.hpp:434
void build_atomic_orbitals_g_space(int kpoint_index, int number_of_plane_waves, const std::vector< int > &g_vector_indices, const Crystal &crystal_structure, const KPointsGrid &kpoint_grid, const PlanewaveBasis &planewave_basis, const PseudopotentialSet &pseudopotential_set, const std::vector< std::vector< std::vector< Real > > > &atomic_wavefunction_table, Real q_spacing, int number_of_q_points, std::vector< std::vector< Complex > > &orbitals)
int count_atomic_orbitals(const Crystal &crystal_structure, const PseudopotentialSet &pseudopotential_set)
void apply_hubbard_starting_eigenvalue(std::vector< Complex > &matrix, int size, int eigenvalue_index, Real value)
Definition seeding.hpp:57
void compute_hubbard_projector_overlaps(int number_of_plane_waves, int total_hubbard_orbitals, int number_of_bands, const Complex *packed_orbitals, const Complex *band_functions, std::vector< Complex > &overlaps)
Definition hubbard.hpp:304
double Real
void convert_gamma_only_projector_overlaps_to_full_sphere(int number_of_plane_waves, int total_hubbard_orbitals, int number_of_bands, const Complex *packed_orbitals, const Complex *band_functions, int g_zero_index, bool band_functions_carry_g_component, std::vector< Complex > &overlaps)
Definition hubbard.hpp:392
void lowdin_orthogonalize_orbitals(std::vector< std::vector< Complex > > &orbitals, std::vector< Complex > overlap_column_major)
std::vector< Complex > compute_smooth_grid_potential_from_dense(const std::vector< Real > &dense_real_space_potential, const PlanewaveBasis &planewave_basis)
HubbardEnergyAndPotential compute_hubbard_energy_and_potential(int manifold_size, Real u_rydberg, const std::vector< Complex > &occupation_matrix)
Definition hubbard.hpp:523
std::unique_ptr< PlanewaveKohnShamChargeDensityCheckpoint > create_charge_density_checkpoint(const NormConservingPlanewaveKohnShamSCFState &scf_state, const std::string &format="qe")
Definition factory.hpp:19
void symmetrize_hubbard_occupation_matrices_under_time_reversal(std::vector< std::vector< std::vector< Complex > > > &occupation_matrices)
Complex compute_phase_factor(Real phase)
Compute e^{-iφ} = cos(φ) - i·sin(φ) (standard structure factor phase).
void symmetrize_hubbard_occupation_matrices(const Crystal &crystal_structure, const std::vector< SymmetryOperation > &symmetry_operations, const std::vector< HubbardManifoldLayout > &layouts, std::vector< std::vector< std::vector< Complex > > > &occupation_matrices)
std::vector< AtomicOrbitalLabel > enumerate_atomic_orbitals(const Crystal &crystal_structure, const PseudopotentialSet &pseudopotential_set)
std::vector< Real > inverse_fft_smooth_potential(const std::vector< Complex > &full_smooth_potential_g, const PlanewaveBasis &planewave_basis)
std::unique_ptr< OverlapOperator > create_overlap_operator(const Crystal &crystal_structure, const NormConservingPlanewaveKohnShamQuantumSystem &quantum_system, const Matrix< Complex > &kleinman_bylander_potential, const execution::ExecutionPolicy &execution_policy)
Definition factory.hpp:23
void compute_kleinman_bylander_projectors(const Vector3D &k_crystal, const Crystal &crystal_structure, const PlanewaveBasis &planewave_basis, const PseudopotentialSet &pseudopotential_set, const BetaFunctionTable &beta_function_table, const std::vector< int > &g_vector_indices, int number_of_plane_waves, int total_number_of_projectors, Matrix< Complex > &kleinman_bylander_potential)
Definition projector.hpp:36
std::unique_ptr< PlanewaveKohnShamWavefunctionCheckpoint > create_wavefunction_checkpoint(const NormConservingPlanewaveKohnShamSCFState &scf_state, const std::string &format="qe")
Definition factory.hpp:19
std::vector< std::vector< std::vector< Real > > > tabulate_atomic_wavefunctions_in_q_space(const PseudopotentialSet &pseudopotential_set, Real cell_volume, Real q_spacing, int number_of_q_points)
int find_g_zero_plane_wave_index(const PlanewaveBasis &planewave_basis, const std::vector< int > &plane_wave_indices, int number_of_plane_waves)
Definition hubbard.hpp:364
Real compute_ewald(const Crystal &crystal_structure, const PlanewaveBasis &planewave_basis)
std::complex< double > Complex
std::vector< HubbardManifold > resolve_hubbard_manifolds(const Crystal &crystal_structure, const std::vector< AtomicOrbitalLabel > &orbital_labels, const std::vector< HubbardSpecification > &specifications)
Definition hubbard.hpp:133
std::unique_ptr< DispersionCalculator > create_dispersion_calculator(const std::string &dispersion_correction, const Crystal &crystal_structure)
Definition factory.hpp:27
std::vector< Complex > charge_density_g
Definition result.hpp:17
std::vector< Complex > total_potential_g
Definition result.hpp:19
std::vector< std::vector< Complex > > total_potential_g_by_spin
Definition result.hpp:33
std::vector< Complex > exchange_correlation_potential_g
Definition result.hpp:34
std::vector< std::vector< Real > > real_space_potential
Definition result.hpp:18
Real exchange_correlation_potential_energy
Definition init.hpp:19
Real exchange_correlation_energy
Definition init.hpp:18
std::vector< std::vector< Real > > effective_potential_real
Definition snapshot.hpp:35
std::vector< Matrix< Real > > one_center_occupations
Definition snapshot.hpp:47
std::vector< std::vector< Real > > charge_density_real
Definition snapshot.hpp:26
std::vector< Real > starting_magnetization
Definition init.hpp:98
std::string hubbard_projector_type
Definition init.hpp:62
std::vector< std::pair< std::string, Vector3D > > band_path
Definition init.hpp:105
std::vector< Real > atomic_starting_magnetization
Definition init.hpp:104
std::vector< HubbardStartingEigenvalue > hubbard_starting_eigenvalues
First-iteration occupation-eigenvalue overrides; empty = no seeding.
Definition init.hpp:55
const PseudopotentialSet * pseudopotential_set
Definition init.hpp:92
3×3 matrix stored row-major: row i = mat[i]
static std::shared_ptr< NormConservingPlanewaveKohnShamQuantumSystem > create_shared(const Crystal &crystal_structure, const PlanewaveBasis &planewave_basis, const PseudopotentialSet &pseudopotential_set)
Definition factory.hpp:50
std::vector< HubbardManifold > hubbard_manifolds
DFT+U (Hubbard) resolved manifolds at convergence; empty means no correction is active.
Definition init.hpp:62
NormConservingPlanewaveKohnShamEnergies energies_data_
Definition init.hpp:45
std::shared_ptr< NormConservingPlanewaveKohnShamQuantumSystem > quantum_system_snapshot_
Definition init.hpp:44
std::vector< std::vector< Complex > > hubbard_d_matrix_per_spin
Definition init.hpp:67
std::vector< std::vector< Real > > charge_density_real
Definition init.hpp:37
std::vector< Complex > total_potential_g
Definition init.hpp:38
const KPointsGrid * kpoint_grid
Definition init.hpp:56
const XCFunctional * exchange_correlation
Definition init.hpp:54
std::vector< Complex > exchange_correlation_potential_g
Definition init.hpp:50
const Crystal * crystal_structure
Definition init.hpp:55
std::vector< std::vector< Real > > real_space_potential
Definition init.hpp:51
const execution::PlanewaveExecutionPolicy * execution_policy
Definition init.hpp:64
const PlanewaveBasis * planewave_basis
Definition init.hpp:53
std::vector< std::vector< Complex > > total_potential_g_by_spin
Definition init.hpp:49
std::vector< Complex > charge_density_g
Definition init.hpp:36
bool overlap_is_identity
False for ultrasoft and PAW, where S is not the identity and is stored.
bool diagonalizer_is_davidson
False for the direct solver, which holds no Davidson workspace.
static PlanewaveMemoryEstimate compute(const PlanewaveMemoryEstimateInputs &inputs)
void log_resident_checkpoint_debug(const std::string &label)
Definition counters.hpp:187
void log_resident_checkpoint(const std::string &label)
Definition counters.hpp:152
static ProfilingCounters & instance()
Definition counters.hpp:220
void release_unused_heap(const std::string &label)
Definition counters.hpp:169
bool converged
Definition init.hpp:27
int scf_iterations
Definition init.hpp:26