40 const Crystal& crystal_structure,
45 const std::string& derivative_method =
"analytical")
46 : crystal_structure_(crystal_structure)
47 , planewave_basis_(planewave_basis)
48 , kpoint_grid_(kpoint_grid)
49 , scf_state_(scf_state)
51 , derivative_method_(derivative_method) {}
55 const Matrix3x3& reciprocal_lattice_vectors =
59 int maximum_angular_momentum = 0;
60 int largest_atom_projector_count = 0;
61 for (
int atom_index = 0; atom_index < crystal_structure_.
number_of_atoms(); atom_index++) {
63 for (
int beta_index = 0;
64 beta_index < pseudopotential_basis.number_of_projectors(species_type_index);
66 maximum_angular_momentum = std::max(
67 maximum_angular_momentum,
68 pseudopotential_basis.beta_angular_momentum(species_type_index, beta_index));
70 largest_atom_projector_count =
71 std::max(largest_atom_projector_count,
72 pseudopotential_basis.number_of_projector_channels(species_type_index));
74 int number_of_lm_components =
75 (maximum_angular_momentum + 1) * (maximum_angular_momentum + 1);
88 for (
int kpoint_index = 0; kpoint_index < number_of_kpoints; kpoint_index++) {
89 int kpoint_state_index = spin_index * number_of_kpoints + kpoint_index;
97 const auto& plane_wave_indices_kpoint =
99 Vector3D kpoint_coordinates_crystal = kpoint_grid_[kpoint_index].coordinates;
100 Real kpoint_weight = kpoint_grid_[kpoint_index].weight;
102 Vector3D kpoint_coordinates_cartesian = crystal_to_cartesian_kpoint(
103 kpoint_coordinates_crystal, reciprocal_lattice_vectors);
106 std::vector<int> occupied_band_indices;
107 std::vector<Real> occupied_band_weights;
108 for (
int band_index = 0; band_index < scf_state_.
number_of_bands(); band_index++) {
109 Real occupation = scf_state_.
occupation(kpoint_state_index, band_index);
112 occupied_band_indices.push_back(band_index);
113 occupied_band_weights.push_back(kpoint_weight * occupation);
115 int number_of_occupied_bands =
static_cast<int>(occupied_band_indices.size());
116 if (number_of_occupied_bands == 0)
120 std::vector<Real> kpoint_plus_g_x, kpoint_plus_g_y, kpoint_plus_g_z;
121 std::vector<Real> kpoint_plus_g_norm_inverse;
122 compute_kpoint_plus_g_vectors(kpoint_coordinates_cartesian,
123 plane_wave_indices_kpoint,
124 number_of_plane_waves_kpoint,
128 kpoint_plus_g_norm_inverse);
137 KpointPlusGGeometry geometry;
138 compute_kpoint_plus_g_geometry(kpoint_coordinates_cartesian,
139 plane_wave_indices_kpoint,
140 number_of_plane_waves_kpoint,
141 number_of_lm_components,
145 std::vector<Complex> wavefunction_matrix(
146 static_cast<std::size_t
>(number_of_plane_waves_kpoint) *
147 number_of_occupied_bands);
148 for (
int occupied_index = 0; occupied_index < number_of_occupied_bands;
150 int band_index = occupied_band_indices[occupied_index];
151 for (
int g_index = 0; g_index < number_of_plane_waves_kpoint; g_index++) {
152 wavefunction_matrix[
static_cast<std::size_t
>(occupied_index) *
153 number_of_plane_waves_kpoint +
156 kpoint_state_index, band_index, g_index);
161 std::vector<Real> occupied_eigenvalues(number_of_occupied_bands);
162 if (use_effective_d_matrix) {
163 for (
int band_n = 0; band_n < number_of_occupied_bands; band_n++) {
164 occupied_eigenvalues[band_n] = scf_state_.
eigenvalue(
165 kpoint_state_index, occupied_band_indices[band_n]);
169 int g_zero_plane_wave_index =
171 ? find_g_zero_plane_wave_index(plane_wave_indices_kpoint,
172 number_of_plane_waves_kpoint)
193 constexpr int minimum_projectors_per_block = 64;
194 int projectors_per_block =
195 std::max(largest_atom_projector_count,
196 std::max(number_of_occupied_bands / 8, minimum_projectors_per_block));
197 BlockWorkspace workspace;
198 workspace.allocate(projectors_per_block, number_of_plane_waves_kpoint);
200 std::array<std::vector<Real>, 6> radial_strain_weights;
201 const std::vector<Real>* kpoint_plus_g_components[3] = {
202 &kpoint_plus_g_x, &kpoint_plus_g_y, &kpoint_plus_g_z};
203 for (
int strain_pair = 0; strain_pair < 6; strain_pair++) {
204 const auto& component_a =
205 *kpoint_plus_g_components[bessel_direction_a[strain_pair]];
206 const auto& component_b =
207 *kpoint_plus_g_components[bessel_direction_b[strain_pair]];
208 radial_strain_weights[strain_pair].resize(number_of_plane_waves_kpoint);
209 for (
int g_index = 0; g_index < number_of_plane_waves_kpoint; g_index++) {
210 radial_strain_weights[strain_pair][g_index] =
211 component_a[g_index] * component_b[g_index] *
212 kpoint_plus_g_norm_inverse[g_index];
216 int block_first_atom = 0;
218 int block_end_atom = block_first_atom;
219 int block_projectors = 0;
221 int atom_projectors = pseudopotential_basis.number_of_projector_channels(
223 if (block_projectors > 0 &&
224 block_projectors + atom_projectors > projectors_per_block) {
227 block_projectors += atom_projectors;
230 if (block_projectors > 0) {
231 accumulate_block(spin_index,
232 kpoint_coordinates_cartesian,
233 plane_wave_indices_kpoint,
234 number_of_plane_waves_kpoint,
236 kpoint_plus_g_components,
237 radial_strain_weights,
239 number_of_occupied_bands,
240 occupied_band_weights,
241 occupied_eigenvalues,
242 g_zero_plane_wave_index,
243 use_effective_d_matrix,
249 block_first_atom = block_end_atom;
254 symmetrize_stress_tensor(result_.
nonlocal);
258 [[nodiscard]]
int find_g_zero_plane_wave_index(
const std::vector<int>& plane_wave_indices,
259 int number_of_plane_waves)
const {
260 for (
int plane_wave_index = 0; plane_wave_index < number_of_plane_waves;
261 plane_wave_index++) {
262 if (planewave_basis_.
g_vectors()[plane_wave_indices[plane_wave_index]]
264 return plane_wave_index;
273 static void complete_gamma_only_overlap_matrix(
int number_of_plane_waves,
274 int number_of_left_functions,
275 int number_of_right_functions,
277 const Complex* right_functions,
278 int g_zero_plane_wave_index,
279 std::vector<Complex>& overlaps) {
280 for (
int left_function_index = 0; left_function_index < number_of_left_functions;
281 left_function_index++) {
282 for (
int right_function_index = 0; right_function_index < number_of_right_functions;
283 right_function_index++) {
284 Real g_zero_product =
285 g_zero_plane_wave_index >= 0
286 ? (std::conj(left_functions[
static_cast<size_t>(left_function_index) *
287 number_of_plane_waves +
288 g_zero_plane_wave_index]) *
289 right_functions[
static_cast<size_t>(right_function_index) *
290 number_of_plane_waves +
291 g_zero_plane_wave_index])
294 size_t overlap_index =
295 static_cast<size_t>(right_function_index) * number_of_left_functions +
297 overlaps[overlap_index] =
298 Complex(2.0 * overlaps[overlap_index].real() - g_zero_product, 0.0);
307 const Matrix3x3& reciprocal_lattice_vectors) {
309 for (
int direction = 0; direction < 3; direction++) {
310 result[direction] = kpoint_crystal.
x * reciprocal_lattice_vectors[0][direction] +
311 kpoint_crystal.
y * reciprocal_lattice_vectors[1][direction] +
312 kpoint_crystal.
z * reciprocal_lattice_vectors[2][direction];
320 void compute_kpoint_plus_g_vectors(
const Vector3D& kpoint_coordinates_cartesian,
321 const std::vector<int>& plane_wave_indices_kpoint,
322 int number_of_plane_waves_kpoint,
323 std::vector<Real>& kpoint_plus_g_x,
324 std::vector<Real>& kpoint_plus_g_y,
325 std::vector<Real>& kpoint_plus_g_z,
326 std::vector<Real>& kpoint_plus_g_norm_inverse)
const {
327 kpoint_plus_g_x.resize(number_of_plane_waves_kpoint);
328 kpoint_plus_g_y.resize(number_of_plane_waves_kpoint);
329 kpoint_plus_g_z.resize(number_of_plane_waves_kpoint);
330 kpoint_plus_g_norm_inverse.resize(number_of_plane_waves_kpoint);
332 for (
int g_index = 0; g_index < number_of_plane_waves_kpoint; g_index++) {
333 const auto& g_vector = planewave_basis_.
g_vectors()[plane_wave_indices_kpoint[g_index]];
334 kpoint_plus_g_x[g_index] = (kpoint_coordinates_cartesian.
x + g_vector.g_cart.x) *
336 kpoint_plus_g_y[g_index] = (kpoint_coordinates_cartesian.
y + g_vector.g_cart.y) *
338 kpoint_plus_g_z[g_index] = (kpoint_coordinates_cartesian.
z + g_vector.g_cart.z) *
340 Real kpoint_plus_g_absolute =
341 std::sqrt(kpoint_plus_g_x[g_index] * kpoint_plus_g_x[g_index] +
342 kpoint_plus_g_y[g_index] * kpoint_plus_g_y[g_index] +
343 kpoint_plus_g_z[g_index] * kpoint_plus_g_z[g_index]);
344 kpoint_plus_g_norm_inverse[g_index] =
346 ? 1.0 / kpoint_plus_g_absolute
351 static constexpr int bessel_direction_a[6] = {0, 0, 0, 1, 1, 2};
352 static constexpr int bessel_direction_b[6] = {0, 1, 2, 1, 2, 2};
359 struct KpointPlusGGeometry {
360 std::vector<std::array<Real, 3>> direction_reciprocal;
361 std::vector<Real> magnitude_squared_reciprocal;
362 std::vector<Real> magnitude_bohr;
363 std::vector<std::vector<Real>> spherical_harmonics;
364 std::vector<std::vector<std::vector<Real>>> spherical_harmonic_derivatives;
367 void compute_kpoint_plus_g_geometry(
const Vector3D& kpoint_coordinates_cartesian,
368 const std::vector<int>& plane_wave_indices_kpoint,
369 int number_of_plane_waves_kpoint,
370 int number_of_lm_components,
371 KpointPlusGGeometry& geometry)
const {
372 geometry.direction_reciprocal.resize(number_of_plane_waves_kpoint);
373 geometry.magnitude_squared_reciprocal.resize(number_of_plane_waves_kpoint);
374 geometry.magnitude_bohr.resize(number_of_plane_waves_kpoint);
375 for (
int g_index = 0; g_index < number_of_plane_waves_kpoint; g_index++) {
376 const auto& g_vector = planewave_basis_.
g_vectors()[plane_wave_indices_kpoint[g_index]];
378 kpg.
x = kpoint_coordinates_cartesian.
x + g_vector.g_cart.x;
379 kpg.
y = kpoint_coordinates_cartesian.
y + g_vector.g_cart.y;
380 kpg.
z = kpoint_coordinates_cartesian.
z + g_vector.g_cart.z;
382 geometry.direction_reciprocal[g_index] = {kpg.
x, kpg.
y, kpg.
z};
383 geometry.magnitude_squared_reciprocal[g_index] = kpg_norm_recip * kpg_norm_recip;
384 geometry.magnitude_bohr[g_index] =
388 number_of_plane_waves_kpoint,
389 geometry.direction_reciprocal,
390 geometry.magnitude_squared_reciprocal,
391 geometry.spherical_harmonics);
392 geometry.spherical_harmonic_derivatives.assign(3, {});
393 for (
int polarization_index = 0; polarization_index < 3; polarization_index++) {
395 number_of_lm_components,
396 number_of_plane_waves_kpoint,
397 geometry.direction_reciprocal,
398 geometry.magnitude_squared_reciprocal,
400 geometry.spherical_harmonic_derivatives[polarization_index]);
405 static constexpr int number_of_projector_kinds = 7;
415 struct BlockWorkspace {
416 std::vector<Complex> columns;
418 void allocate(
int maximum_projectors,
int number_of_plane_waves) {
419 columns.resize(
static_cast<std::size_t
>(number_of_projector_kinds) *
420 static_cast<std::size_t
>(maximum_projectors) * number_of_plane_waves);
438 void accumulate_block(
int spin_index,
439 const Vector3D& kpoint_coordinates_cartesian,
440 const std::vector<int>& plane_wave_indices_kpoint,
441 int number_of_plane_waves_kpoint,
442 const KpointPlusGGeometry& geometry,
443 const std::vector<Real>*
const kpoint_plus_g_components[3],
444 const std::array<std::vector<Real>, 6>& radial_strain_weights,
445 const std::vector<Complex>& wavefunction_matrix,
446 int number_of_occupied_bands,
447 const std::vector<Real>& occupied_band_weights,
448 const std::vector<Real>& occupied_eigenvalues,
449 int g_zero_plane_wave_index,
450 bool use_effective_d_matrix,
453 int number_of_projectors,
454 BlockWorkspace& workspace) {
456 Real inverse_sqrt_cell_volume = 1.0 / std::sqrt(crystal_structure_.
cell_volume());
458 Real inverse_two_pi_over_lattice_parameter =
460 std::size_t plane_waves =
static_cast<std::size_t
>(number_of_plane_waves_kpoint);
463 std::vector<Complex> structure_factor(number_of_plane_waves_kpoint);
464 std::vector<Real> beta_derivative_at_g(number_of_plane_waves_kpoint);
465 std::vector<Real> beta_at_g(number_of_plane_waves_kpoint);
466 int projector_index = 0;
467 for (
int atom_index = first_atom; atom_index < end_atom; atom_index++) {
471 for (
int g_index = 0; g_index < number_of_plane_waves_kpoint; g_index++) {
472 const auto& g_vector =
473 planewave_basis_.
g_vectors()[plane_wave_indices_kpoint[g_index]];
476 kpoint_coordinates_cartesian.
dot(atomic_position));
479 for (
int index_beta = 0;
480 index_beta < pseudopotential_basis.number_of_projectors(index_type);
482 int angular_momentum =
483 pseudopotential_basis.beta_angular_momentum(index_type, index_beta);
486 for (
int g_index = 0; g_index < number_of_plane_waves_kpoint; g_index++) {
487 beta_derivative_at_g[g_index] = pseudopotential_basis.interpolate_dbeta(
488 index_type, index_beta, geometry.magnitude_bohr[g_index]);
489 beta_at_g[g_index] = pseudopotential_basis.interpolate_beta(
490 index_type, index_beta, geometry.magnitude_bohr[g_index]);
494 magnetic_projection);
496 workspace.columns.data() +
497 static_cast<std::size_t
>(projector_index) * plane_waves;
498 std::array<Complex*, 6> strain_projector;
499 for (
int strain_pair = 0; strain_pair < 6; strain_pair++) {
500 strain_projector[strain_pair] =
501 workspace.columns.data() +
502 static_cast<std::size_t
>((strain_pair + 1) * number_of_projectors +
506 for (
int g_index = 0; g_index < number_of_plane_waves_kpoint; g_index++) {
507 Complex phased = structure_factor[g_index] * prefactor;
508 Real spherical_harmonic =
509 geometry.spherical_harmonics[g_index][lm_index];
510 projector[g_index] = beta_at_g[g_index] * spherical_harmonic * phased;
512 beta_derivative_at_g[g_index] * spherical_harmonic * phased;
518 beta_at_g[g_index] * inverse_two_pi_over_lattice_parameter * phased;
519 for (
int strain_pair = 0; strain_pair < 6; strain_pair++) {
520 int direction_a = bessel_direction_a[strain_pair];
521 int direction_b = bessel_direction_b[strain_pair];
522 strain_projector[strain_pair][g_index] =
523 radial * radial_strain_weights[strain_pair][g_index] +
525 geometry.spherical_harmonic_derivatives[direction_a]
526 [g_index][lm_index] *
527 (*kpoint_plus_g_components[direction_b])[g_index];
544 int blas_rows = number_of_projector_kinds * number_of_projectors;
545 int blas_k_pw = number_of_plane_waves_kpoint;
546 int blas_n_bands = number_of_occupied_bands;
547 std::vector<Complex> overlaps(
static_cast<std::size_t
>(blas_rows) *
548 static_cast<std::size_t
>(number_of_occupied_bands),
555 reinterpret_cast<const std::complex<double>*
>(&alpha_blas),
556 reinterpret_cast<const std::complex<double>*
>(workspace.columns.data()),
558 reinterpret_cast<const std::complex<double>*
>(wavefunction_matrix.data()),
560 reinterpret_cast<const std::complex<double>*
>(&beta_blas),
561 reinterpret_cast<std::complex<double>*
>(overlaps.data()),
564 complete_gamma_only_overlap_matrix(number_of_plane_waves_kpoint,
566 number_of_occupied_bands,
567 workspace.columns.data(),
568 wavefunction_matrix.data(),
569 g_zero_plane_wave_index,
574 int projector_offset = 0;
575 for (
int atom_index = first_atom; atom_index < end_atom; atom_index++) {
577 int number_of_betas = pseudopotential_basis.number_of_projectors(species_type_index);
579 std::vector<int> projector_beta_indices, projector_magnetic_indices;
580 int projector_start_index = projector_offset;
581 for (
int beta_index = 0; beta_index < number_of_betas; beta_index++) {
582 int angular_momentum =
583 pseudopotential_basis.beta_angular_momentum(species_type_index, beta_index);
585 projector_beta_indices.push_back(beta_index);
586 projector_magnetic_indices.push_back(magnetic_projection);
590 int number_of_projectors_atom =
static_cast<int>(projector_beta_indices.size());
592 for (
int projector_a_local = 0; projector_a_local < number_of_projectors_atom;
593 projector_a_local++) {
594 for (
int projector_b_local = 0; projector_b_local < number_of_projectors_atom;
595 projector_b_local++) {
596 int angular_momentum_a = pseudopotential_basis.beta_angular_momentum(
597 species_type_index, projector_beta_indices[projector_a_local]);
598 int angular_momentum_b = pseudopotential_basis.beta_angular_momentum(
599 species_type_index, projector_beta_indices[projector_b_local]);
616 Real overlap_integral = 0.0;
617 if (use_effective_d_matrix &&
618 pseudopotential_basis.pseudopotential_set()[species_type_index]
619 .has_augmentation_charges() &&
620 angular_momentum_a == angular_momentum_b &&
621 projector_magnetic_indices[projector_a_local] ==
622 projector_magnetic_indices[projector_b_local]) {
627 .augmentation_overlap_integral(
629 projector_beta_indices[projector_a_local],
630 projector_beta_indices[projector_b_local]);
637 int global_a = projector_start_index + projector_a_local;
638 int global_b = projector_start_index + projector_b_local;
640 Real diagonal_sum = 0.0;
641 Real eigenvalue_diagonal_sum = 0.0;
642 Real strain_sums[6] = {};
643 Real eigenvalue_strain_sums[6] = {};
644 bool has_augmentation_term =
645 use_effective_d_matrix &&
648 for (
int band_n = 0; band_n < number_of_occupied_bands; band_n++) {
649 Real weight = occupied_band_weights[band_n];
650 std::size_t band_offset =
static_cast<std::size_t
>(band_n) * blas_rows;
651 Complex becp_a_conjugate = std::conj(overlaps[band_offset + global_a]);
653 Complex becp_b_value = overlaps[band_offset + global_b];
654 Real diagonal_term = weight * (becp_a_conjugate * becp_b_value).real();
655 diagonal_sum += diagonal_term;
658 has_augmentation_term ? occupied_eigenvalues[band_n] : 0.0;
659 eigenvalue_diagonal_sum += diagonal_term * eigenvalue;
660 for (
int strain_pair = 0; strain_pair < 6; strain_pair++) {
664 overlaps[band_offset +
665 static_cast<std::size_t
>((strain_pair + 1) *
666 number_of_projectors) +
669 strain_sums[strain_pair] += strain_term;
670 eigenvalue_strain_sums[strain_pair] += strain_term * eigenvalue;
674 for (
int direction = 0; direction < 3; direction++) {
675 result_.
nonlocal[direction][direction] +=
676 d_element * diagonal_sum * inverse_cell_volume;
678 for (
int strain_pair = 0; strain_pair < 6; strain_pair++) {
679 int direction_a = bessel_direction_a[strain_pair];
680 int direction_b = bessel_direction_b[strain_pair];
681 result_.
nonlocal[direction_a][direction_b] +=
682 d_element * strain_sums[strain_pair] * inverse_cell_volume;
685 if (has_augmentation_term) {
686 for (
int direction = 0; direction < 3; direction++) {
687 result_.
nonlocal[direction][direction] -=
688 overlap_integral * eigenvalue_diagonal_sum * inverse_cell_volume;
690 for (
int strain_pair = 0; strain_pair < 6; strain_pair++) {
691 int direction_a = bessel_direction_a[strain_pair];
692 int direction_b = bessel_direction_b[strain_pair];
693 result_.
nonlocal[direction_a][direction_b] -=
694 overlap_integral * eigenvalue_strain_sums[strain_pair] *
704 static void symmetrize_stress_tensor(
Real stress[3][3]) {
705 for (
int direction_a = 0; direction_a < 3; direction_a++) {
706 for (
int direction_b = direction_a + 1; direction_b < 3; direction_b++) {
707 stress[direction_b][direction_a] = stress[direction_a][direction_b];
712 const Crystal& crystal_structure_;
717 const std::string derivative_method_;