Loading...
Searching...
No Matches
core_charge_data.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * CoreChargeData — NLCC core charge density data and interpolation.
5 *
6 * Uses the pre-computed CoreChargeDensityTable for interpolation, avoiding
7 * redundant Bessel transforms during initialization.
8 */
9
10#include <vector>
11
21
22namespace q3 {
23
25 public:
26 CoreChargeData() = default;
27
28 /**
29 * Initialize using the pre-built CoreChargeDensityTable to avoid
30 * redundant Bessel transforms. Computes ρ_core(G) via interpolation.
31 */
32 void initialize(const Crystal& crystal_structure,
33 const PlanewaveBasis& planewave_basis,
34 const PseudopotentialSet& pseudopotential_set,
35 const std::vector<Real>& g_vector_magnitudes,
36 Real cell_volume,
37 const CoreChargeDensityTable& core_charge_density_table) {
38 int number_of_species_types = static_cast<int>(pseudopotential_set.size());
39 int number_of_g_vectors = static_cast<int>(g_vector_magnitudes.size());
40
41 // Check if any species has NLCC
42 has_nonlinear_core_correction_ = false;
43 for (int type_index = 0; type_index < number_of_species_types; type_index++) {
44 if (pseudopotential_set[type_index].has_nonlinear_core_correction) {
45 has_nonlinear_core_correction_ = true;
46 break;
47 }
48 }
49
50 if (!has_nonlinear_core_correction_)
51 return;
52
53 // Compute core charge density in reciprocal space using table interpolation
54 core_charge_density_reciprocal_.assign(number_of_g_vectors, Complex(0.0, 0.0));
55 for (int g_vector_index = 0; g_vector_index < number_of_g_vectors; g_vector_index++) {
56 for (int type_index = 0; type_index < number_of_species_types; type_index++) {
57 if (!pseudopotential_set[type_index].has_nonlinear_core_correction)
58 continue;
59 Real q_value = g_vector_magnitudes[g_vector_index];
60 Real core_charge_density_value =
61 core_charge_density_table.interpolate(type_index, q_value);
62
63 Complex structure_factor(0.0, 0.0);
64 for (int atom_index = 0; atom_index < crystal_structure.number_of_atoms();
65 atom_index++) {
66 if (crystal_structure.species_type_index(atom_index) == type_index) {
67 Vector3D atomic_position =
68 crystal_structure.convert_from_crystal_to_cartesian(atom_index);
69 const auto& g_vector = planewave_basis.g_vectors()[g_vector_index];
70 Real phase = constants::two_pi * g_vector.g_cart.dot(atomic_position);
71 structure_factor += compute_phase_factor(phase);
72 }
73 }
74 core_charge_density_reciprocal_[g_vector_index] +=
75 core_charge_density_value * structure_factor / cell_volume;
76 }
77 }
78 }
79
80 [[nodiscard]] bool has_nonlinear_core_correction() const {
81 return has_nonlinear_core_correction_;
82 }
83
84 [[nodiscard]] const std::vector<Complex>& core_charge_density_reciprocal() const {
85 return core_charge_density_reciprocal_;
86 }
87
88 private:
89 bool has_nonlinear_core_correction_{false};
90 std::vector<Complex> core_charge_density_reciprocal_;
91};
92
93} // namespace q3
CoreChargeData()=default
bool has_nonlinear_core_correction() const
const std::vector< Complex > & core_charge_density_reciprocal() const
void initialize(const Crystal &crystal_structure, const PlanewaveBasis &planewave_basis, const PseudopotentialSet &pseudopotential_set, const std::vector< Real > &g_vector_magnitudes, Real cell_volume, const CoreChargeDensityTable &core_charge_density_table)
Real interpolate(int species_type_index, Real q_value) const
Vector3D convert_from_crystal_to_cartesian(int atom_index) const
Definition crystal.hpp:225
int species_type_index(int atom_index) const
Definition crystal.hpp:273
int number_of_atoms() const
Definition crystal.hpp:209
const std::vector< GVector > & g_vectors() const
Definition init.hpp:148
int size() const
Definition set.hpp:98
constexpr Real two_pi
Definition constants.hpp:25
double Real
Complex compute_phase_factor(Real phase)
Compute e^{-iφ} = cos(φ) - i·sin(φ) (standard structure factor phase).
std::complex< double > Complex