Loading...
Searching...
No Matches
core_correction.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * Core correction (NLCC) force contribution.
5 *
6 * Computes the Hellmann-Feynman force from the nonlinear core correction —
7 * the interaction between the exchange-correlation potential and the core
8 * charge density gradient with respect to atomic positions.
9 *
10 * This contribution is only nonzero for pseudopotential_set that include NLCC.
11 * The algorithm is the same for norm-conserving and ultrasoft pseudopotential_set.
12 */
13
14#include <cmath>
15#include <complex>
16#include <vector>
17
24
25namespace q3 {
26
28 public:
29 CoreCorrectionForceCalculator(const Crystal& crystal_structure,
30 const PlanewaveBasis& planewave_basis,
31 const NormConservingPlanewaveBasis& pseudopotential_basis)
32 : crystal_structure_(crystal_structure)
33 , planewave_basis_(planewave_basis)
34 , pseudopotential_basis_(pseudopotential_basis) {}
35
36 std::vector<Vector3D> compute(const std::vector<Complex>& exchange_correlation_potential_g) {
37 std::vector<Vector3D> forces(crystal_structure_.number_of_atoms(), {0.0, 0.0, 0.0});
38 /**
39 * Gamma-only stores only the positive half sphere, and this
40 * summand is even under G -> -G (the imaginary part is odd and
41 * G_alpha is odd), so the omitted half contributes as much again.
42 * Verified against QE's own force decomposition at Gamma
43 * (`verbosity='high'`), where Q3 was exactly half.
44 */
45 Real half_sphere_scale = planewave_basis_.is_gamma_only() ? 2.0 : 1.0;
46
47 if (!pseudopotential_basis_.has_nonlinear_core_correction()) {
48 return forces;
49 }
50
51 int first_nonzero_g_index = planewave_basis_.first_nonzero_g_index();
52
53 for (int atom_index = 0; atom_index < crystal_structure_.number_of_atoms(); atom_index++) {
54 int species_index = crystal_structure_.species_type_index(atom_index);
55 const auto& pseudopotential =
56 pseudopotential_basis_.pseudopotential_set()[species_index];
57 if (!pseudopotential.has_nonlinear_core_correction) {
58 continue;
59 }
60
61 Vector3D atomic_position =
62 crystal_structure_.convert_from_crystal_to_cartesian(atom_index);
63
64 for (int g_vector_index = first_nonzero_g_index;
65 g_vector_index < planewave_basis_.number_of_g_vectors();
66 g_vector_index++) {
67 const auto& g_vector = planewave_basis_.g_vectors()[g_vector_index];
68 Real phase = constants::two_pi * g_vector.g_cart.dot(atomic_position);
69
70 Real g_vector_magnitude = std::sqrt(g_vector.magnitude_squared) *
71 crystal_structure_.two_pi_over_lattice_parameter();
72 Real core_charge_density_value =
73 pseudopotential_basis_.interpolate_core_charge_density(species_index,
74 g_vector_magnitude);
75
76 for (int direction = 0; direction < 3; direction++) {
77 Real g_direction = g_vector.g_cart[direction] *
78 crystal_structure_.two_pi_over_lattice_parameter();
79 /**
80 * F_{s,α} = Ω G_α ρ_core(|G|) Im[V_XC(G) e^{+iGτ_s}] (full sphere, no ×2)
81 * Structure factor must be e^{+iGτ} = compute_phase_factor_conjugate.
82 */
83 Complex contribution = exchange_correlation_potential_g[g_vector_index] *
85 forces[atom_index][direction] += half_sphere_scale * g_direction *
86 contribution.imag() *
87 core_charge_density_value;
88 }
89 }
90 }
91
92 return forces;
93 }
94
95 private:
96 const Crystal& crystal_structure_;
97 const PlanewaveBasis& planewave_basis_;
98 const NormConservingPlanewaveBasis& pseudopotential_basis_;
99};
100
101} // namespace q3
std::vector< Vector3D > compute(const std::vector< Complex > &exchange_correlation_potential_g)
CoreCorrectionForceCalculator(const Crystal &crystal_structure, const PlanewaveBasis &planewave_basis, const NormConservingPlanewaveBasis &pseudopotential_basis)
Vector3D convert_from_crystal_to_cartesian(int atom_index) const
Definition crystal.hpp:225
Real two_pi_over_lattice_parameter() const
Definition crystal.hpp:196
int species_type_index(int atom_index) const
Definition crystal.hpp:273
int number_of_atoms() const
Definition crystal.hpp:209
bool has_nonlinear_core_correction() const
Definition init.hpp:259
Real interpolate_core_charge_density(int element_type, Real q_value) const
Definition init.hpp:332
const PseudopotentialSet & pseudopotential_set() const
Definition init.hpp:156
int number_of_g_vectors() const
Definition init.hpp:145
const std::vector< GVector > & g_vectors() const
Definition init.hpp:148
int first_nonzero_g_index() const
Definition init.hpp:151
bool is_gamma_only() const
Definition init.hpp:157
constexpr Real two_pi
Definition constants.hpp:25
double Real
std::complex< double > Complex
Complex compute_phase_factor_conjugate(Real phase)
Compute e^{+iφ} = cos(φ) + i·sin(φ) (conjugate structure factor phase).