|
1 | 1 | #include "diago_dav_subspace.h" |
2 | 2 |
|
| 3 | +#include <type_traits> |
| 4 | + |
3 | 5 | #include "diago_iter_assist.h" |
4 | 6 |
|
5 | 7 | #include "source_base/module_device/device.h" |
@@ -103,6 +105,8 @@ Diago_DavSubspace<T, Device>::~Diago_DavSubspace() |
103 | 105 | delmem_real_op()(this->d_precondition); |
104 | 106 | delmem_complex_op()(this->d_scc); |
105 | 107 | delmem_real_op()(this->d_eigenvalue); |
| 108 | + delmem_complex_h_op()(this->hcc_h); |
| 109 | + delmem_complex_h_op()(this->scc_h); |
106 | 110 | } |
107 | 111 | #endif |
108 | 112 | } |
@@ -585,8 +589,30 @@ void Diago_DavSubspace<T, Device>::cal_elem(const int& dim, |
585 | 589 | mtfunc::dsp_dav_subspace_reduce(hcc, scc, nbase, this->nbase_x, this->notconv, this->diag_comm.comm); |
586 | 590 | #else |
587 | 591 | assert(this->diag_comm.comm == POOL_WORLD); |
588 | | - Parallel_Reduce::reduce_pool(hcc + nbase * this->nbase_x, notconv * this->nbase_x); |
589 | | - Parallel_Reduce::reduce_pool(scc + nbase * this->nbase_x, notconv * this->nbase_x); |
| 592 | + // For GPU, need to copy to CPU before MPI reduction |
| 593 | + if constexpr (std::is_same<Device, base_device::DEVICE_GPU>::value) |
| 594 | + { |
| 595 | + // Allocate CPU buffers if needed |
| 596 | + if (this->hcc_h == nullptr) |
| 597 | + { |
| 598 | + resmem_complex_h_op()(this->hcc_h, this->nbase_x * this->nbase_x, "DAV::hcc_h"); |
| 599 | + resmem_complex_h_op()(this->scc_h, this->nbase_x * this->nbase_x, "DAV::scc_h"); |
| 600 | + } |
| 601 | + // Copy from GPU to CPU |
| 602 | + syncmem_d2h_op()(this->hcc_h, hcc + nbase * this->nbase_x, notconv * this->nbase_x); |
| 603 | + syncmem_d2h_op()(this->scc_h, scc + nbase * this->nbase_x, notconv * this->nbase_x); |
| 604 | + // Reduce on CPU |
| 605 | + Parallel_Reduce::reduce_pool(this->hcc_h, notconv * this->nbase_x); |
| 606 | + Parallel_Reduce::reduce_pool(this->scc_h, notconv * this->nbase_x); |
| 607 | + // Copy back to GPU |
| 608 | + syncmem_h2d_op()(hcc + nbase * this->nbase_x, this->hcc_h, notconv * this->nbase_x); |
| 609 | + syncmem_h2d_op()(scc + nbase * this->nbase_x, this->scc_h, notconv * this->nbase_x); |
| 610 | + } |
| 611 | + else |
| 612 | + { |
| 613 | + Parallel_Reduce::reduce_pool(hcc + nbase * this->nbase_x, notconv * this->nbase_x); |
| 614 | + Parallel_Reduce::reduce_pool(scc + nbase * this->nbase_x, notconv * this->nbase_x); |
| 615 | + } |
590 | 616 | #endif |
591 | 617 | } |
592 | 618 | #endif |
@@ -615,9 +641,24 @@ void Diago_DavSubspace<T, Device>::diag_zhegvx(const int& nbase, |
615 | 641 | #if defined(__CUDA) || defined(__ROCM) |
616 | 642 | if (this->diag_comm.rank == 0) |
617 | 643 | { |
618 | | - syncmem_complex_op()(this->d_scc, scc, nbase * this->nbase_x); |
619 | | - ct::kernels::lapack_hegvd<T, ct_Device>()(nbase, this->nbase_x, this->hcc, this->d_scc, this->d_eigenvalue, this->vcc); |
620 | | - syncmem_var_d2h_op()((*eigenvalue_iter).data(), this->d_eigenvalue, this->nbase_x); |
| 644 | + // Copy hcc and scc from GPU to CPU for robust eigensolving |
| 645 | + std::vector<T> hcc_h(nbase * this->nbase_x, *this->zero); |
| 646 | + std::vector<T> scc_h(nbase * this->nbase_x, *this->zero); |
| 647 | + syncmem_d2h_op()(hcc_h.data(), this->hcc, nbase * this->nbase_x); |
| 648 | + syncmem_d2h_op()(scc_h.data(), scc, nbase * this->nbase_x); |
| 649 | + |
| 650 | + // Solve on CPU using hegvx (more robust than hegvd for ill-conditioned overlap) |
| 651 | + std::vector<T> vcc_h(nbase * this->nbase_x, *this->zero); |
| 652 | + hegvx_op<T, base_device::DEVICE_CPU>()(this->cpu_ctx, |
| 653 | + nbase, |
| 654 | + this->nbase_x, |
| 655 | + hcc_h.data(), |
| 656 | + scc_h.data(), |
| 657 | + nband, |
| 658 | + (*eigenvalue_iter).data(), |
| 659 | + vcc_h.data()); |
| 660 | + // Copy eigenvectors back to GPU |
| 661 | + syncmem_h2d_op()(this->vcc, vcc_h.data(), nbase * this->nbase_x); |
621 | 662 | } |
622 | 663 | #endif |
623 | 664 | } |
@@ -715,9 +756,25 @@ void Diago_DavSubspace<T, Device>::diag_zhegvx(const int& nbase, |
715 | 756 | if (this->diag_comm.nproc > 1) |
716 | 757 | { |
717 | 758 | // vcc: nbase * nband |
718 | | - for (int i = 0; i < nband; i++) |
| 759 | + if constexpr (std::is_same<Device, base_device::DEVICE_GPU>::value) |
719 | 760 | { |
720 | | - MPI_Bcast(&vcc[i * this->nbase_x], nbase, MPI_DOUBLE_COMPLEX, 0, this->diag_comm.comm); |
| 761 | + // Copy vcc from GPU to CPU for MPI broadcast |
| 762 | + T* vcc_h = nullptr; |
| 763 | + resmem_complex_h_op()(vcc_h, nband * this->nbase_x, "DAV::vcc_h"); |
| 764 | + syncmem_d2h_op()(vcc_h, vcc, nband * this->nbase_x); |
| 765 | + for (int i = 0; i < nband; i++) |
| 766 | + { |
| 767 | + MPI_Bcast(&vcc_h[i * this->nbase_x], nbase, MPI_DOUBLE_COMPLEX, 0, this->diag_comm.comm); |
| 768 | + } |
| 769 | + syncmem_h2d_op()(vcc, vcc_h, nband * this->nbase_x); |
| 770 | + delmem_complex_h_op()(vcc_h); |
| 771 | + } |
| 772 | + else |
| 773 | + { |
| 774 | + for (int i = 0; i < nband; i++) |
| 775 | + { |
| 776 | + MPI_Bcast(&vcc[i * this->nbase_x], nbase, MPI_DOUBLE_COMPLEX, 0, this->diag_comm.comm); |
| 777 | + } |
721 | 778 | } |
722 | 779 | MPI_Bcast((*eigenvalue_iter).data(), nband, MPI_DOUBLE, 0, this->diag_comm.comm); |
723 | 780 | } |
|
0 commit comments