112 const Crystal& crystal_structure,
115 const std::vector<Complex>& total_potential_g,
119 const std::vector<int>& projector_channels_per_type,
120 const std::vector<std::vector<int>>& projector_to_beta_index,
121 const std::vector<std::vector<int>>& projector_combined_lm_index,
122 const std::vector<std::vector<int>>& projector_angular_momentum) {
130 int number_of_lm_projectors =
131 maximum_angular_momentum_q_plus_one * maximum_angular_momentum_q_plus_one;
133 std::vector<std::vector<Real>> effective_d_matrix(number_of_atoms);
135 for (
int atom_index = 0; atom_index < number_of_atoms; atom_index++) {
137 int number_of_projectors_per_species =
138 pseudopotential_set[species_type_index].number_of_projectors;
139 int number_of_projectors = projector_channels_per_type[species_type_index];
140 effective_d_matrix[atom_index].assign(number_of_projectors * number_of_projectors, 0.0);
145 for (
int projector_index_i = 0; projector_index_i < number_of_projectors;
146 projector_index_i++) {
147 for (
int projector_index_j = 0; projector_index_j < number_of_projectors;
148 projector_index_j++) {
149 if (projector_combined_lm_index[species_type_index][projector_index_i] ==
150 projector_combined_lm_index[species_type_index][projector_index_j]) {
151 effective_d_matrix[atom_index][projector_index_i * number_of_projectors +
153 pseudopotential_set[species_type_index].d_ion_matrix
154 [projector_to_beta_index[species_type_index][projector_index_i]]
155 [projector_to_beta_index[species_type_index][projector_index_j]];
161 std::vector<Complex> potential_g_structure_factor_product(number_of_g_vectors);
162 for (
int g_index = 0; g_index < number_of_g_vectors; g_index++) {
163 const auto& g_vector = planewave_basis.
g_vectors()[g_index];
165 potential_g_structure_factor_product[g_index] =
170 for (
int projector_index_i = 0; projector_index_i < number_of_projectors;
171 projector_index_i++) {
172 for (
int projector_index_j = projector_index_i;
173 projector_index_j < number_of_projectors;
174 projector_index_j++) {
175 int beta_index_i = projector_to_beta_index[species_type_index][projector_index_i];
176 int beta_index_j = projector_to_beta_index[species_type_index][projector_index_j];
177 int combined_lm_index_i =
178 projector_combined_lm_index[species_type_index][projector_index_i];
179 int combined_lm_index_j =
180 projector_combined_lm_index[species_type_index][projector_index_j];
181 int angular_momentum_i =
182 projector_angular_momentum[species_type_index][projector_index_i];
183 int angular_momentum_j =
184 projector_angular_momentum[species_type_index][projector_index_j];
186 int projector_pair_index =
187 beta_index_i * number_of_projectors_per_species + beta_index_j;
189 if (combined_lm_index_i >= number_of_lm_projectors ||
190 combined_lm_index_j >= number_of_lm_projectors) {
194 [combined_lm_index_j] == 0) {
200 int product_lm_index;
201 int angular_momentum;
202 int projector_pair_index_for_augmentation_function;
203 Real gaunt_coefficient_value;
205 std::vector<GauntTerm> valid_gaunt_terms;
206 for (
int gaunt_index = 0;
209 [combined_lm_index_j];
211 int product_lm_index =
213 [combined_lm_index_j][gaunt_index];
214 Real gaunt_coefficient_value =
215 gaunt_table.
coefficients[product_lm_index][combined_lm_index_i]
216 [combined_lm_index_j];
217 int angular_momentum =
218 static_cast<int>(std::sqrt(
static_cast<double>(product_lm_index)));
219 if (angular_momentum < std::abs(angular_momentum_i - angular_momentum_j) ||
220 angular_momentum > angular_momentum_i + angular_momentum_j ||
221 (angular_momentum + angular_momentum_i + angular_momentum_j) % 2 != 0) {
224 valid_gaunt_terms.push_back({product_lm_index,
226 projector_pair_index,
227 gaunt_coefficient_value});
230 if (valid_gaunt_terms.empty()) {
234 Complex sum_integral(0.0, 0.0);
235 for (
int g_index = 0; g_index < number_of_g_vectors; g_index++) {
238 Real g_magnitude = g_vector_magnitudes[g_index];
239 for (
const auto& term : valid_gaunt_terms) {
240 Real augmentation_function_value =
243 term.projector_pair_index_for_augmentation_function,
244 term.angular_momentum,
246 Real spherical_harmonic_value =
247 spherical_harmonics_table.
value(g_index, term.product_lm_index);
248 Real integrand_contribution =
249 augmentation_function_value * spherical_harmonic_value;
250 switch (term.angular_momentum % 4) {
252 q_g_real += term.gaunt_coefficient_value * integrand_contribution;
255 q_g_imag -= term.gaunt_coefficient_value * integrand_contribution;
258 q_g_real -= term.gaunt_coefficient_value * integrand_contribution;
261 q_g_imag += term.gaunt_coefficient_value * integrand_contribution;
265 sum_integral += potential_g_structure_factor_product[g_index] *
269 effective_d_matrix[atom_index]
270 [projector_index_i * number_of_projectors + projector_index_j] +=
271 std::real(sum_integral) * cell_volume;
272 if (projector_index_i != projector_index_j) {
273 effective_d_matrix[atom_index][projector_index_j * number_of_projectors +
274 projector_index_i] +=
275 std::real(sum_integral) * cell_volume;
281 return effective_d_matrix;