Loading...
Searching...
No Matches
init.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * NormConservingPlanewaveStressTensorCalculator — aggregates all pseudopotential
5 * stress tensor contributions.
6 *
7 * Coordinates:
8 * - Exchange-correlation stress (NLCC / pseudopotential XC)
9 * - Local pseudopotential stress
10 * - Core-correction stress (NLCC)
11 * - Nonlocal (KB projector) stress — norm-conserving and ultrasoft
12 * - Augmentation stress — ultrasoft only
13 *
14 * Individual contributions are computed by their respective calculator classes
15 * in the internal/ and ultrasoft/internal/ subdirectories.
16 */
17
18#include <chrono>
19#include <string>
20#include <vector>
21
22#include "io/logger.hpp"
37
38namespace q3 {
39
41 public:
43 const Crystal& crystal_structure,
44 const PlanewaveBasis& planewave_basis,
45 const KPointsGrid& kpoint_grid,
47 const Matrix<Real>& projector_overlap_coefficients,
49 const std::string& nonlocal_stress_derivative_method = "analytical")
50 : crystal_structure_(crystal_structure)
51 , planewave_basis_(planewave_basis)
52 , kpoint_grid_(kpoint_grid)
53 , scf_state_(scf_state)
54 , projector_overlap_coefficients_(projector_overlap_coefficients)
55 , result_(result)
56 , nonlocal_stress_derivative_method_(nonlocal_stress_derivative_method) {}
57
58 void compute() {
59 auto timer_0 = std::chrono::high_resolution_clock::now();
60
61 /**
62 * Atomic and ortho-atomic projectors have complete stress derivatives for every
63 * dataset family. Keep this refusal for any future projector type until its
64 * derivative is implemented and validated.
65 */
67 log::warn(" Stress omits the DFT+U contribution for unsupported Hubbard "
68 "projector type '{}'. Reported stress and any cell relaxation built on "
69 "it are NOT trustworthy for this system. Energies are unaffected.",
70 scf_state_.hubbard_projector_type);
71 }
72
73 // 1. Exchange-correlation stress (NLCC correction)
75 crystal_structure_,
76 planewave_basis_,
78 scf_state_,
79 result_);
80 exchange_correlation_calculator.compute();
81 auto timer_1 = std::chrono::high_resolution_clock::now();
82
83 // 2. Local pseudopotential stress
85 crystal_structure_,
86 planewave_basis_,
88 scf_state_,
89 result_);
90 local_calculator.compute();
91 auto timer_2 = std::chrono::high_resolution_clock::now();
92
93 // 3. Core-correction stress (NLCC)
94 CoreCorrectionStressTensorCalculator core_correction_calculator(
95 crystal_structure_,
96 planewave_basis_,
98 scf_state_,
99 result_);
100 core_correction_calculator.compute();
101 auto timer_3 = std::chrono::high_resolution_clock::now();
102
103 // 4. Nonlocal (KB projector) stress — handles both NC (Dion) and US (Deeq)
105 crystal_structure_,
106 planewave_basis_,
107 kpoint_grid_,
108 scf_state_,
109 result_,
110 nonlocal_stress_derivative_method_);
111 nonlocal_calculator.compute();
112 auto timer_4 = std::chrono::high_resolution_clock::now();
113
114 // 5. Augmentation stress — zero for NC, nonzero for USPP
115 auto [potential_by_spin, coefficients_by_spin] = spin_resolved_augmentation_inputs();
116 UltrasoftAugmentationStressTensorCalculator augmentation_calculator(
117 crystal_structure_,
118 planewave_basis_,
119 scf_state_.quantum_system(),
120 potential_by_spin,
121 coefficients_by_spin,
122 result_);
123 augmentation_calculator.compute();
124 auto timer_5 = std::chrono::high_resolution_clock::now();
125
126 /**
127 * 6. DFT+U (Hubbard) stress — zero when no U is applied. Kept out of
128 * `nonlocal` because it is a different derivative (the Hubbard projector's,
129 * not the KB projector's) and reporting them merged would hide a term worth
130 * 29% of the total pressure on silicon at U = 3 eV behind a much larger one.
131 */
132 HubbardStressTensorCalculator hubbard_calculator(
133 crystal_structure_, planewave_basis_, kpoint_grid_, scf_state_, result_);
134 hubbard_calculator.compute();
135 auto timer_6 = std::chrono::high_resolution_clock::now();
136
137 log::debug(" Pseudo stress sub-timing:");
138 log::debug(" xc: {:.1f} ms",
139 std::chrono::duration<double, std::milli>(timer_1 - timer_0).count());
140 log::debug(" local: {:.1f} ms",
141 std::chrono::duration<double, std::milli>(timer_2 - timer_1).count());
142 log::debug(" core_corr: {:.1f} ms",
143 std::chrono::duration<double, std::milli>(timer_3 - timer_2).count());
144 log::debug(" nonlocal: {:.1f} ms",
145 std::chrono::duration<double, std::milli>(timer_4 - timer_3).count());
146 log::debug(" augmentation: {:.1f} ms",
147 std::chrono::duration<double, std::milli>(timer_5 - timer_4).count());
148 log::debug(" hubbard: {:.1f} ms",
149 std::chrono::duration<double, std::milli>(timer_6 - timer_5).count());
150 }
151
152 private:
153 /**
154 * The effective potential and projector occupancies split by spin, with an
155 * unpolarized run returning its single stored channel unchanged. Mirrors
156 * the force calculator's helper of the same name — both terms are the same
157 * pseudopotential derivative and must resolve spin the same way.
158 */
159 [[nodiscard]] std::pair<std::vector<std::vector<Complex>>, std::vector<Matrix<Real>>>
160 spin_resolved_augmentation_inputs() const {
161 const auto& potential_by_spin = scf_state_.total_potential_g_by_spin;
162 const auto& coefficients_by_spin = scf_state_.projector_overlap_coefficients_by_spin;
163 if (potential_by_spin.size() < 2 || coefficients_by_spin.size() != potential_by_spin.size())
164 return {{scf_state_.total_potential_g}, {projector_overlap_coefficients_}};
165 return {potential_by_spin, coefficients_by_spin};
166 }
167
168 const Crystal& crystal_structure_;
169 const PlanewaveBasis& planewave_basis_;
170 const KPointsGrid& kpoint_grid_;
171 const NormConservingPlanewaveKohnShamSCFState& scf_state_;
172 const Matrix<Real>& projector_overlap_coefficients_;
173 StressTensorContributions& result_;
174 const std::string nonlocal_stress_derivative_method_;
175};
176
177} // namespace q3
static bool supports(const NormConservingPlanewaveKohnShamSCFState &scf_state)
Definition hubbard.hpp:119
const NormConservingPlanewaveBasis & pseudopotential_basis() const
Definition init.hpp:65
NormConservingPlanewaveStressTensorCalculator(const Crystal &crystal_structure, const PlanewaveBasis &planewave_basis, const KPointsGrid &kpoint_grid, const NormConservingPlanewaveKohnShamSCFState &scf_state, const Matrix< Real > &projector_overlap_coefficients, StressTensorContributions &result, const std::string &nonlocal_stress_derivative_method="analytical")
Definition init.hpp:42
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
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< Complex > total_potential_g
Definition init.hpp:38
std::vector< std::vector< Complex > > total_potential_g_by_spin
Definition init.hpp:49
Per-contribution stress tensor breakdown (kbar after conversion).