Loading...
Searching...
No Matches
init.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * NormConservingPlanewaveForceCalculator — aggregates all pseudopotential
5 * force contributions.
6 *
7 * Coordinates:
8 * - Local pseudopotential force
9 * - Nonlocal (KB projector) force — norm-conserving and ultrasoft
10 * - Core-correction force (NLCC)
11 * - Augmentation force — ultrasoft only
12 *
13 * Individual contributions are computed by their respective calculator classes
14 * in the internal/ and ultrasoft/internal/ subdirectories.
15 */
16
17#include <vector>
18
31
32namespace q3 {
33
35 public:
37 const PlanewaveBasis& planewave_basis,
38 const KPointsGrid& kpoint_grid,
40 const Matrix<Real>& projector_overlap_coefficients)
41 : crystal_structure_(crystal_structure)
42 , planewave_basis_(planewave_basis)
43 , kpoint_grid_(kpoint_grid)
44 , scf_state_(scf_state)
45 , projector_overlap_coefficients_(projector_overlap_coefficients) {}
46
48 int number_of_atoms = crystal_structure_.number_of_atoms();
49
50 // 1. Local pseudopotential force
52 crystal_structure_,
53 planewave_basis_,
55 std::vector<Vector3D> local_forces = local_calculator.compute(scf_state_.charge_density_g);
56
57 // 2. Nonlocal (KB projector) force — handles both NC and US
59 crystal_structure_, planewave_basis_, kpoint_grid_, scf_state_);
60 std::vector<Vector3D> nonlocal_forces = nonlocal_calculator.compute();
61
62 // 3. Core-correction force (NLCC) — zero if no NLCC
63 std::vector<Vector3D> core_correction_forces(number_of_atoms, {0.0, 0.0, 0.0});
65 CoreCorrectionForceCalculator core_correction_calculator(
66 crystal_structure_,
67 planewave_basis_,
69 core_correction_forces =
70 core_correction_calculator.compute(scf_state_.exchange_correlation_potential_g);
71 }
72
73 // 4. Augmentation force — zero for NC, nonzero for USPP
74 std::vector<Vector3D> augmentation_forces(number_of_atoms, {0.0, 0.0, 0.0});
75 if (scf_state_.quantum_system().has_ultrasoft() &&
76 !projector_overlap_coefficients_.empty()) {
77 UltrasoftForceCalculator ultrasoft_calculator(crystal_structure_, planewave_basis_);
78 auto [potential_by_spin, coefficients_by_spin] = spin_resolved_augmentation_inputs();
79 augmentation_forces = ultrasoft_calculator.compute(
80 scf_state_.quantum_system(), potential_by_spin, coefficients_by_spin);
81 }
82
83 // 5. DFT+U (Hubbard) force — zero unless the input activated it
84 std::vector<Vector3D> hubbard_forces(number_of_atoms, {0.0, 0.0, 0.0});
85 if (!scf_state_.hubbard_manifolds.empty()) {
86 HubbardForceCalculator hubbard_calculator(
87 crystal_structure_, planewave_basis_, kpoint_grid_, scf_state_);
88 hubbard_forces = hubbard_calculator.compute();
89 }
90
91 return PseudopotentialForceContributions{local_forces,
92 nonlocal_forces,
93 core_correction_forces,
94 augmentation_forces,
95 hubbard_forces};
96 }
97
98 private:
99 /**
100 * The effective potential and the projector occupancies, split by spin.
101 *
102 * An unpolarized run stores neither by spin, because there is nothing to
103 * split: the single stored channel *is* the answer, and it is returned as a
104 * one-element pair. A polarized run stores both, and they must be
105 * contracted channel against matching channel — spin-averaging one against
106 * the spin-sum of the other drops ∫(V↑−V↓)(ρ↑−ρ↓) dQ/dR / 2.
107 *
108 * Returns copies rather than references because the unpolarized fallback
109 * has nothing to reference: the by-spin containers are empty there.
110 */
111 [[nodiscard]] std::pair<std::vector<std::vector<Complex>>, std::vector<Matrix<Real>>>
112 spin_resolved_augmentation_inputs() const {
113 const auto& potential_by_spin = scf_state_.total_potential_g_by_spin;
114 const auto& coefficients_by_spin = scf_state_.projector_overlap_coefficients_by_spin;
115 if (potential_by_spin.size() < 2 || coefficients_by_spin.size() != potential_by_spin.size())
116 return {{scf_state_.total_potential_g}, {projector_overlap_coefficients_}};
117 return {potential_by_spin, coefficients_by_spin};
118 }
119
120 const Crystal& crystal_structure_;
121 const PlanewaveBasis& planewave_basis_;
122 const KPointsGrid& kpoint_grid_;
123 const NormConservingPlanewaveKohnShamSCFState& scf_state_;
124 const Matrix<Real>& projector_overlap_coefficients_;
125};
126
127} // namespace q3
std::vector< Vector3D > compute(const std::vector< Complex > &exchange_correlation_potential_g)
int number_of_atoms() const
Definition crystal.hpp:209
std::vector< Vector3D > compute() const
Definition hubbard.hpp:54
std::vector< Vector3D > compute(const std::vector< Complex > &charge_density_g)
Definition local.hpp:33
bool empty() const
Definition matrix.hpp:90
std::vector< Vector3D > compute() const
Definition nonlocal.hpp:62
bool has_nonlinear_core_correction() const
Definition init.hpp:259
PseudopotentialForceContributions compute()
Definition init.hpp:47
NormConservingPlanewaveForceCalculator(const Crystal &crystal_structure, const PlanewaveBasis &planewave_basis, const KPointsGrid &kpoint_grid, const NormConservingPlanewaveKohnShamSCFState &scf_state, const Matrix< Real > &projector_overlap_coefficients)
Definition init.hpp:36
const NormConservingPlanewaveBasis & pseudopotential_basis() const
Definition init.hpp:65
std::vector< Vector3D > compute(const NormConservingPlanewaveKohnShamQuantumSystem &quantum_system, const std::vector< std::vector< Complex > > &potential_g_by_spin, const std::vector< Matrix< Real > > &coefficients_by_spin)
std::vector< Matrix< Real > > projector_overlap_coefficients_by_spin
Definition init.hpp:59
const NormConservingPlanewaveKohnShamQuantumSystem & quantum_system() const override
Definition init.hpp:82
std::vector< HubbardManifold > hubbard_manifolds
DFT+U (Hubbard) resolved manifolds at convergence; empty means no correction is active.
Definition init.hpp:62
std::vector< Complex > total_potential_g
Definition init.hpp:38
std::vector< Complex > exchange_correlation_potential_g
Definition init.hpp:50
std::vector< std::vector< Complex > > total_potential_g_by_spin
Definition init.hpp:49
std::vector< Complex > charge_density_g
Definition init.hpp:36