91 Real madelung_constant = 0.0;
92 if (bravais_lattice_index == 1) {
93 madelung_constant = 2.8373;
94 }
else if (bravais_lattice_index == 2) {
95 madelung_constant = 2.8883;
96 }
else if (bravais_lattice_index == 3) {
97 madelung_constant = 2.8885;
99 throw std::runtime_error(
100 "Makov-Payne correction is only defined for cubic lattices (QE ibrav "
101 "1/2/3 = SC/FCC/BCC); got bravais_lattice_index=" +
102 std::to_string(bravais_lattice_index) +
103 " (0 = explicit/'free' lattice vectors, -3 = BCC's alternate-axes "
104 "primitive-vector convention -- QE's own bound check rejects -3 too, "
105 "not just non-cubic lattices)");
112 Real total_valence_charge = 0.0;
113 Vector3D ionic_center_alat{0.0, 0.0, 0.0};
114 for (
int atom_index = 0; atom_index < number_of_atoms; atom_index++) {
115 Real valence_charge =
117 total_valence_charge += valence_charge;
121 ionic_center_alat = ionic_center_alat / total_valence_charge;
129 Vector3D ionic_dipole_alat{0.0, 0.0, 0.0};
130 Vector3D ionic_quadrupole_alat{0.0, 0.0, 0.0};
131 for (
int atom_index = 0; atom_index < number_of_atoms; atom_index++) {
132 Real valence_charge =
136 ionic_dipole_alat += valence_charge * delta;
137 ionic_quadrupole_alat.
x += valence_charge * delta.
x * delta.
x;
138 ionic_quadrupole_alat.y += valence_charge * delta.
y * delta.
y;
139 ionic_quadrupole_alat.z += valence_charge * delta.
z * delta.
z;
141 Vector3D ionic_dipole = ionic_dipole_alat * alat;
142 Vector3D ionic_quadrupole = ionic_quadrupole_alat * (alat * alat);
150 int grid_dimension_2 = density_grid.grid_dimension_2();
151 int grid_dimension_3 = density_grid.grid_dimension_3();
152 int total_grid_points = density_grid.total_grid_points();
153 int local_grid_points = density_grid.local_grid_points();
161 Real electron_count_raw = 0.0;
162 Vector3D electronic_dipole_raw{0.0, 0.0, 0.0};
163 Vector3D electronic_quadrupole_raw{0.0, 0.0, 0.0};
172 for (
int local_flat_index = 0; local_flat_index < local_grid_points; local_flat_index++) {
173 int global_flat_index = density_grid.global_real_space_index(local_flat_index);
174 int index_3 = global_flat_index % grid_dimension_3;
175 int index_2 = (global_flat_index / grid_dimension_3) % grid_dimension_2;
176 int index_1 = global_flat_index / (grid_dimension_3 * grid_dimension_2);
177 Vector3D fractional_grid_point{
static_cast<Real>(index_1) / grid_dimension_1,
178 static_cast<Real>(index_2) / grid_dimension_2,
179 static_cast<Real>(index_3) / grid_dimension_3};
180 Vector3D grid_point_alat = lattice_vectors_transpose * fractional_grid_point;
181 Vector3D displacement = grid_point_alat - ionic_center_alat;
183 Vector3D fractional_displacement = lattice_inverse_transpose * displacement;
184 fractional_displacement.
x -= std::round(fractional_displacement.
x);
185 fractional_displacement.
y -= std::round(fractional_displacement.
y);
186 fractional_displacement.
z -= std::round(fractional_displacement.
z);
187 Vector3D wrapped_displacement = lattice_vectors_transpose * fractional_displacement;
189 Real total_density_at_point = 0.0;
190 for (
int spin_index = 0; spin_index < number_of_spin_components; spin_index++) {
191 total_density_at_point +=
195 electron_count_raw += total_density_at_point;
196 electronic_dipole_raw += total_density_at_point * wrapped_displacement;
197 electronic_quadrupole_raw.
x +=
198 total_density_at_point * wrapped_displacement.
x * wrapped_displacement.
x;
199 electronic_quadrupole_raw.y +=
200 total_density_at_point * wrapped_displacement.
y * wrapped_displacement.
y;
201 electronic_quadrupole_raw.z +=
202 total_density_at_point * wrapped_displacement.
z * wrapped_displacement.
z;
205 std::vector<Real> electronic_moments = {
207 electronic_dipole_raw.x,
208 electronic_dipole_raw.y,
209 electronic_dipole_raw.z,
210 electronic_quadrupole_raw.x,
211 electronic_quadrupole_raw.y,
212 electronic_quadrupole_raw.z,
217 electron_count_raw = electronic_moments[0];
218 electronic_dipole_raw =
219 Vector3D{electronic_moments[1], electronic_moments[2], electronic_moments[3]};
220 electronic_quadrupole_raw =
221 Vector3D{electronic_moments[4], electronic_moments[5], electronic_moments[6]};
223 Real grid_sum_to_integral_scale =
224 crystal_structure.
cell_volume() /
static_cast<Real>(total_grid_points);
225 Real electron_count = electron_count_raw * grid_sum_to_integral_scale;
226 Vector3D electronic_dipole = electronic_dipole_raw * grid_sum_to_integral_scale * alat;
228 electronic_quadrupole_raw * grid_sum_to_integral_scale * (alat * alat);
230 Real net_charge = total_valence_charge - electron_count;
231 Vector3D dipole = ionic_dipole - electronic_dipole;
232 Real quadrupole_trace = (ionic_quadrupole.
x - electronic_quadrupole.
x) +
233 (ionic_quadrupole.
y - electronic_quadrupole.
y) +
234 (ionic_quadrupole.
z - electronic_quadrupole.
z);
235 Real dipole_norm_squared = dipole.
x * dipole.
x + dipole.
y * dipole.
y + dipole.
z * dipole.
z;
239 Real first_order_in_ry = madelung_constant * net_charge * net_charge / alat;
241 (net_charge * quadrupole_trace - dipole_norm_squared) /
242 (alat * alat * alat) * e2;
247 result.
terms_in_ry = {{
"first_order", first_order_in_ry},
248 {
"second_order", second_order_in_ry}};