67 const Crystal& crystal_structure,
73 std::shared_ptr<execution::gpu::device::GPUDeviceBackend> device_backend)
74 : crystal_structure_{crystal_structure}
75 , planewave_basis_{planewave_basis}
76 , kpoint_grid_{kpoint_grid}
77 , pseudopotential_quantum_system_{pseudopotential_quantum_system}
79 , gpu_fft_grid_{gpu_fft_grid}
80 , device_backend_{std::move(device_backend)}
82 , device_smooth_potential_(0, device_backend_)
83 , device_smooth_potential_single_(0, device_backend_)
84 , device_g_to_fft_mapping_(0, device_backend_)
85 , device_kinetic_energy_squared_(0, device_backend_)
86 , device_kinetic_energy_squared_single_(0, device_backend_)
87 , device_projector_matrix_(0, device_backend_)
88 , device_projector_matrix_single_(0, device_backend_)
89 , device_dense_d_matrix_(0, device_backend_)
90 , device_fft_workspace_(0, device_backend_)
91 , device_fft_workspace_single_(0, device_backend_)
92 , device_fft_batch_workspace_(0, device_backend_)
93 , device_fft_batch_workspace_single_(0, device_backend_)
94 , device_minus_g_to_fft_mapping_(0, device_backend_) {
99 if (gpu_fft_grid_ !=
nullptr) {
100 const auto& wave_fft = planewave_basis_.
fft_wave();
101 gpu_fft_grid_->
init(wave_fft.grid_dimension_1(),
102 wave_fft.grid_dimension_2(),
103 wave_fft.grid_dimension_3());
116 use_mixed_precision_ = use_mixed_precision;
117 if (use_mixed_precision) {
118 log::info(
" GPU applicator: mixed-precision FP32 FFT enabled");
131 cached_smooth_potential_ =
132 compute_smooth_grid_potential(real_space_potential, planewave_basis_);
135 cached_scaled_potential_.resize(local_smooth_grid_points);
137 for (
int index = 0; index < local_smooth_grid_points; ++index) {
138 cached_scaled_potential_[index] =
139 cached_smooth_potential_[index] * inverse_total_points;
144 local_smooth_grid_points, device_backend_);
145 std::memcpy(device_smooth_potential_.
data(),
146 cached_scaled_potential_.data(),
147 local_smooth_grid_points *
sizeof(
Real));
151 local_smooth_grid_points, device_backend_);
153 cached_scaled_potential_.data(),
154 device_smooth_potential_single_.
data());
156 smooth_potential_cache_valid_ =
true;
157 cached_dense_d_matrix_.clear();
168 int number_of_plane_waves,
169 const std::vector<int>& g_vector_indices,
170 const std::vector<Real>& kinetic_energy_squared)
override {
171 current_kpoint_index_ = kpoint_index;
172 current_number_of_plane_waves_ = number_of_plane_waves;
175 precompute_g_to_fft_mapping(number_of_plane_waves, g_vector_indices, planewave_basis_);
178 device_g_to_fft_mapping_ =
180 std::memcpy(device_g_to_fft_mapping_.
data(),
181 g_to_fft_mapping_.data(),
182 number_of_plane_waves *
sizeof(
int));
186 number_of_plane_waves, device_backend_);
187 std::memcpy(device_minus_g_to_fft_mapping_.
data(),
188 minus_g_to_fft_mapping_.data(),
189 number_of_plane_waves *
sizeof(
int));
191 device_minus_g_to_fft_mapping_ =
196 device_kinetic_energy_squared_ =
198 std::memcpy(device_kinetic_energy_squared_.
data(),
199 kinetic_energy_squared.data(),
200 number_of_plane_waves *
sizeof(
Real));
204 number_of_plane_waves, device_backend_);
206 kinetic_energy_squared.data(),
207 device_kinetic_energy_squared_single_.
data());
210 Vector3D kpoint_coordinates = kpoint_grid_[kpoint_index].coordinates;
218 number_of_plane_waves,
220 cached_projector_matrix_);
222 if (!cached_projector_matrix_.
empty()) {
223 int total_projectors =
static_cast<int>(cached_projector_matrix_.
rows());
224 current_total_projectors_ = total_projectors;
225 int projector_data_size = total_projectors * number_of_plane_waves;
229 projector_data_size, device_backend_);
230 std::memcpy(device_projector_matrix_.
data(),
231 cached_projector_matrix_.
data(),
232 projector_data_size *
sizeof(
Complex));
235 device_projector_matrix_single_ =
239 cached_projector_matrix_.
data(),
240 device_projector_matrix_single_.
data());
243 build_dense_d_matrix(total_projectors);
245 current_total_projectors_ = 0;
259 Complex* output_hamiltonian_wavefunctions,
260 int number_of_vectors)
override {
261 int number_of_plane_waves = current_number_of_plane_waves_;
262 int leading_dimension = std::max(number_of_plane_waves, 1);
266 if (
static_cast<int>(device_fft_workspace_.
size()) < local_smooth_grid_points) {
268 local_smooth_grid_points, device_backend_);
274 number_of_plane_waves,
275 device_kinetic_energy_squared_.
data(),
277 output_hamiltonian_wavefunctions);
280 if (use_mixed_precision_) {
282 apply_local_potential_mixed_precision(input_wavefunctions,
283 output_hamiltonian_wavefunctions,
285 number_of_plane_waves,
286 local_smooth_grid_points);
289 apply_local_potential_double_precision(input_wavefunctions,
290 output_hamiltonian_wavefunctions,
292 number_of_plane_waves,
293 local_smooth_grid_points);
297 if (current_total_projectors_ > 0) {
298 apply_nonlocal_projectors_double(input_wavefunctions,
299 output_hamiltonian_wavefunctions,
300 number_of_plane_waves,
303 device_backend_->synchronize();
315 int number_of_vectors) {
316 int number_of_plane_waves = current_number_of_plane_waves_;
321 if (
static_cast<int>(device_fft_workspace_single_.
size()) < local_smooth_grid_points) {
323 local_smooth_grid_points, device_backend_);
329 number_of_plane_waves,
330 device_kinetic_energy_squared_single_.
data(),
332 output_hamiltonian_wavefunctions);
339 int batch_workspace_size = local_smooth_grid_points * number_of_vectors;
340 if (
static_cast<int>(device_fft_batch_workspace_single_.
size()) < batch_workspace_size) {
341 device_fft_batch_workspace_single_ =
349 number_of_plane_waves,
350 local_smooth_grid_points,
351 device_g_to_fft_mapping_.
data(),
352 is_gamma ? device_minus_g_to_fft_mapping_.
data() :
nullptr,
355 device_fft_batch_workspace_single_.
data());
364 local_smooth_grid_points,
365 device_smooth_potential_single_.
data(),
366 device_fft_batch_workspace_single_.
data());
375 number_of_plane_waves,
376 local_smooth_grid_points,
377 device_g_to_fft_mapping_.
data(),
378 device_fft_batch_workspace_single_.
data(),
379 output_hamiltonian_wavefunctions);
382 if (current_total_projectors_ > 0) {
383 apply_nonlocal_projectors_single(input_wavefunctions,
384 output_hamiltonian_wavefunctions,
385 number_of_plane_waves,
388 device_backend_->synchronize();
392 smooth_potential_cache_valid_ =
false;
393 cached_dense_d_matrix_.clear();
400 return smooth_potential_cache_valid_;
407 return cached_scaled_potential_;
414 return g_to_fft_mapping_;
421 return minus_g_to_fft_mapping_;
460 void apply_local_potential_double_precision(
const Complex* input_wavefunctions,
461 Complex* output_hamiltonian_wavefunctions,
462 int number_of_vectors,
463 int number_of_plane_waves,
464 int local_smooth_grid_points) {
467 if (gpu_fft_grid_ !=
nullptr) {
472 int batch_workspace_size = local_smooth_grid_points * number_of_vectors;
473 if (
static_cast<int>(device_fft_batch_workspace_.
size()) < batch_workspace_size) {
475 batch_workspace_size, device_backend_);
481 number_of_plane_waves,
482 local_smooth_grid_points,
483 device_g_to_fft_mapping_.
data(),
484 is_gamma ? device_minus_g_to_fft_mapping_.
data() : nullptr,
487 device_fft_batch_workspace_.data());
496 local_smooth_grid_points,
497 device_smooth_potential_.
data(),
498 device_fft_batch_workspace_.
data());
507 number_of_plane_waves,
508 local_smooth_grid_points,
509 device_g_to_fft_mapping_.
data(),
510 device_fft_batch_workspace_.
data(),
511 output_hamiltonian_wavefunctions);
514 const FFTGrid& fft_wave = planewave_basis_.
fft_wave();
516 for (
int vector_index = 0; vector_index < number_of_vectors; ++vector_index) {
517 const Complex* psi = &input_wavefunctions[vector_index * number_of_plane_waves];
519 &output_hamiltonian_wavefunctions[vector_index * number_of_plane_waves];
522 std::memset(fft_input, 0, local_smooth_grid_points *
sizeof(
Complex));
523 for (
int g_index = 0; g_index < number_of_plane_waves; ++g_index) {
524 int fft_index = g_to_fft_mapping_[g_index];
525 if (fft_index >= 0) {
526 fft_input[fft_index] = psi[g_index];
531 for (
int g_index = 1; g_index < number_of_plane_waves; ++g_index) {
532 int fft_minus = minus_g_to_fft_mapping_[g_index];
533 fft_input[fft_minus] = std::conj(psi[g_index]);
538 fft_wave.execute_inverse_raw_on_buffers();
539 Complex* fft_output = fft_wave.output_buffer();
542 for (
int grid_index = 0; grid_index < local_smooth_grid_points; ++grid_index) {
543 fft_output[grid_index] *= cached_scaled_potential_[grid_index];
547 fft_wave.prepare_forward_from_output();
548 fft_wave.execute_forward_on_buffers();
549 fft_output = fft_wave.output_buffer();
552 for (
int g_index = 0; g_index < number_of_plane_waves; ++g_index) {
553 int fft_index = g_to_fft_mapping_[g_index];
554 if (fft_index >= 0) {
555 hpsi[g_index] += fft_output[fft_index];
572 void apply_local_potential_mixed_precision(
const Complex* input_wavefunctions,
573 Complex* output_hamiltonian_wavefunctions,
574 int number_of_vectors,
575 int number_of_plane_waves,
576 int local_smooth_grid_points) {
579 if (
static_cast<int>(device_fft_workspace_single_.
size()) < local_smooth_grid_points) {
580 device_fft_workspace_single_ = execution::gpu::device::GPUDeviceBuffer<ComplexSingle>(
581 local_smooth_grid_points, device_backend_);
583 if (
static_cast<int>(device_smooth_potential_single_.
size()) < local_smooth_grid_points) {
585 device_smooth_potential_single_ = execution::gpu::device::GPUDeviceBuffer<RealSingle>(
586 local_smooth_grid_points, device_backend_);
587 for (
int grid_index = 0; grid_index < local_smooth_grid_points; ++grid_index) {
588 device_smooth_potential_single_.
data()[grid_index] =
589 static_cast<float>(cached_scaled_potential_[grid_index]);
593 for (
int vector_index = 0; vector_index < number_of_vectors; ++vector_index) {
594 const Complex* psi = &input_wavefunctions[vector_index * number_of_plane_waves];
595 Complex* hpsi = &output_hamiltonian_wavefunctions[vector_index * number_of_plane_waves];
597 if (gpu_fft_grid_ !=
nullptr) {
605 number_of_plane_waves,
606 local_smooth_grid_points,
607 device_g_to_fft_mapping_.
data(),
610 planewave_basis_.is_gamma_only(),
612 device_fft_workspace_single_.data());
620 local_smooth_grid_points,
621 device_smooth_potential_single_.
data(),
622 device_fft_workspace_single_.
data());
630 number_of_plane_waves,
631 local_smooth_grid_points,
632 device_g_to_fft_mapping_.
data(),
633 device_fft_workspace_single_.
data(),
640 const FFTGrid& fft_wave = planewave_basis_.
fft_wave();
644 std::memset(fft_buffer, 0, local_smooth_grid_points *
sizeof(
Complex));
645 for (
int g_index = 0; g_index < number_of_plane_waves; ++g_index) {
646 int fft_index = g_to_fft_mapping_[g_index];
647 if (fft_index >= 0) {
648 float real_part =
static_cast<float>(psi[g_index].real());
649 float imag_part =
static_cast<float>(psi[g_index].imag());
650 fft_buffer[fft_index] =
Complex(real_part, imag_part);
655 for (
int g_index = 1; g_index < number_of_plane_waves; ++g_index) {
656 int fft_minus = minus_g_to_fft_mapping_[g_index];
657 float real_part =
static_cast<float>(psi[g_index].real());
658 float imag_part =
static_cast<float>(psi[g_index].imag());
659 fft_buffer[fft_minus] =
Complex(real_part, -imag_part);
664 fft_wave.execute_inverse_raw_on_buffers();
665 Complex* fft_output = fft_wave.output_buffer();
668 for (
int grid_index = 0; grid_index < local_smooth_grid_points; ++grid_index) {
669 float potential_value = device_smooth_potential_single_.
data()[grid_index];
671 static_cast<float>(fft_output[grid_index].real()) * potential_value;
673 static_cast<float>(fft_output[grid_index].imag()) * potential_value;
674 fft_output[grid_index] =
Complex(real_result, imag_result);
678 fft_wave.prepare_forward_from_output();
679 fft_wave.execute_forward_on_buffers();
680 fft_output = fft_wave.output_buffer();
683 for (
int g_index = 0; g_index < number_of_plane_waves; ++g_index) {
684 int fft_index = g_to_fft_mapping_[g_index];
685 if (fft_index >= 0) {
686 hpsi[g_index] += fft_output[fft_index];
700 void apply_nonlocal_projectors_double(
const Complex* input_wavefunctions,
701 Complex* output_hamiltonian_wavefunctions,
702 int number_of_plane_waves,
703 int number_of_vectors) {
705 int leading_dimension = std::max(number_of_plane_waves, 1);
706 int total_projectors = current_total_projectors_;
709 execution::gpu::device::GPUDeviceBuffer<Complex> overlap_buffer(
710 total_projectors * number_of_vectors, device_backend_);
711 execution::gpu::device::GPUDeviceBuffer<Complex> scaled_overlap_buffer(
712 total_projectors * number_of_vectors, device_backend_);
727 int double_number_of_plane_waves = 2 * number_of_plane_waves;
728 int double_leading_dimension = 2 * leading_dimension;
731 execution::gpu::device::GPUDeviceBuffer<double> device_overlap_real(
732 static_cast<size_t>(total_projectors) * number_of_vectors, device_backend_);
734 const double* real_projectors =
735 reinterpret_cast<const double*
>(device_projector_matrix_.
data());
736 const double* real_wavefunctions =
reinterpret_cast<const double*
>(input_wavefunctions);
742 double_number_of_plane_waves,
745 double_leading_dimension,
747 double_leading_dimension,
749 device_overlap_real.data(),
752 device_backend_->synchronize();
759 for (
int vector_index = 0; vector_index < number_of_vectors; ++vector_index) {
760 const Complex* psi_g0 = &input_wavefunctions[vector_index * number_of_plane_waves];
761 for (
int projector_index = 0; projector_index < total_projectors;
764 device_projector_matrix_.
data()[projector_index * number_of_plane_waves];
765 int index = projector_index + vector_index * total_projectors;
767 device_overlap_real.data()[index] - (std::conj(beta_g0) * psi_g0[0]).real();
768 overlap_buffer.data()[index] =
Complex(value, 0.0);
777 number_of_plane_waves,
779 device_projector_matrix_.
data(),
784 overlap_buffer.data(),
795 device_dense_d_matrix_.
data(),
797 overlap_buffer.data(),
800 scaled_overlap_buffer.data(),
806 number_of_plane_waves,
810 device_projector_matrix_.
data(),
812 scaled_overlap_buffer.data(),
815 output_hamiltonian_wavefunctions,
824 void apply_nonlocal_projectors_single(
const ComplexSingle* input_wavefunctions,
826 int number_of_plane_waves,
827 int number_of_vectors) {
829 int leading_dimension = std::max(number_of_plane_waves, 1);
830 int total_projectors = current_total_projectors_;
833 execution::gpu::device::GPUDeviceBuffer<ComplexSingle> overlap_buffer(
834 total_projectors * number_of_vectors, device_backend_);
835 execution::gpu::device::GPUDeviceBuffer<ComplexSingle> scaled_overlap_buffer(
836 total_projectors * number_of_vectors, device_backend_);
839 execution::gpu::device::GPUDeviceBuffer<ComplexSingle> device_d_matrix_single(
840 total_projectors * total_projectors, device_backend_);
842 device_dense_d_matrix_.
data(),
843 device_d_matrix_single.data());
854 number_of_plane_waves,
856 device_projector_matrix_single_.
data(),
861 overlap_buffer.data(),
871 device_d_matrix_single.data(),
873 overlap_buffer.data(),
876 scaled_overlap_buffer.data(),
882 number_of_plane_waves,
886 device_projector_matrix_single_.
data(),
888 scaled_overlap_buffer.data(),
891 output_hamiltonian_wavefunctions,
900 void build_dense_d_matrix(
int total_projectors) {
901 cached_dense_d_matrix_.assign(
static_cast<size_t>(total_projectors) * total_projectors,
904 int starting_projector_index = 0;
905 for (
int atom_index = 0; atom_index < crystal_structure_.
number_of_atoms(); ++atom_index) {
910 for (
int projector_a = 0; projector_a < projectors_for_atom; ++projector_a) {
911 for (
int projector_b = 0; projector_b < projectors_for_atom; ++projector_b) {
913 atom_index, species_index, projector_a, projector_b,
spin_channel_);
915 int row = starting_projector_index + projector_a;
916 int col = starting_projector_index + projector_b;
917 cached_dense_d_matrix_[
static_cast<size_t>(row) +
918 static_cast<size_t>(col) * total_projectors] =
923 starting_projector_index += projectors_for_atom;
927 device_dense_d_matrix_ = execution::gpu::device::GPUDeviceBuffer<Complex>(
928 total_projectors * total_projectors, device_backend_);
929 std::memcpy(device_dense_d_matrix_.
data(),
930 cached_dense_d_matrix_.data(),
931 total_projectors * total_projectors *
sizeof(
Complex));
943 compute_smooth_grid_potential(
const std::vector<Real>& dense_real_space_potential,
944 const PlanewaveBasis& planewave_basis)
const {
949 if (planewave_basis.fft_rho().local_grid_points() !=
950 planewave_basis.fft_rho().total_grid_points()) {
951 throw std::runtime_error(
952 "The GPU Hamiltonian applicator does not support band-distributed MPI: this rank "
954 std::to_string(planewave_basis.fft_rho().local_grid_points()) +
" of " +
955 std::to_string(planewave_basis.fft_rho().total_grid_points()) +
956 " density grid points, and the device path assumes the whole grid. Run one rank "
957 "per k-point pool, or use the CPU path. This was an assert, which a release "
958 "build compiles out.");
962 auto full_smooth_potential_g =
976 void precompute_g_to_fft_mapping(
int number_of_plane_waves,
977 const std::vector<int>& g_vector_indices,
978 const PlanewaveBasis& planewave_basis) {
981 number_of_plane_waves, g_vector_indices, planewave_basis, g_to_fft_mapping_);
984 if (planewave_basis.is_gamma_only()) {
985 minus_g_to_fft_mapping_.resize(number_of_plane_waves);
986 for (
int g_vector_index = 0; g_vector_index < number_of_plane_waves; g_vector_index++) {
987 const auto& g_vector =
988 planewave_basis.g_vectors()[g_vector_indices[g_vector_index]];
989 int miller_index_1 =
static_cast<int>(std::round(g_vector.miller.x));
990 int miller_index_2 =
static_cast<int>(std::round(g_vector.miller.y));
991 int miller_index_3 =
static_cast<int>(std::round(g_vector.miller.z));
992 minus_g_to_fft_mapping_[g_vector_index] =
993 planewave_basis.fft_wave().g_vector_to_fft_grid_index(
994 -miller_index_1, -miller_index_2, -miller_index_3);
997 minus_g_to_fft_mapping_.clear();
1003 const Crystal& crystal_structure_;
1004 const PlanewaveBasis& planewave_basis_;
1005 const KPointsGrid& kpoint_grid_;
1006 const NormConservingPlanewaveKohnShamQuantumSystem& pseudopotential_quantum_system_;
1007 execution::gpu::blas::GPUBLAS& gpu_blas_;
1008 gpu::GPUFFTGrid* gpu_fft_grid_;
1009 std::shared_ptr<execution::gpu::device::GPUDeviceBackend> device_backend_;
1010 bool use_mixed_precision_ =
false;
1014 int current_kpoint_index_ = 0;
1015 int current_number_of_plane_waves_ = 0;
1016 int current_total_projectors_ = 0;
1020 std::vector<Real> cached_smooth_potential_;
1021 std::vector<Real> cached_scaled_potential_;
1022 bool smooth_potential_cache_valid_ =
false;
1023 std::vector<Complex> cached_dense_d_matrix_;
1024 Matrix<Complex> cached_projector_matrix_;
1028 std::vector<int> g_to_fft_mapping_;
1029 std::vector<int> minus_g_to_fft_mapping_;
1034 execution::gpu::device::GPUDeviceBuffer<Real> device_smooth_potential_;
1035 execution::gpu::device::GPUDeviceBuffer<RealSingle> device_smooth_potential_single_;
1038 execution::gpu::device::GPUDeviceBuffer<int> device_g_to_fft_mapping_;
1039 execution::gpu::device::GPUDeviceBuffer<int> device_minus_g_to_fft_mapping_;
1042 execution::gpu::device::GPUDeviceBuffer<Real> device_kinetic_energy_squared_;
1043 execution::gpu::device::GPUDeviceBuffer<RealSingle> device_kinetic_energy_squared_single_;
1046 execution::gpu::device::GPUDeviceBuffer<Complex> device_projector_matrix_;
1047 execution::gpu::device::GPUDeviceBuffer<ComplexSingle> device_projector_matrix_single_;
1050 execution::gpu::device::GPUDeviceBuffer<Complex> device_dense_d_matrix_;
1053 execution::gpu::device::GPUDeviceBuffer<Complex> device_fft_workspace_;
1054 execution::gpu::device::GPUDeviceBuffer<ComplexSingle> device_fft_workspace_single_;
1057 execution::gpu::device::GPUDeviceBuffer<Complex> device_fft_batch_workspace_;
1058 execution::gpu::device::GPUDeviceBuffer<ComplexSingle> device_fft_batch_workspace_single_;