diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index a7494c191f..ae735fb8d8 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -157,21 +157,25 @@ target_link_libraries(abacus_link_libs INTERFACE abacus::feature_libs set(_abacus_linalg_libs) set(_abacus_linalg_include_dirs) +# C_PACK is optional for DSP builds. With MT_CPACK_DIR set, the serial +# generalized eigensolver is offloaded to cpack_zhegvx_driver from libc_pack.a; +# otherwise the fallback in source_hsolver/cpack_zhegvx_fallback.cpp forwards it +# to the configured LAPACK provider's zhegvx_ (see issue #8247). if(USE_DSP) - if(NOT MT_CPACK_DIR) - message( - FATAL_ERROR - "USE_DSP requires MT_CPACK_DIR to be set to the DSP C_PACK install prefix " - "(the directory containing lib/libc_pack.a).") - endif() - set(_abacus_cpack_library "${MT_CPACK_DIR}/lib/libc_pack.a") - if(NOT EXISTS "${_abacus_cpack_library}") - message( - FATAL_ERROR - "MT_CPACK_DIR is set to '${MT_CPACK_DIR}' but '${_abacus_cpack_library}' does not exist." - ) + if(MT_CPACK_DIR) + set(_abacus_cpack_library "${MT_CPACK_DIR}/lib/libc_pack.a") + if(NOT EXISTS "${_abacus_cpack_library}") + message( + FATAL_ERROR + "MT_CPACK_DIR is set to '${MT_CPACK_DIR}' but '${_abacus_cpack_library}' does not exist." + ) + endif() + list(APPEND _abacus_linalg_libs ${_abacus_cpack_library}) + else() + message(STATUS + "USE_DSP without MT_CPACK_DIR: C_PACK disabled, the serial generalized " + "eigensolver falls back to the configured LAPACK provider (zhegvx).") endif() - list(APPEND _abacus_linalg_libs ${_abacus_cpack_library}) endif() if(USE_KML) diff --git a/source/source_hsolver/CMakeLists.txt b/source/source_hsolver/CMakeLists.txt index 8a4b36cc14..a415316e10 100644 --- a/source/source_hsolver/CMakeLists.txt +++ b/source/source_hsolver/CMakeLists.txt @@ -26,6 +26,14 @@ if(ENABLE_LCAO) list(APPEND objects diago_elpa.cpp diago_elpa_native.cpp) endif() + # DSP build without C_PACK: provide the zhegvx_ fallback for + # cpack_zhegvx_driver (used by diago_lapack.cpp under __DSP). + if(USE_DSP AND NOT MT_CPACK_DIR) + list(APPEND objects + cpack_zhegvx_fallback.cpp + ) + endif() + if(USE_CUDA) set(cuda_objects ./kernels/hegvd_op.cpp ./kernels/cuda/diag_cusolver.cu diago_cusolver.cpp diago_cusolver.h) diff --git a/source/source_hsolver/cpack_zhegvx_fallback.cpp b/source/source_hsolver/cpack_zhegvx_fallback.cpp new file mode 100644 index 0000000000..25bc6f20bf --- /dev/null +++ b/source/source_hsolver/cpack_zhegvx_fallback.cpp @@ -0,0 +1,64 @@ +// Fallback for DSP builds without C_PACK (MT_CPACK_DIR unset). +// +// diago_lapack.cpp calls cpack_zhegvx_driver under __DSP. The symbol normally +// comes from libc_pack.a; when C_PACK is not linked, this translation unit +// provides it by forwarding to the configured LAPACK provider's zhegvx_. CMake adds this +// file only when USE_DSP is on and MT_CPACK_DIR is unset, so it never coexists +// with libc_pack.a. See issue #8247. + +#include "source_base/module_external/lapack_connector.h" + +#ifdef __DSP + +void cpack_zhegvx_driver(const int* itype, + const char* jobz, + const char* range, + const char* uplo, + const int* n, + std::complex* a, + const int* lda, + std::complex* b, + const int* ldb, + const double* vl, + const double* vu, + const int* il, + const int* iu, + const double* abstol, + int* m, + double* w, + std::complex* z, + const int* ldz, + std::complex* work, + const int* lwork, + double* rwork, + int* iwork, + int* ifail, + int* info) +{ + zhegvx_(itype, + jobz, + range, + uplo, + n, + a, + lda, + b, + ldb, + vl, + vu, + il, + iu, + abstol, + m, + w, + z, + ldz, + work, + lwork, + rwork, + iwork, + ifail, + info); +} + +#endif diff --git a/source/source_hsolver/unittests/CMakeLists.txt b/source/source_hsolver/unittests/CMakeLists.txt index b46d9bf1ad..95e9cc675f 100644 --- a/source/source_hsolver/unittests/CMakeLists.txt +++ b/source/source_hsolver/unittests/CMakeLists.txt @@ -79,17 +79,22 @@ if(ENABLE_MPI) ../../source_cell/reciprocal_grid.cpp) if(ENABLE_LCAO) + # DSP build without C_PACK: diago_lapack.cpp then needs the zhegvx_ + # fallback for cpack_zhegvx_driver. + if(USE_DSP AND NOT MT_CPACK_DIR) + set(_dsp_cpack_fallback_src ../cpack_zhegvx_fallback.cpp) + endif() if(TARGET ELPA::ELPA) addtest( TARGET MODULE_HSOLVER_LCAO LIBS parameter ELPA::ELPA base genelpa psi device SOURCES test_diago_lcao.cpp ../diago_elpa.cpp ../diago_elpa_native.cpp - ../diago_scalapack.cpp ../diago_lapack.cpp) + ../diago_scalapack.cpp ../diago_lapack.cpp ${_dsp_cpack_fallback_src}) else() addtest( TARGET MODULE_HSOLVER_LCAO LIBS parameter base psi device - SOURCES test_diago_lcao.cpp ../diago_scalapack.cpp ../diago_lapack.cpp) + SOURCES test_diago_lcao.cpp ../diago_scalapack.cpp ../diago_lapack.cpp ${_dsp_cpack_fallback_src}) endif() if(TARGET PEXSI::PEXSI) diff --git a/source/source_hsolver/unittests/test_diago_lcao.cpp b/source/source_hsolver/unittests/test_diago_lcao.cpp index d61f0e0a44..956b375246 100644 --- a/source/source_hsolver/unittests/test_diago_lcao.cpp +++ b/source/source_hsolver/unittests/test_diago_lcao.cpp @@ -491,6 +491,7 @@ INSTANTIATE_TEST_SUITE_P( DiagoPrepare>(0, 0, 1, 0, "genelpa", "H-KPoints-Si2.dat", "S-KPoints-Si2.dat"), #endif // DiagoPrepare>(0, 0, 32, 0, "genelpa", "H-KPoints-Si64.dat", "S-KPoints-Si64.dat"), + DiagoPrepare>(0, 0, 1, 0, "lapack", "H-KPoints-Si2.dat", "S-KPoints-Si2.dat"), DiagoPrepare>(0, 0, 1, 0, "scalapack_gvx", "H-KPoints-Si2.dat", "S-KPoints-Si2.dat"), DiagoPrepare>(0, 0, 32, 0, "scalapack_gvx", "H-KPoints-Si64.dat", "S-KPoints-Si64.dat")));