From d41a0e1d81b21bf58ba1e52a62603b7b5a229d3d Mon Sep 17 00:00:00 2001 From: linpz Date: Sat, 13 Jul 2024 13:00:22 +0800 Subject: [PATCH 01/19] Fix C++ compiler warning --- source/module_hamilt_lcao/module_gint/gint.h | 2 +- source/module_lr/utils/lr_util.cpp | 2 +- source/module_lr/utils/lr_util.h | 4 ++-- source/module_lr/utils/lr_util.hpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/module_hamilt_lcao/module_gint/gint.h b/source/module_hamilt_lcao/module_gint/gint.h index b4fb0a3b74..3416ebef6b 100644 --- a/source/module_hamilt_lcao/module_gint/gint.h +++ b/source/module_hamilt_lcao/module_gint/gint.h @@ -22,7 +22,7 @@ class Gint { hamilt::HContainer* get_hRGint() const { return hRGint; } std::vector*> get_DMRGint() const { return DMRGint; } - const int get_ncxyz() const { return ncxyz; } + int get_ncxyz() const { return ncxyz; } // the unified interface to grid integration void cal_gint(Gint_inout* inout); diff --git a/source/module_lr/utils/lr_util.cpp b/source/module_lr/utils/lr_util.cpp index 83491eb343..ea6eca97f9 100644 --- a/source/module_lr/utils/lr_util.cpp +++ b/source/module_lr/utils/lr_util.cpp @@ -5,7 +5,7 @@ namespace LR_Util { /// =================PHYSICS==================== - const int cal_nocc(int nelec) { return nelec / ModuleBase::DEGSPIN + nelec % static_cast(ModuleBase::DEGSPIN); } + int cal_nocc(int nelec) { return nelec / ModuleBase::DEGSPIN + nelec % static_cast(ModuleBase::DEGSPIN); } std::pair>> set_ix_map_diagonal(bool mode, int nocc, int nvirt) diff --git a/source/module_lr/utils/lr_util.h b/source/module_lr/utils/lr_util.h index 147fce62ce..f569d3b105 100644 --- a/source/module_lr/utils/lr_util.h +++ b/source/module_lr/utils/lr_util.h @@ -20,11 +20,11 @@ namespace LR_Util /// @tparam TCell /// @param ucell template - const int cal_nelec(const TCell& ucell); + int cal_nelec(const TCell& ucell); /// @brief calculate the number of occupied orbitals /// @param nelec - const int cal_nocc(int nelec); + int cal_nocc(int nelec); /// @brief set the index map: ix to (ic, iv) and vice versa /// by diagonal traverse the c-v pairs diff --git a/source/module_lr/utils/lr_util.hpp b/source/module_lr/utils/lr_util.hpp index 0e2b29e44c..90ae84c84a 100644 --- a/source/module_lr/utils/lr_util.hpp +++ b/source/module_lr/utils/lr_util.hpp @@ -10,7 +10,7 @@ namespace LR_Util /// =================PHYSICS==================== template - const int cal_nelec(const TCell& ucell) { + int cal_nelec(const TCell& ucell) { int nelec = 0; for (int it = 0; it < ucell.ntype; ++it) nelec += ucell.atoms[it].ncpp.zv * ucell.atoms[it].na; From a21dc75720c0b19a725005c7f44926d754013601 Mon Sep 17 00:00:00 2001 From: linpz Date: Sat, 13 Jul 2024 22:35:29 +0800 Subject: [PATCH 02/19] Refactor Exx_LRI::cal_exx_stress() to LibRI loop3 --- source/module_ri/Exx_LRI.hpp | 12 ++++++++- source/module_ri/LRI_CV_Tools.h | 7 +++++- source/module_ri/LRI_CV_Tools.hpp | 41 +++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/source/module_ri/Exx_LRI.hpp b/source/module_ri/Exx_LRI.hpp index 63f6d5c5a9..cd3eb06128 100644 --- a/source/module_ri/Exx_LRI.hpp +++ b/source/module_ri/Exx_LRI.hpp @@ -140,6 +140,11 @@ void Exx_LRI::cal_exx_ions() {{"writable_dVws",true}}); this->cv.dVws = LRI_CV_Tools::get_dCVws(dVs); this->exx_lri.set_dVs(std::move(dVs), this->info.V_grad_threshold); + if(GlobalV::CAL_STRESS) + { + std::array>>,3>,3> dVRs = LRI_CV_Tools::cal_dMRs(dVs); + this->exx_lri.set_dVRs(std::move(dVRs), this->info.V_grad_threshold); + } } const std::array period_Cs = LRI_CV_Tools::cal_latvec_range(2); @@ -160,6 +165,11 @@ void Exx_LRI::cal_exx_ions() std::array>>,3> &dCs = std::get<1>(Cs_dCs); this->cv.dCws = LRI_CV_Tools::get_dCVws(dCs); this->exx_lri.set_dCs(std::move(dCs), this->info.C_grad_threshold); + if(GlobalV::CAL_STRESS) + { + std::array>>,3>,3> dCRs = LRI_CV_Tools::cal_dMRs(dCs); + this->exx_lri.set_dCRs(std::move(dCRs), this->info.C_grad_threshold); + } } ModuleBase::timer::tick("Exx_LRI", "cal_exx_ions"); } @@ -209,7 +219,7 @@ void Exx_LRI::post_process_Hexx( std::map -double Exx_LRI::post_process_Eexx(const double& Eexx_in) const +double Exx_LRI::post_process_Eexx(const double& Eexx_in) const { ModuleBase::TITLE("Exx_LRI","post_process_Eexx"); const double SPIN_multiple = std::map{ {1,2}, {2,1}, {4,1} }.at(GlobalV::NSPIN); // why? diff --git a/source/module_ri/LRI_CV_Tools.h b/source/module_ri/LRI_CV_Tools.h index ebf6c80526..a40bdbbf49 100644 --- a/source/module_ri/LRI_CV_Tools.h +++ b/source/module_ri/LRI_CV_Tools.h @@ -84,7 +84,12 @@ namespace LRI_CV_Tools template extern std::map,std::array,3>>>> get_dCVws( - const std::array>,RI::Tensor>>,3> &dCVs); + const std::array>,RI::Tensor>>,3> &dCVs); + + template + extern std::array,RI::Tensor>>,3>,3> + cal_dMRs( + const std::array,RI::Tensor>>,3> &dMs); } #include "LRI_CV_Tools.hpp" diff --git a/source/module_ri/LRI_CV_Tools.hpp b/source/module_ri/LRI_CV_Tools.hpp index 8ad95c3715..6333c208b8 100644 --- a/source/module_ri/LRI_CV_Tools.hpp +++ b/source/module_ri/LRI_CV_Tools.hpp @@ -312,4 +312,45 @@ LRI_CV_Tools::get_dCVws( return dCVws; } + +// dMRs[ipos0][ipos1] = \nabla_{ipos0} M R_{ipos1} +template +std::array,RI::Tensor>>,3>,3> +LRI_CV_Tools::cal_dMRs( + const std::array,RI::Tensor>>,3> &dMs) +{ + auto get_R_delta = [&](const TA &iat0, const std::pair &A1) -> std::array + { + const TA iat1 = A1.first; + const TC &cell1 = A1.second; + const int it0 = GlobalC::ucell.iat2it[iat0]; + const int ia0 = GlobalC::ucell.iat2ia[iat0]; + const int it1 = GlobalC::ucell.iat2it[iat1]; + const int ia1 = GlobalC::ucell.iat2ia[iat1]; + const ModuleBase::Vector3 tau0 = GlobalC::ucell.atoms[it0].tau[ia0]; + const ModuleBase::Vector3 tau1 = GlobalC::ucell.atoms[it1].tau[ia1]; + const Abfs::Vector3_Order R_delta = -tau0+tau1+(RI_Util::array3_to_Vector3(cell1)*GlobalC::ucell.latvec); + return std::array{R_delta.x, R_delta.y, R_delta.z}; + }; + constexpr int Npos = 3; + std::array,RI::Tensor>>,Npos>,Npos> dMRs; + for(int ipos0=0; ipos0 A1 = dMs_B.first; + const RI::Tensor &dM = dMs_B.second; + const std::array R_delta = get_R_delta(iat0, A1); + dMRs[ipos0][ipos1][iat0][A1] = dM * R_delta[ipos1]; + } + } + } + } + return dMRs; +} #endif \ No newline at end of file From 1e716e1e82015daeec92ef7511b538a6d5ca0710 Mon Sep 17 00:00:00 2001 From: linpz Date: Mon, 29 Jul 2024 19:17:42 +0800 Subject: [PATCH 03/19] Feature: add input and info CV_grad_R_threshold for exx --- source/module_hamilt_general/module_xc/exx_info.h | 2 ++ source/module_io/input_conv.cpp | 2 ++ source/module_io/read_input_item_other.cpp | 12 ++++++++++++ source/module_parameter/input_parameter.h | 2 ++ source/module_ri/Exx_LRI.hpp | 4 ++-- 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/source/module_hamilt_general/module_xc/exx_info.h b/source/module_hamilt_general/module_xc/exx_info.h index 80a609e929..b0f2dae935 100644 --- a/source/module_hamilt_general/module_xc/exx_info.h +++ b/source/module_hamilt_general/module_xc/exx_info.h @@ -47,6 +47,8 @@ struct Exx_Info double cauchy_threshold = 0; double C_grad_threshold = 0; double V_grad_threshold = 0; + double C_grad_R_threshold = 0; + double V_grad_R_threshold = 0; double cauchy_force_threshold = 0; double cauchy_stress_threshold = 0; double ccp_rmesh_times = 10; diff --git a/source/module_io/input_conv.cpp b/source/module_io/input_conv.cpp index f6d7e8b4cf..bd706695e2 100644 --- a/source/module_io/input_conv.cpp +++ b/source/module_io/input_conv.cpp @@ -684,6 +684,8 @@ void Input_Conv::Convert() GlobalC::exx_info.info_ri.cauchy_threshold = PARAM.inp.exx_cauchy_threshold; GlobalC::exx_info.info_ri.C_grad_threshold = PARAM.inp.exx_c_grad_threshold; GlobalC::exx_info.info_ri.V_grad_threshold = PARAM.inp.exx_v_grad_threshold; + GlobalC::exx_info.info_ri.C_grad_R_threshold = PARAM.inp.exx_c_grad_r_threshold; + GlobalC::exx_info.info_ri.V_grad_R_threshold = PARAM.inp.exx_v_grad_r_threshold; GlobalC::exx_info.info_ri.cauchy_force_threshold = PARAM.inp.exx_cauchy_force_threshold; GlobalC::exx_info.info_ri.cauchy_stress_threshold = PARAM.inp.exx_cauchy_stress_threshold; GlobalC::exx_info.info_ri.ccp_rmesh_times = std::stod(PARAM.inp.exx_ccp_rmesh_times); diff --git a/source/module_io/read_input_item_other.cpp b/source/module_io/read_input_item_other.cpp index 991cfb5f72..9c629317d0 100644 --- a/source/module_io/read_input_item_other.cpp +++ b/source/module_io/read_input_item_other.cpp @@ -552,6 +552,18 @@ void ReadInput::item_others() read_sync_double(exx_v_grad_threshold); this->add_item(item); } + { + Input_Item item("exx_c_grad_r_threshold"); + item.annotation = "threshold to screen nabla C matrix in exx"; + read_sync_double(exx_c_grad_r_threshold); + this->add_item(item); + } + { + Input_Item item("exx_v_grad_r_threshold"); + item.annotation = "threshold to screen nabla V matrix in exx"; + read_sync_double(exx_v_grad_r_threshold); + this->add_item(item); + } { Input_Item item("exx_cauchy_force_threshold"); item.annotation = "threshold to screen exx force using Cauchy-Schwartz inequality"; diff --git a/source/module_parameter/input_parameter.h b/source/module_parameter/input_parameter.h index d755145dbc..bcd630dc67 100644 --- a/source/module_parameter/input_parameter.h +++ b/source/module_parameter/input_parameter.h @@ -369,6 +369,8 @@ struct Input_para double exx_cauchy_threshold = 1e-07; ///< threshold to screen exx using Cauchy-Schwartz inequality double exx_c_grad_threshold = 0.0001; ///< threshold to screen nabla C matrix in exx double exx_v_grad_threshold = 0.1; ///< threshold to screen nabla V matrix in exx + double exx_c_grad_r_threshold = 0.0001; ///< threshold to screen nabla C matrix in exx + double exx_v_grad_r_threshold = 0.1; ///< threshold to screen nabla V matrix in exx double exx_cauchy_force_threshold = 1e-07; ///< threshold to screen exx force using Cauchy-Schwartz ///< inequality double exx_cauchy_stress_threshold = 1e-07; ///< threshold to screen exx stress using Cauchy-Schwartz diff --git a/source/module_ri/Exx_LRI.hpp b/source/module_ri/Exx_LRI.hpp index cd3eb06128..0ed3681138 100644 --- a/source/module_ri/Exx_LRI.hpp +++ b/source/module_ri/Exx_LRI.hpp @@ -143,7 +143,7 @@ void Exx_LRI::cal_exx_ions() if(GlobalV::CAL_STRESS) { std::array>>,3>,3> dVRs = LRI_CV_Tools::cal_dMRs(dVs); - this->exx_lri.set_dVRs(std::move(dVRs), this->info.V_grad_threshold); + this->exx_lri.set_dVRs(std::move(dVRs), this->info.V_grad_R_threshold); } } @@ -168,7 +168,7 @@ void Exx_LRI::cal_exx_ions() if(GlobalV::CAL_STRESS) { std::array>>,3>,3> dCRs = LRI_CV_Tools::cal_dMRs(dCs); - this->exx_lri.set_dCRs(std::move(dCRs), this->info.C_grad_threshold); + this->exx_lri.set_dCRs(std::move(dCRs), this->info.C_grad_R_threshold); } } ModuleBase::timer::tick("Exx_LRI", "cal_exx_ions"); From a9c8ce41d33dd9075d504ee2b8e46dc24cd78f87 Mon Sep 17 00:00:00 2001 From: linpz Date: Mon, 29 Jul 2024 20:12:08 +0800 Subject: [PATCH 04/19] Delete exx_lri.set_csm_threshold() --- source/module_ri/Exx_LRI.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/source/module_ri/Exx_LRI.hpp b/source/module_ri/Exx_LRI.hpp index 0ed3681138..a8b63f19d0 100644 --- a/source/module_ri/Exx_LRI.hpp +++ b/source/module_ri/Exx_LRI.hpp @@ -182,8 +182,6 @@ void Exx_LRI::cal_exx_elec(const std::vector, std::set>> judge = RI_2D_Comm::get_2D_judge(pv); - this->exx_lri.set_csm_threshold(this->info.cauchy_threshold); - this->Hexxs.resize(GlobalV::NSPIN); this->Eexx = 0; for(int is=0; is::cal_exx_force() { ModuleBase::TITLE("Exx_LRI","cal_exx_force"); ModuleBase::timer::tick("Exx_LRI", "cal_exx_force"); - - this->exx_lri.set_csm_threshold(this->info.cauchy_force_threshold); this->force_exx.create(GlobalC::ucell.nat, Ndim); for(int is=0; is::cal_exx_stress() { ModuleBase::TITLE("Exx_LRI","cal_exx_stress"); ModuleBase::timer::tick("Exx_LRI", "cal_exx_stress"); - - this->exx_lri.set_csm_threshold(this->info.cauchy_stress_threshold); this->stress_exx.create(Ndim, Ndim); for(int is=0; is Date: Tue, 30 Jul 2024 02:34:02 +0800 Subject: [PATCH 05/19] Update LibRI in toolchain to v0.2.0 --- toolchain/scripts/stage4/install_libri.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toolchain/scripts/stage4/install_libri.sh b/toolchain/scripts/stage4/install_libri.sh index d33fe3068f..78af9ab2ab 100755 --- a/toolchain/scripts/stage4/install_libri.sh +++ b/toolchain/scripts/stage4/install_libri.sh @@ -11,8 +11,8 @@ [ "${BASH_SOURCE[0]}" ] && SCRIPT_NAME="${BASH_SOURCE[0]}" || SCRIPT_NAME=$0 SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_NAME")/.." && pwd -P)" -libri_ver="0.1.1" -libri_sha256="51deb08aa373e54d2c123b57bfd4b3507accac0d496a94b766eaeadccd9e4bd0" +libri_ver="0.2.0" +libri_sha256="ad79dfbc3ed8ff066c85549a2737d29205dbf755b38ea216ab2ab42754f80389" source "${SCRIPT_DIR}"/common_vars.sh source "${SCRIPT_DIR}"/tool_kit.sh source "${SCRIPT_DIR}"/signal_trap.sh From ab01840d99844813260d28f98f9d6ba2041c468b Mon Sep 17 00:00:00 2001 From: linpz Date: Tue, 30 Jul 2024 02:56:11 +0800 Subject: [PATCH 06/19] Update submodule deps/LibRI to v0.2.0 --- deps/LibRI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/LibRI b/deps/LibRI index 553c91c0be..3883b699f5 160000 --- a/deps/LibRI +++ b/deps/LibRI @@ -1 +1 @@ -Subproject commit 553c91c0be1d60a86e7666f0502ef866c366c600 +Subproject commit 3883b699f50eccd84993e849843452e22d035015 From b4f05c140e011e579ea305226255a95041c018a6 Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Tue, 9 Jan 2024 22:04:42 +0800 Subject: [PATCH 07/19] symmetry rotation for EXX enable time-reversal symmetry fix: unify row-continous fix bug and add tests find irreducible atompair real space Hamiltonian rotation new algorithm to find irreducible sector fix wrong O-lattice in M matrix's phase factor H(R) rotation: parallel ver. irreducible sector stars; type name refactor useful test for Hexx new algorithm to find irreducible sector small fix of generative algorithm --- examples/hse/lcao_Si2/INPUT | 2 +- source/Makefile.Objects | 2 + source/module_base/scalapack_connector.h | 15 +- source/module_cell/klist.cpp | 66 +++ source/module_cell/klist.h | 15 +- .../module_cell/module_symmetry/symmetry.cpp | 2 +- source/module_cell/module_symmetry/symmetry.h | 16 +- source/module_esolver/esolver_ks_lcao.cpp | 4 +- source/module_esolver/lcao_before_scf.cpp | 4 +- source/module_io/input_conv.cpp | 6 +- source/module_ri/CMakeLists.txt | 2 + source/module_ri/Exx_LRI_interface.h | 22 +- source/module_ri/Exx_LRI_interface.hpp | 51 +- source/module_ri/RI_2D_Comm.h | 164 +++--- source/module_ri/RI_2D_Comm.hpp | 47 +- source/module_ri/RI_Util.h | 1 + source/module_ri/RPA_LRI.hpp | 25 +- .../module_ri/symmetry_irreducible_sector.cpp | 247 +++++++++ source/module_ri/symmetry_rotation.cpp | 483 ++++++++++++++++++ source/module_ri/symmetry_rotation.h | 234 +++++++++ source/module_ri/symmetry_rotation_R.hpp | 266 ++++++++++ .../symmetry_rotation_R_hcontainer.hpp | 233 +++++++++ source/module_ri/test/CMakeLists.txt | 6 + .../module_ri/test/symmetry_rotation_test.cpp | 173 +++++++ tests/integrate/281_NO_KP_HSE_symmetry/INPUT | 42 ++ tests/integrate/281_NO_KP_HSE_symmetry/KPT | 4 + tests/integrate/281_NO_KP_HSE_symmetry/STRU | 22 + tests/integrate/281_NO_KP_HSE_symmetry/jd | 1 + .../281_NO_KP_HSE_symmetry/result.ref | 8 + tests/integrate/CASES_CPU.txt | 1 + 30 files changed, 2024 insertions(+), 140 deletions(-) create mode 100644 source/module_ri/symmetry_irreducible_sector.cpp create mode 100644 source/module_ri/symmetry_rotation.cpp create mode 100644 source/module_ri/symmetry_rotation.h create mode 100644 source/module_ri/symmetry_rotation_R.hpp create mode 100644 source/module_ri/symmetry_rotation_R_hcontainer.hpp create mode 100644 source/module_ri/test/symmetry_rotation_test.cpp create mode 100644 tests/integrate/281_NO_KP_HSE_symmetry/INPUT create mode 100644 tests/integrate/281_NO_KP_HSE_symmetry/KPT create mode 100644 tests/integrate/281_NO_KP_HSE_symmetry/STRU create mode 100644 tests/integrate/281_NO_KP_HSE_symmetry/jd create mode 100644 tests/integrate/281_NO_KP_HSE_symmetry/result.ref diff --git a/examples/hse/lcao_Si2/INPUT b/examples/hse/lcao_Si2/INPUT index 642e2ccb4a..44709e756e 100644 --- a/examples/hse/lcao_Si2/INPUT +++ b/examples/hse/lcao_Si2/INPUT @@ -10,7 +10,7 @@ ecutwfc 100 scf_thr 1e-8 scf_nmax 100 gamma_only 0 -symmetry -1 +symmetry 1 smearing_method gauss mixing_type broyden mixing_beta 0.4 diff --git a/source/Makefile.Objects b/source/Makefile.Objects index 6c9de9c849..b3a707ed87 100644 --- a/source/Makefile.Objects +++ b/source/Makefile.Objects @@ -602,6 +602,8 @@ OBJS_MODULE_RI=conv_coulomb_pot_k.o\ RI_2D_Comm.o\ Mix_DMk_2D.o\ Mix_Matrix.o\ + symmetry_rotation.o\ + symmetry_irreducible_sector.o\ OBJS_PARALLEL=parallel_common.o\ parallel_global.o\ diff --git a/source/module_base/scalapack_connector.h b/source/module_base/scalapack_connector.h index 5bcdd3187e..a0bd591f00 100644 --- a/source/module_base/scalapack_connector.h +++ b/source/module_base/scalapack_connector.h @@ -208,7 +208,20 @@ class ScalapackConnector B, &IB, &JB, DESCB, &beta, C, &IC, &JC, DESCC); } - static inline + static inline + void gemm( + const char transa, const char transb, + const int M, const int N, const int K, + const double alpha, + const double* A, const int IA, const int JA, const int* DESCA, + const double* B, const int IB, const int JB, const int* DESCB, + const double beta, + double* C, const int IC, const int JC, const int* DESCC) + { + pdgemm_(&transa, &transb, &M, &N, &K, &alpha, A, &IA, &JA, DESCA, + B, &IB, &JB, DESCB, &beta, C, &IC, &JC, DESCC); + } + static inline void getrf( const int M, const int N, std::complex *A, const int IA, const int JA, const int *DESCA, diff --git a/source/module_cell/klist.cpp b/source/module_cell/klist.cpp index b54cb80f4b..97565dca3e 100644 --- a/source/module_cell/klist.cpp +++ b/source/module_cell/klist.cpp @@ -924,6 +924,38 @@ void K_Vectors::ibz_kpoint(const ModuleSymmetry::Symmetry& symm, } delete[] kkmatrix; + +#ifdef __EXX + // setup kstars according to the final (max-norm) kvec_d_ibz + this->kstars.resize(nkstot_ibz); + if (ModuleSymmetry::Symmetry::symm_flag == 1) + { + for (int i = 0; i < nkstot; ++i) + { + int exist_number = -1; + int isym = 0; + for (int j = 0; j < nrotkm; ++j) + { + kvec_rot = kvec_d[i] * kgmatrix[j]; + restrict_kpt(kvec_rot); + for (int k = 0; k < this->nkstot_ibz; ++k) + { + if (symm.equal(kvec_rot.x, this->kvec_d_ibz[k].x) && + symm.equal(kvec_rot.y, this->kvec_d_ibz[k].y) && + symm.equal(kvec_rot.z, this->kvec_d_ibz[k].z)) + { + isym = j; + exist_number = k; + break; + } + } + if (exist_number != -1) break; + } + this->kstars[exist_number].insert(std::make_pair(isym, kvec_d[i])); + } + } +#endif + // output in kpoints file std::stringstream ss; ss << " " << std::setw(40) << "nkstot" @@ -1196,6 +1228,40 @@ void K_Vectors::mpi_k() wk[i] = wk_aux[k_index]; isk[i] = isk_aux[k_index]; } + +#ifdef __EXX + if (ModuleSymmetry::Symmetry::symm_flag == 1) + {//bcast kstars + this->kstars.resize(nkstot); + for (int ikibz = 0;ikibz < nkstot;++ikibz) + { + int starsize = this->kstars[ikibz].size(); + Parallel_Common::bcast_int(starsize); + GlobalV::ofs_running << "starsize: " << starsize << std::endl; + auto ks = this->kstars[ikibz].begin(); + for (int ik = 0;ik < starsize;++ik) + { + int isym; + ModuleBase::Vector3 ks_vec(0, 0, 0); + if (GlobalV::MY_RANK == 0) + { + isym = ks->first; + ks_vec = ks->second; + ++ks; + } + Parallel_Common::bcast_int(isym); + Parallel_Common::bcast_double(ks_vec.x); + Parallel_Common::bcast_double(ks_vec.y); + Parallel_Common::bcast_double(ks_vec.z); + GlobalV::ofs_running << "isym: " << isym << " ks_vec: " << ks_vec.x << " " << ks_vec.y << " " << ks_vec.z << std::endl; + if (GlobalV::MY_RANK != 0) + { + kstars[ikibz].insert(std::make_pair(isym, ks_vec)); + } + } + } + } +#endif } // END SUBROUTINE #endif diff --git a/source/module_cell/klist.h b/source/module_cell/klist.h index 1c13ecd508..1dbbb2c2fb 100644 --- a/source/module_cell/klist.h +++ b/source/module_cell/klist.h @@ -22,6 +22,11 @@ class K_Vectors int nmp[3]; /// Number of Monhorst-Pack std::vector kl_segids; /// index of kline segment + /// @brief equal k points to each ibz-kpont, corresponding to a certain symmetry operations. + /// dim: [iks_ibz][(isym, kvec_d)] + std::vector>> kstars; + + K_Vectors(); ~K_Vectors(); K_Vectors& operator=(const K_Vectors&) = default; @@ -109,11 +114,11 @@ class K_Vectors * @return int Returns the global index of the k-point. * * @note The function calculates the global index by dividing the total number of k-points (nkstot) by the number of - * process pools (KPAR), and adding the remainder if the process pool ID (MY_POOL) is less than the remainder. * @note The function is declared as inline for efficiency. */ inline int getik_global(const int& ik) const; +<<<<<<< HEAD int get_nks() const { return this->nks; @@ -149,11 +154,11 @@ class K_Vectors this->nkstot_full = value; } - private: - int nks; // number of symmetry-reduced k points in this pool(processor, up+dw) - int nkstot; /// number of symmetry-reduced k points in full k mesh - int nkstot_full; /// number of k points before symmetry reduction in full k mesh + /// dim: [iks_ibz][(isym, kvec_d)] + std::vector>> kstars; +private: +>>>>>>> 627516392 (symmetry rotation for EXX) int nspin; bool kc_done; bool kd_done; diff --git a/source/module_cell/module_symmetry/symmetry.cpp b/source/module_cell/module_symmetry/symmetry.cpp index 6c19ef1e35..745410cdb7 100644 --- a/source/module_cell/module_symmetry/symmetry.cpp +++ b/source/module_cell/module_symmetry/symmetry.cpp @@ -1936,7 +1936,7 @@ void Symmetry::gtrans_convert(const ModuleBase::Vector3* va, ModuleBase: vb[i]=va[i]*a*bi; } } -void Symmetry::gmatrix_invmap(const ModuleBase::Matrix3* s, const int n, int* invmap) +void Symmetry::gmatrix_invmap(const ModuleBase::Matrix3* s, const int n, int* invmap) const { ModuleBase::Matrix3 eig(1, 0, 0, 0, 1, 0, 0, 0, 1); ModuleBase::Matrix3 tmp; diff --git a/source/module_cell/module_symmetry/symmetry.h b/source/module_cell/module_symmetry/symmetry.h index 3626cddc52..f0552d9a74 100644 --- a/source/module_cell/module_symmetry/symmetry.h +++ b/source/module_cell/module_symmetry/symmetry.h @@ -114,11 +114,16 @@ class Symmetry : public Symmetry_Basic //convert n translation-vectors from va on basis {a1, a2, a3} to vb on basis {b1, b2, b3} void gtrans_convert(const ModuleBase::Vector3* va, ModuleBase::Vector3* vb, const int n, const ModuleBase::Matrix3 &a, const ModuleBase::Matrix3 &b)const; - void gmatrix_invmap(const ModuleBase::Matrix3* s, const int n, int* invmap); - void hermite_normal_form(const ModuleBase::Matrix3 &s, ModuleBase::Matrix3 &H, ModuleBase::Matrix3 &b) const; - /// @brief return a map that is inequivalent atom index to its symmetry multiplicity - std::map inequivalent_atoms() const; - private: + void gmatrix_invmap(const ModuleBase::Matrix3* s, const int n, int* invmap) const; + void hermite_normal_form(const ModuleBase::Matrix3& s, ModuleBase::Matrix3& H, ModuleBase::Matrix3& b) const; + /// @brief return a map that is inequivalent atom index to its symmetry multiplicity + std::map inequivalent_atoms() const; + int get_rotated_atom(int isym, int iat)const + { + if (!this->isym_rotiat_.empty()) { return this->isym_rotiat_[isym][iat]; } + else { return -1; } + } +private: // (s)tart (p)osition of atom (t)ype which // has (min)inal number. @@ -144,6 +149,7 @@ class Symmetry : public Symmetry_Basic /// Loop the magmom of each atoms in its type when NSPIN>1. If not all the same, primitive cells should not be looped in rhog_symmetry. bool magmom_same_check(const Atom* atoms)const; + }; } diff --git a/source/module_esolver/esolver_ks_lcao.cpp b/source/module_esolver/esolver_ks_lcao.cpp index fda4aefd18..7c82a424b3 100644 --- a/source/module_esolver/esolver_ks_lcao.cpp +++ b/source/module_esolver/esolver_ks_lcao.cpp @@ -619,11 +619,11 @@ void ESolver_KS_LCAO::iter_init(const int istep, const int iter) // calculate exact-exchange if (GlobalC::exx_info.info_ri.real_number) { - this->exd->exx_eachiterinit(*dynamic_cast*>(this->pelec)->get_DM(), iter); + this->exd->exx_eachiterinit(*dynamic_cast*>(this->pelec)->get_DM(), this->kv, iter); } else { - this->exc->exx_eachiterinit(*dynamic_cast*>(this->pelec)->get_DM(), iter); + this->exc->exx_eachiterinit(*dynamic_cast*>(this->pelec)->get_DM(), this->kv, iter); } #endif diff --git a/source/module_esolver/lcao_before_scf.cpp b/source/module_esolver/lcao_before_scf.cpp index 5b545ff419..75e16de91e 100644 --- a/source/module_esolver/lcao_before_scf.cpp +++ b/source/module_esolver/lcao_before_scf.cpp @@ -208,11 +208,11 @@ void ESolver_KS_LCAO::before_scf(const int istep) #ifdef __EXX // set xc type before the first cal of xc in pelec->init_scf if (GlobalC::exx_info.info_ri.real_number) { - this->exd->exx_beforescf(this->kv, *this->p_chgmix); + this->exd->exx_beforescf(this->kv, *this->p_chgmix, GlobalC::ucell, this->pv); } else { - this->exc->exx_beforescf(this->kv, *this->p_chgmix); + this->exc->exx_beforescf(this->kv, *this->p_chgmix, GlobalC::ucell, this->pv); } #endif // __EXX diff --git a/source/module_io/input_conv.cpp b/source/module_io/input_conv.cpp index 55430e192d..3ce1142f68 100644 --- a/source/module_io/input_conv.cpp +++ b/source/module_io/input_conv.cpp @@ -514,10 +514,10 @@ void Input_Conv::Convert() Exx_Abfs::Jle::Ecut_exx = PARAM.inp.exx_opt_orb_ecut; Exx_Abfs::Jle::tolerence = PARAM.inp.exx_opt_orb_tolerence; - // EXX does not support symmetry=1 - if (PARAM.inp.calculation != "nscf" && PARAM.inp.symmetry == "1") + // EXX does not support symmetry for nspin==4 + if (PARAM.inp.calculation != "nscf" && PARAM.inp.symmetry == "1" && PARAM.inp.nspin == 4) { - ModuleSymmetry::Symmetry::symm_flag = 0; + ModuleSymmetry::Symmetry::symm_flag = -1; } } #endif // __LCAO diff --git a/source/module_ri/CMakeLists.txt b/source/module_ri/CMakeLists.txt index d56707d66d..f9ae703074 100644 --- a/source/module_ri/CMakeLists.txt +++ b/source/module_ri/CMakeLists.txt @@ -7,6 +7,8 @@ if (ENABLE_LIBRI) exx_lip.cpp Mix_DMk_2D.cpp Mix_Matrix.cpp + symmetry_rotation.cpp + symmetry_irreducible_sector.cpp ) if(ENABLE_LCAO) diff --git a/source/module_ri/Exx_LRI_interface.h b/source/module_ri/Exx_LRI_interface.h index cf30babb77..f825203811 100644 --- a/source/module_ri/Exx_LRI_interface.h +++ b/source/module_ri/Exx_LRI_interface.h @@ -3,6 +3,7 @@ #include "Exx_LRI.h" #include "module_ri/Mix_DMk_2D.h" +#include "module_ri/symmetry_rotation.h" #include class LCAO_Matrix; @@ -12,6 +13,18 @@ namespace elecstate class ElecState; template class DensityMatrix; + + /// for symmetry, multi-k, nspin<4: restore DM(k) form DM(k_ibz) + std::vector>> restore_dm(const K_Vectors& kv, + const std::vector>>& dm_k_ibz, + const ModuleSymmetry::Symmetry_rotation& symrot, + const Parallel_2D& pv); + /// do nothing if gamma_only + std::vector> restore_dm(const K_Vectors& kv, + const std::vector>& dm_k_ibz, + const ModuleSymmetry::Symmetry_rotation& symrot, + const Parallel_2D& pv); + } template @@ -36,11 +49,11 @@ class Exx_LRI_Interface // Processes in ESolver_KS_LCAO /// @brief in beforescf: set xc type, opt_orb, do DM mixing - void exx_beforescf(const K_Vectors& kv, const Charge_Mixing& chgmix); + void exx_beforescf(const K_Vectors& kv, const Charge_Mixing& chgmix, const UnitCell& ucell, const Parallel_2D& pv); /// @brief in eachiterinit: do DM mixing and calculate Hexx when entering 2nd SCF void exx_eachiterinit(const elecstate::DensityMatrix& dm/**< double should be Tdata if complex-PBE-DM is supported*/, - const int& iter); + const K_Vectors& kv, const int& iter); /// @brief in hamilt2density: calculate Hexx and Eexx void exx_hamilt2density(elecstate::ElecState& elec, const Parallel_Orbitals& pv, const int iter); @@ -51,10 +64,13 @@ class Exx_LRI_Interface const elecstate::DensityMatrix& dm/**< double should be Tdata if complex-PBE-DM is supported*/, const K_Vectors& kv, int& iter); - int two_level_step = 0; private: std::shared_ptr> exx_ptr; Mix_DMk_2D mix_DMk_2D; + int two_level_step = 0; + + bool exx_spacegroup_symmetry = false; + ModuleSymmetry::Symmetry_rotation symrot_; }; #include "Exx_LRI_interface.hpp" diff --git a/source/module_ri/Exx_LRI_interface.hpp b/source/module_ri/Exx_LRI_interface.hpp index 2da1fd43f2..035928977a 100644 --- a/source/module_ri/Exx_LRI_interface.hpp +++ b/source/module_ri/Exx_LRI_interface.hpp @@ -35,7 +35,7 @@ void Exx_LRI_Interface::read_Hexxs_cereal(const std::string& file_name } template -void Exx_LRI_Interface::exx_beforescf(const K_Vectors& kv, const Charge_Mixing& chgmix) +void Exx_LRI_Interface::exx_beforescf(const K_Vectors& kv, const Charge_Mixing& chgmix, const UnitCell& ucell, const Parallel_2D& pv) { #ifdef __MPI if (GlobalC::exx_info.info_global.cal_exx) @@ -43,16 +43,26 @@ void Exx_LRI_Interface::exx_beforescf(const K_Vectors& kv, const Charg if (GlobalC::restart.info_load.load_H_finish && !GlobalC::restart.info_load.restart_exx) { XC_Functional::set_xc_type(GlobalC::ucell.atoms[0].ncpp.xc_func); } else { - if (GlobalC::ucell.atoms[0].ncpp.xc_func == "HF" || GlobalC::ucell.atoms[0].ncpp.xc_func == "PBE0" || GlobalC::ucell.atoms[0].ncpp.xc_func == "HSE") + if (ucell.atoms[0].ncpp.xc_func == "HF" || ucell.atoms[0].ncpp.xc_func == "PBE0" || ucell.atoms[0].ncpp.xc_func == "HSE") { XC_Functional::set_xc_type("pbe"); } - else if (GlobalC::ucell.atoms[0].ncpp.xc_func == "SCAN0") + else if (ucell.atoms[0].ncpp.xc_func == "SCAN0") { XC_Functional::set_xc_type("scan"); } } + this->exx_ptr->cal_exx_ions(); + + // initialize the rotation matrix in AO representation + this->exx_spacegroup_symmetry = (GlobalV::NSPIN < 4 && ModuleSymmetry::Symmetry::symm_flag == 1); + if (this->exx_spacegroup_symmetry) + { + this->symrot_.get_return_lattice_all(ucell.symm, ucell.atoms, ucell.st); + this->symrot_.cal_Ms(kv, ucell, pv); + this->symrot_.find_irreducible_sector(ucell.symm, ucell.atoms, ucell.st, this->symrot_.get_Rs_from_BvK(kv)); + } } if (Exx_Abfs::Jle::generate_matrix) @@ -66,8 +76,11 @@ void Exx_LRI_Interface::exx_beforescf(const K_Vectors& kv, const Charg // set initial parameter for mix_DMk_2D if(GlobalC::exx_info.info_global.cal_exx) - { - this->mix_DMk_2D.set_nks(kv.get_nks(), GlobalV::GAMMA_ONLY_LOCAL); + { + if (this->exx_spacegroup_symmetry) + {this->mix_DMk_2D.set_nks(kv.get_nkstot_full() * (GlobalV::NSPIN == 2 ? 2 : 1), GlobalV::GAMMA_ONLY_LOCAL);} + else + {this->mix_DMk_2D.set_nks(kv.get_nks(), GlobalV::GAMMA_ONLY_LOCAL);} if(GlobalC::exx_info.info_global.separate_loop) { this->mix_DMk_2D.set_mixing(nullptr); } else { @@ -80,18 +93,21 @@ void Exx_LRI_Interface::exx_beforescf(const K_Vectors& kv, const Charg } template -void Exx_LRI_Interface::exx_eachiterinit(const elecstate::DensityMatrix& dm, const int& iter) +void Exx_LRI_Interface::exx_eachiterinit(const elecstate::DensityMatrix& dm, const K_Vectors& kv, const int& iter) { if (GlobalC::exx_info.info_global.cal_exx) { if (!GlobalC::exx_info.info_global.separate_loop && this->two_level_step) { - const bool flag_restart = (iter==1) ? true : false; - this->mix_DMk_2D.mix(dm.get_DMK_vector(), flag_restart); + const bool flag_restart = (iter == 1) ? true : false; + if (this->exx_spacegroup_symmetry) + this->mix_DMk_2D.mix(symrot_.restore_dm(kv, dm.get_DMK_vector(), *dm.get_paraV_pointer()), flag_restart); + else + this->mix_DMk_2D.mix(dm.get_DMK_vector(), flag_restart); const std::vector>,RI::Tensor>>> Ds = GlobalV::GAMMA_ONLY_LOCAL ? RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_gamma_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN) - : RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_k_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN); + : RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_k_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN, this->exx_spacegroup_symmetry); this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer()); } } @@ -178,14 +194,27 @@ bool Exx_LRI_Interface::exx_after_converge( timeval t_start; gettimeofday(&t_start, nullptr); const bool flag_restart = (this->two_level_step == 0) ? true : false; - this->mix_DMk_2D.mix(dm.get_DMK_vector(), flag_restart); + + if (this->exx_spacegroup_symmetry) + this->mix_DMk_2D.mix(symrot_.restore_dm(kv, dm.get_DMK_vector(), *dm.get_paraV_pointer()), flag_restart); + else + this->mix_DMk_2D.mix(dm.get_DMK_vector(), flag_restart); // GlobalC::exx_lcao.cal_exx_elec(p_esolver->LOC, p_esolver->LOWF.wfc_k_grid); const std::vector>,RI::Tensor>>> Ds = GlobalV::GAMMA_ONLY_LOCAL ? RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_gamma_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN) - : RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_k_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN); + : RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_k_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN, this->exx_spacegroup_symmetry); this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer()); + + if (!this->exx_spacegroup_symmetry)this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_ref"); + + // check the rotation of S(R) + this->symrot_.find_irreducible_sector(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, this->symrot_.get_Rs_from_adjacent_list(GlobalC::ucell, GlobalC::GridD, *lm.ParaV)); + this->symrot_.test_HR_rotation(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, *(dynamic_cast*>(&hamilt)->getSR())); + // check the rotation of Hexx + // this->symrot_.test_HR_rotation(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, this->exx_ptr->Hexxs[0]); + iter = 0; this->two_level_step++; diff --git a/source/module_ri/RI_2D_Comm.h b/source/module_ri/RI_2D_Comm.h index 64b82f4094..9cc927e807 100644 --- a/source/module_ri/RI_2D_Comm.h +++ b/source/module_ri/RI_2D_Comm.h @@ -1,83 +1,83 @@ -//======================= -// AUTHOR : Peize Lin -// DATE : 2022-08-17 -//======================= - -#ifndef RI_2D_COMM_H -#define RI_2D_COMM_H - -#include "module_basis/module_ao/parallel_orbitals.h" -#include "module_hamilt_lcao/module_hcontainer/hcontainer.h" -#include "module_cell/klist.h" - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace RI_2D_Comm -{ - using TA = int; - using Tcell = int; - static const size_t Ndim = 3; - using TC = std::array; - using TAC = std::pair; - -//public: - template - extern std::vector>>> - split_m2D_ktoR(const K_Vectors& kv, const std::vector& mks_2D, const Parallel_2D& pv, const int nspin); - - // judge[is] = {s0, s1} - extern std::vector, std::set>> - get_2D_judge(const Parallel_2D& pv); - - template - extern void add_Hexx( - const K_Vectors& kv, - const int ik, - const double alpha, - const std::vector>>>& Hs, - const Parallel_Orbitals& pv, - TK* hk); - - template - extern void add_HexxR( - const int current_spin, - const double alpha, - const std::vector>>>& Hs, - const Parallel_Orbitals& pv, - const int npol, - hamilt::HContainer& HlocR, - const RI::Cell_Nearest* const cell_nearest = nullptr); - - template - extern std::vector> Hexxs_to_Hk( - const K_Vectors &kv, - const Parallel_Orbitals &pv, - const std::vector< std::map>>> &Hexxs, - const int ik); - template - std::vector> pulay_mixing( - const Parallel_Orbitals &pv, - std::deque>> &Hk_seq, - const std::vector> &Hk_new, - const double mixing_beta, - const std::string mixing_mode); - -//private: - extern std::vector get_ik_list(const K_Vectors &kv, const int is_k); - extern inline std::tuple get_iat_iw_is_block(const int iwt); - extern inline int get_is_block(const int is_k, const int is_row_b, const int is_col_b); - extern inline std::tuple split_is_block(const int is_b); - extern inline int get_iwt(const int iat, const int iw_b, const int is_b); -} - -#include "RI_2D_Comm.hpp" - +//======================= +// AUTHOR : Peize Lin +// DATE : 2022-08-17 +//======================= + +#ifndef RI_2D_COMM_H +#define RI_2D_COMM_H + +#include "module_basis/module_ao/parallel_orbitals.h" +#include "module_hamilt_lcao/module_hcontainer/hcontainer.h" +#include "module_cell/klist.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace RI_2D_Comm +{ + using TA = int; + using Tcell = int; + static const size_t Ndim = 3; + using TC = std::array; + using TAC = std::pair; + +//public: + template + extern std::vector>>> + split_m2D_ktoR(const K_Vectors& kv, const std::vector& mks_2D, const Parallel_2D& pv, const int nspin, const bool spgsym = false); + + // judge[is] = {s0, s1} + extern std::vector, std::set>> + get_2D_judge(const Parallel_2D& pv); + + template + extern void add_Hexx( + const K_Vectors& kv, + const int ik, + const double alpha, + const std::vector>>>& Hs, + const Parallel_Orbitals& pv, + TK* hk); + + template + extern void add_HexxR( + const int current_spin, + const double alpha, + const std::vector>>>& Hs, + const Parallel_Orbitals& pv, + const int npol, + hamilt::HContainer& HlocR, + const RI::Cell_Nearest* const cell_nearest = nullptr); + + template + extern std::vector> Hexxs_to_Hk( + const K_Vectors &kv, + const Parallel_Orbitals &pv, + const std::vector< std::map>>> &Hexxs, + const int ik); + template + std::vector> pulay_mixing( + const Parallel_Orbitals &pv, + std::deque>> &Hk_seq, + const std::vector> &Hk_new, + const double mixing_beta, + const std::string mixing_mode); + +//private: + extern std::vector get_ik_list(const K_Vectors &kv, const int is_k); + extern inline std::tuple get_iat_iw_is_block(const int iwt); + extern inline int get_is_block(const int is_k, const int is_row_b, const int is_col_b); + extern inline std::tuple split_is_block(const int is_b); + extern inline int get_iwt(const int iat, const int iw_b, const int is_b); +} + +#include "RI_2D_Comm.hpp" + #endif \ No newline at end of file diff --git a/source/module_ri/RI_2D_Comm.hpp b/source/module_ri/RI_2D_Comm.hpp index 0f5a576e87..aeebcc2b2a 100644 --- a/source/module_ri/RI_2D_Comm.hpp +++ b/source/module_ri/RI_2D_Comm.hpp @@ -29,7 +29,7 @@ inline RI::Tensor> tensor_conj(const RI::Tensor -auto RI_2D_Comm::split_m2D_ktoR(const K_Vectors& kv, const std::vector& mks_2D, const Parallel_2D& pv, const int nspin) +auto RI_2D_Comm::split_m2D_ktoR(const K_Vectors & kv, const std::vector&mks_2D, const Parallel_2D & pv, const int nspin, const bool spgsym) -> std::vector>>> { ModuleBase::TITLE("RI_2D_Comm","split_m2D_ktoR"); @@ -45,14 +45,10 @@ auto RI_2D_Comm::split_m2D_ktoR(const K_Vectors& kv, const std::vector ik_list = RI_2D_Comm::get_ik_list(kv, is_k); for(const TC &cell : RI_Util::get_Born_von_Karmen_cells(period)) { - RI::Tensor mR_2D; - for(const int ik : ik_list) - { - using Tdata_m = typename Tmatrix::value_type; - RI::Tensor mk_2D = RI_Util::Vector_to_Tensor(*mks_2D[ik], pv.get_col_size(), pv.get_row_size()); - const Tdata_m frac = SPIN_multiple - * RI::Global_Func::convert( std::exp( - -ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT * (kv.kvec_c[ik] * (RI_Util::array3_to_Vector3(cell) * GlobalC::ucell.latvec)))); + RI::Tensor mR_2D; + int ik_full = 0; + for (const int ik : ik_list) + { auto set_mR_2D = [&mR_2D](auto&& mk_frac) { if (mR_2D.empty()) { mR_2D = RI::Global_Func::convert(mk_frac); @@ -61,15 +57,30 @@ auto RI_2D_Comm::split_m2D_ktoR(const K_Vectors& kv, const std::vector(mk_frac); } }; - if (static_cast(std::round(SPIN_multiple * kv.wk[ik] - * kv.get_nkstot_full())) - == 2) { - set_mR_2D(mk_2D * (frac * 0.5) + tensor_conj(mk_2D * (frac * 0.5))); - } else { - set_mR_2D(mk_2D * frac); + using Tdata_m = typename Tmatrix::value_type; + if (!spgsym) + { + RI::Tensor mk_2D = RI_Util::Vector_to_Tensor(*mks_2D[ik], pv.get_col_size(), pv.get_row_size()); + const Tdata_m frac = SPIN_multiple + * RI::Global_Func::convert(std::exp( + -ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT * (kv.kvec_c[ik] * (RI_Util::array3_to_Vector3(cell) * GlobalC::ucell.latvec)))); + if (static_cast(std::round(SPIN_multiple * kv.wk[ik] * kv.get_nkstot_full())) == 2) + { set_mR_2D(mk_2D * (frac * 0.5) + tensor_conj(mk_2D * (frac * 0.5))); } + else { set_mR_2D(mk_2D * frac); } + } + else + { // traverse kstar, ik means ik_ibz + for (auto& isym_kvd : kv.kstars[ik % ik_list.size()]) + { + RI::Tensor mk_2D = RI_Util::Vector_to_Tensor(*mks_2D[ik_full + is_k * kv.get_nkstot_full()], pv.get_col_size(), pv.get_row_size()); + const Tdata_m frac = SPIN_multiple + * RI::Global_Func::convert(std::exp( + -ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT * ((isym_kvd.second * GlobalC::ucell.G) * (RI_Util::array3_to_Vector3(cell) * GlobalC::ucell.latvec)))); + set_mR_2D(mk_2D * frac); + ++ik_full; + } } } - for(int iwt0_2D=0; iwt0_2D!=mR_2D.shape[0]; ++iwt0_2D) { const int iwt0 = @@ -100,8 +111,8 @@ auto RI_2D_Comm::split_m2D_ktoR(const K_Vectors& kv, const std::vector #include +#include namespace RI_Util { diff --git a/source/module_ri/RPA_LRI.hpp b/source/module_ri/RPA_LRI.hpp index 1da295cef2..f4754f6c2a 100644 --- a/source/module_ri/RPA_LRI.hpp +++ b/source/module_ri/RPA_LRI.hpp @@ -8,6 +8,7 @@ #include #include #include +#include "module_ri/symmetry_rotation.h" #include "RPA_LRI.h" #include "module_parameter/parameter.h" @@ -73,14 +74,26 @@ void RPA_LRI::cal_postSCF_exx(const elecstate::DensityMatrix const K_Vectors& kv) { Mix_DMk_2D mix_DMk_2D; - mix_DMk_2D.set_nks(kv.get_nks(), GlobalV::GAMMA_ONLY_LOCAL); + bool exx_spacegroup_symmetry = (GlobalV::NSPIN < 4 && ModuleSymmetry::Symmetry::symm_flag == 1); + if (exx_spacegroup_symmetry) + {mix_DMk_2D.set_nks(kv.get_nkstot_full() * (GlobalV::NSPIN == 2 ? 2 : 1), GlobalV::GAMMA_ONLY_LOCAL);} + else + {mix_DMk_2D.set_nks(kv.get_nks(), GlobalV::GAMMA_ONLY_LOCAL);} + mix_DMk_2D.set_mixing(nullptr); - mix_DMk_2D.mix(dm.get_DMK_vector(), true); - const std::vector>>> Ds - = GlobalV::GAMMA_ONLY_LOCAL + if (exx_spacegroup_symmetry) + { + ModuleSymmetry::Symmetry_rotation symrot; + symrot.cal_Ms(kv, GlobalC::ucell, *dm.get_paraV_pointer()); + mix_DMk_2D.mix(symrot.restore_dm(kv, dm.get_DMK_vector(), *dm.get_paraV_pointer()), true); + } + else { mix_DMk_2D.mix(dm.get_DMK_vector(), true); } + + const std::vector>>> + Ds = GlobalV::GAMMA_ONLY_LOCAL ? RI_2D_Comm::split_m2D_ktoR(kv, mix_DMk_2D.get_DMk_gamma_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN) - : RI_2D_Comm::split_m2D_ktoR(kv, mix_DMk_2D.get_DMk_k_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN); - + : RI_2D_Comm::split_m2D_ktoR(kv, mix_DMk_2D.get_DMk_k_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN, exx_spacegroup_symmetry); + // set parameters for bare Coulomb potential GlobalC::exx_info.info_global.ccp_type = Conv_Coulomb_Pot_K::Ccp_Type::Hf; GlobalC::exx_info.info_global.hybrid_alpha = 1; diff --git a/source/module_ri/symmetry_irreducible_sector.cpp b/source/module_ri/symmetry_irreducible_sector.cpp new file mode 100644 index 0000000000..15104db1ad --- /dev/null +++ b/source/module_ri/symmetry_irreducible_sector.cpp @@ -0,0 +1,247 @@ +#include "symmetry_rotation.h" + +namespace ModuleSymmetry +{ + int Symmetry_rotation::round2int(const double x) const + { + return x > 0 ? static_cast(x + eps_) : static_cast(x - eps_); + } + + TC Symmetry_rotation::rotate_R_by_formula(const Symmetry& symm, + const int isym, const int iat1, const int iat2, const TC& R, const char gauge) const + { + const TCdouble R_double(static_cast(R[0]), static_cast(R[1]), static_cast(R[2])); + const TCdouble Rrot_double = (gauge == 'L') + ? R_double * symm.gmatrix[isym] + this->return_lattice_[iat1][isym] - this->return_lattice_[iat2][isym] + : R_double * symm.gmatrix[isym] + this->return_lattice_[iat2][isym] - this->return_lattice_[iat1][isym]; + return { round2int(Rrot_double.x), round2int(Rrot_double.y), round2int(Rrot_double.z) }; + } + TapR Symmetry_rotation::rotate_R_by_formula(const Symmetry& symm, + const int isym, const TapR& apR, const char gauge) const + { + const Tap& aprot = { symm.get_rotated_atom(isym, apR.first.first), symm.get_rotated_atom(isym, apR.first.second) }; + return { aprot, this->rotate_R_by_formula(symm, isym, apR.first.first, apR.first.second, apR.second, gauge) }; + } + + TCdouble Symmetry_rotation::get_aRb_direct(const Atom* atoms, const Statistics& st, + const int iat1, const int iat2, const TCdouble& R, const char gauge)const + { + return TCdouble(atoms[st.iat2it[iat1]].taud[st.iat2ia[iat1]] - atoms[st.iat2it[iat2]].taud[st.iat2ia[iat2]]) + (gauge == 'L' ? R : TCdouble(-R)); + } + + TCdouble Symmetry_rotation::get_aRb_direct(const Atom* atoms, const Statistics& st, + const int iat1, const int iat2, const TC& R, const char gauge) const + { + const TCdouble R_double(static_cast(R[0]), static_cast(R[1]), static_cast(R[2])); + return get_aRb_direct(atoms, st, iat1, iat2, R_double); + } + + void Symmetry_rotation::find_irreducible_atom_pairs(const Symmetry& symm) + { + ModuleBase::TITLE("Symmetry_rotation", "find_irreducible_atom_pairs"); + this->eps_ = symm.epsilon; + for (int iat1 = 0;iat1 < symm.nat;++iat1) + for (int iat2 = 0;iat2 < symm.nat;++iat2) + { + Tap pair = { iat1, iat2 }; + bool exist = false; + for (int isym = 0;isym < symm.nrotk;++isym) + { + Tap rotpair = { symm.get_rotated_atom(isym,iat1), symm.get_rotated_atom(isym,iat2) }; + for (int ip = 0;ip < this->atompair_stars_.size();++ip) // current irreduceble pairs + { + if (rotpair == this->atompair_stars_[ip].at(0)) + { + this->atompair_stars_[ip].insert({ isym, pair }); + exist = true; + break; + } + } + if (exist)break; + } + if (!exist)this->atompair_stars_.push_back({ {0, pair} }); + } + } + + void Symmetry_rotation::find_irreducible_atom_pairs_set(const Symmetry& symm) + { + ModuleBase::TITLE("Symmetry_rotation", "find_irreducible_atom_pairs_set"); + this->eps_ = symm.epsilon; + std::vector invmap(symm.nrotk, -1); + symm.gmatrix_invmap(symm.gmatrix, symm.nrotk, invmap.data()); + // contruct initial ap-set + std::set ap_set; + for (int iat1 = 0; iat1 < symm.nat; ++iat1) + for (int iat2 = 0; iat2 < symm.nat; ++iat2) + ap_set.insert({ iat1, iat2 }); + while (!ap_set.empty()) + { + Tap ap = *ap_set.begin(); + std::map ap_star; + for (int isym = 0; isym < symm.nrotk; ++isym) + { + Tap rotpair = { symm.get_rotated_atom(isym,ap.first), symm.get_rotated_atom(isym,ap.second) }; + if (ap_set.find(rotpair) != ap_set.end()) + { + ap_star.insert({ invmap[isym], rotpair }); + ap_set.erase(rotpair); + } + } + this->atompair_stars_.push_back(ap_star); + } + } + + inline void output_atompair_stars(const std::vector>& ap_stars) + { + std::cout << "stars of irreducible atom pairs: " << std::endl; + for (int ip = 0; ip < ap_stars.size(); ++ip) + { + std::cout << "atom pair star " << ip << ": " << std::endl; + for (const auto& ap : ap_stars[ip]) + std::cout << "isym=" << ap.first << ", atompair=(" << ap.second.first << ", " << ap.second.second << ") " << std::endl; + } + } + + void Symmetry_rotation::test_irreducible_atom_pairs(const Symmetry& symm) + { + std::cout << "Algorithm 1: find irreducible atom pairs by set" << std::endl; + this->find_irreducible_atom_pairs_set(symm); + output_atompair_stars(this->atompair_stars_); + + std::cout << std::endl; + this->atompair_stars_.clear(); + std::cout << "Algorithm 2: find irreducible atom pairs by judge" << std::endl; + this->find_irreducible_atom_pairs(symm); + output_atompair_stars(this->atompair_stars_); + } + + std::vector Symmetry_rotation::get_Rs_from_BvK(const K_Vectors& kv) const + { + const TC& period = RI_Util::get_Born_vonKarmen_period(kv); + return RI_Util::get_Born_von_Karmen_cells(period); + } + std::vector Symmetry_rotation::get_Rs_from_adjacent_list(const UnitCell& ucell, Grid_Driver& gd, const Parallel_Orbitals& pv) const + { + // find the union set of Rs for all the atom pairs + std::set Rs_set; + for (int iat1 = 0;iat1 < ucell.nat;++iat1) + { + auto tau1 = ucell.get_tau(iat1); + int it1 = ucell.iat2it[iat1], ia1 = ucell.iat2ia[iat1]; + AdjacentAtomInfo adjs; + gd.Find_atom(ucell, tau1, it1, ia1, &adjs); + for (int ad = 0; ad < adjs.adj_num + 1; ++ad) + { + const int it2 = adjs.ntype[ad]; + const int ia2 = adjs.natom[ad]; + int iat2 = ucell.itia2iat(it2, ia2); + if (pv.get_row_size(iat1) && pv.get_col_size(iat2)) + { + const ModuleBase::Vector3& R_index = adjs.box[ad]; + if (ucell.cal_dtau(iat1, iat2, R_index).norm() * ucell.lat0 + < ucell.atoms[it1].Rcut + ucell.atoms[it2].Rcut) + Rs_set.insert({ R_index.x, R_index.y, R_index.z }); + } + } + } + // set to vector + std::vector Rs(Rs_set.size()); + for (auto& R : Rs_set) Rs.push_back(R); + return Rs; + } + + void Symmetry_rotation::output_full_map_to_irreducible_sector(const int nat) + { + std::cout << "Final map to irreducible sector: " << std::endl; + for (auto& apR_isym_irapR : this->full_map_to_irreducible_sector_) + { + const Tap& ap = apR_isym_irapR.first.first; + const TC& R = apR_isym_irapR.first.second; + const Tap& irap = apR_isym_irapR.second.second.first; + const TC& irR = apR_isym_irapR.second.second.second; + std::cout << "atompair (" << ap.first << ", " << ap.second << "), R=(" << R[0] << ", " << R[1] << ", " << R[2] << ") -> " + << "isym=" << apR_isym_irapR.second.first << " -> irreducible atompair (" << irap.first << ", " << irap.second << "), irreducible R=(" + << irR[0] << ", " << irR[1] << ", " << irR[2] << ")" << std::endl; + } + } + + void Symmetry_rotation::output_sector_star() + { + std::cout << "Found " << this->sector_stars_.size() << " irreducible sector stars:" << std::endl; + // for (auto& irs_star : this->sector_stars_) + for (int istar = 0;istar < this->sector_stars_.size();++istar) + { + std::cout << "in star " << istar << " with size " << this->sector_stars_[istar].size() << ":\n"; + for (auto& isym_ap_R : this->sector_stars_[istar]) + std::cout << "isym=" << isym_ap_R.first << ", atompair=(" << isym_ap_R.second.first.first << ", " << isym_ap_R.second.first.second << "), R=(" + << isym_ap_R.second.second[0] << ", " << isym_ap_R.second.second[1] << ", " << isym_ap_R.second.second[2] << ")" << std::endl; + } + // print irreducible sector + std::cout << "irreducible sector: " << std::endl; + for (auto& irap_irR : this->irreducible_sector_) + { + for (auto& irR : irap_irR.second) + std::cout << "atompair (" << irap_irR.first.first << ", " << irap_irR.first.second << "), R = (" << irR[0] << ", " << irR[1] << ", " << irR[2] << ") \n"; + std::cout << std::endl; + } + } + + void Symmetry_rotation::find_irreducible_sector(const Symmetry& symm, const Atom* atoms, const Statistics& st, const std::vector& Rs) + { + this->full_map_to_irreducible_sector_.clear(); + this->irreducible_sector_.clear(); + this->sector_stars_.clear(); + + if (this->return_lattice_.empty()) this->get_return_lattice_all(symm, atoms, st); + if (this->atompair_stars_.empty()) this->find_irreducible_atom_pairs(symm); + + // contruct {atom pair, R} set + // constider different number of Rs for different atom pairs later. + std::map> apR_all; + for (int iat1 = 0;iat1 < st.nat; iat1++) + for (int iat2 = 0; iat2 < st.nat; iat2++) + for (auto& R : Rs) + apR_all[{iat1, iat2}].insert(R); + + // get invmap + std::vector invmap(symm.nrotk, -1); + symm.gmatrix_invmap(symm.gmatrix, symm.nrotk, invmap.data()); + + while (!apR_all.empty()) + { + const Tap& irap = apR_all.begin()->first; + const TC irR = *apR_all[irap].begin(); + const TapR& irapR = { irap, irR }; + std::map sector_star; + for (int isym = 0;isym < symm.nrotk;++isym) + { + const TapR& apRrot = this->rotate_R_by_formula(symm, invmap[isym], irapR); + const Tap& aprot = apRrot.first; + const TC& Rrot = apRrot.second; + if (apR_all.count(aprot) && apR_all.at(aprot).count(Rrot)) + { + this->full_map_to_irreducible_sector_.insert({ apRrot, {isym, irapR} }); + sector_star.insert({ isym, apRrot }); + apR_all[aprot].erase(Rrot); + if (apR_all.at(aprot).empty()) apR_all.erase(aprot); + if (apR_all.empty()) break; + } + }// end for isym + if (!sector_star.empty()) + { + this->sector_stars_.push_back(sector_star); + if (this->irreducible_sector_.count(irap)) + this->irreducible_sector_.at(irap).insert(irR); + else + this->irreducible_sector_.insert({ irap, {irR} }); + } + } + // test + int total_apR_in_star = 0; + for (auto& sector : this->sector_stars_) + total_apR_in_star += sector.size(); + assert(total_apR_in_star == this->full_map_to_irreducible_sector_.size()); + this->output_full_map_to_irreducible_sector(st.nat); + this->output_sector_star(); + } +} \ No newline at end of file diff --git a/source/module_ri/symmetry_rotation.cpp b/source/module_ri/symmetry_rotation.cpp new file mode 100644 index 0000000000..c1375b8396 --- /dev/null +++ b/source/module_ri/symmetry_rotation.cpp @@ -0,0 +1,483 @@ +#include "module_base/constants.h" +#include +#include "module_base/parallel_reduce.h" +#include "module_base/scalapack_connector.h" +#include "module_base/tool_title.h" +#include "module_base/timer.h" +#include "symmetry_rotation.h" +#include "module_hamilt_pw/hamilt_pwdft/global.h" + +namespace ModuleSymmetry +{ + void Symmetry_rotation::cal_Ms(const K_Vectors& kv, + //const std::vector>& kstars, + const UnitCell& ucell, const Parallel_2D& pv) + { + ModuleBase::TITLE("Symmetry_rotation", "cal_Ms"); + ModuleBase::timer::tick("Symmetry_rotation", "cal_Ms"); + + this->nsym_ = ucell.symm.nrotk; + this->eps_ = ucell.symm.epsilon; + + // 1. calculate the rotation matrix in real spherical harmonics representation for each symmetry operation: [T_l (isym)]_mm' + std::vector gmatc(nsym_); + for (int i = 0;i < nsym_;++i) gmatc[i] = this->direct_to_cartesian(ucell.symm.gmatrix[i], ucell.latvec); + this->cal_rotmat_Slm(gmatc.data(), ucell.lmax); + + // 2. calculate the rotation matrix in AO-representation for each ibz_kpoint and symmetry operation: M(k, isym) + auto restrict_kpt = [](const TCdouble& kvec, const double& symm_prec) -> TCdouble + {// in (-0.5, 0.5] + TCdouble kvec_res; + kvec_res.x = fmod(kvec.x + 100.5 - 0.5 * symm_prec, 1) - 0.5 + 0.5 * symm_prec; + kvec_res.y = fmod(kvec.y + 100.5 - 0.5 * symm_prec, 1) - 0.5 + 0.5 * symm_prec; + kvec_res.z = fmod(kvec.z + 100.5 - 0.5 * symm_prec, 1) - 0.5 + 0.5 * symm_prec; + if (std::abs(kvec_res.x) < symm_prec) kvec_res.x = 0.0; + if (std::abs(kvec_res.y) < symm_prec) kvec_res.y = 0.0; + if (std::abs(kvec_res.z) < symm_prec) kvec_res.z = 0.0; + return kvec_res; + }; + int nks_ibz = kv.kstars.size(); // kv.nks = 2 * kv.nks_ibz when nspin=2 + this->Ms_.resize(nks_ibz); + for (int ik_ibz = 0;ik_ibz < nks_ibz;++ik_ibz) + { + // const TCdouble& kvec_d_ibz = restrict_kpt((*kstars[ik_ibz].begin()).second * ucell.symm.kgmatrix[(*kstars[ik_ibz].begin()).first], ucell.symm.epsilon); + for (auto& isym_kvd : kv.kstars[ik_ibz]) + if (isym_kvd.first < nsym_) + this->Ms_[ik_ibz][isym_kvd.first] = this->contruct_2d_rot_mat_ao(ucell.symm, ucell.atoms, ucell.st, kv.kvec_d[ik_ibz], isym_kvd.first, pv); + } + + // output Ms of isym=1 + // std::ofstream ofs("Ms_kibz7_sym7.dat"); + // for (int i = 0;i < pv.get_row_size();++i) + // { + // for (int j = 0;j < pv.get_col_size();++j) + // { + // ofs << std::setprecision(10) << this->Ms_[7][7][j * pv.get_col_size() + i] << " "; + // } + // ofs << std::endl; + // } + // ofs << std::endl; + // ofs.close(); + + ModuleBase::timer::tick("Symmetry_rotation", "cal_Ms"); + } + + std::vector>> Symmetry_rotation::restore_dm(const K_Vectors& kv, + const std::vector>>& dm_k_ibz, const Parallel_2D& pv)const + { + ModuleBase::TITLE("Symmetry_rotation", "restore_dm"); + ModuleBase::timer::tick("Symmetry_rotation", "restore_dm"); + auto vec3_eq = [](const TCdouble& v1, const TCdouble& v2, const double& prec) -> bool + { + return (std::abs(v1.x - v2.x) < prec) && (std::abs(v1.y - v2.y) < prec) && (std::abs(v1.z - v2.z) < prec); + }; + auto vec_conj = [](const std::vector>& z, const double scal = 1.0) -> std::vector> + { + std::vector> z_conj(z.size()); + for (int i = 0;i < z.size();++i) z_conj[i] = std::conj(z[i]) * scal; + return z_conj; + }; + std::vector>> dm_k_full; + int nspin0 = GlobalV::NSPIN == 2 ? 2 : 1; + dm_k_full.reserve(kv.nkstot_full * nspin0); //nkstot_full didn't doubled by spin + int nk = kv.nkstot / nspin0; + for (int is = 0;is < nspin0;++is) + for (int ik_ibz = 0;ik_ibz < nk;++ik_ibz) + for (auto& isym_kvd : kv.kstars[ik_ibz]) + if (isym_kvd.first == 0) + { + double factor = 1.0 / static_cast(kv.kstars[ik_ibz].size()); + std::vector> dm_scaled(pv.get_local_size()); + for (int i = 0;i < pv.get_local_size();++i) dm_scaled[i] = factor * dm_k_ibz[ik_ibz + is * nk][i]; + dm_k_full.push_back(dm_scaled); + } + else if (vec3_eq(isym_kvd.second, -kv.kvec_d[ik_ibz], this->eps_) && this->TRS_first_) + dm_k_full.push_back(vec_conj(dm_k_ibz[ik_ibz + is * nk], 1.0 / static_cast(kv.kstars[ik_ibz].size()))); + else if (isym_kvd.first < nsym_) //space group operations + dm_k_full.push_back(this->rot_matrix_ao(dm_k_ibz[ik_ibz + is * nk], ik_ibz, kv.kstars[ik_ibz].size(), isym_kvd.first, pv)); + else // TRS*spacegroup operations + dm_k_full.push_back(this->rot_matrix_ao(dm_k_ibz[ik_ibz + is * nk], ik_ibz, kv.kstars[ik_ibz].size(), isym_kvd.first - nsym_, pv, true)); + + + // test for output +/* + std::ofstream ofs("DM.dat"); + int ik = 0; + for (int ikibz = 0;ikibz < kv.nkstot / nspin0;++ikibz) + for (auto& isym_kvd : kv.kstars[ikibz]) + { + ofs << "isym=" << isym_kvd.first << std::endl; + ofs << " k = " << isym_kvd.second.x << " " << isym_kvd.second.y << " " << isym_kvd.second.z << std::endl; + ofs << "DM(k):" << std::endl; + for (int i = 0;i < pv.get_row_size();++i) + { + for (int j = 0;j < pv.get_col_size();++j) + { + ofs << dm_k_full[ik][j * pv.get_row_size() + i] << " "; + } + ofs << std::endl; + } + ++ik; + ofs << std::endl; + } + ofs.close(); +*/ + ModuleBase::timer::tick("Symmetry_rotation", "restore_dm"); + return dm_k_full; + } + std::vector> Symmetry_rotation::restore_dm(const K_Vectors& kv, + const std::vector>& dm_k_ibz, const Parallel_2D& pv)const + { + return dm_k_ibz;// do nothing for gamma_only + } + + // calculate Wigner D matrix + double Symmetry_rotation::wigner_d(const double beta, const int l, const int m1, const int m2) const + { + auto factorial = [](int n) -> int { + int result = 1; + for (int i = 1;i <= n;++i) result *= i; + return result; + }; + double result = 0.0; + for (int i = std::max(0, m2 - m1);i <= std::min(l - m1, l + m2);++i) + result += std::pow(-1, i) * std::sqrt(factorial(l + m1) * factorial(l - m1) * factorial(l + m2) * factorial(l - m2)) + * std::pow(std::cos(beta / 2), 2 * l + m2 - m1 - 2 * i) * std::pow(-std::sin(beta / 2), m1 - m2 + 2 * i) + / (factorial(i) * factorial(l - m1 - i) * factorial(l + m2 - i) * factorial(i - m2 + m1)); + return result; + } + + std::complex Symmetry_rotation::wigner_D(const TCdouble& euler_angle, const int l, const int m1, const int m2, const bool inv) const + { + std::complex prefac(inv ? std::pow(-1, l) : 1, 0); + return std::exp(-ModuleBase::IMAG_UNIT * static_cast(m1) * euler_angle.x) + * std::exp(-ModuleBase::IMAG_UNIT * static_cast(m2) * euler_angle.z) + * wigner_d(euler_angle.y, l, m1, m2) * prefac; + } + + // c^l_{m1, m2}= + std::complex Symmetry_rotation::ovlp_Ylm_Slm(const int l, const int m1, const int m2) const + { + if (m1 == m2) + { + if (m1 == 0) return 1.0; + if (m1 > 0) return 1 / std::sqrt(2); + if (m1 < 0) return std::pow(-1, m1) * ModuleBase::IMAG_UNIT / std::sqrt(2); + } + else if (m1 == -m2) + { + if (m1 > 0) return -ModuleBase::IMAG_UNIT / std::sqrt(2); + if (m1 < 0) return std::pow(-1, m1) / std::sqrt(2); + } + return 0.0; + } + + // reference: https://github.com/minyez/abf_trans/blob/f9e68e68069a94610d89e077bfe6e8ffac0b097d/src/rotate.cpp#L118 + // because the atom position here is row vector, the original gmatrix(eular angle) is transposed. + // gmatc: the rotation matrix under the basis of cartesian coordinates + // gmatc should be a rotation matrix, i.e. det(gmatc)=1 + TCdouble Symmetry_rotation::get_euler_angle(const ModuleBase::Matrix3& gmatc) const + { + double threshold = 1e-8; + double alpha, beta, gamma; + if (std::fabs(gmatc.e32) > threshold || std::fabs(gmatc.e31) > threshold) // sin(beta) is not zero + { + // use the 2-angle elements to get alpha and gamma + alpha = std::atan2(gmatc.e32, gmatc.e31); + if (alpha < 0) alpha += 2 * ModuleBase::PI; + gamma = std::atan2(gmatc.e23, -gmatc.e13); + if (gamma < 0) gamma += 2 * ModuleBase::PI; + // use the larger one of 2-angle elements to calculate beta + if (std::fabs(gmatc.e32) > std::fabs(gmatc.e31)) + beta = std::atan2(gmatc.e32 / std::sin(alpha), gmatc.e33); + else + beta = std::atan2(gmatc.e31 / std::cos(alpha), gmatc.e33); + } + else + {//sin(beta)=0, beta = 0 or pi, only (alpha+gamma) or (alpha-gamma) is important. now assign this to alpha. + alpha = std::atan2(gmatc.e12, gmatc.e11); + if (alpha < 0) alpha += 2 * ModuleBase::PI; + // if beta=0, gmatc.e11=cos(alpha+gamma), gmatc.e21=sin(alpha+gamma) + // if beta=pi, gmatc.e11=cos(pi+alpha-gamma), gmatc.e21=sin(pi+alpha-gamma) + if (gmatc.e33 > 0) + { + beta = 0; + gamma = 0; //alpha+gamma=alpha => gamma=0 + } + else + { + beta = ModuleBase::PI; + gamma = ModuleBase::PI;// pi+alpha-gamma=alpha => gamma=pi + } + } + return TCdouble(alpha, beta, gamma); + } + + // in: the real value of m in range {-l, -l+1, ..., 0, ..., l-1, l} + // out: the index of the orbital in a fixed {n, l}, i.e. the index in array [0, 1, -1, 2, -2, ...] + inline int m2im(int m) + { + return (m > 0 ? 2 * m - 1 : -2 * m); + } + + /// T_mm' = [c^\dagger D c]_mm' + void Symmetry_rotation::cal_rotmat_Slm(const ModuleBase::Matrix3* gmatc, const int lmax) + { + auto set_integer = [](ModuleBase::ComplexMatrix& mat) -> void + { + double zero_thres = 1e-10; + for (int i = 0;i < mat.nr;++i) + for (int j = 0;j < mat.nc;++j) + { + if (std::abs(mat(i, j).real() - std::round(mat(i, j).real())) < zero_thres) mat(i, j).real(std::round(mat(i, j).real())); + if (std::abs(mat(i, j).imag() - std::round(mat(i, j).imag())) < zero_thres) mat(i, j).imag(std::round(mat(i, j).imag())); + } + }; + this->rotmat_Slm_.resize(nsym_); + // c matrix is independent on isym + std::vector c_mm(lmax + 1); + for (int l = 0;l <= lmax;++l) + { + c_mm[l].create(2 * l + 1, 2 * l + 1); + for (int m1 = -l;m1 <= l;++m1) + for (int m2 = -l;m2 <= l;++m2) + c_mm[l](m2im(m1), m2im(m2)) = ovlp_Ylm_Slm(l, m1, m2); + } + for (int isym = 0;isym < nsym_;++isym) + { + // if R is a reflection operation, calculate D^l(R)=(-1)^l*D^l(IR), so the euler angle of (IR) is needed. + TCdouble euler_angle = get_euler_angle(gmatc[isym].Det() > 0 ? + gmatc[isym] : gmatc[isym] * ModuleBase::Matrix3(-1, 0, 0, 0, -1, 0, 0, 0, -1)); + + this->rotmat_Slm_[isym].resize(lmax + 1); + for (int l = 0;l <= lmax;++l) + {// wigner D matrix + ModuleBase::ComplexMatrix D_mm(2 * l + 1, 2 * l + 1); + for (int m1 = -l;m1 <= l;++m1) + for (int m2 = -l;m2 <= l;++m2) + D_mm(m2im(m1), m2im(m2)) = wigner_D(euler_angle, l, m1, m2, (gmatc[isym].Det() < 0)); + this->rotmat_Slm_[isym][l] = transpose(c_mm[l], /*conj=*/true) * D_mm * c_mm[l]; + // set_integer(this->rotmat_Slm_[isym][l]); + } + } +/* + std::vector euler_angles_test(nsym_); + for (int isym = 0;isym < nsym_;++isym) euler_angles_test[isym] = + get_euler_angle(gmatc[isym].Det() > 0 ? gmatc[isym] : gmatc[isym] * ModuleBase::Matrix3(-1, 0, 0, 0, -1, 0, 0, 0, -1)); + + auto test_Tmm = [&]()-> void + { + std::ofstream ofs("Tlm.dat"); + for (int isym = 0;isym < nsym_;++isym) + { + ofs << "isym=" << isym << std::endl; + ofs << "gmatrix_cart=" << std::endl; + ofs << gmatc[isym].e11 << " " << gmatc[isym].e12 << " " << gmatc[isym].e13 << std::endl; + ofs << gmatc[isym].e21 << " " << gmatc[isym].e22 << " " << gmatc[isym].e23 << std::endl; + ofs << gmatc[isym].e31 << " " << gmatc[isym].e32 << " " << gmatc[isym].e33 << std::endl; + ofs << "gmatrix_direct=" << std::endl; + ofs << GlobalC::ucell.symm.gmatrix[isym].e11 << " " << GlobalC::ucell.symm.gmatrix[isym].e12 << " " << GlobalC::ucell.symm.gmatrix[isym].e13 << std::endl; + ofs << GlobalC::ucell.symm.gmatrix[isym].e21 << " " << GlobalC::ucell.symm.gmatrix[isym].e22 << " " << GlobalC::ucell.symm.gmatrix[isym].e23 << std::endl; + ofs << GlobalC::ucell.symm.gmatrix[isym].e31 << " " << GlobalC::ucell.symm.gmatrix[isym].e32 << " " << GlobalC::ucell.symm.gmatrix[isym].e33 << std::endl; + ofs << "kgmatrix_direct=" << std::endl; + ofs << GlobalC::ucell.symm.kgmatrix[isym].e11 << " " << GlobalC::ucell.symm.kgmatrix[isym].e12 << " " << GlobalC::ucell.symm.kgmatrix[isym].e13 << std::endl; + ofs << GlobalC::ucell.symm.kgmatrix[isym].e21 << " " << GlobalC::ucell.symm.kgmatrix[isym].e22 << " " << GlobalC::ucell.symm.kgmatrix[isym].e23 << std::endl; + ofs << GlobalC::ucell.symm.kgmatrix[isym].e31 << " " << GlobalC::ucell.symm.kgmatrix[isym].e32 << " " << GlobalC::ucell.symm.kgmatrix[isym].e33 << std::endl; + ofs << "euler_angle/pi: " << euler_angles_test[isym].x / ModuleBase::PI << " " + << euler_angles_test[isym].y / ModuleBase::PI << " " << euler_angles_test[isym].z / ModuleBase::PI << std::endl; + for (int l = 0;l <= lmax;++l) + for (int i = 0;i < 2 * l + 1;++i) + { + for (int j = 0;j < 2 * l + 1;++j) ofs << this->rotmat_Slm_[isym][l](i, j) << " "; + ofs << std::endl; + } + } + ofs.close(); + }; + test_Tmm(); + */ + } + + // Perfoming {R|t} to atom position r in the R=0 lattice, we get Rr+t, which may get out of R=0 lattice, + // whose image in R=0 lattice is r'=Rr+t-O. This function is to get O for each atom and each symmetry operation. + // the range of direct position is [-0.5, 0.5). + TCdouble Symmetry_rotation::get_return_lattice(const Symmetry& symm, + const ModuleBase::Matrix3& gmatd, const TCdouble gtransd, + const TCdouble& posd_a1, const TCdouble& posd_a2)const + { + // auto restrict_center = [&symm](const TCdouble& v) -> TCdouble { + // // in [-0.5, 0.5) + // TCdouble vr; + // vr.x = fmod(v.x + 100.5 + 0.5 * symm.epsilon, 1) - 0.5 - 0.5 * symm.epsilon; + // vr.y = fmod(v.y + 100.5 + 0.5 * symm.epsilon, 1) - 0.5 - 0.5 * symm.epsilon; + // vr.z = fmod(v.z + 100.5 + 0.5 * symm.epsilon, 1) - 0.5 - 0.5 * symm.epsilon; + // if (std::abs(vr.x) < symm.epsilon) vr.x = 0.0; + // if (std::abs(vr.y) < symm.epsilon) vr.y = 0.0; + // if (std::abs(vr.z) < symm.epsilon) vr.z = 0.0; + // return vr; + // }; + auto restrict_center = [&symm](const TCdouble& v) -> TCdouble { + // in [0,1) + TCdouble vr; + vr.x = fmod(v.x + 100 + symm.epsilon, 1) - symm.epsilon; + vr.y = fmod(v.y + 100 + symm.epsilon, 1) - symm.epsilon; + vr.z = fmod(v.z + 100 + symm.epsilon, 1) - symm.epsilon; + if (std::abs(vr.x) < symm.epsilon) vr.x = 0.0; + if (std::abs(vr.y) < symm.epsilon) vr.y = 0.0; + if (std::abs(vr.z) < symm.epsilon) vr.z = 0.0; + return vr; + }; + auto check_integer = [&symm](const double x) -> void { + assert(symm.equal(x, std::round(x))); + }; + TCdouble rotpos1 = restrict_center(posd_a1) * gmatd + restrict_center(gtransd); // row vector + TCdouble return_lattice_double = rotpos1 - restrict_center(posd_a2); +#ifdef __DEBUG + check_integer(return_lattice_double.x); + check_integer(return_lattice_double.y); + check_integer(return_lattice_double.z); +#endif + return TCdouble(std::round(return_lattice_double.x), std::round(return_lattice_double.y), std::round(return_lattice_double.z)); + } + + inline void output_return_lattice(const std::vector>& return_lattice) + { + std::cout << "return lattice:" << std::endl; + for (int iat = 0;iat < return_lattice.size();++iat) + { + std::cout << "atom" << iat << std::endl; + for (int isym = 0;isym < return_lattice[iat].size();++isym) + std::cout << "isym=" << isym << ", return lattice=" << + return_lattice[iat][isym].x << " " << return_lattice[iat][isym].y << " " << return_lattice[iat][isym].z << std::endl; + } + } + + void Symmetry_rotation::get_return_lattice_all(const Symmetry& symm, const Atom* atoms, const Statistics& st) + { + ModuleBase::TITLE("Symmetry_rotation", "get_return_lattice_all"); + this->return_lattice_.resize(st.nat, std::vector(symm.nrotk)); + for (int iat1 = 0;iat1 < st.nat;++iat1) + { + int it = st.iat2it[iat1]; + int ia1 = st.iat2ia[iat1]; + for (int isym = 0;isym < symm.nrotk;++isym) + { + int iat2 = symm.get_rotated_atom(isym, iat1); + int ia2 = st.iat2ia[iat2]; + this->return_lattice_[iat1][isym] = get_return_lattice(symm, symm.gmatrix[isym], symm.gtrans[isym], atoms[it].taud[ia1], atoms[it].taud[ia2]); + } + } + // test: output return_lattice + output_return_lattice(this->return_lattice_); + } + + void Symmetry_rotation::set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, std::vector>& obj_mat, const Parallel_2D& pv) const + { // caution: ComplaxMatrix is row-major(col-continuous), but obj_mat is col-major(row-continuous) + for (int j = 0;j < block.nr;++j)//outside dimension + for (int i = 0;i < block.nc;++i) //inside dimension + if (pv.in_this_processor(starti + i, startj + j)) + { + int index = pv.global2local_col(startj + j) * pv.get_row_size() + pv.global2local_row(starti + i); + obj_mat[index] = block(j, i); + } + } + + void Symmetry_rotation::set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, std::vector& obj_mat, const Parallel_2D& pv) const + { // caution: ComplaxMatrix is row-major(col-continuous), but obj_mat is col-major(row-continuous) + for (int j = 0;j < block.nr;++j)//outside dimension + for (int i = 0;i < block.nc;++i) //inside dimension + if (pv.in_this_processor(starti + i, startj + j)) + { + int index = pv.global2local_col(startj + j) * pv.get_row_size() + pv.global2local_row(starti + i); + obj_mat[index] = block(j, i).real(); + } + } + + // 2d-block parallized rotation matrix in AO-representation, denoted as M. + // finally we will use D(k)=M(R, k)^\dagger*D(Rk)*M(R, k) to recover D(k) from D(Rk) in cal_Ms. + std::vector> Symmetry_rotation::contruct_2d_rot_mat_ao(const Symmetry& symm, const Atom* atoms, const Statistics& cell_st, + const TCdouble& kvec_d_ibz, int isym, const Parallel_2D& pv) const + { + std::vector> M_isym(pv.get_local_size(), 0.0); + for (int iat1 = 0;iat1 < cell_st.nat;++iat1) + { + int it = cell_st.iat2it[iat1]; // it1=it2 + int ia1 = cell_st.iat2ia[iat1]; + int iat2 = symm.get_rotated_atom(isym, iat1); //iat2=rot(iat1) + int ia2 = cell_st.iat2ia[iat2]; + // cal phase factor from return lattice: exp(-ik_ibz*O) + double arg = 2 * ModuleBase::PI * kvec_d_ibz * this->return_lattice_[ia1][isym]; + std::complexphase_factor = std::complex(std::cos(arg), std::sin(arg)); + int iw1start = atoms[it].stapos_wf + ia1 * atoms[it].nw; + int iw2start = atoms[it].stapos_wf + ia2 * atoms[it].nw; + int iw = 0; + while (iw < atoms[it].nw) + { + int l = atoms[it].iw2l[iw]; + int nm = 2 * l + 1; + //caution: the order of m in orbitals may be different from increasing + set_block_to_mat2d(iw1start + iw, iw2start + iw, + phase_factor * this->rotmat_Slm_[isym][l], M_isym, pv); + iw += nm; + } + } + return M_isym; + } + + // void cal_Ms (kstar), maybe use map to stare Ms + + // D(k) = M^*(R, k) D(k_ibz) M^T(R, k) + // the link ik_ibz-isym-ik can be found in kstars. + std::vector> Symmetry_rotation::rot_matrix_ao(const std::vector>& DMkibz, + const int ik_ibz, const int kstar_size, const int isym, const Parallel_2D& pv, const bool TRS_conj) const + { + std::vector> DMk(pv.nloc, 0.0); + std::vector> DMkibz_M(pv.nloc, 0.0); // intermediate result + const char dagger = 'C'; + const char transpose = 'T'; + const char notrans = 'N'; + std::complex alpha(1.0, 0.0); + const std::complex beta(0.0, 0.0); + const int nbasis = GlobalV::NLOCAL; + const int i1 = 1; + + // if TRS_conj, calculate [M^* D M^T]^* = [D^\dagger M^T]^T M^\dagger + // else, calculate M^* D M^T = [D^T M^\dagger]^T M^T + + // step 1 + pzgemm_(TRS_conj ? &dagger : &transpose, TRS_conj ? &transpose : &dagger, &nbasis, &nbasis, &nbasis, + &alpha, DMkibz.data(), &i1, &i1, pv.desc, this->Ms_[ik_ibz].at(isym).data(), &i1, &i1, pv.desc, + &beta, DMkibz_M.data(), &i1, &i1, pv.desc); + + //step 2 + alpha.real(1.0 / static_cast(kstar_size)); + pzgemm_(&transpose, TRS_conj ? &dagger : &transpose, &nbasis, &nbasis, &nbasis, + &alpha, DMkibz_M.data(), &i1, &i1, pv.desc, this->Ms_[ik_ibz].at(isym).data(), &i1, &i1, pv.desc, + &beta, DMk.data(), &i1, &i1, pv.desc); + + // but if we store D^*(=D^T, col-maj/row-inside), we sould calculate D^*(k) = M D^*(k_ibz) M^dagger + // step 1 + // if (TRS_conj) + // pzgemm_(&dagger, &dagger, &nbasis, &nbasis, &nbasis, + // &alpha, this->Ms_[ik_ibz].at(isym).data(), &i1, &i1, pv.desc, DMkibz.data(), &i1, &i1, pv.desc, + // &beta, DMkibz_M.data(), &i1, &i1, pv.desc); + // else + // pzgemm_(¬rans, ¬rans, &nbasis, &nbasis, &nbasis, + // &alpha, DMkibz.data(), &i1, &i1, pv.desc, this->Ms_[ik_ibz].at(isym).data(), &i1, &i1, pv.desc, + // &beta, DMkibz_M.data(), &i1, &i1, pv.desc); + + // //step 2 + // alpha.real(1.0 / static_cast(kstar_size)); + // pzgemm_(TRS_conj ? &transpose : &dagger, TRS_conj ? &transpose : ¬rans, &nbasis, &nbasis, &nbasis, + // &alpha, this->Ms_[ik_ibz].at(isym).data(), &i1, &i1, pv.desc, DMkibz_M.data(), &i1, &i1, pv.desc, + // &beta, DMk.data(), &i1, &i1, pv.desc); + + return DMk; + } + + ModuleBase::Matrix3 Symmetry_rotation::direct_to_cartesian(const ModuleBase::Matrix3& d, const ModuleBase::Matrix3& latvec) + { + return latvec.Inverse() * d * latvec; + } + +} \ No newline at end of file diff --git a/source/module_ri/symmetry_rotation.h b/source/module_ri/symmetry_rotation.h new file mode 100644 index 0000000000..6bb3098733 --- /dev/null +++ b/source/module_ri/symmetry_rotation.h @@ -0,0 +1,234 @@ +#pragma once +#include "module_base/abfs-vector3_order.h" +#include "module_base/complexmatrix.h" +#include "module_base/matrix3.h" +#include +#include +#include +#include "module_basis/module_ao/parallel_2d.h" +#include "module_cell/unitcell.h" +#include "module_cell/module_symmetry/symmetry.h" +#include "module_cell/klist.h" +#include +#include "module_hamilt_lcao/module_hcontainer/hcontainer.h" +#include "module_cell/module_neighbor/sltk_grid_driver.h" +// for test +#include "Exx_LRI.h" + +namespace ModuleSymmetry +{ + using Tap = std::pair; + using TC = std::array; + using TapR = std::pair; + using TCdouble = Abfs::Vector3_Order; + + struct ap_less_func + { + bool operator()(const Tap& lhs, const Tap& rhs) const + { + if (lhs.first < rhs.first)return true; + else if (lhs.first > rhs.first)return false; + else return lhs.second < rhs.second; + } + }; + struct apR_less_func + { + bool operator()(const TapR& lhs, const TapR& rhs) const + { + if (lhs.first < rhs.first)return true; + else if (lhs.first > rhs.first)return false; + else return lhs.second < rhs.second; + } + }; + struct len_less_func + { + int norm2(const TC& R)const + { + return R[0] * R[0] + R[1] * R[1] + R[2] * R[2]; + } + bool operator()(const TC& lhs, const TC& rhs) const + { + if (norm2(lhs) < norm2(rhs))return true; + else if (norm2(lhs) > norm2(rhs))return false; + else return lhs < rhs; + } + }; + + class Symmetry_rotation + { + public: + Symmetry_rotation() {}; + ~Symmetry_rotation() {}; + //-------------------------------------------------------------------------------- + /// functions to contruct rotation matrix in AO-representation + + /// The top-level calculation interface of this class. calculate the rotation matrix in AO representation: M + /// only need once call in each ion step (decided by the configuration) + /// @param kstars equal k points to each ibz-kpont, corresponding to a certain symmetry operations. + void cal_Ms(const K_Vectors& kv, + //const std::vector>& kstars, + const UnitCell& ucell, const Parallel_2D& pv); + + /// Use calculated M matrix to recover D(k) from D(k_ibz): D(k) = M(R, k)^\dagger D(k_ibz) M(R, k) + /// the link "ik_ibz-isym-ik" can be found in kstars: k_bz = gmat[isym](k) + std::vector>>restore_dm(const K_Vectors& kv, + const std::vector>>& dm_k_ibz, + const Parallel_2D& pv)const; + std::vector>restore_dm(const K_Vectors& kv, + const std::vector>& dm_k_ibz, + const Parallel_2D& pv)const; + std::vector> rot_matrix_ao(const std::vector>& DMkibz, + const int ik_ibz, const int kstar_size, const int isym, const Parallel_2D& pv, const bool TRS_conj = false) const; + + /// calculate Wigner D matrix + double wigner_d(const double beta, const int l, const int m1, const int m2) const; + std::complex wigner_D(const TCdouble& euler_angle, const int l, const int m1, const int m2, const bool inv) const; + + /// c^l_{m1, m2}= + std::complex ovlp_Ylm_Slm(const int l, const int m1, const int m2) const; + + /// calculate euler angle from rotation matrix + TCdouble get_euler_angle(const ModuleBase::Matrix3& gmatc) const; + + /// T_mm' = [c^\dagger D c]_mm', the rotation matrix in the representation of real sphere harmonics + void cal_rotmat_Slm(const ModuleBase::Matrix3* gmatc, const int lmax); + + /// Perfoming {R|t} to atom position r in the R=0 lattice, we get Rr+t, which may get out of R=0 lattice, + /// whose image in R=0 lattice is r'=Rr+t-O. This function is to get O for each atom and each symmetry operation. + /// the range of direct position is [-0.5, 0.5). + TCdouble get_return_lattice(const Symmetry& symm, + const ModuleBase::Matrix3& gmatd, const TCdouble gtransd, + const TCdouble& posd_a1, const TCdouble& posd_a2)const; + void get_return_lattice_all(const Symmetry& symm, const Atom* atoms, const Statistics& st); + + /// set a block matrix onto a 2d-parallelized matrix, at the position (starti, startj) + void set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, std::vector>& obj_mat, const Parallel_2D& pv) const; + void set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, std::vector& obj_mat, const Parallel_2D& pv) const; + + /// 2d-block parallized rotation matrix in AO-representation, denoted as M. + /// finally we will use D(k)=M(R, k)^\dagger*D(Rk)*M(R, k) to recover D(k) from D(Rk). + std::vector> contruct_2d_rot_mat_ao(const Symmetry& symm, const Atom* atoms, const Statistics& cell_st, + const TCdouble& kvec_d_ibz, int isym, const Parallel_2D& pv) const; + + ModuleBase::Matrix3 direct_to_cartesian(const ModuleBase::Matrix3& d, const ModuleBase::Matrix3& latvec); + + std::vector>& get_rotmat_Slm() { return this->rotmat_Slm_; } + + //-------------------------------------------------------------------------------- + /// The main function to find irreducible sector: {abR} + void find_irreducible_sector(const Symmetry& symm, const Atom* atoms, const Statistics& st, const std::vector& Rs); + std::vector get_Rs_from_BvK(const K_Vectors& kv)const; + std::vector get_Rs_from_adjacent_list(const UnitCell& ucell, Grid_Driver& gd, const Parallel_Orbitals& pv)const; + const std::map>& get_irreducible_sector()const { return this->irreducible_sector_; } + // const std::map>> convirt_irreducible_sector() {}; + //-------------------------------------------------------------------------------- + + //-------------------------------------------------------------------------------- + /// The main functions to rotate matrices + /// Given H(R) in the irreduceble sector, calculate H(R) for all the atompairs and cells. + template // RI::Tensor type + std::map, RI::Tensor>> restore_HR( + const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, + const std::map, RI::Tensor>>& HR_irreduceble); + template // HContainer type + void restore_HR( + const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, + const hamilt::HContainer& HR_irreduceble, hamilt::HContainer& HR_rotated); + + //-------------------------------------------------------------------------------- + /// test functions + /// test H(R) rotation: giver a full H(R), pick out H(R) in the irreducible sector, rotate it, and compare with the original full H(R) + template // RI::Tensor type, using col-major implementation + void test_HR_rotation(const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, + const std::map, RI::Tensor>>& HR_full); + template // HContainer type, using row-major implementation + void test_HR_rotation(const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, + const hamilt::HContainer& HR_full); + template // HContainer type + void print_HR(const std::map, RI::Tensor>>& HR, const std::string name); + + // check whether Ds can be reduced in cal_Hs + template + void test_sector_equivalence_in_cal_Hs(const TapR& iapR_test, + const std::vector, RI::Tensor>>>& Ds_full, + Exx_LRI& exx_lri, const Parallel_Orbitals& pv); + //-------------------------------------------------------------------------------- + + private: + int round2int(const double x)const; + + //-------------------------------------------------------------------------------- + /// The sub functions to find irreducible sector: {abR} + + /// gauge='L' means H(R)=; gauge='R' means H(R)=<0|H|R> + /// gauge='L': R'=R+O_1-O_2; gauge='R': R'=R+O_2-O_1 + TC rotate_R_by_formula(const Symmetry& symm, const int isym, const int iat1, const int iat2, const TC& R, const char gauge = 'R')const; + TapR rotate_R_by_formula(const Symmetry& symm, const int isym, const TapR& iapR, const char gauge = 'R')const; + /// gauge='L': tau_a + R - tau_b; gauge='R': tau_a - tau_b - R (direct) + TCdouble get_aRb_direct(const Atom* atoms, const Statistics& st, const int iat1, const int iat2, const TC& R, const char gauge = 'R')const; + TCdouble get_aRb_direct(const Atom* atoms, const Statistics& st, const int iat1, const int iat2, const TCdouble& R, const char gauge = 'R')const; + + /// find the irreducible atom pairs + /// algorithm 1: the way finding irreducible k-points + void find_irreducible_atom_pairs(const Symmetry& symm); + /// algorithm 2: taking out atom pairs from the initial set + void find_irreducible_atom_pairs_set(const Symmetry& symm); + /// double check between the two algorithms + void test_irreducible_atom_pairs(const Symmetry& symm); + + void output_full_map_to_irreducible_sector(const int nat); + void output_sector_star(); + + //-------------------------------------------------------------------------------- + + /// The sub functions to rotate matrices + /// mode='H': H_12(R)=T^\dagger(V)H_1'2'(VR+O_1-O_2)T(V) + /// mode='D': D_12(R)=T^T(V)D_1'2'(VR+O_1-O_2)T^*(V) + template // RI::Tensor type, blas + RI::Tensor rotate_atompair_serial(const RI::Tensor& t, const int isym, + const Atom& a1, const Atom& a2, const char mode, bool output = false); + template // HContainer type, pblas + void rotate_atompair_parallel(const TR* Alocal_in, const int isym, const Atom* atoms, const Statistics& st, + const Tap& ap_in, const Tap& ap_out, const char mode, const Parallel_Orbitals& pv, TR* Alocal_out, const bool output = false); + + //-------------------------------------------------------------------------------- + + int nsym_ = 1; + + double eps_ = 1e-6; + + bool TRS_first_ = true; //if R(k)=-k, firstly use TRS to restore D(k) from D(R(k)), i.e conjugate D(R(k)). + + /// the rotation matrix under the basis of S_l^m. size: [nsym][lmax][nm*nm] + std::vector> rotmat_Slm_; + // [natom][nsym], phase factor corresponding to a certain kvec_d_ibz + // std::vector>> phase_factor_; + + /// The unitary matrix associate D(Rk) with D(k) for each ibz-kpoint Rk and each symmetry operation. + /// size: [nks_ibz][nsym][nbasis*nbasis], only need to calculate once. + std::vector>>> Ms_; + + /// irreducible sector + /// irreducible atom pairs: [n_iap][(isym, ap=(iat1, iat2))] + std::vector> atompair_stars_; + + ///The index range of the orbital matrix to be calculated: irreducible R in irreducible atom pairs + // (including R in other atom pairs that cannot rotate into R_stars_[irreducebule_ap]) + std::map> irreducible_sector_; + + // //[natoms*natoms](R, (isym, irreducible_R)) + // std::vector>> full_map_to_irreducible_sector_; + // (abR) -> (isym, abR) + std::map, apR_less_func> full_map_to_irreducible_sector_; + + // all the {abR}s , where the isym=0 one in each star forms the irreducible sector. + // [irreducible sector size][isym, ((ab),R)] + std::vector> sector_stars_; + + /// the direct lattice vector of {R|t}\tau-\tau' for each atoms and each symmetry operation. [natom][nsym] + std::vector> return_lattice_; + }; +} + +#include "symmetry_rotation_R.hpp" +#include "symmetry_rotation_R_hcontainer.hpp" \ No newline at end of file diff --git a/source/module_ri/symmetry_rotation_R.hpp b/source/module_ri/symmetry_rotation_R.hpp new file mode 100644 index 0000000000..a27032630a --- /dev/null +++ b/source/module_ri/symmetry_rotation_R.hpp @@ -0,0 +1,266 @@ +#include "symmetry_rotation.h" +#include "module_ri/RI_Util.h" +#include "module_base/blas_connector.h" +#include +#include + +namespace ModuleSymmetry +{ + template + std::map, RI::Tensor>> Symmetry_rotation::restore_HR( + const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, + const std::map, RI::Tensor>>& HR_irreduceble) + { + ModuleBase::TITLE("Symmetry_rotation", "restore_HR"); + std::map, RI::Tensor>> HR_full; + + for (auto& apR_isym_irapR : this->full_map_to_irreducible_sector_) + { + const Tap& ap = apR_isym_irapR.first.first; + const TC& R = apR_isym_irapR.first.second; + const int& isym = apR_isym_irapR.second.first; + const Tap& irap = apR_isym_irapR.second.second.first; + const TC& irR = apR_isym_irapR.second.second.second; + // rotate the matrix and pack data + // H_12(R)=T^\dagger(V)H_1'2'(VR+O_1-O_2)T(V) + if (HR_irreduceble.find(irap.first) != HR_irreduceble.end() && HR_irreduceble.at(irap.first).find({ irap.second, irR }) != HR_irreduceble.at(irap.first).end()) + HR_full[ap.first][{ap.second, R}] = rotate_atompair_serial(HR_irreduceble.at(irap.first).at({ irap.second, irR }), + isym, atoms[st.iat2it[irap.first]], atoms[st.iat2it[irap.second]], mode); + else + std::cout << "not found: current atom pair =(" << ap.first << "," << ap.second << "), R=(" << R[0] << "," << R[1] << "," << R[2] << "), irreducible atom pair =(" << irap.first << "," << irap.second << "), irR=(" << irR[0] << "," << irR[1] << "," << irR[2] << ")\n"; + } + return HR_full; + } + + template + inline void print_tensor(const RI::Tensor& t, const std::string& name) + { + std::cout << name << ":\n"; + for (int i = 0;i < t.shape[0];++i) + { + for (int j = 0;j < t.shape[1];++j) + std::cout << t(i, j) << " "; + std::cout << std::endl; + } + } + + template + RI::Tensor Symmetry_rotation::rotate_atompair_serial(const RI::Tensor& A, const int isym, + const Atom& a1, const Atom& a2, const char mode, const bool output) + { // due to col-contiguous, actually what we know is T^T and H^T (or D^T), + // and what we calculate is(H'^T = T ^ T * H ^ T * T^*) or (D'^T = T ^ \dagger * D ^ T * T) + auto set_block = [](const int starti, const int startj, const ModuleBase::ComplexMatrix& block, + RI::Tensor>& obj_tensor)->void + { // both ComplexMatrix and RI::Tensor are row-major (col-contiguous) + for (int i = 0;i < block.nr;++i) + for (int j = 0;j < block.nc;++j) + obj_tensor(starti + i, startj + j) = block(i, j); + }; + auto set_rotation_matrix = [&, this](const Atom& a) -> RI::Tensor> + { + RI::Tensor> T({ static_cast(a.nw), static_cast(a.nw) }); // check if zero + int iw = 0; + while (iw < a.nw) + { + int l = a.iw2l[iw]; + int nm = 2 * l + 1; + set_block(iw, iw, this->rotmat_Slm_[isym][l], T); + iw += nm; + } + return T; + }; + + bool sametype = (a1.label == a2.label); + assert(A.shape[0] == a1.nw);//col + assert(A.shape[1] == a2.nw);//row + // contrut T matrix + const RI::Tensor>& T1 = set_rotation_matrix(a1); + const RI::Tensor>& T2 = sametype ? T1 : set_rotation_matrix(a2); + + // A*T_2 (atom 2 is contiguous) + const char notrans = 'N', transpose = 'T', dagger = 'C'; + const std::complex alpha(1.0, 0.0), beta(0.0, 0.0); + const RI::Tensor>& A_complex = RI::Global_Func::convert>(A); + + RI::Tensor> TAT(A.shape); + RI::Tensor> AT2(A.shape); + if (mode == 'H') + { // H'^T = T2^T * H^T * T1^* + zgemm_(¬rans, ¬rans, &a2.nw, &a1.nw, &a2.nw, &alpha, T2.ptr(), &a2.nw, A_complex.ptr(), &a2.nw, &beta, AT2.ptr(), &a2.nw); + zgemm_(¬rans, &dagger, &a2.nw, &a1.nw, &a1.nw, &alpha, AT2.ptr(), &a2.nw, T1.ptr(), &a1.nw, &beta, TAT.ptr(), &a2.nw); + } + else if (mode == 'D') + { //T2^\dagger * D^T * T1 = [(D^T)^T * (T2^T)^\dagger]^T * (T1^T)^T + zgemm_(&transpose, &dagger, &a1.nw, &a2.nw, &a2.nw, &alpha, A_complex.ptr(), &a2.nw, T2.ptr(), &a2.nw, &beta, AT2.ptr(), &a1.nw); + zgemm_(&transpose, &transpose, &a2.nw, &a1.nw, &a1.nw, &alpha, AT2.ptr(), &a1.nw, T1.ptr(), &a1.nw, &beta, TAT.ptr(), &a2.nw); + } + else throw std::invalid_argument("Symmetry_rotation::rotate_atompair_tensor: invalid mode."); + if (output) + { + print_tensor(A, "A"); + print_tensor(T1, "T1"); + print_tensor(T2, "T2"); + print_tensor(TAT, "TAT"); + } + return RI::Global_Func::convert(TAT); + } + + template + void Symmetry_rotation::print_HR(const std::map, RI::Tensor>>& HR, const std::string name) + { + for (auto& HR_ia1 : HR) + { + int iat1 = HR_ia1.first; + for (auto& HR_ia12R : HR_ia1.second) + { + int iat2 = HR_ia12R.first.first; + TC R = HR_ia12R.first.second; + const RI::Tensor& HR_tensor = HR_ia12R.second; + std::cout << "atom pair (" << iat1 << ", " << iat2 << "), R=(" << R[0] << "," << R[1] << "," << R[2] << "), "; + print_tensor(HR_tensor, name); + } + } + } + + template + void Symmetry_rotation::test_HR_rotation(const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, + const std::map, RI::Tensor>>& HR_full) + { + ModuleBase::TITLE("Symmetry_rotation", "test_HR_rotation"); + + // 1. pick out H(R) in the irreducible sector from full H(R) + std::map, RI::Tensor>> HR_irreduceble; + for (auto& irap_Rs : this->irreducible_sector_) + { + const Tap& irap = irap_Rs.first; + for (auto& irR : irap_Rs.second) + { + const std::pair a2_irR = { irap.second, irR }; + HR_irreduceble[irap.first][a2_irR] = (HR_full.at(irap.first).count(a2_irR) != 0) ? + HR_full.at(irap.first).at(a2_irR) + : RI::Tensor(HR_full.at(irap.first).begin()->second.shape); + } + } + // 2. rotate + std::map, RI::Tensor>> HR_rotated = restore_HR(symm, atoms, st, mode, HR_irreduceble); + // 3. compare + for (auto& HR_ia1 : HR_rotated) + { + int iat1 = HR_ia1.first; + for (auto& HR_ia12R : HR_ia1.second) + { + int iat2 = HR_ia12R.first.first; + TC R = HR_ia12R.first.second; + const RI::Tensor& HR_rot = HR_ia12R.second; + if (HR_full.at(iat1).count({ iat2, R }) == 0)// rot back but not found + { + std::cout << "R_rot not found in atom pair (" << iat1 << ", " << iat2 << "): R=(" << R[0] << "," << R[1] << "," << R[2] << "):\n"; + continue; + } + const RI::Tensor& HR_ref = HR_full.at(iat1).at({ iat2, R }); + assert(HR_rot.shape[0] == HR_ref.shape[0]); + assert(HR_rot.shape[1] == HR_ref.shape[1]); + // output + std::cout << "atom pair (" << iat1 << ", " << iat2 << "), R=(" << R[0] << "," << R[1] << "," << R[2] << "):\n"; + print_tensor(HR_rot, std::string("R_rot").insert(0, 1, mode)); + print_tensor(HR_ref, std::string("R_ref").insert(0, 1, mode)); + } + } + } + + template + void Symmetry_rotation::test_sector_equivalence_in_cal_Hs(const TapR& apR_test, + const std::vector, RI::Tensor>>>& Ds_full, + Exx_LRI& exx_lri, const Parallel_Orbitals& pv) + { + // 1. pick out D(R) on one of the irreducible {abR}s from full D(R) + std::vector, RI::Tensor>>> Ds_one_in_sector = Ds_full; + for (auto& a1_a2R_tensor : Ds_one_in_sector[0]) + { + const int& iat1 = a1_a2R_tensor.first; + for (auto& a2R_tensor : a1_a2R_tensor.second) + { + const int& iat2 = a2R_tensor.first.first; + const TC& R = a2R_tensor.first.second; + const TapR& apR = { {iat1, iat2}, R }; + if (apR.first == apR_test.first && apR.second == apR_test.second) + a2R_tensor.second = Ds_full[0].at(iat1).at({ iat2, R }); + else + a2R_tensor.second = RI::Tensor(a2R_tensor.second.shape); + } + } + exx_lri.cal_exx_elec(Ds_one_in_sector, pv); + const std::vector, RI::Tensor>>> Hexxs_one_in_sector = exx_lri.get_Hexxs(); + + + //2. pick out D(R) on the whole sector star of the tested irreducible {abR} + TapR irapR_test = this->full_map_to_irreducible_sector_.at(apR_test).second; + std::vector, RI::Tensor>>> Ds_sector_star = Ds_full; + for (auto& a1_a2R_tensor : Ds_sector_star[0]) + { + const int& iat1 = a1_a2R_tensor.first; + for (auto& a2R_tensor : a1_a2R_tensor.second) + { + const int& iat2 = a2R_tensor.first.first; + const TC& R = a2R_tensor.first.second; + const TapR& apR = { {iat1, iat2}, R }; + const TapR& irapR = this->full_map_to_irreducible_sector_.at(apR).second; + if (irapR.first == irapR_test.first && irapR.second == irapR_test.second) + a2R_tensor.second = Ds_full[0].at(iat1).at({ iat2, R }); + else + a2R_tensor.second = RI::Tensor(a2R_tensor.second.shape); + } + } + exx_lri.cal_exx_elec(Ds_sector_star, pv); + const std::vector, RI::Tensor>>> Hexxs_sector_star = exx_lri.get_Hexxs(); + + // test: output Ds + std::cout << "Ds_one_in_sector[0].size(): " << Ds_one_in_sector[0].size() << std::endl; + for (auto& a1_a2R_tensor : Ds_one_in_sector[0]) + { + const int& iat1 = a1_a2R_tensor.first; + for (auto& a2R_tensor : a1_a2R_tensor.second) + { + const int& iat2 = a2R_tensor.first.first; + const TC& R = a2R_tensor.first.second; + std::cout << "atom pair (" << iat1 << ", " << iat2 << "), R=(" << R[0] << "," << R[1] << "," << R[2] << "):\n"; + const RI::Tensor& Ds_one = a2R_tensor.second; + const RI::Tensor& Ds_star = Ds_sector_star[0].at(iat1).at({ iat2, R }); + print_tensor(Ds_one, "Ds_one"); + print_tensor(Ds_star, "Ds_star"); + } + } + + // 3. compare + // get sector star size + auto get_star_size = [this](const TapR& apR_test)->int + { + for (auto& ss : this->sector_stars_) + { + const TapR& star_apR = ss.begin()->second; + const TapR& star_irapR = this->full_map_to_irreducible_sector_.at(star_apR).second; + if (star_apR.first == apR_test.first && star_apR.second == apR_test.second) + return ss.size(); + } + return 0; + }; + + const int starsize = get_star_size(apR_test); + std::cout << "star size of tested apR: " << starsize << std::endl; + std::cout << "Hexxs_one_in_sector[0].size(): " << Hexxs_one_in_sector[0].size() << std::endl; + for (auto& a1_a2R_tensor : Hexxs_one_in_sector[0]) + { + const int& iat1 = a1_a2R_tensor.first; + for (auto& a2R_tensor : a1_a2R_tensor.second) + { + const int& iat2 = a2R_tensor.first.first; + const TC& R = a2R_tensor.first.second; + std::cout << "atom pair (" << iat1 << ", " << iat2 << "), R=(" << R[0] << "," << R[1] << "," << R[2] << "):\n"; + const RI::Tensor& Hexxs_one = a2R_tensor.second; + const RI::Tensor& Hexxs_star = Hexxs_sector_star[0].at(iat1).at({ iat2, R }); + print_tensor(Hexxs_one * RI::Global_Func::convert(static_cast(starsize)), "Hexxs_one* starsize"); + print_tensor(Hexxs_star, "Hexxs_star"); + } + } + } +} \ No newline at end of file diff --git a/source/module_ri/symmetry_rotation_R_hcontainer.hpp b/source/module_ri/symmetry_rotation_R_hcontainer.hpp new file mode 100644 index 0000000000..8e4a6d4fed --- /dev/null +++ b/source/module_ri/symmetry_rotation_R_hcontainer.hpp @@ -0,0 +1,233 @@ +#include "symmetry_rotation.h" +#include "module_base/blas_connector.h" +#include "module_base/parallel_reduce.h" +namespace ModuleSymmetry +{ + template + inline void print_global(const TR* tlocal, const int nr, const int nc, const std::string name) + { + GlobalV::ofs_running << name << std::endl; + for (int i = 0;i < nr;++i) + { + for (int j = 0;j < nc;++j) GlobalV::ofs_running << tlocal[j + i * nc] << " "; + GlobalV::ofs_running << "\n"; + } + } + template + inline void print_local(const Parallel_Orbitals& pv, const TR* tlocal, const std::string name) + { + GlobalV::ofs_running << name << std::endl; + for (int i = 0;i < pv.get_row_size();++i) + { + for (int j = 0;j < pv.get_col_size();++j) GlobalV::ofs_running << tlocal[j + i * pv.get_col_size()] << " "; + GlobalV::ofs_running << "\n"; + } + } + template + inline void print_atompair_local(const Parallel_Orbitals& pv, const int iat1, const int iat2, const TR* tlocal, const std::string name) + { + GlobalV::ofs_running << name << std::endl; + for (int i = 0;i < pv.get_row_size(iat1);++i) + { + for (int j = 0;j < pv.get_col_size(iat2);++j) GlobalV::ofs_running << tlocal[j + i * pv.get_col_size(iat2)] << " "; + GlobalV::ofs_running << "\n"; + } + } + + template // HContainer type + void Symmetry_rotation::restore_HR( + const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, + const hamilt::HContainer& HR_irreduceble, + hamilt::HContainer& HR_rotated) + { + ModuleBase::TITLE("Symmetry_rotation", "restore_HR"); + for (auto& apR_isym_irapR : this->full_map_to_irreducible_sector_) + { + const Tap& ap = apR_isym_irapR.first.first; + const TC& R = apR_isym_irapR.first.second; + const int& isym = apR_isym_irapR.second.first; + const Tap& irap = apR_isym_irapR.second.second.first; + const TC& irR = apR_isym_irapR.second.second.second; + assert(irR == this->rotate_R_by_formula(symm, isym, ap.first, ap.second, R)); + // get in and out pointer from HContainer + const hamilt::AtomPair& irap_hc = HR_irreduceble.get_atom_pair(irap.first, irap.second); + const int irR_hc = irap_hc.find_R(irR[0], irR[1], irR[2]); + if (irR_hc < 0) continue; + const TR* irijR_ptr = irap_hc.get_pointer(irR_hc); + const hamilt::AtomPair& ap_hc = HR_rotated.get_atom_pair(ap.first, ap.second); + const int R_hc = ap_hc.find_R(R[0], R[1], R[2]); + if (R_hc < 0) continue; + TR* ijR_ptr = ap_hc.get_pointer(R_hc); + rotate_atompair_parallel(irijR_ptr, isym, atoms, st, irap, ap, mode, *irap_hc.get_paraV(), ijR_ptr); + } + + } + + inline void set_block(const int starti, const int startj, const int nr, const ModuleBase::ComplexMatrix& block, double* obj) + { // row-major (col-contiguous) + for (int i = 0;i < block.nr;++i) + for (int j = 0;j < block.nc;++j) + obj[starti + i + (startj + j) * nr] = block(j, i).real(); + }; + inline void set_block(const int starti, const int startj, const int nr, const ModuleBase::ComplexMatrix& block, std::complex* obj) + { // row-major (col-contiguous) + for (int i = 0;i < block.nr;++i) + for (int j = 0;j < block.nc;++j) + obj[starti + i + (startj + j) * nr] = block(j, i); + }; + template + void Symmetry_rotation::rotate_atompair_parallel(const TR* Alocal_in, const int isym, const Atom* atoms, const Statistics& st, + const Tap& ap_in, const Tap& ap_out, const char mode, const Parallel_Orbitals& pv, TR* Alocal_out, const bool output) + { + // all the matrices are row-major (col-contiguous) + int iat1 = ap_in.first, iat2 = ap_in.second; + int it1 = st.iat2it[iat1], it2 = st.iat2it[iat2]; + int ia1 = st.iat2ia[iat1], ia2 = st.iat2ia[iat2]; + // contruct T matrix + std::vector T1, T2; + auto set_rotation_matrix = [&](const int& it, const int& ia, std::vector& T)->int + { + T.resize(atoms[it].nw * atoms[it].nw, 0.0); + const int iwstart = atoms[it].stapos_wf + ia * atoms[it].nw; + int iw = 0; + while (iw < atoms[it].nw) + { + int l = atoms[it].iw2l[iw]; + int nm = 2 * l + 1; + // this->set_block_to_mat2d(iwstart, iwstart, this->rotmat_Slm_[isym][l], T_full_2d, pv); + set_block(iw, iw, atoms[it].nw, this->rotmat_Slm_[isym][l], T.data()); + iw += nm; + } + return iwstart; + }; + int iw1start = set_rotation_matrix(it1, ia1, T1); + int iw2start = set_rotation_matrix(it2, ia2, T2); + + // copy Aocal_in to a global atom-pair matrix + std::vector A(atoms[it1].nw * atoms[it2].nw, 0.0); + + int abr1 = pv.atom_begin_row[iat1], abc2 = pv.atom_begin_col[iat2]; + if (abr1 >= 0 && abc2 >= 0) + { // "pv.local2global_row(i) - iw1start": global index in current atom pair + for (int j = 0;j < pv.get_col_size(iat2);++j) + for (int i = 0;i < pv.get_row_size(iat1);++i) + A[(pv.local2global_row(i + abr1) - iw1start) * atoms[it2].nw + (pv.local2global_col(j + abc2) - iw2start)] + = Alocal_in[j + i * pv.get_col_size(iat2)]; + } + if (output) print_global(A.data(), atoms[it1].nw, atoms[it2].nw, "A before allreduce"); + Parallel_Reduce::reduce_all(A.data(), A.size()); + + // rotate + const char notrans = 'N', transpose = 'T', dagger = 'C'; + // const std::complex alpha(1.0, 0.0), beta(0.0, 0.0); + std::vector AT2(atoms[it1].nw * atoms[it2].nw, 0.0); + std::vector TAT(atoms[it1].nw * atoms[it2].nw, 0.0); + if (mode == 'H') + { // H'=T1^\dagger * H * T2 + BlasConnector::gemm(notrans, notrans, atoms[it1].nw, atoms[it2].nw, atoms[it2].nw, + 1.0, A.data(), atoms[it2].nw, T2.data(), atoms[it2].nw, 0.0, AT2.data(), atoms[it2].nw); + BlasConnector::gemm(dagger, notrans, atoms[it1].nw, atoms[it2].nw, atoms[it1].nw, + 1.0, T1.data(), atoms[it1].nw, AT2.data(), atoms[it2].nw, 0.0, TAT.data(), atoms[it2].nw); + } + else if (mode == 'D') + { // D' = T1^T * D * T2^* = T1^T * [T2^\dagger * D^T]^T + BlasConnector::gemm(dagger, transpose, atoms[it2].nw, atoms[it1].nw, atoms[it2].nw, + 1.0, T2.data(), atoms[it2].nw, A.data(), atoms[it2].nw, 0.0, AT2.data(), atoms[it1].nw); + BlasConnector::gemm(transpose, transpose, atoms[it1].nw, atoms[it2].nw, atoms[it1].nw, + 1.0, T1.data(), atoms[it1].nw, AT2.data(), atoms[it1].nw, 0.0, TAT.data(), atoms[it2].nw); + } + else throw std::invalid_argument("Symmetry_rotation::rotate_atompair_tensor: invalid mode."); + + if (output) + { + print_global(A.data(), atoms[it1].nw, atoms[it2].nw, "A"); + print_global(T1.data(), atoms[it1].nw, atoms[it1].nw, "T1"); + print_global(TAT.data(), atoms[it1].nw, atoms[it2].nw, "TAT"); + print_atompair_local(pv, iat1, iat2, Alocal_out, "Alocal_out"); + } + + // copy back to Alocal_out + iat1 = ap_out.first, iat2 = ap_out.second; + it1 = st.iat2it[iat1], it2 = st.iat2it[iat2]; + ia1 = st.iat2ia[iat1], ia2 = st.iat2ia[iat2]; + abr1 = pv.atom_begin_row[iat1], abc2 = pv.atom_begin_col[iat2]; + iw1start = atoms[it1].stapos_wf + ia1 * atoms[it1].nw; + iw2start = atoms[it2].stapos_wf + ia2 * atoms[it2].nw; + if (abr1 >= 0 && abc2 >= 0) + {// ap_in index for TAT but ap_out index for Alocal_out + for (int j = 0;j < pv.get_col_size(iat2);++j) + for (int i = 0;i < pv.get_row_size(iat1);++i) + Alocal_out[j + i * pv.get_col_size(iat2)] + = TAT[(pv.local2global_row(i + abr1) - iw1start) * atoms[it2].nw + (pv.local2global_col(j + abc2) - iw2start)]; + } + } + + template + void Symmetry_rotation::test_HR_rotation(const Symmetry& symm, const Atom* atoms, const Statistics& st, + const char mode, const hamilt::HContainer& HR_full) + { + ModuleBase::TITLE("Symmetry_rotation", "test_HR_rotation"); + auto get_irreducible_ijR_info = [&HR_full, this]() -> std::vector + { + std::vector irreducible_ijR_info; + irreducible_ijR_info.push_back(this->irreducible_sector_.size()); + for (auto& irap_irR : this->irreducible_sector_) + { + const int iat1 = irap_irR.first.first, iat2 = irap_irR.first.second; + irreducible_ijR_info.insert(irreducible_ijR_info.end(), { iat1, iat2, 0 }); + int nR = 0; + for (auto& R : irap_irR.second) + if (HR_full.get_atom_pair(iat1, iat2).find_R(R[0], R[1], R[2]) >= 0) + { + irreducible_ijR_info.insert(irreducible_ijR_info.end(), R.begin(), R.end()); + ++nR; + } + irreducible_ijR_info[irreducible_ijR_info.size() - 3 * nR - 1] = nR; + } + return irreducible_ijR_info; + }; + + const Parallel_Orbitals* pv = HR_full.get_atom_pair(0, 0).get_paraV(); + // 1. pick out H(R) in the irreducible sector from full H(R) + const std::vector& irreducible_ijR_info = get_irreducible_ijR_info(); + hamilt::HContainer HR_irreducible(pv, nullptr, &irreducible_ijR_info); + HR_irreducible.set_zero(); + for (auto& irap_irR : this->irreducible_sector_) + { + const int iat1 = irap_irR.first.first, iat2 = irap_irR.first.second; + const hamilt::AtomPair& irap = HR_irreducible.get_atom_pair(iat1, iat2); + const hamilt::AtomPair& ap_full = HR_full.get_atom_pair(iat1, iat2); + for (auto& R : irap_irR.second) + if (irap.find_R(R[0], R[1], R[2]) >= 0) + { // out-of-range R can be added to irreducible sector to be calculated, but not in this test for lack of reference + TR* irptr = irap.get_HR_values(R[0], R[1], R[2]).get_pointer(); + TR* ptr = ap_full.get_HR_values(R[0], R[1], R[2]).get_pointer(); + std::copy(ptr, ptr + pv->get_row_size(iat1) * pv->get_col_size(iat2), irptr); + } + } + + //2. rotate + hamilt::HContainer HR_rotated(HR_full); + HR_rotated.set_zero(); + this->restore_HR(symm, atoms, st, mode, HR_irreducible, HR_rotated); + //3. compare + for (int iat1 = 0;iat1 < st.nat;++iat1) + { + for (int iat2 = 0;iat2 < st.nat;++iat2) + { + const hamilt::AtomPair& ap_full = HR_full.get_atom_pair(iat1, iat2); + const hamilt::AtomPair& ap_rotated = HR_rotated.get_atom_pair(iat1, iat2); + assert(ap_full.get_R_size() == ap_rotated.get_R_size()); + for (int irR = 0;irR < ap_full.get_R_size();++irR) + { + const TR* full_ptr = ap_full.get_pointer(irR); + int* R = ap_full.get_R_index(irR); + const TR* rotated_ptr = ap_rotated.get_HR_values(R[0], R[1], R[2]).get_pointer(); + GlobalV::ofs_running << "atom pair: (" << iat1 << ", " << iat2 << "), R: (" << R[0] << " " << R[1] << " " << R[2] << ")\n"; + print_atompair_local(*pv, iat1, iat2, rotated_ptr, std::string("R_rot").insert(0, 1, mode)); + print_atompair_local(*pv, iat1, iat2, full_ptr, std::string("R_ref").insert(0, 1, mode)); + } + } + } + } +} \ No newline at end of file diff --git a/source/module_ri/test/CMakeLists.txt b/source/module_ri/test/CMakeLists.txt index 94c25481e3..dbd535c5fc 100644 --- a/source/module_ri/test/CMakeLists.txt +++ b/source/module_ri/test/CMakeLists.txt @@ -5,4 +5,10 @@ AddTest( TARGET dm_mixing_test LIBS base ${math_libs} device SOURCES dm_mixing_test.cpp ../Mix_DMk_2D.cpp ../Mix_Matrix.cpp +) +AddTest( + TARGET symmetry_rotation + LIBS base ${math_libs} device symmetry + SOURCES symmetry_rotation_test.cpp ../symmetry_rotation.cpp ../../module_basis/module_ao/parallel_2d.cpp + ../../module_io/output.cpp ) \ No newline at end of file diff --git a/source/module_ri/test/symmetry_rotation_test.cpp b/source/module_ri/test/symmetry_rotation_test.cpp new file mode 100644 index 0000000000..3c04c1d7db --- /dev/null +++ b/source/module_ri/test/symmetry_rotation_test.cpp @@ -0,0 +1,173 @@ +#include "mpi.h" +#include "../symmetry_rotation.h" +#include "gtest/gtest.h" +#define DOUBLETHRESHOLD 1e-8 + +/* + +tested functions: +- wigner_d +- wigner_D +- ovlp_Ylm_Slm +- get_euler_angle +- cal_rotmat_Slm +- get_return_lattice + +untested functions: +- cal_Ms (depending on UnitCell,K_Vectors, Parallel_2D) +- restore_dm (depending on Ms) +- rot_matrix_ao (depending on Ms) + +*/ + +// mock the useless functions +pseudo::pseudo() {} +pseudo::~pseudo() {} +Atom::Atom() {} +Atom::~Atom() {} +Atom_pseudo::Atom_pseudo() {} +Atom_pseudo::~Atom_pseudo() {} +UnitCell::UnitCell() {} +UnitCell::~UnitCell() {} +InfoNonlocal::InfoNonlocal() {} +InfoNonlocal::~InfoNonlocal() {} +Magnetism::Magnetism() {} +Magnetism::~Magnetism() {} + +class SymmetryRotationTest : public testing::Test +{ +protected: + void SetUp() override + { + //init pv + int myrank, dsize; + MPI_Comm_rank(MPI_COMM_WORLD, &myrank); + MPI_Comm_size(MPI_COMM_WORLD, &dsize); + pv.set_block_size(1); + pv.set_proc_dim(dsize); + pv.mpi_create_cart(MPI_COMM_WORLD); + std::ofstream ofs; + pv.set_local2global(matsize, matsize, ofs, ofs); + pv.set_desc(matsize, matsize, pv.get_row_size()); + pv.set_global2local(matsize, matsize, true, ofs); + } + ModuleBase::Matrix3 C41 = ModuleBase::Matrix3(0, 1, 0, -1, 0, 0, 0, 0, 1); + std::vector> wigerD_p_C41_ref = { ModuleBase::IMAG_UNIT, 0, 0, 0, 1, 0, 0, 0, -ModuleBase::IMAG_UNIT }; + std::vector> cmm_p_C41_ref = { -ModuleBase::IMAG_UNIT / sqrt(2), 0, -1 / sqrt(2), 0, 1, 0, -ModuleBase::IMAG_UNIT / sqrt(2), 0, 1 / sqrt(2) }; + std::vector> c_dagger_D_c_C41_ref = { 1, 0, 0, 0, 0, -1, 0, 1, 0 }; + ModuleSymmetry::Symmetry_rotation symrot; + Parallel_2D pv; + const int matsize = 5; //2s1p +}; + +// inline void outmat(ModuleBase::ComplexMatrix& mat, int size, std::string name) +// { +// std::cout << name << std::endl; +// for (int i = 0;i < size;++i) +// { +// for (int j = 0;j < size;++j)std::cout << mat(i, j) << " "; +// std::cout << std::endl; +// } +// } +TEST_F(SymmetryRotationTest, Wignerd) +{ + EXPECT_NEAR(symrot.wigner_d(0, 1, 0, 0), 1, DOUBLETHRESHOLD); + EXPECT_NEAR(symrot.wigner_d(0, 1, 1, 1), 1, DOUBLETHRESHOLD); + EXPECT_NEAR(symrot.wigner_d(0, 1, -1, -1), 1, DOUBLETHRESHOLD); +} +TEST_F(SymmetryRotationTest, WignerD) +{ + ModuleBase::ComplexMatrix wignerD_p_C41(3, 3); + int l = 1; + for (int m1 = -l;m1 <= l;++m1) + for (int m2 = -l;m2 <= l;++m2) + { + int i = m1 + l, j = m2 + l; + wignerD_p_C41(i, j) = symrot.wigner_D(ModuleBase::Vector3(0, 0, ModuleBase::PI / 2), 1, m1, m2, false); + EXPECT_NEAR(wignerD_p_C41(i, j).real(), wigerD_p_C41_ref[i * 3 + j].real(), DOUBLETHRESHOLD); + EXPECT_NEAR(wignerD_p_C41(i, j).imag(), wigerD_p_C41_ref[i * 3 + j].imag(), DOUBLETHRESHOLD); + // alpha and gamma are the same when beta = 0 + wignerD_p_C41(i, j) = symrot.wigner_D(ModuleBase::Vector3(ModuleBase::PI / 2, 0, 0), 1, m1, m2, false); + EXPECT_NEAR(wignerD_p_C41(i, j).real(), wigerD_p_C41_ref[i * 3 + j].real(), DOUBLETHRESHOLD); + EXPECT_NEAR(wignerD_p_C41(i, j).imag(), wigerD_p_C41_ref[i * 3 + j].imag(), DOUBLETHRESHOLD); + } + // outmat(wignerD_p_C41, 3, "wignerD_p_C41_cal"); + +} + +TEST_F(SymmetryRotationTest, EulerAngle) +{ + ModuleBase::Vector3 euler_angle = symrot.get_euler_angle(C41); + EXPECT_NEAR(euler_angle.x + euler_angle.z, ModuleBase::PI / 2, DOUBLETHRESHOLD); + EXPECT_NEAR(euler_angle.y, 0, DOUBLETHRESHOLD); +} + +TEST_F(SymmetryRotationTest, OvlpYS) +{ + ModuleBase::ComplexMatrix c_mm_p(3, 3); + int l = 1; + for (int m1 = -l;m1 <= l;++m1) + for (int m2 = -l;m2 <= l;++m2) + { + int i = m1 + l, j = m2 + l; + c_mm_p(i, j) = symrot.ovlp_Ylm_Slm(l, m1, m2); + EXPECT_NEAR(c_mm_p(i, j).real(), cmm_p_C41_ref[i * 3 + j].real(), DOUBLETHRESHOLD); + EXPECT_NEAR(c_mm_p(i, j).imag(), cmm_p_C41_ref[i * 3 + j].imag(), DOUBLETHRESHOLD); + } +} + +TEST_F(SymmetryRotationTest, RotMat) +{ + symrot.cal_rotmat_Slm(&C41, 1); + ModuleBase::ComplexMatrix& rotmat = symrot.get_rotmat_Slm()[0][1]; + int l = 1; + for (int m1 = -l;m1 <= l;++m1) + for (int m2 = -l;m2 <= l;++m2) + { + int i = m1 + l, j = m2 + l; + EXPECT_NEAR(rotmat(i, j).real(), c_dagger_D_c_C41_ref[i * 3 + j].real(), DOUBLETHRESHOLD); + EXPECT_NEAR(rotmat(i, j).imag(), c_dagger_D_c_C41_ref[i * 3 + j].imag(), DOUBLETHRESHOLD); + } +} + +TEST_F(SymmetryRotationTest, GetReturnLattice) +{ + ModuleBase::Vector3 posd_a1(1. / 3., 1. / 3., 0.2); + ModuleBase::Vector3 posd_a2(1. / 3., 1. / 3., -0.2); + ModuleBase::Vector3 gtransd(0, 0, 0); + ModuleBase::Matrix3 gmatd(-1, 1, 0, -1, 0, 0, 0, 0, -1); + ModuleBase::Vector3 return_lattice = symrot.get_return_lattice(ModuleSymmetry::Symmetry(), gmatd, gtransd, posd_a1, posd_a2); + EXPECT_NEAR(return_lattice.x, -1, DOUBLETHRESHOLD); + EXPECT_NEAR(return_lattice.y, 0, DOUBLETHRESHOLD); + EXPECT_NEAR(return_lattice.z, -1, DOUBLETHRESHOLD); +} + +TEST_F(SymmetryRotationTest, SetBlockToMat2d) +{ + std::vector> obj_mat(pv.get_local_size()); + for (int j = 0;j < pv.get_col_size();++j) + for (int i = 0;i < pv.get_row_size();++i) + obj_mat[j * pv.get_row_size() + i] = std::complex(static_cast(pv.local2global_row(i)), static_cast(pv.local2global_col(j))); + ModuleBase::ComplexMatrix block(2, 2); + block(0, 0) = 0; block(0, 1) = -1; block(1, 0) = -2; block(1, 1) = -3; + symrot.set_block_to_mat2d(2, 3, block, obj_mat, pv); + for (int i = 2;i < 4;++i) + for (int j = 3;j < 5;++j) + { + int local_index = pv.global2local_col(j) * pv.get_row_size() + pv.global2local_row(i); + if (pv.in_this_processor(i, j)) + { + EXPECT_NEAR(obj_mat[local_index].real(), block(j - 3, i - 2).real(), DOUBLETHRESHOLD); + EXPECT_NEAR(obj_mat[local_index].imag(), block(j - 3, i - 2).imag(), DOUBLETHRESHOLD); + } + } +} + +int main(int argc, char** argv) +{ + MPI_Init(&argc, &argv); + testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + MPI_Finalize(); + return result; +} diff --git a/tests/integrate/281_NO_KP_HSE_symmetry/INPUT b/tests/integrate/281_NO_KP_HSE_symmetry/INPUT new file mode 100644 index 0000000000..de6213b974 --- /dev/null +++ b/tests/integrate/281_NO_KP_HSE_symmetry/INPUT @@ -0,0 +1,42 @@ +INPUT_PARAMETERS +#Parameters (1.General) +suffix autotest +ntype 1 +symmetry 1 +gamma_only 0 +nspin 1 + +#Parameters (2.Iteration) +ecutwfc 20 +scf_thr 1E-5 +scf_nmax 100 + +calculation scf +cal_force 1 +cal_stress 1 + +#Parameters (3.Basis) +basis_type lcao +ks_solver genelpa + +#Parameters (4.Smearing) +smearing_method gauss +smearing_sigma 0.002 + +#Parameters (5.Mixing) +mixing_type broyden + +#Parameters (7.Hybrid) +dft_functional hse +exx_real_number 1 +exx_pca_threshold 1E-4 +exx_c_threshold 1E-4 +exx_v_threshold 1 +exx_dm_threshold 1E-4 +exx_cauchy_threshold 1E-6 +exx_ccp_rmesh_times 1 +exx_separate_loop 1 +exx_hybrid_step 3 + +pseudo_dir ../../PP_ORB +orbital_dir ../../PP_ORB diff --git a/tests/integrate/281_NO_KP_HSE_symmetry/KPT b/tests/integrate/281_NO_KP_HSE_symmetry/KPT new file mode 100644 index 0000000000..f5f7f4ec34 --- /dev/null +++ b/tests/integrate/281_NO_KP_HSE_symmetry/KPT @@ -0,0 +1,4 @@ +K_POINTS +0 +Gamma +2 2 2 0 0 0 diff --git a/tests/integrate/281_NO_KP_HSE_symmetry/STRU b/tests/integrate/281_NO_KP_HSE_symmetry/STRU new file mode 100644 index 0000000000..b7249c0d0c --- /dev/null +++ b/tests/integrate/281_NO_KP_HSE_symmetry/STRU @@ -0,0 +1,22 @@ +ATOMIC_SPECIES +Si 1.000 Si_dojo_nsoc.upf + +NUMERICAL_ORBITAL +Si_dojo_6au.orb + +LATTICE_CONSTANT +1.889766 + +LATTICE_VECTORS +0.0 2.708337 2.708337 +2.708337 0.0 2.708337 +2.708337 2.708337 0.0 + +ATOMIC_POSITIONS +Direct + +Si +0.0 +2 +0.125 0.125 0.125 1 1 1 +0.875 0.875 0.875 1 1 1 diff --git a/tests/integrate/281_NO_KP_HSE_symmetry/jd b/tests/integrate/281_NO_KP_HSE_symmetry/jd new file mode 100644 index 0000000000..88ac4f7c94 --- /dev/null +++ b/tests/integrate/281_NO_KP_HSE_symmetry/jd @@ -0,0 +1 @@ +HSE calculation on Si, multiple k-points, cal force and stress, exx real number, symmetry=1 \ No newline at end of file diff --git a/tests/integrate/281_NO_KP_HSE_symmetry/result.ref b/tests/integrate/281_NO_KP_HSE_symmetry/result.ref new file mode 100644 index 0000000000..f73f407581 --- /dev/null +++ b/tests/integrate/281_NO_KP_HSE_symmetry/result.ref @@ -0,0 +1,8 @@ +etotref -202.5354488440458738 +etotperatomref -101.2677244220 +totalforceref 0.000000 +totalstressref 1591.165740 +pointgroupref D_3d +spacegroupref O_h +nksibzref 3 +totaltimeref 40.36 diff --git a/tests/integrate/CASES_CPU.txt b/tests/integrate/CASES_CPU.txt index 73d8931702..738344ff0d 100644 --- a/tests/integrate/CASES_CPU.txt +++ b/tests/integrate/CASES_CPU.txt @@ -195,6 +195,7 @@ 270_NO_MD_1O 270_NO_MD_2O 281_NO_KP_HSE +281_NO_KP_HSE_symmetry 282_NO_KP_HSE_complex 283_NO_KP_HF 284_NO_KP_PBE0 From f56f23c9c4e7404a7028dbcc7c7201c4c2990eb5 Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Mon, 4 Mar 2024 01:32:49 +0800 Subject: [PATCH 08/19] apply H(R) symmetry to loop3-LibRI refactor and delete useless code fix D(k) rotation --- source/module_ri/Exx_LRI.h | 14 +- source/module_ri/Exx_LRI.hpp | 41 +++-- source/module_ri/Exx_LRI_interface.h | 1 + source/module_ri/Exx_LRI_interface.hpp | 48 ++++- source/module_ri/RPA_LRI.hpp | 14 +- .../module_ri/symmetry_irreducible_sector.cpp | 172 +++++++++--------- source/module_ri/symmetry_rotation.cpp | 82 ++++----- source/module_ri/symmetry_rotation.h | 45 +++-- source/module_ri/symmetry_rotation_R.hpp | 110 ++--------- .../symmetry_rotation_R_hcontainer.hpp | 7 +- 10 files changed, 257 insertions(+), 277 deletions(-) diff --git a/source/module_ri/Exx_LRI.h b/source/module_ri/Exx_LRI.h index 74f8744e0b..f11fcd2e3b 100644 --- a/source/module_ri/Exx_LRI.h +++ b/source/module_ri/Exx_LRI.h @@ -18,6 +18,8 @@ #include #include +#include "symmetry_rotation.h" + class Parallel_Orbitals; template @@ -74,7 +76,9 @@ class Exx_LRI RI::Exx exx_lri; void cal_exx_ions(); - void cal_exx_elec(const std::vector>>> &Ds, const Parallel_Orbitals &pv); + void cal_exx_elec(const std::vector>>>& Ds, + const Parallel_Orbitals& pv, + const ModuleSymmetry::Symmetry_rotation* p_symrot = nullptr); void post_process_Hexx( std::map>> &Hexxs_io ) const; double post_process_Eexx(const double& Eexx_in) const; @@ -82,10 +86,10 @@ class Exx_LRI friend class RPA_LRI, Tdata>; friend class Exx_LRI_Interface; friend class Exx_LRI_Interface, Tdata>; - friend class LR::ESolver_LR; - friend class LR::ESolver_LR, double>; - friend class LR::OperatorLREXX; - friend class LR::OperatorLREXX>; + friend class LR::ESolver_LR; + friend class LR::ESolver_LR, double>; + friend class LR::OperatorLREXX; + friend class LR::OperatorLREXX>; }; #include "Exx_LRI.hpp" diff --git a/source/module_ri/Exx_LRI.hpp b/source/module_ri/Exx_LRI.hpp index 63f6d5c5a9..abb782fc0f 100644 --- a/source/module_ri/Exx_LRI.hpp +++ b/source/module_ri/Exx_LRI.hpp @@ -165,7 +165,9 @@ void Exx_LRI::cal_exx_ions() } template -void Exx_LRI::cal_exx_elec(const std::vector>>> &Ds, const Parallel_Orbitals &pv) +void Exx_LRI::cal_exx_elec(const std::vector>>>& Ds, + const Parallel_Orbitals& pv, + const ModuleSymmetry::Symmetry_rotation* p_symrot) { ModuleBase::TITLE("Exx_LRI","cal_exx_elec"); ModuleBase::timer::tick("Exx_LRI", "cal_exx_elec"); @@ -178,18 +180,29 @@ void Exx_LRI::cal_exx_elec(const std::vectorEexx = 0; for(int is=0; isexx_lri.set_Ds(Ds[is], this->info.dm_threshold); - this->exx_lri.cal_Hs(); - } - else - { - this->exx_lri.set_Ds(Ds[is], this->info.dm_threshold, std::to_string(is)); - this->exx_lri.cal_Hs({"","",std::to_string(is)}); - } - this->Hexxs[is] = RI::Communicate_Tensors_Map_Judge::comm_map2_first( - this->mpi_comm, std::move(this->exx_lri.Hs), std::get<0>(judge[is]), std::get<1>(judge[is])); + if (!(GlobalV::CAL_FORCE || GlobalV::CAL_STRESS)) + { + this->exx_lri.set_Ds(Ds[is], this->info.dm_threshold); + this->exx_lri.cal_Hs({ "","","" }, + (p_symrot == nullptr) ? std::map, std::set >({}) : p_symrot->get_irreducible_sector(), + (p_symrot == nullptr) ? true : false); + } + else + { + this->exx_lri.set_Ds(Ds[is], this->info.dm_threshold, std::to_string(is)); + this->exx_lri.cal_Hs({ "","",std::to_string(is) }); + } + this->Hexxs[is] = RI::Communicate_Tensors_Map_Judge::comm_map2_first( + this->mpi_comm, std::move(this->exx_lri.Hs), std::get<0>(judge[is]), std::get<1>(judge[is])); + + if (p_symrot != nullptr) + { + this->Hexxs[is] = p_symrot->restore_HR(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, 'H', this->Hexxs[is]); + // cal energy using full Hs + this->exx_lri.energy = this->exx_lri.post_2D.cal_energy( + this->exx_lri.post_2D.saves["Ds_"], + this->Hexxs[is]); + } this->Eexx += std::real(this->exx_lri.energy); post_process_Hexx(this->Hexxs[is]); } @@ -209,7 +222,7 @@ void Exx_LRI::post_process_Hexx( std::map -double Exx_LRI::post_process_Eexx(const double& Eexx_in) const +double Exx_LRI::post_process_Eexx(const double& Eexx_in) const { ModuleBase::TITLE("Exx_LRI","post_process_Eexx"); const double SPIN_multiple = std::map{ {1,2}, {2,1}, {4,1} }.at(GlobalV::NSPIN); // why? diff --git a/source/module_ri/Exx_LRI_interface.h b/source/module_ri/Exx_LRI_interface.h index f825203811..b526aa76b8 100644 --- a/source/module_ri/Exx_LRI_interface.h +++ b/source/module_ri/Exx_LRI_interface.h @@ -70,6 +70,7 @@ class Exx_LRI_Interface int two_level_step = 0; bool exx_spacegroup_symmetry = false; + bool restore_dm_only = false; // true for test ModuleSymmetry::Symmetry_rotation symrot_; }; diff --git a/source/module_ri/Exx_LRI_interface.hpp b/source/module_ri/Exx_LRI_interface.hpp index 035928977a..3bfadb22a0 100644 --- a/source/module_ri/Exx_LRI_interface.hpp +++ b/source/module_ri/Exx_LRI_interface.hpp @@ -108,7 +108,8 @@ void Exx_LRI_Interface::exx_eachiterinit(const elecstate::DensityMatri Ds = GlobalV::GAMMA_ONLY_LOCAL ? RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_gamma_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN) : RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_k_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN, this->exx_spacegroup_symmetry); - this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer()); + if (this->exx_spacegroup_symmetry && !restore_dm_only) { this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer(), &this->symrot_); } + else { this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer()); } } } } @@ -205,16 +206,49 @@ bool Exx_LRI_Interface::exx_after_converge( Ds = GlobalV::GAMMA_ONLY_LOCAL ? RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_gamma_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN) : RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_k_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN, this->exx_spacegroup_symmetry); - this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer()); - if (!this->exx_spacegroup_symmetry)this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_ref"); + // check the rotation of Ds + // this->symrot_.test_HR_rotation(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, 'D', Ds[0]); + + // check the rotation of H(R) before adding exx + // this->symrot_.find_irreducible_sector(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, this->symrot_.get_Rs_from_adjacent_list(GlobalC::ucell, GlobalC::GridD, *lm.ParaV)); + // this->symrot_.test_HR_rotation(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, 'H', *(dynamic_cast*>(&hamilt)->getHR())); + // exit(0); + + if (this->exx_spacegroup_symmetry) + { + if (restore_dm_only) + { + this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer()); // restore DM but not Hexx + // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_restore-DM-only"); // test + } + else + { + this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer(), &this->symrot_); + // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_irreducible"); // test + // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_restored"); // test + } + } + else + { + this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer()); + // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_ref"); + } + // ======================== test ======================== + // if (this->two_level_step)exit(0); // check the rotation of S(R) - this->symrot_.find_irreducible_sector(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, this->symrot_.get_Rs_from_adjacent_list(GlobalC::ucell, GlobalC::GridD, *lm.ParaV)); - this->symrot_.test_HR_rotation(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, *(dynamic_cast*>(&hamilt)->getSR())); - // check the rotation of Hexx - // this->symrot_.test_HR_rotation(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, this->exx_ptr->Hexxs[0]); + // this->symrot_.find_irreducible_sector(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, this->symrot_.get_Rs_from_adjacent_list(GlobalC::ucell, GlobalC::GridD, *lm.ParaV)); + // this->symrot_.test_HR_rotation(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, 'H', *(dynamic_cast*>(&hamilt)->getSR())); + // check the rotation of D(R): no atom pair? + // symrot_.find_irreducible_sector(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, symrot_.get_Rs_from_adjacent_list(GlobalC::ucell, GlobalC::GridD, *this->DM->get_paraV_pointer())); + // symrot_.test_HR_rotation(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, 'D', *(this->DM->get_DMR_pointer(0))); + + // check the rotation of Hexx + // this->symrot_.test_HR_rotation(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, 'H', this->exx_ptr->Hexxs[0]); + // exit(0);// break after test + // ======================== test ======================== iter = 0; this->two_level_step++; diff --git a/source/module_ri/RPA_LRI.hpp b/source/module_ri/RPA_LRI.hpp index f4754f6c2a..f41854e9a5 100644 --- a/source/module_ri/RPA_LRI.hpp +++ b/source/module_ri/RPA_LRI.hpp @@ -81,9 +81,10 @@ void RPA_LRI::cal_postSCF_exx(const elecstate::DensityMatrix {mix_DMk_2D.set_nks(kv.get_nks(), GlobalV::GAMMA_ONLY_LOCAL);} mix_DMk_2D.set_mixing(nullptr); + ModuleSymmetry::Symmetry_rotation symrot; if (exx_spacegroup_symmetry) { - ModuleSymmetry::Symmetry_rotation symrot; + symrot.get_return_lattice_all(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st); symrot.cal_Ms(kv, GlobalC::ucell, *dm.get_paraV_pointer()); mix_DMk_2D.mix(symrot.restore_dm(kv, dm.get_DMK_vector(), *dm.get_paraV_pointer()), true); } @@ -101,7 +102,16 @@ void RPA_LRI::cal_postSCF_exx(const elecstate::DensityMatrix exx_lri_rpa.init(mpi_comm_in, kv); exx_lri_rpa.cal_exx_ions(); - exx_lri_rpa.cal_exx_elec(Ds, *dm.get_paraV_pointer()); + + if (exx_spacegroup_symmetry) + { + symrot.find_irreducible_sector(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, symrot.get_Rs_from_BvK(kv)); + exx_lri_rpa.cal_exx_elec(Ds, *dm.get_paraV_pointer(), &symrot); + } + else + { + exx_lri_rpa.cal_exx_elec(Ds, *dm.get_paraV_pointer()); + } // cout<<"postSCF_Eexx: "<eps_ = symm.epsilon; - for (int iat1 = 0;iat1 < symm.nat;++iat1) - for (int iat2 = 0;iat2 < symm.nat;++iat2) - { - Tap pair = { iat1, iat2 }; - bool exist = false; - for (int isym = 0;isym < symm.nrotk;++isym) - { - Tap rotpair = { symm.get_rotated_atom(isym,iat1), symm.get_rotated_atom(isym,iat2) }; - for (int ip = 0;ip < this->atompair_stars_.size();++ip) // current irreduceble pairs - { - if (rotpair == this->atompair_stars_[ip].at(0)) - { - this->atompair_stars_[ip].insert({ isym, pair }); - exist = true; - break; - } - } - if (exist)break; - } - if (!exist)this->atompair_stars_.push_back({ {0, pair} }); - } - } - - void Symmetry_rotation::find_irreducible_atom_pairs_set(const Symmetry& symm) - { - ModuleBase::TITLE("Symmetry_rotation", "find_irreducible_atom_pairs_set"); - this->eps_ = symm.epsilon; - std::vector invmap(symm.nrotk, -1); - symm.gmatrix_invmap(symm.gmatrix, symm.nrotk, invmap.data()); - // contruct initial ap-set - std::set ap_set; - for (int iat1 = 0; iat1 < symm.nat; ++iat1) - for (int iat2 = 0; iat2 < symm.nat; ++iat2) - ap_set.insert({ iat1, iat2 }); - while (!ap_set.empty()) - { - Tap ap = *ap_set.begin(); - std::map ap_star; - for (int isym = 0; isym < symm.nrotk; ++isym) - { - Tap rotpair = { symm.get_rotated_atom(isym,ap.first), symm.get_rotated_atom(isym,ap.second) }; - if (ap_set.find(rotpair) != ap_set.end()) - { - ap_star.insert({ invmap[isym], rotpair }); - ap_set.erase(rotpair); - } - } - this->atompair_stars_.push_back(ap_star); - } - } - - inline void output_atompair_stars(const std::vector>& ap_stars) - { - std::cout << "stars of irreducible atom pairs: " << std::endl; - for (int ip = 0; ip < ap_stars.size(); ++ip) - { - std::cout << "atom pair star " << ip << ": " << std::endl; - for (const auto& ap : ap_stars[ip]) - std::cout << "isym=" << ap.first << ", atompair=(" << ap.second.first << ", " << ap.second.second << ") " << std::endl; - } - } - - void Symmetry_rotation::test_irreducible_atom_pairs(const Symmetry& symm) - { - std::cout << "Algorithm 1: find irreducible atom pairs by set" << std::endl; - this->find_irreducible_atom_pairs_set(symm); - output_atompair_stars(this->atompair_stars_); - - std::cout << std::endl; - this->atompair_stars_.clear(); - std::cout << "Algorithm 2: find irreducible atom pairs by judge" << std::endl; - this->find_irreducible_atom_pairs(symm); - output_atompair_stars(this->atompair_stars_); - } + // void Symmetry_rotation::find_irreducible_atom_pairs(const Symmetry& symm) + // { + // ModuleBase::TITLE("Symmetry_rotation", "find_irreducible_atom_pairs"); + // this->eps_ = symm.epsilon; + // for (int iat1 = 0;iat1 < symm.nat;++iat1) + // for (int iat2 = 0;iat2 < symm.nat;++iat2) + // { + // Tap pair = { iat1, iat2 }; + // bool exist = false; + // for (int isym = 0;isym < symm.nrotk;++isym) + // { + // Tap rotpair = { symm.get_rotated_atom(isym,iat1), symm.get_rotated_atom(isym,iat2) }; + // for (int ip = 0;ip < this->atompair_stars_.size();++ip) // current irreduceble pairs + // { + // if (rotpair == this->atompair_stars_[ip].at(0)) + // { + // this->atompair_stars_[ip].insert({ isym, pair }); + // exist = true; + // break; + // } + // } + // if (exist)break; + // } + // if (!exist)this->atompair_stars_.push_back({ {0, pair} }); + // } + // } + + // void Symmetry_rotation::find_irreducible_atom_pairs_set(const Symmetry& symm) + // { + // ModuleBase::TITLE("Symmetry_rotation", "find_irreducible_atom_pairs_set"); + // this->eps_ = symm.epsilon; + // if (this->invmap_.empty()) + // { + // this->invmap_.resize(symm.nrotk); + // symm.gmatrix_invmap(symm.gmatrix, symm.nrotk, invmap_.data()); + // } + // // contruct initial ap-set + // std::set ap_set; + // for (int iat1 = 0; iat1 < symm.nat; ++iat1) + // for (int iat2 = 0; iat2 < symm.nat; ++iat2) + // ap_set.insert({ iat1, iat2 }); + // while (!ap_set.empty()) + // { + // Tap ap = *ap_set.begin(); + // std::map ap_star; + // for (int isym = 0; isym < symm.nrotk; ++isym) + // { + // Tap rotpair = { symm.get_rotated_atom(isym,ap.first), symm.get_rotated_atom(isym,ap.second) }; + // if (ap_set.find(rotpair) != ap_set.end()) + // { + // ap_star.insert({ this->invmap_[isym], rotpair }); + // ap_set.erase(rotpair); + // } + // } + // this->atompair_stars_.push_back(ap_star); + // } + // } + + // inline void output_atompair_stars(const std::vector>& ap_stars) + // { + // std::cout << "stars of irreducible atom pairs: " << std::endl; + // for (int ip = 0; ip < ap_stars.size(); ++ip) + // { + // std::cout << "atom pair star " << ip << ": " << std::endl; + // for (const auto& ap : ap_stars[ip]) + // std::cout << "isym=" << ap.first << ", atompair=(" << ap.second.first << ", " << ap.second.second << ") " << std::endl; + // } + // } + + // void Symmetry_rotation::test_irreducible_atom_pairs(const Symmetry& symm) + // { + // std::cout << "Algorithm 1: find irreducible atom pairs by set" << std::endl; + // this->find_irreducible_atom_pairs_set(symm); + // output_atompair_stars(this->atompair_stars_); + + // std::cout << std::endl; + // this->atompair_stars_.clear(); + // std::cout << "Algorithm 2: find irreducible atom pairs by judge" << std::endl; + // this->find_irreducible_atom_pairs(symm); + // output_atompair_stars(this->atompair_stars_); + // } std::vector Symmetry_rotation::get_Rs_from_BvK(const K_Vectors& kv) const { @@ -193,7 +196,7 @@ namespace ModuleSymmetry this->sector_stars_.clear(); if (this->return_lattice_.empty()) this->get_return_lattice_all(symm, atoms, st); - if (this->atompair_stars_.empty()) this->find_irreducible_atom_pairs(symm); + // if (this->atompair_stars_.empty()) this->find_irreducible_atom_pairs(symm); // contruct {atom pair, R} set // constider different number of Rs for different atom pairs later. @@ -204,18 +207,21 @@ namespace ModuleSymmetry apR_all[{iat1, iat2}].insert(R); // get invmap - std::vector invmap(symm.nrotk, -1); - symm.gmatrix_invmap(symm.gmatrix, symm.nrotk, invmap.data()); + if (this->invmap_.empty()) + { + this->invmap_.resize(symm.nrotk); + symm.gmatrix_invmap(symm.gmatrix, symm.nrotk, invmap_.data()); + } while (!apR_all.empty()) { - const Tap& irap = apR_all.begin()->first; + const Tap irap = apR_all.begin()->first; const TC irR = *apR_all[irap].begin(); const TapR& irapR = { irap, irR }; std::map sector_star; for (int isym = 0;isym < symm.nrotk;++isym) { - const TapR& apRrot = this->rotate_R_by_formula(symm, invmap[isym], irapR); + const TapR& apRrot = this->rotate_R_by_formula(symm, this->invmap_[isym], irapR); const Tap& aprot = apRrot.first; const TC& Rrot = apRrot.second; if (apR_all.count(aprot) && apR_all.at(aprot).count(Rrot)) diff --git a/source/module_ri/symmetry_rotation.cpp b/source/module_ri/symmetry_rotation.cpp index c1375b8396..2d187fb3f1 100644 --- a/source/module_ri/symmetry_rotation.cpp +++ b/source/module_ri/symmetry_rotation.cpp @@ -18,7 +18,11 @@ namespace ModuleSymmetry this->nsym_ = ucell.symm.nrotk; this->eps_ = ucell.symm.epsilon; - + if (this->invmap_.empty()) + { + this->invmap_.resize(ucell.symm.nrotk); + ucell.symm.gmatrix_invmap(ucell.symm.gmatrix, ucell.symm.nrotk, invmap_.data()); + } // 1. calculate the rotation matrix in real spherical harmonics representation for each symmetry operation: [T_l (isym)]_mm' std::vector gmatc(nsym_); for (int i = 0;i < nsym_;++i) gmatc[i] = this->direct_to_cartesian(ucell.symm.gmatrix[i], ucell.latvec); @@ -371,30 +375,32 @@ namespace ModuleSymmetry output_return_lattice(this->return_lattice_); } - void Symmetry_rotation::set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, std::vector>& obj_mat, const Parallel_2D& pv) const + void Symmetry_rotation::set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, + std::vector>& obj_mat, const Parallel_2D& pv, const bool trans) const { // caution: ComplaxMatrix is row-major(col-continuous), but obj_mat is col-major(row-continuous) for (int j = 0;j < block.nr;++j)//outside dimension for (int i = 0;i < block.nc;++i) //inside dimension if (pv.in_this_processor(starti + i, startj + j)) { int index = pv.global2local_col(startj + j) * pv.get_row_size() + pv.global2local_row(starti + i); - obj_mat[index] = block(j, i); + obj_mat[index] = trans ? block(i, j) : block(j, i); } } - void Symmetry_rotation::set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, std::vector& obj_mat, const Parallel_2D& pv) const + void Symmetry_rotation::set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, + std::vector& obj_mat, const Parallel_2D& pv, const bool trans) const { // caution: ComplaxMatrix is row-major(col-continuous), but obj_mat is col-major(row-continuous) for (int j = 0;j < block.nr;++j)//outside dimension for (int i = 0;i < block.nc;++i) //inside dimension if (pv.in_this_processor(starti + i, startj + j)) { int index = pv.global2local_col(startj + j) * pv.get_row_size() + pv.global2local_row(starti + i); - obj_mat[index] = block(j, i).real(); + obj_mat[index] = trans ? block(i, j).real() : block(j, i).real(); } } // 2d-block parallized rotation matrix in AO-representation, denoted as M. - // finally we will use D(k)=M(R, k)^\dagger*D(Rk)*M(R, k) to recover D(k) from D(Rk) in cal_Ms. + // finally we will use D(k)=M(R, k)^\dagger*D(Rk)*M(R, k) to D(k) from D(Rk) in cal_Ms. std::vector> Symmetry_rotation::contruct_2d_rot_mat_ao(const Symmetry& symm, const Atom* atoms, const Statistics& cell_st, const TCdouble& kvec_d_ibz, int isym, const Parallel_2D& pv) const { @@ -406,7 +412,7 @@ namespace ModuleSymmetry int iat2 = symm.get_rotated_atom(isym, iat1); //iat2=rot(iat1) int ia2 = cell_st.iat2ia[iat2]; // cal phase factor from return lattice: exp(-ik_ibz*O) - double arg = 2 * ModuleBase::PI * kvec_d_ibz * this->return_lattice_[ia1][isym]; + double arg = 2 * ModuleBase::PI * kvec_d_ibz * this->return_lattice_[iat1][isym]; std::complexphase_factor = std::complex(std::cos(arg), std::sin(arg)); int iw1start = atoms[it].stapos_wf + ia1 * atoms[it].nw; int iw2start = atoms[it].stapos_wf + ia2 * atoms[it].nw; @@ -416,8 +422,8 @@ namespace ModuleSymmetry int l = atoms[it].iw2l[iw]; int nm = 2 * l + 1; //caution: the order of m in orbitals may be different from increasing - set_block_to_mat2d(iw1start + iw, iw2start + iw, - phase_factor * this->rotmat_Slm_[isym][l], M_isym, pv); + set_block_to_mat2d(iw2start + iw, iw1start + iw, + phase_factor * this->rotmat_Slm_[isym][l], M_isym, pv, true); iw += nm; } } @@ -426,7 +432,9 @@ namespace ModuleSymmetry // void cal_Ms (kstar), maybe use map to stare Ms - // D(k) = M^*(R, k) D(k_ibz) M^T(R, k) + // D(k) = M^T(R, k) D(k_ibz) M^*(R, k), if D(k) is col-maj + // D^T(k) = M^\dagger(R, k) D^T(k_ibz) M(R, k), if D(k) is row-maj + // Ds from RI_2D_Comm are row-maj // the link ik_ibz-isym-ik can be found in kstars. std::vector> Symmetry_rotation::rot_matrix_ao(const std::vector>& DMkibz, const int ik_ibz, const int kstar_size, const int isym, const Parallel_2D& pv, const bool TRS_conj) const @@ -440,38 +448,28 @@ namespace ModuleSymmetry const std::complex beta(0.0, 0.0); const int nbasis = GlobalV::NLOCAL; const int i1 = 1; - - // if TRS_conj, calculate [M^* D M^T]^* = [D^\dagger M^T]^T M^\dagger - // else, calculate M^* D M^T = [D^T M^\dagger]^T M^T - - // step 1 - pzgemm_(TRS_conj ? &dagger : &transpose, TRS_conj ? &transpose : &dagger, &nbasis, &nbasis, &nbasis, - &alpha, DMkibz.data(), &i1, &i1, pv.desc, this->Ms_[ik_ibz].at(isym).data(), &i1, &i1, pv.desc, - &beta, DMkibz_M.data(), &i1, &i1, pv.desc); - - //step 2 - alpha.real(1.0 / static_cast(kstar_size)); - pzgemm_(&transpose, TRS_conj ? &dagger : &transpose, &nbasis, &nbasis, &nbasis, - &alpha, DMkibz_M.data(), &i1, &i1, pv.desc, this->Ms_[ik_ibz].at(isym).data(), &i1, &i1, pv.desc, - &beta, DMk.data(), &i1, &i1, pv.desc); - - // but if we store D^*(=D^T, col-maj/row-inside), we sould calculate D^*(k) = M D^*(k_ibz) M^dagger - // step 1 - // if (TRS_conj) - // pzgemm_(&dagger, &dagger, &nbasis, &nbasis, &nbasis, - // &alpha, this->Ms_[ik_ibz].at(isym).data(), &i1, &i1, pv.desc, DMkibz.data(), &i1, &i1, pv.desc, - // &beta, DMkibz_M.data(), &i1, &i1, pv.desc); - // else - // pzgemm_(¬rans, ¬rans, &nbasis, &nbasis, &nbasis, - // &alpha, DMkibz.data(), &i1, &i1, pv.desc, this->Ms_[ik_ibz].at(isym).data(), &i1, &i1, pv.desc, - // &beta, DMkibz_M.data(), &i1, &i1, pv.desc); - - // //step 2 - // alpha.real(1.0 / static_cast(kstar_size)); - // pzgemm_(TRS_conj ? &transpose : &dagger, TRS_conj ? &transpose : ¬rans, &nbasis, &nbasis, &nbasis, - // &alpha, this->Ms_[ik_ibz].at(isym).data(), &i1, &i1, pv.desc, DMkibz_M.data(), &i1, &i1, pv.desc, - // &beta, DMk.data(), &i1, &i1, pv.desc); - + if (TRS_conj) + { + // D^T* = M^T [M^T (D^T)^T]^\dagger + pzgemm_(&transpose, &transpose, &nbasis, &nbasis, &nbasis, + &alpha, this->Ms_[ik_ibz].at(isym).data(), &i1, &i1, pv.desc, DMkibz.data(), &i1, &i1, pv.desc, + &beta, DMkibz_M.data(), &i1, &i1, pv.desc); + alpha.real(1.0 / static_cast(kstar_size)); + pzgemm_(&transpose, &dagger, &nbasis, &nbasis, &nbasis, + &alpha, this->Ms_[ik_ibz].at(isym).data(), &i1, &i1, pv.desc, DMkibz_M.data(), &i1, &i1, pv.desc, + &beta, DMk.data(), &i1, &i1, pv.desc); + } + else + { + // D^T = M^\daggger D^T M + pzgemm_(&dagger, ¬rans, &nbasis, &nbasis, &nbasis, + &alpha, this->Ms_[ik_ibz].at(isym).data(), &i1, &i1, pv.desc, DMkibz.data(), &i1, &i1, pv.desc, + &beta, DMkibz_M.data(), &i1, &i1, pv.desc); + alpha.real(1.0 / static_cast(kstar_size)); + pzgemm_(¬rans, ¬rans, &nbasis, &nbasis, &nbasis, + &alpha, DMkibz_M.data(), &i1, &i1, pv.desc, this->Ms_[ik_ibz].at(isym).data(), &i1, &i1, pv.desc, + &beta, DMk.data(), &i1, &i1, pv.desc); + } return DMk; } diff --git a/source/module_ri/symmetry_rotation.h b/source/module_ri/symmetry_rotation.h index 6bb3098733..2c63e61769 100644 --- a/source/module_ri/symmetry_rotation.h +++ b/source/module_ri/symmetry_rotation.h @@ -13,7 +13,7 @@ #include "module_hamilt_lcao/module_hcontainer/hcontainer.h" #include "module_cell/module_neighbor/sltk_grid_driver.h" // for test -#include "Exx_LRI.h" +// #include "Exx_LRI.h" namespace ModuleSymmetry { @@ -101,9 +101,12 @@ namespace ModuleSymmetry const TCdouble& posd_a1, const TCdouble& posd_a2)const; void get_return_lattice_all(const Symmetry& symm, const Atom* atoms, const Statistics& st); - /// set a block matrix onto a 2d-parallelized matrix, at the position (starti, startj) - void set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, std::vector>& obj_mat, const Parallel_2D& pv) const; - void set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, std::vector& obj_mat, const Parallel_2D& pv) const; + /// set a block matrix onto a 2d-parallelized matrix(col-maj), at the position (starti, startj) + /// if trans=true, the block matrix is transposed before setting + void set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, + std::vector>& obj_mat, const Parallel_2D& pv, const bool trans = false) const; + void set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, + std::vector& obj_mat, const Parallel_2D& pv, const bool trans = false) const; /// 2d-block parallized rotation matrix in AO-representation, denoted as M. /// finally we will use D(k)=M(R, k)^\dagger*D(Rk)*M(R, k) to recover D(k) from D(Rk). @@ -129,11 +132,11 @@ namespace ModuleSymmetry template // RI::Tensor type std::map, RI::Tensor>> restore_HR( const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, - const std::map, RI::Tensor>>& HR_irreduceble); + const std::map, RI::Tensor>>& HR_irreduceble)const; template // HContainer type void restore_HR( const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, - const hamilt::HContainer& HR_irreduceble, hamilt::HContainer& HR_rotated); + const hamilt::HContainer& HR_irreduceble, hamilt::HContainer& HR_rotated)const; //-------------------------------------------------------------------------------- /// test functions @@ -145,13 +148,7 @@ namespace ModuleSymmetry void test_HR_rotation(const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, const hamilt::HContainer& HR_full); template // HContainer type - void print_HR(const std::map, RI::Tensor>>& HR, const std::string name); - - // check whether Ds can be reduced in cal_Hs - template - void test_sector_equivalence_in_cal_Hs(const TapR& iapR_test, - const std::vector, RI::Tensor>>>& Ds_full, - Exx_LRI& exx_lri, const Parallel_Orbitals& pv); + void print_HR(const std::map, RI::Tensor>>& HR, const std::string name);; //-------------------------------------------------------------------------------- private: @@ -168,13 +165,13 @@ namespace ModuleSymmetry TCdouble get_aRb_direct(const Atom* atoms, const Statistics& st, const int iat1, const int iat2, const TC& R, const char gauge = 'R')const; TCdouble get_aRb_direct(const Atom* atoms, const Statistics& st, const int iat1, const int iat2, const TCdouble& R, const char gauge = 'R')const; - /// find the irreducible atom pairs - /// algorithm 1: the way finding irreducible k-points - void find_irreducible_atom_pairs(const Symmetry& symm); - /// algorithm 2: taking out atom pairs from the initial set - void find_irreducible_atom_pairs_set(const Symmetry& symm); - /// double check between the two algorithms - void test_irreducible_atom_pairs(const Symmetry& symm); + // /// find the irreducible atom pairs + // /// algorithm 1: the way finding irreducible k-points + // void find_irreducible_atom_pairs(const Symmetry& symm); + // /// algorithm 2: taking out atom pairs from the initial set + // void find_irreducible_atom_pairs_set(const Symmetry& symm); + // /// double check between the two algorithms + // void test_irreducible_atom_pairs(const Symmetry& symm); void output_full_map_to_irreducible_sector(const int nat); void output_sector_star(); @@ -186,10 +183,10 @@ namespace ModuleSymmetry /// mode='D': D_12(R)=T^T(V)D_1'2'(VR+O_1-O_2)T^*(V) template // RI::Tensor type, blas RI::Tensor rotate_atompair_serial(const RI::Tensor& t, const int isym, - const Atom& a1, const Atom& a2, const char mode, bool output = false); + const Atom& a1, const Atom& a2, const char mode, bool output = false)const; template // HContainer type, pblas void rotate_atompair_parallel(const TR* Alocal_in, const int isym, const Atom* atoms, const Statistics& st, - const Tap& ap_in, const Tap& ap_out, const char mode, const Parallel_Orbitals& pv, TR* Alocal_out, const bool output = false); + const Tap& ap_in, const Tap& ap_out, const char mode, const Parallel_Orbitals& pv, TR* Alocal_out, const bool output = false)const; //-------------------------------------------------------------------------------- @@ -210,7 +207,7 @@ namespace ModuleSymmetry /// irreducible sector /// irreducible atom pairs: [n_iap][(isym, ap=(iat1, iat2))] - std::vector> atompair_stars_; + // std::vector> atompair_stars_; ///The index range of the orbital matrix to be calculated: irreducible R in irreducible atom pairs // (including R in other atom pairs that cannot rotate into R_stars_[irreducebule_ap]) @@ -227,6 +224,8 @@ namespace ModuleSymmetry /// the direct lattice vector of {R|t}\tau-\tau' for each atoms and each symmetry operation. [natom][nsym] std::vector> return_lattice_; + + std::vector invmap_; }; } diff --git a/source/module_ri/symmetry_rotation_R.hpp b/source/module_ri/symmetry_rotation_R.hpp index a27032630a..8d0364da12 100644 --- a/source/module_ri/symmetry_rotation_R.hpp +++ b/source/module_ri/symmetry_rotation_R.hpp @@ -1,6 +1,7 @@ #include "symmetry_rotation.h" #include "module_ri/RI_Util.h" #include "module_base/blas_connector.h" +#include "module_base/timer.h" #include #include @@ -9,11 +10,12 @@ namespace ModuleSymmetry template std::map, RI::Tensor>> Symmetry_rotation::restore_HR( const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, - const std::map, RI::Tensor>>& HR_irreduceble) + const std::map, RI::Tensor>>& HR_irreduceble) const { ModuleBase::TITLE("Symmetry_rotation", "restore_HR"); + ModuleBase::timer::tick("Symmetry_rotation", "restore_HR"); std::map, RI::Tensor>> HR_full; - + // openmp slows down this for loop, why? for (auto& apR_isym_irapR : this->full_map_to_irreducible_sector_) { const Tap& ap = apR_isym_irapR.first.first; @@ -29,6 +31,7 @@ namespace ModuleSymmetry else std::cout << "not found: current atom pair =(" << ap.first << "," << ap.second << "), R=(" << R[0] << "," << R[1] << "," << R[2] << "), irreducible atom pair =(" << irap.first << "," << irap.second << "), irR=(" << irR[0] << "," << irR[1] << "," << irR[2] << ")\n"; } + ModuleBase::timer::tick("Symmetry_rotation", "restore_HR"); return HR_full; } @@ -46,7 +49,7 @@ namespace ModuleSymmetry template RI::Tensor Symmetry_rotation::rotate_atompair_serial(const RI::Tensor& A, const int isym, - const Atom& a1, const Atom& a2, const char mode, const bool output) + const Atom& a1, const Atom& a2, const char mode, const bool output)const { // due to col-contiguous, actually what we know is T^T and H^T (or D^T), // and what we calculate is(H'^T = T ^ T * H ^ T * T^*) or (D'^T = T ^ \dagger * D ^ T * T) auto set_block = [](const int starti, const int startj, const ModuleBase::ComplexMatrix& block, @@ -88,6 +91,12 @@ namespace ModuleSymmetry { // H'^T = T2^T * H^T * T1^* zgemm_(¬rans, ¬rans, &a2.nw, &a1.nw, &a2.nw, &alpha, T2.ptr(), &a2.nw, A_complex.ptr(), &a2.nw, &beta, AT2.ptr(), &a2.nw); zgemm_(¬rans, &dagger, &a2.nw, &a1.nw, &a1.nw, &alpha, AT2.ptr(), &a2.nw, T1.ptr(), &a1.nw, &beta, TAT.ptr(), &a2.nw); + // row-maj version + // BlasConnector::gemm(notrans, notrans, a1.nw, a2.nw, a2.nw, + // alpha, A_complex.ptr(), a2.nw, T2.ptr(), a2.nw, beta, AT2.ptr(), a2.nw); + // BlasConnector::gemm(dagger, notrans, a1.nw, a2.nw, a1.nw, + // alpha, T1.ptr(), a1.nw, AT2.ptr(), a2.nw, beta, TAT.ptr(), a2.nw); + } else if (mode == 'D') { //T2^\dagger * D^T * T1 = [(D^T)^T * (T2^T)^\dagger]^T * (T1^T)^T @@ -168,99 +177,4 @@ namespace ModuleSymmetry } } - template - void Symmetry_rotation::test_sector_equivalence_in_cal_Hs(const TapR& apR_test, - const std::vector, RI::Tensor>>>& Ds_full, - Exx_LRI& exx_lri, const Parallel_Orbitals& pv) - { - // 1. pick out D(R) on one of the irreducible {abR}s from full D(R) - std::vector, RI::Tensor>>> Ds_one_in_sector = Ds_full; - for (auto& a1_a2R_tensor : Ds_one_in_sector[0]) - { - const int& iat1 = a1_a2R_tensor.first; - for (auto& a2R_tensor : a1_a2R_tensor.second) - { - const int& iat2 = a2R_tensor.first.first; - const TC& R = a2R_tensor.first.second; - const TapR& apR = { {iat1, iat2}, R }; - if (apR.first == apR_test.first && apR.second == apR_test.second) - a2R_tensor.second = Ds_full[0].at(iat1).at({ iat2, R }); - else - a2R_tensor.second = RI::Tensor(a2R_tensor.second.shape); - } - } - exx_lri.cal_exx_elec(Ds_one_in_sector, pv); - const std::vector, RI::Tensor>>> Hexxs_one_in_sector = exx_lri.get_Hexxs(); - - - //2. pick out D(R) on the whole sector star of the tested irreducible {abR} - TapR irapR_test = this->full_map_to_irreducible_sector_.at(apR_test).second; - std::vector, RI::Tensor>>> Ds_sector_star = Ds_full; - for (auto& a1_a2R_tensor : Ds_sector_star[0]) - { - const int& iat1 = a1_a2R_tensor.first; - for (auto& a2R_tensor : a1_a2R_tensor.second) - { - const int& iat2 = a2R_tensor.first.first; - const TC& R = a2R_tensor.first.second; - const TapR& apR = { {iat1, iat2}, R }; - const TapR& irapR = this->full_map_to_irreducible_sector_.at(apR).second; - if (irapR.first == irapR_test.first && irapR.second == irapR_test.second) - a2R_tensor.second = Ds_full[0].at(iat1).at({ iat2, R }); - else - a2R_tensor.second = RI::Tensor(a2R_tensor.second.shape); - } - } - exx_lri.cal_exx_elec(Ds_sector_star, pv); - const std::vector, RI::Tensor>>> Hexxs_sector_star = exx_lri.get_Hexxs(); - - // test: output Ds - std::cout << "Ds_one_in_sector[0].size(): " << Ds_one_in_sector[0].size() << std::endl; - for (auto& a1_a2R_tensor : Ds_one_in_sector[0]) - { - const int& iat1 = a1_a2R_tensor.first; - for (auto& a2R_tensor : a1_a2R_tensor.second) - { - const int& iat2 = a2R_tensor.first.first; - const TC& R = a2R_tensor.first.second; - std::cout << "atom pair (" << iat1 << ", " << iat2 << "), R=(" << R[0] << "," << R[1] << "," << R[2] << "):\n"; - const RI::Tensor& Ds_one = a2R_tensor.second; - const RI::Tensor& Ds_star = Ds_sector_star[0].at(iat1).at({ iat2, R }); - print_tensor(Ds_one, "Ds_one"); - print_tensor(Ds_star, "Ds_star"); - } - } - - // 3. compare - // get sector star size - auto get_star_size = [this](const TapR& apR_test)->int - { - for (auto& ss : this->sector_stars_) - { - const TapR& star_apR = ss.begin()->second; - const TapR& star_irapR = this->full_map_to_irreducible_sector_.at(star_apR).second; - if (star_apR.first == apR_test.first && star_apR.second == apR_test.second) - return ss.size(); - } - return 0; - }; - - const int starsize = get_star_size(apR_test); - std::cout << "star size of tested apR: " << starsize << std::endl; - std::cout << "Hexxs_one_in_sector[0].size(): " << Hexxs_one_in_sector[0].size() << std::endl; - for (auto& a1_a2R_tensor : Hexxs_one_in_sector[0]) - { - const int& iat1 = a1_a2R_tensor.first; - for (auto& a2R_tensor : a1_a2R_tensor.second) - { - const int& iat2 = a2R_tensor.first.first; - const TC& R = a2R_tensor.first.second; - std::cout << "atom pair (" << iat1 << ", " << iat2 << "), R=(" << R[0] << "," << R[1] << "," << R[2] << "):\n"; - const RI::Tensor& Hexxs_one = a2R_tensor.second; - const RI::Tensor& Hexxs_star = Hexxs_sector_star[0].at(iat1).at({ iat2, R }); - print_tensor(Hexxs_one * RI::Global_Func::convert(static_cast(starsize)), "Hexxs_one* starsize"); - print_tensor(Hexxs_star, "Hexxs_star"); - } - } - } } \ No newline at end of file diff --git a/source/module_ri/symmetry_rotation_R_hcontainer.hpp b/source/module_ri/symmetry_rotation_R_hcontainer.hpp index 8e4a6d4fed..781cd7959d 100644 --- a/source/module_ri/symmetry_rotation_R_hcontainer.hpp +++ b/source/module_ri/symmetry_rotation_R_hcontainer.hpp @@ -38,9 +38,10 @@ namespace ModuleSymmetry void Symmetry_rotation::restore_HR( const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, const hamilt::HContainer& HR_irreduceble, - hamilt::HContainer& HR_rotated) + hamilt::HContainer& HR_rotated)const { ModuleBase::TITLE("Symmetry_rotation", "restore_HR"); + ModuleBase::timer::tick("Symmetry_rotation", "restore_HR"); for (auto& apR_isym_irapR : this->full_map_to_irreducible_sector_) { const Tap& ap = apR_isym_irapR.first.first; @@ -60,7 +61,7 @@ namespace ModuleSymmetry TR* ijR_ptr = ap_hc.get_pointer(R_hc); rotate_atompair_parallel(irijR_ptr, isym, atoms, st, irap, ap, mode, *irap_hc.get_paraV(), ijR_ptr); } - + ModuleBase::timer::tick("Symmetry_rotation", "restore_HR"); } inline void set_block(const int starti, const int startj, const int nr, const ModuleBase::ComplexMatrix& block, double* obj) @@ -77,7 +78,7 @@ namespace ModuleSymmetry }; template void Symmetry_rotation::rotate_atompair_parallel(const TR* Alocal_in, const int isym, const Atom* atoms, const Statistics& st, - const Tap& ap_in, const Tap& ap_out, const char mode, const Parallel_Orbitals& pv, TR* Alocal_out, const bool output) + const Tap& ap_in, const Tap& ap_out, const char mode, const Parallel_Orbitals& pv, TR* Alocal_out, const bool output)const { // all the matrices are row-major (col-contiguous) int iat1 = ap_in.first, iat2 = ap_in.second; From eda1358b03170a809ea6c076a362c94d8c9d93db Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Mon, 11 Mar 2024 15:59:27 +0800 Subject: [PATCH 09/19] refactor ModuleSymmetry --- .../module_cell/module_symmetry/symmetry.cpp | 46 ++++++------ source/module_cell/module_symmetry/symmetry.h | 15 ++-- .../module_symmetry/symmetry_basic.cpp | 75 +++++++++---------- .../module_symmetry/symmetry_basic.h | 11 ++- 4 files changed, 73 insertions(+), 74 deletions(-) diff --git a/source/module_cell/module_symmetry/symmetry.cpp b/source/module_cell/module_symmetry/symmetry.cpp index 745410cdb7..67ce48ef59 100644 --- a/source/module_cell/module_symmetry/symmetry.cpp +++ b/source/module_cell/module_symmetry/symmetry.cpp @@ -153,7 +153,8 @@ void Symmetry::analy_sys(const Lattice& lat, const Statistics& st, Atom* atoms, this->itmin_start = istart[it]; } } - this->getgroup(nrot_out, nrotk_out, ofs_running, pos_spinup.data()); + this->getgroup(nrot_out, nrotk_out, ofs_running, this->nop, this->symop, this->gmatrix, this->gtrans, + pos_spinup.data(), this->rotpos, this->index, this->itmin_type, this->itmin_start, this->istart, this->na); // recover na and istart for (int it = 0;it < ntype;++it) { @@ -164,11 +165,14 @@ void Symmetry::analy_sys(const Lattice& lat, const Statistics& st, Atom* atoms, } // For AFM analysis End //------------------------------------------------------------ - } else { + } + else + { // get the real symmetry operations according to the input structure // nrot_out: the number of pure point group rotations // nrotk_out: the number of all space group operations - this->getgroup(nrot_out, nrotk_out, ofs_running, this->newpos); + this->getgroup(nrot_out, nrotk_out, ofs_running, this->nop, this->symop, this->gmatrix, this->gtrans, + this->newpos, this->rotpos, this->index, this->itmin_type, this->itmin_start, this->istart, this->na); } }; @@ -287,16 +291,16 @@ void Symmetry::analy_sys(const Lattice& lat, const Statistics& st, Atom* atoms, // 3. output to running.log //---------------------------------- // output the point group - this->pointgroup(this->nrot, this->pgnumber, this->pgname, this->gmatrix, ofs_running); + bool valid_group = this->pointgroup(this->nrot, this->pgnumber, this->pgname, this->gmatrix, ofs_running); ModuleBase::GlobalFunc::OUT(ofs_running,"POINT GROUP", this->pgname); // output the space group - this->pointgroup(this->nrotk, this->spgnumber, this->spgname, this->gmatrix, ofs_running); + valid_group = this->pointgroup(this->nrotk, this->spgnumber, this->spgname, this->gmatrix, ofs_running); ModuleBase::GlobalFunc::OUT(ofs_running, "POINT GROUP IN SPACE GROUP", this->spgname); //----------------------------- // 4. For the case where point group is not complete due to symmetry_prec //----------------------------- - if (!this->valid_group) + if (!valid_group) { // select the operations that have the inverse std::vectorinvmap(this->nrotk, -1); this->gmatrix_invmap(this->gmatrix, this->nrotk, invmap.data()); @@ -881,7 +885,9 @@ void Symmetry::lattice_type( } -void Symmetry::getgroup(int& nrot, int& nrotk, std::ofstream& ofs_running, double* pos) +void Symmetry::getgroup(int& nrot, int& nrotk, std::ofstream& ofs_running, const int& nop, + const ModuleBase::Matrix3* symop, ModuleBase::Matrix3* gmatrix, ModuleBase::Vector3* gtrans, + double* pos, double* rotpos, int* index, int itmin_type, int itmin_start, int* istart, int* na)const { ModuleBase::TITLE("Symmetry", "getgroup"); @@ -905,9 +911,7 @@ void Symmetry::getgroup(int& nrot, int& nrotk, std::ofstream& ofs_running, doubl //std::cout << "nop = " <checksym(this->symop[i], this->gtrans[i], pos); - // std::cout << "s_flag =" <checksym(this->symop[i], this->gtrans[i], pos, rotpos, index, itmin_type, itmin_start, istart, na); if (s_flag == 1) { //------------------------------ @@ -985,7 +989,8 @@ void Symmetry::getgroup(int& nrot, int& nrotk, std::ofstream& ofs_running, doubl return; } -void Symmetry::checksym(ModuleBase::Matrix3 &s, ModuleBase::Vector3 >rans, double* pos) +bool Symmetry::checksym(const ModuleBase::Matrix3& s, ModuleBase::Vector3& gtrans, + double* pos, double* rotpos, int* index, int itmin_type, int itmin_start, int* istart, int* na)const { //---------------------------------------------- // checks whether a point group symmetry element @@ -994,7 +999,7 @@ void Symmetry::checksym(ModuleBase::Matrix3 &s, ModuleBase::Vector3 >r // the start atom index. bool no_diff = false; ModuleBase::Vector3 trans(2.0, 2.0, 2.0); - s_flag = 0; + bool s_flag = 0; for (int it = 0; it < ntype; it++) { @@ -1049,9 +1054,9 @@ void Symmetry::checksym(ModuleBase::Matrix3 &s, ModuleBase::Vector3 >r //--------------------------------------------------------- // itmin_start = the start atom positions of species itmin //--------------------------------------------------------- - sptmin.x = rotpos[itmin_start*3]; - sptmin.y = rotpos[itmin_start*3+1]; - sptmin.z = rotpos[itmin_start*3+2]; + // (s)tart (p)osition of atom (t)ype which has (min)inal number. + ModuleBase::Vector3 sptmin(pos[itmin_start * 3], pos[itmin_start * 3 + 1], pos[itmin_start * 3 + 2]); + for (int i = itmin_start; i < itmin_start + na[itmin_type]; ++i) { //set up the current test std::vector "gtrans" @@ -1141,13 +1146,12 @@ void Symmetry::checksym(ModuleBase::Matrix3 &s, ModuleBase::Vector3 >r gtrans.y = trans.y; gtrans.z = trans.z; } - return; + return s_flag; } void Symmetry::pricell(double* pos, const Atom* atoms) { bool no_diff = false; - s_flag = 0; ptrans.clear(); for (int it = 0; it < ntype; it++) @@ -1182,10 +1186,10 @@ void Symmetry::pricell(double* pos, const Atom* atoms) //--------------------------------------------------------- // itmin_start = the start atom positions of species itmin - //--------------------------------------------------------- - sptmin.x = pos[itmin_start*3]; - sptmin.y = pos[itmin_start*3+1]; - sptmin.z = pos[itmin_start*3+2]; + //--------------------------------------------------------- + // (s)tart (p)osition of atom (t)ype which has (min)inal number. + ModuleBase::Vector3 sptmin(pos[itmin_start * 3], pos[itmin_start * 3 + 1], pos[itmin_start * 3 + 2]); + for (int i = itmin_start; i < itmin_start + na[itmin_type]; ++i) { //set up the current test std::vector "gtrans" diff --git a/source/module_cell/module_symmetry/symmetry.h b/source/module_cell/module_symmetry/symmetry.h index f0552d9a74..885fa73e07 100644 --- a/source/module_cell/module_symmetry/symmetry.h +++ b/source/module_cell/module_symmetry/symmetry.h @@ -68,8 +68,7 @@ class Symmetry : public Symmetry_Basic ModuleBase::Vector3 gtrans[48]; ModuleBase::Matrix3 symop[48]; //the rotation matrices for the pure bravais lattice - int nop; //the number of point group operations of the pure bravais lattice without basis - int s_flag; //whether the current matrix is one of all space group operations + int nop; //the number of point group operations of the pure bravais lattice without basis int nrot; //the number of pure point group rotations int nrotk = -1; //the number of all space group operations, >0 means the nrotk has been analyzed int max_nrotk = -1; ///< record the maximum number of symmetry operations during cell-relax @@ -90,8 +89,11 @@ class Symmetry : public Symmetry_Basic double* cel_const, double* pre_const, int& real_brav, std::string& bravname, const Atom* atoms, bool convert_atoms, double* newpos = nullptr)const; - void getgroup(int& nrot, int& nrotk, std::ofstream& ofs_running, double* pos); - void checksym(ModuleBase::Matrix3& s, ModuleBase::Vector3& gtrans, double* pos); + void getgroup(int& nrot, int& nrotk, std::ofstream& ofs_running, const int& nop, + const ModuleBase::Matrix3* symop, ModuleBase::Matrix3* gmatrix, ModuleBase::Vector3* gtrans, + double* pos, double* rotpos, int* index, int itmin_type, int itmin_start, int* istart, int* na)const; + bool checksym(const ModuleBase::Matrix3& s, ModuleBase::Vector3& gtrans, + double* pos, double* rotpos, int* index, int itmin_type, int itmin_start, int* istart, int* na)const; /// @brief primitive cell analysis void pricell(double* pos, const Atom* atoms); @@ -125,14 +127,9 @@ class Symmetry : public Symmetry_Basic } private: - // (s)tart (p)osition of atom (t)ype which - // has (min)inal number. - ModuleBase::Vector3 sptmin; - /// atom-map for each symmetry operation: isym_rotiat[isym][iat]=rotiat std::vector> isym_rotiat_; - /// @brief set atom map for each symmetry operation void set_atom_map(const Atom* atoms); /// @brief check if all the atoms are movable diff --git a/source/module_cell/module_symmetry/symmetry_basic.cpp b/source/module_cell/module_symmetry/symmetry_basic.cpp index b9ba19d08b..52abe8ba10 100644 --- a/source/module_cell/module_symmetry/symmetry_basic.cpp +++ b/source/module_cell/module_symmetry/symmetry_basic.cpp @@ -50,7 +50,7 @@ void Symmetry_Basic::check_boundary(double &x)const return; } -double Symmetry_Basic::get_translation_vector(const double &x1, const double &x2) +double Symmetry_Basic::get_translation_vector(const double& x1, const double& x2) const { double t=0.0; // "t"ranslation t = x2 - x1; @@ -67,7 +67,7 @@ void Symmetry_Basic::check_translation(double &x, const double &t) const return; } -double Symmetry_Basic::check_diff(const double &x1, const double &x2) +double Symmetry_Basic::check_diff(const double& x1, const double& x2)const { double diff = x1 - x2; diff = fmod(diff + 100,1); @@ -655,7 +655,7 @@ void Symmetry_Basic::setgroup(ModuleBase::Matrix3* symop, int &nop, const int &i } int Symmetry_Basic::subgroup(const int& nrot, const int& ninv, const int& nc2, const int& nc3, const int& nc4, const int& nc6, - const int& ns1, const int& ns3, const int& ns4, const int& ns6) + const int& ns1, const int& ns3, const int& ns4, const int& ns6)const { if (nrot > 24) { @@ -731,7 +731,7 @@ int Symmetry_Basic::subgroup(const int& nrot, const int& ninv, const int& nc2, c } return 1;//C_1 } -void Symmetry_Basic::pointgroup(const int& nrot, int& pgnumber, std::string& pgname, const ModuleBase::Matrix3* gmatrix, std::ofstream& ofs_running) +bool Symmetry_Basic::pointgroup(const int& nrot, int& pgnumber, std::string& pgname, const ModuleBase::Matrix3* gmatrix, std::ofstream& ofs_running)const { //------------------------------------------------------------------------- //return the name of the point group @@ -757,25 +757,25 @@ void Symmetry_Basic::pointgroup(const int& nrot, int& pgnumber, std::string& pgn { pgnumber = 1; pgname="C_1"; - return; + return true; } if(nrot == 3) { pgnumber = 9; pgname="C_3"; - return; + return true; } if(nrot == 16) { pgnumber = 20; pgname="D_4h"; - return; + return true; } if(nrot == 48) { pgnumber = 32; pgname="O_h"; - return; + return true; } //------------------------------------------------------------------------------- @@ -853,19 +853,19 @@ void Symmetry_Basic::pointgroup(const int& nrot, int& pgnumber, std::string& pgn { pgnumber = 2; pgname="S_2"; - return; + return true; } if(nc2 == 1) { pgnumber = 3; pgname="C_2"; - return; + return true; } if(ns1 == 1) { pgnumber = 4; pgname="C_1h"; - return; + return true; } } if(nrot == 4) @@ -874,31 +874,31 @@ void Symmetry_Basic::pointgroup(const int& nrot, int& pgnumber, std::string& pgn { pgnumber = 5; pgname="C_2h"; - return; + return true; } if(nc2 == 3) { pgnumber = 6; pgname="D_2"; - return; + return true; } if(ns1 == 2) { pgnumber = 7; pgname="C_2v"; - return; + return true; } if(nc4 == 2) { pgnumber = 14; pgname="C_4"; - return; + return true; } if(ns4 == 2) { pgnumber = 15; pgname="S_4"; - return; + return true; } } if(nrot == 6) @@ -907,31 +907,31 @@ void Symmetry_Basic::pointgroup(const int& nrot, int& pgnumber, std::string& pgn { pgnumber = 10; pgname="S_6"; - return; + return true; } if(nc2 == 3) { pgnumber = 11; pgname="D_3"; - return; + return true; } if(ns1 == 3) { pgnumber = 12; pgname="C_3v"; - return; + return true; } if(nc2 == 1) { pgnumber = 21; pgname="C_6"; - return; + return true; } if(ns1 == 1) { pgnumber = 22; pgname="C_3h"; - return; + return true; } } if(nrot == 8) @@ -940,31 +940,31 @@ void Symmetry_Basic::pointgroup(const int& nrot, int& pgnumber, std::string& pgn { pgnumber = 8; pgname="D_2h"; - return; + return true; } if(ns1 == 1) { pgnumber = 16; pgname="C_4h"; - return; + return true; } if(ns1 == 0) { pgnumber = 17; pgname="D_4"; - return; + return true; } if(ns1 == 4) { pgnumber = 18; pgname="C_4v"; - return; + return true; } if(ns1 == 2) { pgnumber = 19; pgname="D_2d"; - return; + return true; } } if(nrot == 12) @@ -973,37 +973,37 @@ void Symmetry_Basic::pointgroup(const int& nrot, int& pgnumber, std::string& pgn { pgnumber = 13; pgname="D_3d"; - return; + return true; } if(ns1 == 1) { pgnumber = 23; pgname="C_6h"; - return; + return true; } if(nc2 == 7) { pgnumber = 24; pgname="D_6"; - return; + return true; } if(ns1 == 6) { pgnumber = 25; pgname="C_6v"; - return; + return true; } if(ns1 == 4) { pgnumber = 26; pgname="D_3h"; - return; + return true; } if(nc3 == 8) { pgnumber = 28; pgname="T"; - return; + return true; } } if(nrot == 24) @@ -1012,33 +1012,32 @@ void Symmetry_Basic::pointgroup(const int& nrot, int& pgnumber, std::string& pgn { pgnumber = 27; pgname="D_6h"; - return; + return true; } if(ninv == 1) { pgnumber = 29; pgname="T_h"; - return; + return true; } if(nc4 == 6) { pgnumber = 30; pgname="O"; - return; + return true; } if(ns4 == 6) { pgnumber = 31; pgname="T_d"; - return; + return true; } } GlobalV::ofs_running << "\n WARNING: Symmetry operations cannot completely constitute a point group.\n\ It'll be better to try another `symmetry_prec`.\n Now search the subgroups ..." << std::endl; pgnumber = this->subgroup(nrot, ninv, nc2, nc3, nc4, nc6, ns1, ns3, ns4, ns6); pgname = pgdict[pgnumber]; - this->valid_group = false; - return; + return false; } diff --git a/source/module_cell/module_symmetry/symmetry_basic.h b/source/module_cell/module_symmetry/symmetry_basic.h index de5575cccd..5a2a5bf567 100644 --- a/source/module_cell/module_symmetry/symmetry_basic.h +++ b/source/module_cell/module_symmetry/symmetry_basic.h @@ -23,9 +23,9 @@ class Symmetry_Basic // control accuray bool equal(const double &m, const double &n)const; void check_boundary(double &x)const; - double get_translation_vector(const double &x1, const double &x2); + double get_translation_vector(const double& x1, const double& x2)const; void check_translation(double &x, const double &t) const; - double check_diff(const double &x1, const double &x2); + double check_diff(const double& x1, const double& x2) const; void veccon( double *va, @@ -48,12 +48,11 @@ class Symmetry_Basic /// find out the greatest subgrop according to the number of operations of certain type. /// used to deal with incomplete group due to a subtle`symmetry_prec` int subgroup(const int& nrot, const int& ninv, const int& nc2, const int& nc3, const int& nc4, const int& nc6, - const int& ns1, const int& ns3, const int& ns4, const int& ns6); + const int& ns1, const int& ns3, const int& ns4, const int& ns6)const; + bool pointgroup(const int& nrot, int& pgnumber, std::string& pgname, const ModuleBase::Matrix3* gmatrix, std::ofstream& ofs_running)const; protected: - bool valid_group = true; //whether the operators {gmatrix|gtrans} constitute a valid group - std::string get_brav_name(const int ibrav) const; - void pointgroup(const int &nrot,int &pgnumber,std::string &pgname, const ModuleBase::Matrix3* gmatrix, std::ofstream &ofs_running); + std::string get_brav_name(const int ibrav) const; void atom_ordering(double *posi, const int natom, int *subindex); void atom_ordering_new(double *posi, const int natom, int *subindex) const; From 97e71d8fc140df71d9ed3a0bac63ea2fce80fa5d Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Mon, 11 Mar 2024 16:08:31 +0800 Subject: [PATCH 10/19] analyze BvK supercell's symmetry --- source/module_ri/Exx_LRI_interface.hpp | 4 +- source/module_ri/RPA_LRI.hpp | 4 +- .../module_ri/symmetry_irreducible_sector.cpp | 19 ++- source/module_ri/symmetry_rotation.cpp | 155 +++++++++++++++++- source/module_ri/symmetry_rotation.h | 16 +- 5 files changed, 189 insertions(+), 9 deletions(-) diff --git a/source/module_ri/Exx_LRI_interface.hpp b/source/module_ri/Exx_LRI_interface.hpp index 3bfadb22a0..dcbc9cefe2 100644 --- a/source/module_ri/Exx_LRI_interface.hpp +++ b/source/module_ri/Exx_LRI_interface.hpp @@ -59,9 +59,11 @@ void Exx_LRI_Interface::exx_beforescf(const K_Vectors& kv, const Charg this->exx_spacegroup_symmetry = (GlobalV::NSPIN < 4 && ModuleSymmetry::Symmetry::symm_flag == 1); if (this->exx_spacegroup_symmetry) { + const std::array& period = RI_Util::get_Born_vonKarmen_period(kv); this->symrot_.get_return_lattice_all(ucell.symm, ucell.atoms, ucell.st); this->symrot_.cal_Ms(kv, ucell, pv); - this->symrot_.find_irreducible_sector(ucell.symm, ucell.atoms, ucell.st, this->symrot_.get_Rs_from_BvK(kv)); + this->symrot_.find_irreducible_sector(ucell.symm, ucell.atoms, ucell.st, + RI_Util::get_Born_von_Karmen_cells(period), period, ucell.lat); } } diff --git a/source/module_ri/RPA_LRI.hpp b/source/module_ri/RPA_LRI.hpp index f41854e9a5..e65412358c 100644 --- a/source/module_ri/RPA_LRI.hpp +++ b/source/module_ri/RPA_LRI.hpp @@ -105,7 +105,9 @@ void RPA_LRI::cal_postSCF_exx(const elecstate::DensityMatrix if (exx_spacegroup_symmetry) { - symrot.find_irreducible_sector(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, symrot.get_Rs_from_BvK(kv)); + const std::array period = RI_Util::get_Born_vonKarmen_period(kv); + symrot.find_irreducible_sector(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, + RI_Util::get_Born_von_Karmen_cells(period), period, GlobalC::ucell.lat); exx_lri_rpa.cal_exx_elec(Ds, *dm.get_paraV_pointer(), &symrot); } else diff --git a/source/module_ri/symmetry_irreducible_sector.cpp b/source/module_ri/symmetry_irreducible_sector.cpp index 5ad5da07a0..1039b689df 100644 --- a/source/module_ri/symmetry_irreducible_sector.cpp +++ b/source/module_ri/symmetry_irreducible_sector.cpp @@ -189,7 +189,7 @@ namespace ModuleSymmetry } } - void Symmetry_rotation::find_irreducible_sector(const Symmetry& symm, const Atom* atoms, const Statistics& st, const std::vector& Rs) + void Symmetry_rotation::find_irreducible_sector(const Symmetry& symm, const Atom* atoms, const Statistics& st, const std::vector& Rs, const TC& period, const Lattice& lat) { this->full_map_to_irreducible_sector_.clear(); this->irreducible_sector_.clear(); @@ -213,14 +213,29 @@ namespace ModuleSymmetry symm.gmatrix_invmap(symm.gmatrix, symm.nrotk, invmap_.data()); } + // get symmetry of BvK supercell + if (this->isymbvk_to_isym_.empty()) + this->gen_symmetry_BvK(symm, atoms, lat, st, period); + assert(!this->isymbvk_to_isym_.empty()); + // std::vector in_2d_plain; + // const bool judge_2d = (symm.real_brav == 4); + // if (judge_2d) in_2d_plain = this->in_plain(symm, lat.latvec); + while (!apR_all.empty()) { const Tap irap = apR_all.begin()->first; const TC irR = *apR_all[irap].begin(); const TapR& irapR = { irap, irR }; std::map sector_star; - for (int isym = 0;isym < symm.nrotk;++isym) + for (int isymbvk = 0;isymbvk < this->bvk_nsym_;++isymbvk) { + // if (judge_2d) + // { + // std::cout << "isym=" << isym << ", inv[isym]=" << invmap_[isym] << std::endl; + // assert(in_2d_plain[isym] == in_2d_plain[invmap_[isym]]); + // if (!in_2d_plain[isym]) continue; + // } + const int& isym = this->isymbvk_to_isym_[isymbvk]; const TapR& apRrot = this->rotate_R_by_formula(symm, this->invmap_[isym], irapR); const Tap& aprot = apRrot.first; const TC& Rrot = apRrot.second; diff --git a/source/module_ri/symmetry_rotation.cpp b/source/module_ri/symmetry_rotation.cpp index 2d187fb3f1..fa3d0e4746 100644 --- a/source/module_ri/symmetry_rotation.cpp +++ b/source/module_ri/symmetry_rotation.cpp @@ -4,6 +4,7 @@ #include "module_base/scalapack_connector.h" #include "module_base/tool_title.h" #include "module_base/timer.h" +#include "module_base/mathzone.h" #include "symmetry_rotation.h" #include "module_hamilt_pw/hamilt_pwdft/global.h" @@ -473,9 +474,161 @@ namespace ModuleSymmetry return DMk; } - ModuleBase::Matrix3 Symmetry_rotation::direct_to_cartesian(const ModuleBase::Matrix3& d, const ModuleBase::Matrix3& latvec) + ModuleBase::Matrix3 Symmetry_rotation::direct_to_cartesian(const ModuleBase::Matrix3& d, const ModuleBase::Matrix3& latvec)const { return latvec.Inverse() * d * latvec; } + std::vector inline get_isymbvk_to_isym_map(const std::vector& bvkgmat, const ModuleSymmetry::Symmetry& symm) + { + auto matequal = [&symm](ModuleBase::Matrix3 a, ModuleBase::Matrix3 b) + { + return (symm.equal(a.e11, b.e11) && symm.equal(a.e12, b.e12) && symm.equal(a.e13, b.e13) && + symm.equal(a.e21, b.e21) && symm.equal(a.e22, b.e22) && symm.equal(a.e23, b.e23) && + symm.equal(a.e31, b.e31) && symm.equal(a.e23, b.e23) && symm.equal(a.e33, b.e33)); + }; + std::vector isymbvk2isym(bvkgmat.size(), -1); + for (int isymbvk = 0;isymbvk < bvkgmat.size();++isymbvk) + { + for (int isym = 0;isym < symm.nrotk;++isym) + { + if (matequal(bvkgmat[isymbvk], symm.gmatrix[isym])) + { + isymbvk2isym[isymbvk] = isym; + break; + } + } + } + return isymbvk2isym; + } + + inline int gcd(const int a, const int b) + { + assert(a > 0 && b > 0); + int c = a % b; + return (c == 0) ? b : gcd(b, c); + } + void Symmetry_rotation::gen_symmetry_BvK(const ModuleSymmetry::Symmetry& symm, const Atom* atoms, const Lattice& lat, const Statistics& st, const TC bvk_period) + { + ModuleBase::TITLE("Symmetry_rotation", "gen_symmetry_BvK"); + auto set_matrix3 = [](const ModuleBase::Vector3& a1, const ModuleBase::Vector3& a2, const ModuleBase::Vector3& a3) + -> ModuleBase::Matrix3 {return ModuleBase::Matrix3(a1.x, a1.y, a1.z, a2.x, a2.y, a2.z, a3.x, a3.y, a3.z);}; + + if (bvk_period[0] == bvk_period[1] && bvk_period[0] == bvk_period[2]) + { //the BvK supercell has the same symmetry as the original cell + this->bvk_nsym_ = symm.nrotk; + this->isymbvk_to_isym_.resize(symm.nrotk); + for (int isym = 0;isym < symm.nrotk;++isym) this->isymbvk_to_isym_[isym] = isym; + return; + } + + // extern lattice to minimal BvK lattice, and set direct coordinates in min BvK lattice + int bvk_gcd = gcd(bvk_period[0], gcd(bvk_period[1], bvk_period[2])); + const TC bvk_min_period = TC({ bvk_period[0] / bvk_gcd, bvk_period[1] / bvk_gcd, bvk_period[2] / bvk_gcd }); + const int bvk_nat = st.nat * bvk_min_period[0] * bvk_min_period[1] * bvk_min_period[2]; + std::vector bvk_na(st.ntype); + std::vector bvk_istart(st.ntype, 0); + int bvk_itmin_start = 0, bvk_itmin_type = 0; + for (int it = 0;it < st.ntype;++it) + { + bvk_na[it] = atoms[it].na * bvk_min_period[0] * bvk_min_period[1] * bvk_min_period[2]; + if (it > 0) bvk_istart[it] = bvk_istart[it - 1] + bvk_na[it - 1]; + if (bvk_na[it] < bvk_na[bvk_itmin_type]) + { + bvk_itmin_type = it; + bvk_itmin_start = bvk_istart[it]; + } + } + + std::vector bvk_dpos(3 * bvk_nat); + std::vector bvk_rot_dpos(3 * bvk_nat); + std::vector order_index(bvk_nat + 2); + ModuleBase::Vector3 a1, a2, a3, s1, s2, s3; // a: to be optimized; s: original + s1 = a1 = lat.a1 * static_cast(bvk_min_period[0]); + s2 = a2 = lat.a2 * static_cast(bvk_min_period[1]); + s3 = a3 = lat.a3 * static_cast(bvk_min_period[2]); + ModuleBase::Matrix3 bvk_min_lat = set_matrix3(s1, s2, s3); + int at = 0; + for (int it = 0; it < st.ntype; ++it) + for (int c1 = 0;c1 < bvk_min_period[0];++c1) + for (int c2 = 0;c2 < bvk_min_period[1];++c2) + for (int c3 = 0;c3 < bvk_min_period[2];++c3) + for (int ia = 0; ia < atoms[it].na; ++ia) + { + bvk_dpos[3 * at] = (static_cast (c1) + atoms[it].taud[ia].x) / static_cast(bvk_min_period[0]); + bvk_dpos[3 * at + 1] = (static_cast (c2) + atoms[it].taud[ia].y) / static_cast(bvk_min_period[1]); + bvk_dpos[3 * at + 2] = (static_cast (c3) + atoms[it].taud[ia].z) / static_cast(bvk_min_period[2]); + for (int k = 0; k < 3; ++k) + { + symm.check_translation(bvk_dpos[3 * at + k], -floor(bvk_dpos[3 * at + k])); + symm.check_boundary(bvk_dpos[3 * at + k]); + } + ++at; + } + + // analyze bravis and generate optimized lattice for minimal BvK lattice + double cel_const[6], pre_const[6]; + int bvk_brav; + std::string bvk_latname; + // bvk_brav = symm.standard_lat(s1, s2, s3, cel_const); //not enough, optimal lattice may change after cell-extension + symm.lattice_type(a1, a2, a3, s1, s2, s3, cel_const, pre_const, bvk_brav, bvk_latname, nullptr, false, nullptr); + ModuleBase::Matrix3 bvk_min_optlat = set_matrix3(a1, a2, a3); + // convert the direct coordinates to the optimized lattice + for (int i = 0;i < bvk_nat;++i) + { + ModuleBase::Vector3 taud(bvk_dpos[3 * i], bvk_dpos[3 * i + 1], bvk_dpos[3 * i + 2]); + taud = taud * bvk_min_lat * bvk_min_optlat.Inverse(); + bvk_dpos[3 * i] = taud.x; + bvk_dpos[3 * i + 1] = taud.y; + bvk_dpos[3 * i + 2] = taud.z; + for (int k = 0; k < 3; ++k) + { + symm.check_translation(bvk_dpos[3 * i + k], -floor(bvk_dpos[3 * i + k])); + symm.check_boundary(bvk_dpos[3 * i + k]); + } + } + + // generate symmetry operation of the BvK lattice using the original optlat-direct coordinates + std::vector bvk_op(symm.nrotk); + int bvk_nop; + symm.setgroup(bvk_op.data(), bvk_nop, bvk_brav); + bvk_op.resize(bvk_nop); + int bvk_npg, bvk_nsg, bvk_pgnum, bvk_sgnum; + std::string bvk_pgname, bvk_sgname; + this->bvk_gmatrix_.resize(48); + this->bvk_gtrans_.resize(48); + symm.getgroup(bvk_npg, bvk_nsg, GlobalV::ofs_running, bvk_nop, + bvk_op.data(), this->bvk_gmatrix_.data(), this->bvk_gtrans_.data(), + bvk_dpos.data(), bvk_rot_dpos.data(), order_index.data(), + bvk_itmin_type, bvk_itmin_start, bvk_istart.data(), bvk_na.data()); + this->bvk_gmatrix_.resize(bvk_nsg); + this->bvk_gtrans_.resize(bvk_nsg); + this->bvk_nsym_ = bvk_nsg; + symm.pointgroup(bvk_npg, bvk_pgnum, bvk_pgname, this->bvk_gmatrix_.data(), GlobalV::ofs_running); + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "POINT GROUP OF BvK SCELL", bvk_pgname); + symm.pointgroup(bvk_nsg, bvk_sgnum, bvk_sgname, this->bvk_gmatrix_.data(), GlobalV::ofs_running); + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "POINT GROUP IN SPACE GROUP OF BvK SCELL", bvk_pgname); + symm.gmatrix_convert_int(this->bvk_gmatrix_.data(), this->bvk_gmatrix_.data(), bvk_nsg, bvk_min_optlat, bvk_min_lat); + + // get map from bvk-op to original op + this->isymbvk_to_isym_ = get_isymbvk_to_isym_map(this->bvk_gmatrix_, symm); + return; + } + + std::vector Symmetry_rotation::in_plain(const ModuleSymmetry::Symmetry& symm, const ModuleBase::Matrix3& latvec)const + { + // get euler angel of the cartesian gmatrix in optimal lattice + std::vector gmatc(symm.nrotk); + symm.gmatrix_convert_int(symm.gmatrix, gmatc.data(), symm.nrotk, latvec, symm.optlat); + for (auto& g : gmatc) g = direct_to_cartesian(g, symm.optlat); + std::vector in_plain(symm.nrotk, false); + for (int i = 0;i < symm.nrotk;++i) + { + TCdouble euler_angle = get_euler_angle(gmatc[i]); + if (symm.equal(euler_angle.y, 0.0) || symm.equal(euler_angle.y, ModuleBase::PI)) in_plain[i] = true; + } + return in_plain; + } + + } \ No newline at end of file diff --git a/source/module_ri/symmetry_rotation.h b/source/module_ri/symmetry_rotation.h index 2c63e61769..5a95926893 100644 --- a/source/module_ri/symmetry_rotation.h +++ b/source/module_ri/symmetry_rotation.h @@ -12,8 +12,6 @@ #include #include "module_hamilt_lcao/module_hcontainer/hcontainer.h" #include "module_cell/module_neighbor/sltk_grid_driver.h" -// for test -// #include "Exx_LRI.h" namespace ModuleSymmetry { @@ -113,13 +111,14 @@ namespace ModuleSymmetry std::vector> contruct_2d_rot_mat_ao(const Symmetry& symm, const Atom* atoms, const Statistics& cell_st, const TCdouble& kvec_d_ibz, int isym, const Parallel_2D& pv) const; - ModuleBase::Matrix3 direct_to_cartesian(const ModuleBase::Matrix3& d, const ModuleBase::Matrix3& latvec); + ModuleBase::Matrix3 direct_to_cartesian(const ModuleBase::Matrix3& d, const ModuleBase::Matrix3& latvec)const; std::vector>& get_rotmat_Slm() { return this->rotmat_Slm_; } //-------------------------------------------------------------------------------- /// The main function to find irreducible sector: {abR} - void find_irreducible_sector(const Symmetry& symm, const Atom* atoms, const Statistics& st, const std::vector& Rs); + void find_irreducible_sector(const Symmetry& symm, const Atom* atoms, const Statistics& st, + const std::vector& Rs, const TC& period, const Lattice& lat); std::vector get_Rs_from_BvK(const K_Vectors& kv)const; std::vector get_Rs_from_adjacent_list(const UnitCell& ucell, Grid_Driver& gd, const Parallel_Orbitals& pv)const; const std::map>& get_irreducible_sector()const { return this->irreducible_sector_; } @@ -187,7 +186,12 @@ namespace ModuleSymmetry template // HContainer type, pblas void rotate_atompair_parallel(const TR* Alocal_in, const int isym, const Atom* atoms, const Statistics& st, const Tap& ap_in, const Tap& ap_out, const char mode, const Parallel_Orbitals& pv, TR* Alocal_out, const bool output = false)const; + //-------------------------------------------------------------------------------- + /// The sub functions judge special symmetry + void gen_symmetry_BvK(const Symmetry& symm, const Atom* atoms, const Lattice& lat, const Statistics& st, const TC bvk_period); + /// whether in 2D plain or not for each symmetry operation + std::vector in_plain(const ModuleSymmetry::Symmetry& symm, const ModuleBase::Matrix3& latvec)const; //-------------------------------------------------------------------------------- int nsym_ = 1; @@ -226,6 +230,10 @@ namespace ModuleSymmetry std::vector> return_lattice_; std::vector invmap_; + std::vector isymbvk_to_isym_; + std::vector bvk_gmatrix_; + std::vector> bvk_gtrans_; + int bvk_nsym_; }; } From 652aca827b422b1e5dc29fc4014b50b45de83d19 Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Thu, 14 Mar 2024 16:30:40 +0800 Subject: [PATCH 11/19] fix energy when cal_force/stress=1 --- source/module_ri/symmetry_rotation.cpp | 2 +- source/module_ri/symmetry_rotation.h | 2 +- source/module_ri/symmetry_rotation_R.hpp | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source/module_ri/symmetry_rotation.cpp b/source/module_ri/symmetry_rotation.cpp index fa3d0e4746..e8e42fa08f 100644 --- a/source/module_ri/symmetry_rotation.cpp +++ b/source/module_ri/symmetry_rotation.cpp @@ -589,7 +589,7 @@ namespace ModuleSymmetry } // generate symmetry operation of the BvK lattice using the original optlat-direct coordinates - std::vector bvk_op(symm.nrotk); + std::vector bvk_op(48); int bvk_nop; symm.setgroup(bvk_op.data(), bvk_nop, bvk_brav); bvk_op.resize(bvk_nop); diff --git a/source/module_ri/symmetry_rotation.h b/source/module_ri/symmetry_rotation.h index 5a95926893..aa839d30fe 100644 --- a/source/module_ri/symmetry_rotation.h +++ b/source/module_ri/symmetry_rotation.h @@ -147,7 +147,7 @@ namespace ModuleSymmetry void test_HR_rotation(const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, const hamilt::HContainer& HR_full); template // HContainer type - void print_HR(const std::map, RI::Tensor>>& HR, const std::string name);; + void print_HR(const std::map, RI::Tensor>>& HR, const std::string name, const double& threshold = 0.0); //-------------------------------------------------------------------------------- private: diff --git a/source/module_ri/symmetry_rotation_R.hpp b/source/module_ri/symmetry_rotation_R.hpp index 8d0364da12..98720a4597 100644 --- a/source/module_ri/symmetry_rotation_R.hpp +++ b/source/module_ri/symmetry_rotation_R.hpp @@ -36,13 +36,13 @@ namespace ModuleSymmetry } template - inline void print_tensor(const RI::Tensor& t, const std::string& name) + inline void print_tensor(const RI::Tensor& t, const std::string& name, const double& threshold = 0.0) { std::cout << name << ":\n"; for (int i = 0;i < t.shape[0];++i) { for (int j = 0;j < t.shape[1];++j) - std::cout << t(i, j) << " "; + std::cout << ((std::abs(t(i, j)) > threshold) ? t(i, j) : static_cast(0)) << " "; std::cout << std::endl; } } @@ -115,7 +115,7 @@ namespace ModuleSymmetry } template - void Symmetry_rotation::print_HR(const std::map, RI::Tensor>>& HR, const std::string name) + void Symmetry_rotation::print_HR(const std::map, RI::Tensor>>& HR, const std::string name, const double& threshold) { for (auto& HR_ia1 : HR) { @@ -126,7 +126,7 @@ namespace ModuleSymmetry TC R = HR_ia12R.first.second; const RI::Tensor& HR_tensor = HR_ia12R.second; std::cout << "atom pair (" << iat1 << ", " << iat2 << "), R=(" << R[0] << "," << R[1] << "," << R[2] << "), "; - print_tensor(HR_tensor, name); + print_tensor(HR_tensor, name, threshold); } } } From 22cd3a68f55a24d32574ad324bfba7911d8e69db Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Thu, 14 Mar 2024 17:38:53 +0800 Subject: [PATCH 12/19] add parameter exx_symmetry_realspace --- docs/advanced/input_files/input-main.md | 10 ++++++++ .../module_xc/exx_info.h | 1 + source/module_io/input_conv.cpp | 1 + source/module_io/read_input_item_exx_dftu.cpp | 6 +++++ source/module_parameter/input_parameter.h | 1 + source/module_ri/Exx_LRI_interface.h | 1 - source/module_ri/Exx_LRI_interface.hpp | 23 +++++++------------ 7 files changed, 27 insertions(+), 16 deletions(-) diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index f17cf945ea..44cb6a26bc 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -241,6 +241,7 @@ - [exx\_opt\_orb\_ecut](#exx_opt_orb_ecut) - [exx\_opt\_orb\_tolerence](#exx_opt_orb_tolerence) - [exx\_real\_number](#exx_real_number) + - [exx\_symmetry\_realspace](#exx_symmetry_realspace) - [rpa\_ccp\_rmesh\_times](#rpa_ccp_rmesh_times) - [Molecular dynamics](#molecular-dynamics) - [md\_type](#md_type) @@ -2402,6 +2403,15 @@ These variables are relevant when using hybrid functionals. - **Description**: How many times larger the radial mesh required is to that of atomic orbitals in the postprocess calculation of the **bare** Coulomb matrix for RPA, GW, etc. - **Default**: 10 +### exx_symmetry_realspace + +- **Type**: Boolean +- **Availability**: *[symmetry](#symmetry)==1* and exx calculation (*[dft_fuctional](#dft_functional)==hse/hf/pbe0/scan0/opt_orb* or *[rpa](#rpa)==True*) +- **Description**: + - False: only rotate k-space density matrix D(k) from irreducible k-points to accelerate diagonalization + - True: rotate both D(k) and Hexx(R) to accelerate both diagonalization and EXX calculation +- **Default**: True + [back to top](#full-list-of-input-keywords) ## Molecular dynamics diff --git a/source/module_hamilt_general/module_xc/exx_info.h b/source/module_hamilt_general/module_xc/exx_info.h index 80a609e929..161e4518e3 100644 --- a/source/module_hamilt_general/module_xc/exx_info.h +++ b/source/module_hamilt_general/module_xc/exx_info.h @@ -17,6 +17,7 @@ struct Exx_Info bool separate_loop = true; size_t hybrid_step = 1; + bool exx_symmetry_realspace = true; }; Exx_Info_Global info_global; diff --git a/source/module_io/input_conv.cpp b/source/module_io/input_conv.cpp index 3ce1142f68..e59fbaee08 100644 --- a/source/module_io/input_conv.cpp +++ b/source/module_io/input_conv.cpp @@ -496,6 +496,7 @@ void Input_Conv::Convert() GlobalC::exx_info.info_global.separate_loop = PARAM.inp.exx_separate_loop; GlobalC::exx_info.info_global.hybrid_step = PARAM.inp.exx_hybrid_step; GlobalC::exx_info.info_global.mixing_beta_for_loop1 = PARAM.inp.exx_mixing_beta; + GlobalC::exx_info.info_global.exx_symmetry_realspace = INPUT.exx_symmetry_realspace; GlobalC::exx_info.info_lip.lambda = PARAM.inp.exx_lambda; GlobalC::exx_info.info_ri.real_number = std::stoi(PARAM.inp.exx_real_number); diff --git a/source/module_io/read_input_item_exx_dftu.cpp b/source/module_io/read_input_item_exx_dftu.cpp index 4763138da1..79edc45632 100644 --- a/source/module_io/read_input_item_exx_dftu.cpp +++ b/source/module_io/read_input_item_exx_dftu.cpp @@ -247,6 +247,12 @@ void ReadInput::item_exx() }; this->add_item(item); } + { + Input_Item item("exx_symmetry_realspace"); + item.annotation = "whether to reduce real-space sector in Hexx calculation"; + read_sync_bool(input.exx_symmetry_realspace); + this->add_item(item); + } { Input_Item item("rpa_ccp_rmesh_times"); item.annotation = "how many times larger the radial mesh required for " diff --git a/source/module_parameter/input_parameter.h b/source/module_parameter/input_parameter.h index e84ae1719f..6b9b454daa 100644 --- a/source/module_parameter/input_parameter.h +++ b/source/module_parameter/input_parameter.h @@ -482,6 +482,7 @@ struct Input_para double exx_opt_orb_ecut = 0.0; ///< the cut-off of plane wave expansion for opt ABFs double exx_opt_orb_tolerence = 0.0; ///< the threshold when solving for the zeros of spherical Bessel ///< functions for opt ABFs + bool exx_symmetry_realspace; ///< true for rotate H(R) and D(k) and false for rotate D(k) only double rpa_ccp_rmesh_times = 10.0; ///< how many times larger the radial mesh required for ///< calculating Columb potential is to that of atomic orbitals // ============== #Parameters (16.dft+u) ====================== diff --git a/source/module_ri/Exx_LRI_interface.h b/source/module_ri/Exx_LRI_interface.h index b526aa76b8..f825203811 100644 --- a/source/module_ri/Exx_LRI_interface.h +++ b/source/module_ri/Exx_LRI_interface.h @@ -70,7 +70,6 @@ class Exx_LRI_Interface int two_level_step = 0; bool exx_spacegroup_symmetry = false; - bool restore_dm_only = false; // true for test ModuleSymmetry::Symmetry_rotation symrot_; }; diff --git a/source/module_ri/Exx_LRI_interface.hpp b/source/module_ri/Exx_LRI_interface.hpp index dcbc9cefe2..de535b23ca 100644 --- a/source/module_ri/Exx_LRI_interface.hpp +++ b/source/module_ri/Exx_LRI_interface.hpp @@ -110,7 +110,7 @@ void Exx_LRI_Interface::exx_eachiterinit(const elecstate::DensityMatri Ds = GlobalV::GAMMA_ONLY_LOCAL ? RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_gamma_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN) : RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_k_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN, this->exx_spacegroup_symmetry); - if (this->exx_spacegroup_symmetry && !restore_dm_only) { this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer(), &this->symrot_); } + if (this->exx_spacegroup_symmetry && GlobalC::exx_info.info_global.symmetry_rotate_realspace) { this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer(), &this->symrot_); } else { this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer()); } } } @@ -217,24 +217,17 @@ bool Exx_LRI_Interface::exx_after_converge( // this->symrot_.test_HR_rotation(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, 'H', *(dynamic_cast*>(&hamilt)->getHR())); // exit(0); - if (this->exx_spacegroup_symmetry) + if (this->exx_spacegroup_symmetry && GlobalC::exx_info.info_global.symmetry_rotate_realspace) { - if (restore_dm_only) - { - this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer()); // restore DM but not Hexx - // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_restore-DM-only"); // test - } - else - { - this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer(), &this->symrot_); - // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_irreducible"); // test - // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_restored"); // test - } + this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer(), &this->symrot_); + // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_irreducible"); // test + // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_restored"); // test } else { - this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer()); - // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_ref"); + this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer()); // restore DM but not Hexx + // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_restore-DM-only"); // test + // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_ref"); // test } // ======================== test ======================== // if (this->two_level_step)exit(0); From 52a4ad5396d1f30fd8d550935e10738816bf4067 Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Thu, 14 Mar 2024 17:39:22 +0800 Subject: [PATCH 13/19] fix gmatrix_convert --- source/module_ri/symmetry_rotation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/module_ri/symmetry_rotation.cpp b/source/module_ri/symmetry_rotation.cpp index e8e42fa08f..b72babe640 100644 --- a/source/module_ri/symmetry_rotation.cpp +++ b/source/module_ri/symmetry_rotation.cpp @@ -608,8 +608,8 @@ namespace ModuleSymmetry ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "POINT GROUP OF BvK SCELL", bvk_pgname); symm.pointgroup(bvk_nsg, bvk_sgnum, bvk_sgname, this->bvk_gmatrix_.data(), GlobalV::ofs_running); ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "POINT GROUP IN SPACE GROUP OF BvK SCELL", bvk_pgname); - symm.gmatrix_convert_int(this->bvk_gmatrix_.data(), this->bvk_gmatrix_.data(), bvk_nsg, bvk_min_optlat, bvk_min_lat); - + symm.gmatrix_convert_int(this->bvk_gmatrix_.data(), this->bvk_gmatrix_.data(), bvk_nsg, bvk_min_optlat, lat.latvec); + symm.gtrans_convert(this->bvk_gtrans_.data(), this->bvk_gtrans_.data(), bvk_nsg, bvk_min_optlat, lat.latvec); // get map from bvk-op to original op this->isymbvk_to_isym_ = get_isymbvk_to_isym_map(this->bvk_gmatrix_, symm); return; From ccb0ef651239685d870429c69796a26495bf658b Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Sun, 17 Mar 2024 01:12:03 +0800 Subject: [PATCH 14/19] refactor: seperate irreducible_sector out of symmetry_rotation fix a symmetry bug fix default value rebase develop and small fix refactor rotation funcs pointer-type interface for rotation funcs --- CMakeLists.txt | 2 +- .../module_cell/module_symmetry/symmetry.cpp | 4 +- source/module_ri/CMakeLists.txt | 5 +- source/module_ri/Exx_LRI.h | 2 +- source/module_ri/Exx_LRI.hpp | 19 +- source/module_ri/Exx_LRI_interface.h | 4 +- source/module_ri/Exx_LRI_interface.hpp | 5 +- source/module_ri/RPA_LRI.hpp | 13 +- source/module_ri/exx_symmetry/CMakeLists.txt | 21 ++ .../irreducible_sector.cpp} | 196 ++++------- .../exx_symmetry/irreducible_sector.h | 132 +++++++ .../exx_symmetry/irreducible_sector_bvk.cpp | 160 +++++++++ .../{ => exx_symmetry}/symmetry_rotation.cpp | 321 ++++-------------- .../{ => exx_symmetry}/symmetry_rotation.h | 152 ++------- .../symmetry_rotation_R.hpp | 160 ++++++--- .../symmetry_rotation_R_hcontainer.hpp | 10 +- .../exx_symmetry/test/CMakeLists.txt | 10 + .../test/symmetry_rotation_test.cpp | 0 source/module_ri/test/CMakeLists.txt | 6 - 19 files changed, 626 insertions(+), 596 deletions(-) create mode 100644 source/module_ri/exx_symmetry/CMakeLists.txt rename source/module_ri/{symmetry_irreducible_sector.cpp => exx_symmetry/irreducible_sector.cpp} (51%) create mode 100644 source/module_ri/exx_symmetry/irreducible_sector.h create mode 100644 source/module_ri/exx_symmetry/irreducible_sector_bvk.cpp rename source/module_ri/{ => exx_symmetry}/symmetry_rotation.cpp (55%) rename source/module_ri/{ => exx_symmetry}/symmetry_rotation.h (58%) rename source/module_ri/{ => exx_symmetry}/symmetry_rotation_R.hpp (51%) rename source/module_ri/{ => exx_symmetry}/symmetry_rotation_R_hcontainer.hpp (96%) create mode 100644 source/module_ri/exx_symmetry/test/CMakeLists.txt rename source/module_ri/{ => exx_symmetry}/test/symmetry_rotation_test.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f1af466ee0..311cd92ba7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -532,7 +532,7 @@ if(ENABLE_LIBRI) else() message(FATAL_ERROR "Must provide LIBRI_DIR for RI related features.") endif() - target_link_libraries(${ABACUS_BIN_NAME} ri) + target_link_libraries(${ABACUS_BIN_NAME} ri exx_symmetry) add_compile_definitions(__EXX EXX_DM=3 EXX_H_COMM=2 TEST_EXX_LCAO=0 TEST_EXX_RADIAL=1) endif() diff --git a/source/module_cell/module_symmetry/symmetry.cpp b/source/module_cell/module_symmetry/symmetry.cpp index 67ce48ef59..aa72f1d584 100644 --- a/source/module_cell/module_symmetry/symmetry.cpp +++ b/source/module_cell/module_symmetry/symmetry.cpp @@ -911,7 +911,7 @@ void Symmetry::getgroup(int& nrot, int& nrotk, std::ofstream& ofs_running, const //std::cout << "nop = " <checksym(this->symop[i], this->gtrans[i], pos, rotpos, index, itmin_type, itmin_start, istart, na); + bool s_flag = this->checksym(symop[i], gtrans[i], pos, rotpos, index, itmin_type, itmin_start, istart, na); if (s_flag == 1) { //------------------------------ @@ -1055,7 +1055,7 @@ bool Symmetry::checksym(const ModuleBase::Matrix3& s, ModuleBase::Vector3 sptmin(pos[itmin_start * 3], pos[itmin_start * 3 + 1], pos[itmin_start * 3 + 2]); + ModuleBase::Vector3 sptmin(rotpos[itmin_start * 3], rotpos[itmin_start * 3 + 1], rotpos[itmin_start * 3 + 2]); for (int i = itmin_start; i < itmin_start + na[itmin_type]; ++i) { diff --git a/source/module_ri/CMakeLists.txt b/source/module_ri/CMakeLists.txt index f9ae703074..8f32dd6430 100644 --- a/source/module_ri/CMakeLists.txt +++ b/source/module_ri/CMakeLists.txt @@ -1,4 +1,7 @@ if (ENABLE_LIBRI) + + add_subdirectory(exx_symmetry) + list(APPEND objects Matrix_Orbs11.cpp Matrix_Orbs21.cpp @@ -7,8 +10,6 @@ if (ENABLE_LIBRI) exx_lip.cpp Mix_DMk_2D.cpp Mix_Matrix.cpp - symmetry_rotation.cpp - symmetry_irreducible_sector.cpp ) if(ENABLE_LCAO) diff --git a/source/module_ri/Exx_LRI.h b/source/module_ri/Exx_LRI.h index f11fcd2e3b..0e508f4240 100644 --- a/source/module_ri/Exx_LRI.h +++ b/source/module_ri/Exx_LRI.h @@ -18,7 +18,7 @@ #include #include -#include "symmetry_rotation.h" +#include "exx_symmetry/symmetry_rotation.h" class Parallel_Orbitals; diff --git a/source/module_ri/Exx_LRI.hpp b/source/module_ri/Exx_LRI.hpp index abb782fc0f..fd1fea9759 100644 --- a/source/module_ri/Exx_LRI.hpp +++ b/source/module_ri/Exx_LRI.hpp @@ -180,18 +180,13 @@ void Exx_LRI::cal_exx_elec(const std::vectorEexx = 0; for(int is=0; isexx_lri.set_Ds(Ds[is], this->info.dm_threshold); - this->exx_lri.cal_Hs({ "","","" }, - (p_symrot == nullptr) ? std::map, std::set >({}) : p_symrot->get_irreducible_sector(), - (p_symrot == nullptr) ? true : false); - } - else - { - this->exx_lri.set_Ds(Ds[is], this->info.dm_threshold, std::to_string(is)); - this->exx_lri.cal_Hs({ "","",std::to_string(is) }); - } + std::string suffix = ((GlobalV::CAL_FORCE || GlobalV::CAL_STRESS) ? std::to_string(is) : ""); + + this->exx_lri.set_Ds(Ds[is], this->info.dm_threshold, suffix); + this->exx_lri.cal_Hs({ "","",suffix }, + (p_symrot == nullptr) ? std::map, std::set >({}) : p_symrot->get_irreducible_sector(), + (p_symrot == nullptr) ? true : false); + this->Hexxs[is] = RI::Communicate_Tensors_Map_Judge::comm_map2_first( this->mpi_comm, std::move(this->exx_lri.Hs), std::get<0>(judge[is]), std::get<1>(judge[is])); diff --git a/source/module_ri/Exx_LRI_interface.h b/source/module_ri/Exx_LRI_interface.h index f825203811..9eb213815a 100644 --- a/source/module_ri/Exx_LRI_interface.h +++ b/source/module_ri/Exx_LRI_interface.h @@ -3,7 +3,7 @@ #include "Exx_LRI.h" #include "module_ri/Mix_DMk_2D.h" -#include "module_ri/symmetry_rotation.h" +#include "module_ri/exx_symmetry/symmetry_rotation.h" #include class LCAO_Matrix; @@ -64,10 +64,10 @@ class Exx_LRI_Interface const elecstate::DensityMatrix& dm/**< double should be Tdata if complex-PBE-DM is supported*/, const K_Vectors& kv, int& iter); + int two_level_step = 0; private: std::shared_ptr> exx_ptr; Mix_DMk_2D mix_DMk_2D; - int two_level_step = 0; bool exx_spacegroup_symmetry = false; ModuleSymmetry::Symmetry_rotation symrot_; diff --git a/source/module_ri/Exx_LRI_interface.hpp b/source/module_ri/Exx_LRI_interface.hpp index de535b23ca..e798dd56c3 100644 --- a/source/module_ri/Exx_LRI_interface.hpp +++ b/source/module_ri/Exx_LRI_interface.hpp @@ -60,10 +60,9 @@ void Exx_LRI_Interface::exx_beforescf(const K_Vectors& kv, const Charg if (this->exx_spacegroup_symmetry) { const std::array& period = RI_Util::get_Born_vonKarmen_period(kv); - this->symrot_.get_return_lattice_all(ucell.symm, ucell.atoms, ucell.st); - this->symrot_.cal_Ms(kv, ucell, pv); this->symrot_.find_irreducible_sector(ucell.symm, ucell.atoms, ucell.st, RI_Util::get_Born_von_Karmen_cells(period), period, ucell.lat); + this->symrot_.cal_Ms(kv, ucell, pv); } } @@ -221,7 +220,7 @@ bool Exx_LRI_Interface::exx_after_converge( { this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer(), &this->symrot_); // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_irreducible"); // test - // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_restored"); // test + // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_restored", 1e-10); // test } else { diff --git a/source/module_ri/RPA_LRI.hpp b/source/module_ri/RPA_LRI.hpp index e65412358c..e833245253 100644 --- a/source/module_ri/RPA_LRI.hpp +++ b/source/module_ri/RPA_LRI.hpp @@ -8,7 +8,7 @@ #include #include #include -#include "module_ri/symmetry_rotation.h" +#include "module_ri/exx_symmetry/symmetry_rotation.h" #include "RPA_LRI.h" #include "module_parameter/parameter.h" @@ -84,7 +84,9 @@ void RPA_LRI::cal_postSCF_exx(const elecstate::DensityMatrix ModuleSymmetry::Symmetry_rotation symrot; if (exx_spacegroup_symmetry) { - symrot.get_return_lattice_all(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st); + const std::array period = RI_Util::get_Born_vonKarmen_period(kv); + symrot.find_irreducible_sector(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, + RI_Util::get_Born_von_Karmen_cells(period), period, GlobalC::ucell.lat); symrot.cal_Ms(kv, GlobalC::ucell, *dm.get_paraV_pointer()); mix_DMk_2D.mix(symrot.restore_dm(kv, dm.get_DMK_vector(), *dm.get_paraV_pointer()), true); } @@ -104,16 +106,9 @@ void RPA_LRI::cal_postSCF_exx(const elecstate::DensityMatrix exx_lri_rpa.cal_exx_ions(); if (exx_spacegroup_symmetry) - { - const std::array period = RI_Util::get_Born_vonKarmen_period(kv); - symrot.find_irreducible_sector(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, - RI_Util::get_Born_von_Karmen_cells(period), period, GlobalC::ucell.lat); exx_lri_rpa.cal_exx_elec(Ds, *dm.get_paraV_pointer(), &symrot); - } else - { exx_lri_rpa.cal_exx_elec(Ds, *dm.get_paraV_pointer()); - } // cout<<"postSCF_Eexx: "< 0 ? static_cast(x + eps_) : static_cast(x - eps_); - } - - TC Symmetry_rotation::rotate_R_by_formula(const Symmetry& symm, + TC Irreducible_Sector::rotate_R(const Symmetry& symm, const int isym, const int iat1, const int iat2, const TC& R, const char gauge) const { + auto round2int = [symm](const double x) -> int { return x > 0 ? static_cast(x + symm.epsilon) : static_cast(x - symm.epsilon); }; const TCdouble R_double(static_cast(R[0]), static_cast(R[1]), static_cast(R[2])); const TCdouble Rrot_double = (gauge == 'L') ? R_double * symm.gmatrix[isym] + this->return_lattice_[iat1][isym] - this->return_lattice_[iat2][isym] : R_double * symm.gmatrix[isym] + this->return_lattice_[iat2][isym] - this->return_lattice_[iat1][isym]; return { round2int(Rrot_double.x), round2int(Rrot_double.y), round2int(Rrot_double.z) }; } - TapR Symmetry_rotation::rotate_R_by_formula(const Symmetry& symm, + TapR Irreducible_Sector::rotate_apR_by_formula(const Symmetry& symm, const int isym, const TapR& apR, const char gauge) const { const Tap& aprot = { symm.get_rotated_atom(isym, apR.first.first), symm.get_rotated_atom(isym, apR.first.second) }; - return { aprot, this->rotate_R_by_formula(symm, isym, apR.first.first, apR.first.second, apR.second, gauge) }; + return { aprot, this->rotate_R(symm, isym, apR.first.first, apR.first.second, apR.second, gauge) }; } - TCdouble Symmetry_rotation::get_aRb_direct(const Atom* atoms, const Statistics& st, + TCdouble Irreducible_Sector::get_aRb_direct(const Atom* atoms, const Statistics& st, const int iat1, const int iat2, const TCdouble& R, const char gauge)const { return TCdouble(atoms[st.iat2it[iat1]].taud[st.iat2ia[iat1]] - atoms[st.iat2it[iat2]].taud[st.iat2ia[iat2]]) + (gauge == 'L' ? R : TCdouble(-R)); } - TCdouble Symmetry_rotation::get_aRb_direct(const Atom* atoms, const Statistics& st, + TCdouble Irreducible_Sector::get_aRb_direct(const Atom* atoms, const Statistics& st, const int iat1, const int iat2, const TC& R, const char gauge) const { const TCdouble R_double(static_cast(R[0]), static_cast(R[1]), static_cast(R[2])); return get_aRb_direct(atoms, st, iat1, iat2, R_double); } - // void Symmetry_rotation::find_irreducible_atom_pairs(const Symmetry& symm) - // { - // ModuleBase::TITLE("Symmetry_rotation", "find_irreducible_atom_pairs"); - // this->eps_ = symm.epsilon; - // for (int iat1 = 0;iat1 < symm.nat;++iat1) - // for (int iat2 = 0;iat2 < symm.nat;++iat2) - // { - // Tap pair = { iat1, iat2 }; - // bool exist = false; - // for (int isym = 0;isym < symm.nrotk;++isym) - // { - // Tap rotpair = { symm.get_rotated_atom(isym,iat1), symm.get_rotated_atom(isym,iat2) }; - // for (int ip = 0;ip < this->atompair_stars_.size();++ip) // current irreduceble pairs - // { - // if (rotpair == this->atompair_stars_[ip].at(0)) - // { - // this->atompair_stars_[ip].insert({ isym, pair }); - // exist = true; - // break; - // } - // } - // if (exist)break; - // } - // if (!exist)this->atompair_stars_.push_back({ {0, pair} }); - // } - // } - - // void Symmetry_rotation::find_irreducible_atom_pairs_set(const Symmetry& symm) - // { - // ModuleBase::TITLE("Symmetry_rotation", "find_irreducible_atom_pairs_set"); - // this->eps_ = symm.epsilon; - // if (this->invmap_.empty()) - // { - // this->invmap_.resize(symm.nrotk); - // symm.gmatrix_invmap(symm.gmatrix, symm.nrotk, invmap_.data()); - // } - // // contruct initial ap-set - // std::set ap_set; - // for (int iat1 = 0; iat1 < symm.nat; ++iat1) - // for (int iat2 = 0; iat2 < symm.nat; ++iat2) - // ap_set.insert({ iat1, iat2 }); - // while (!ap_set.empty()) - // { - // Tap ap = *ap_set.begin(); - // std::map ap_star; - // for (int isym = 0; isym < symm.nrotk; ++isym) - // { - // Tap rotpair = { symm.get_rotated_atom(isym,ap.first), symm.get_rotated_atom(isym,ap.second) }; - // if (ap_set.find(rotpair) != ap_set.end()) - // { - // ap_star.insert({ this->invmap_[isym], rotpair }); - // ap_set.erase(rotpair); - // } - // } - // this->atompair_stars_.push_back(ap_star); - // } - // } - - // inline void output_atompair_stars(const std::vector>& ap_stars) - // { - // std::cout << "stars of irreducible atom pairs: " << std::endl; - // for (int ip = 0; ip < ap_stars.size(); ++ip) - // { - // std::cout << "atom pair star " << ip << ": " << std::endl; - // for (const auto& ap : ap_stars[ip]) - // std::cout << "isym=" << ap.first << ", atompair=(" << ap.second.first << ", " << ap.second.second << ") " << std::endl; - // } - // } - - // void Symmetry_rotation::test_irreducible_atom_pairs(const Symmetry& symm) - // { - // std::cout << "Algorithm 1: find irreducible atom pairs by set" << std::endl; - // this->find_irreducible_atom_pairs_set(symm); - // output_atompair_stars(this->atompair_stars_); - - // std::cout << std::endl; - // this->atompair_stars_.clear(); - // std::cout << "Algorithm 2: find irreducible atom pairs by judge" << std::endl; - // this->find_irreducible_atom_pairs(symm); - // output_atompair_stars(this->atompair_stars_); - // } + inline void output_return_lattice(const std::vector>& return_lattice) + { + std::cout << "return lattice:" << std::endl; + for (int iat = 0;iat < return_lattice.size();++iat) + { + std::cout << "atom" << iat << std::endl; + for (int isym = 0;isym < return_lattice[iat].size();++isym) + std::cout << "isym=" << isym << ", return lattice=" << + return_lattice[iat][isym].x << " " << return_lattice[iat][isym].y << " " << return_lattice[iat][isym].z << std::endl; + } + } - std::vector Symmetry_rotation::get_Rs_from_BvK(const K_Vectors& kv) const + // Perfoming {R|t} to atom position r in the R=0 lattice, we get Rr+t, which may get out of R=0 lattice, + // whose image in R=0 lattice is r'=Rr+t-O. This function is to get O for each atom and each symmetry operation. + // the range of direct position is [-0.5, 0.5). + TCdouble Irreducible_Sector::get_return_lattice(const Symmetry& symm, + const ModuleBase::Matrix3& gmatd, const TCdouble gtransd, + const TCdouble& posd_a1, const TCdouble& posd_a2)const { - const TC& period = RI_Util::get_Born_vonKarmen_period(kv); - return RI_Util::get_Born_von_Karmen_cells(period); + // auto restrict_center = [&symm](const TCdouble& v) -> TCdouble { + // // in [-0.5, 0.5) + // TCdouble vr; + // vr.x = fmod(v.x + 100.5 + 0.5 * symm.epsilon, 1) - 0.5 - 0.5 * symm.epsilon; + // vr.y = fmod(v.y + 100.5 + 0.5 * symm.epsilon, 1) - 0.5 - 0.5 * symm.epsilon; + // vr.z = fmod(v.z + 100.5 + 0.5 * symm.epsilon, 1) - 0.5 - 0.5 * symm.epsilon; + // if (std::abs(vr.x) < symm.epsilon) vr.x = 0.0; + // if (std::abs(vr.y) < symm.epsilon) vr.y = 0.0; + // if (std::abs(vr.z) < symm.epsilon) vr.z = 0.0; + // return vr; + // }; + auto restrict_center = [&symm](const TCdouble& v) -> TCdouble { + // in [0,1) + TCdouble vr; + vr.x = fmod(v.x + 100 + symm.epsilon, 1) - symm.epsilon; + vr.y = fmod(v.y + 100 + symm.epsilon, 1) - symm.epsilon; + vr.z = fmod(v.z + 100 + symm.epsilon, 1) - symm.epsilon; + if (std::abs(vr.x) < symm.epsilon) vr.x = 0.0; + if (std::abs(vr.y) < symm.epsilon) vr.y = 0.0; + if (std::abs(vr.z) < symm.epsilon) vr.z = 0.0; + return vr; + }; + auto check_integer = [&symm](const double x) -> void { + assert(symm.equal(x, std::round(x))); + }; + TCdouble rotpos1 = restrict_center(posd_a1) * gmatd + restrict_center(gtransd); // row vector + TCdouble return_lattice_double = rotpos1 - restrict_center(posd_a2); +#ifdef __DEBUG + check_integer(return_lattice_double.x); + check_integer(return_lattice_double.y); + check_integer(return_lattice_double.z); +#endif + return TCdouble(std::round(return_lattice_double.x), std::round(return_lattice_double.y), std::round(return_lattice_double.z)); } - std::vector Symmetry_rotation::get_Rs_from_adjacent_list(const UnitCell& ucell, Grid_Driver& gd, const Parallel_Orbitals& pv) const + + void Irreducible_Sector::get_return_lattice_all(const Symmetry& symm, const Atom* atoms, const Statistics& st) { - // find the union set of Rs for all the atom pairs - std::set Rs_set; - for (int iat1 = 0;iat1 < ucell.nat;++iat1) + ModuleBase::TITLE("Symmetry_rotation", "get_return_lattice_all"); + this->return_lattice_.resize(st.nat, std::vector(symm.nrotk)); + for (int iat1 = 0;iat1 < st.nat;++iat1) { - auto tau1 = ucell.get_tau(iat1); - int it1 = ucell.iat2it[iat1], ia1 = ucell.iat2ia[iat1]; - AdjacentAtomInfo adjs; - gd.Find_atom(ucell, tau1, it1, ia1, &adjs); - for (int ad = 0; ad < adjs.adj_num + 1; ++ad) + int it = st.iat2it[iat1]; + int ia1 = st.iat2ia[iat1]; + for (int isym = 0;isym < symm.nrotk;++isym) { - const int it2 = adjs.ntype[ad]; - const int ia2 = adjs.natom[ad]; - int iat2 = ucell.itia2iat(it2, ia2); - if (pv.get_row_size(iat1) && pv.get_col_size(iat2)) - { - const ModuleBase::Vector3& R_index = adjs.box[ad]; - if (ucell.cal_dtau(iat1, iat2, R_index).norm() * ucell.lat0 - < ucell.atoms[it1].Rcut + ucell.atoms[it2].Rcut) - Rs_set.insert({ R_index.x, R_index.y, R_index.z }); - } + int iat2 = symm.get_rotated_atom(isym, iat1); + int ia2 = st.iat2ia[iat2]; + this->return_lattice_[iat1][isym] = get_return_lattice(symm, symm.gmatrix[isym], symm.gtrans[isym], atoms[it].taud[ia1], atoms[it].taud[ia2]); } } - // set to vector - std::vector Rs(Rs_set.size()); - for (auto& R : Rs_set) Rs.push_back(R); - return Rs; + // test: output return_lattice + output_return_lattice(this->return_lattice_); } - void Symmetry_rotation::output_full_map_to_irreducible_sector(const int nat) + void Irreducible_Sector::output_full_map_to_irreducible_sector(const int nat) { std::cout << "Final map to irreducible sector: " << std::endl; for (auto& apR_isym_irapR : this->full_map_to_irreducible_sector_) @@ -168,7 +120,7 @@ namespace ModuleSymmetry } } - void Symmetry_rotation::output_sector_star() + void Irreducible_Sector::output_sector_star() { std::cout << "Found " << this->sector_stars_.size() << " irreducible sector stars:" << std::endl; // for (auto& irs_star : this->sector_stars_) @@ -189,7 +141,7 @@ namespace ModuleSymmetry } } - void Symmetry_rotation::find_irreducible_sector(const Symmetry& symm, const Atom* atoms, const Statistics& st, const std::vector& Rs, const TC& period, const Lattice& lat) + void Irreducible_Sector::find_irreducible_sector(const Symmetry& symm, const Atom* atoms, const Statistics& st, const std::vector& Rs, const TC& period, const Lattice& lat) { this->full_map_to_irreducible_sector_.clear(); this->irreducible_sector_.clear(); @@ -236,7 +188,7 @@ namespace ModuleSymmetry // if (!in_2d_plain[isym]) continue; // } const int& isym = this->isymbvk_to_isym_[isymbvk]; - const TapR& apRrot = this->rotate_R_by_formula(symm, this->invmap_[isym], irapR); + const TapR& apRrot = this->rotate_apR_by_formula(symm, this->invmap_[isym], irapR); const Tap& aprot = apRrot.first; const TC& Rrot = apRrot.second; if (apR_all.count(aprot) && apR_all.at(aprot).count(Rrot)) diff --git a/source/module_ri/exx_symmetry/irreducible_sector.h b/source/module_ri/exx_symmetry/irreducible_sector.h new file mode 100644 index 0000000000..ed73d8c1b2 --- /dev/null +++ b/source/module_ri/exx_symmetry/irreducible_sector.h @@ -0,0 +1,132 @@ +#pragma once +#include +#include +#include +#include "module_base/abfs-vector3_order.h" +#include "module_base/complexmatrix.h" +#include "module_base/matrix3.h" +#include "module_cell/unitcell.h" +#include "module_cell/module_symmetry/symmetry.h" +#include "module_cell/klist.h" + +namespace ModuleSymmetry +{ + using Tap = std::pair; + using TC = std::array; + using TapR = std::pair; + using TCdouble = Abfs::Vector3_Order; + + class Irreducible_Sector + { + public: + struct ap_less_func + { + bool operator()(const Tap& lhs, const Tap& rhs) const + { + if (lhs.first < rhs.first)return true; + else if (lhs.first > rhs.first)return false; + else return lhs.second < rhs.second; + } + }; + struct apR_less_func + { + bool operator()(const TapR& lhs, const TapR& rhs) const + { + if (lhs.first < rhs.first)return true; + else if (lhs.first > rhs.first)return false; + else return lhs.second < rhs.second; + } + }; + struct len_less_func + { + int norm2(const TC& R)const + { + return R[0] * R[0] + R[1] * R[1] + R[2] * R[2]; + } + bool operator()(const TC& lhs, const TC& rhs) const + { + if (norm2(lhs) < norm2(rhs))return true; + else if (norm2(lhs) > norm2(rhs))return false; + else return lhs < rhs; + } + }; + + //-------------------------------------------------------------------------------- + /// The main function to find irreducible sector: {abR} + void find_irreducible_sector(const Symmetry& symm, const Atom* atoms, const Statistics& st, + const std::vector& Rs, const TC& period, const Lattice& lat); + const std::map>& get_irreducible_sector()const { return this->irreducible_sector_; } + // const std::map>> convirt_irreducible_sector() {}; + //-------------------------------------------------------------------------------- + + /// Perfoming {R|t} to atom position r in the R=0 lattice, we get Rr+t, which may get out of R=0 lattice, + /// whose image in R=0 lattice is r'=Rr+t-O. This function is to get O for each atom and each symmetry operation. + /// the range of direct position is [-0.5, 0.5). + TCdouble get_return_lattice(const Symmetry& symm, + const ModuleBase::Matrix3& gmatd, const TCdouble gtransd, + const TCdouble& posd_a1, const TCdouble& posd_a2)const; + void get_return_lattice_all(const Symmetry& symm, const Atom* atoms, const Statistics& st); + + protected: + //-------------------------------------------------------------------------------- + /// The sub functions to find irreducible sector: {abR} + + /// gauge='L' means H(R)=; gauge='R' means H(R)=<0|H|R> + /// gauge='L': R'=R+O_1-O_2; gauge='R': R'=R+O_2-O_1 + TC rotate_R(const Symmetry& symm, const int isym, const int iat1, const int iat2, const TC& R, const char gauge = 'R')const; + TapR rotate_apR_by_formula(const Symmetry& symm, const int isym, const TapR& iapR, const char gauge = 'R')const; + /// gauge='L': tau_a + R - tau_b; gauge='R': tau_a - tau_b - R (direct) + TCdouble get_aRb_direct(const Atom* atoms, const Statistics& st, const int iat1, const int iat2, const TC& R, const char gauge = 'R')const; + TCdouble get_aRb_direct(const Atom* atoms, const Statistics& st, const int iat1, const int iat2, const TCdouble& R, const char gauge = 'R')const; + + ModuleBase::Matrix3 direct_to_cartesian(const ModuleBase::Matrix3& d, const ModuleBase::Matrix3& latvec)const; + + // /// find the irreducible atom pairs + // /// algorithm 1: the way finding irreducible k-points + // void find_irreducible_atom_pairs(const Symmetry& symm); + // /// algorithm 2: taking out atom pairs from the initial set + // void find_irreducible_atom_pairs_set(const Symmetry& symm); + // /// double check between the two algorithms + // void test_irreducible_atom_pairs(const Symmetry& symm); + + void output_full_map_to_irreducible_sector(const int nat); + void output_sector_star(); + + //-------------------------------------------------------------------------------- + /// The sub functions judge special symmetry + void gen_symmetry_BvK(const Symmetry& symm, const Atom* atoms, const Lattice& lat, const Statistics& st, const TC bvk_period); + /// whether in 2D plain or not for each symmetry operation + // std::vector in_plain(const ModuleSymmetry::Symmetry& symm, const ModuleBase::Matrix3& latvec)const; + //-------------------------------------------------------------------------------- + + //-------------------------------------------------------------------------------- + /// irreducible atom pairs: [n_iap][(isym, ap=(iat1, iat2))] + // std::vector> atompair_stars_; + + ///The index range of the orbital matrix to be calculated: irreducible R in irreducible atom pairs + // (including R in other atom pairs that cannot rotate into R_stars_[irreducebule_ap]) + std::map> irreducible_sector_; + + // //[natoms*natoms](R, (isym, irreducible_R)) + // std::vector>> full_map_to_irreducible_sector_; + // (abR) -> (isym, abR) + std::map, apR_less_func> full_map_to_irreducible_sector_; + + // all the {abR}s , where the isym=0 one in each star forms the irreducible sector. + // [irreducible sector size][isym, ((ab),R)] + std::vector> sector_stars_; + + /// the direct lattice vector of {R|t}\tau-\tau' for each atoms and each symmetry operation. [natom][nsym] + std::vector> return_lattice_; + + std::vector invmap_; + + /// symmetry info for BvK supercell + std::vector isymbvk_to_isym_; + std::vector bvk_gmatrix_; + std::vector> bvk_gtrans_; + int bvk_nsym_; + + friend class Symmetry_rotation; + }; +} \ No newline at end of file diff --git a/source/module_ri/exx_symmetry/irreducible_sector_bvk.cpp b/source/module_ri/exx_symmetry/irreducible_sector_bvk.cpp new file mode 100644 index 0000000000..6c40eda06e --- /dev/null +++ b/source/module_ri/exx_symmetry/irreducible_sector_bvk.cpp @@ -0,0 +1,160 @@ +#include "irreducible_sector.h" +namespace ModuleSymmetry +{ + ModuleBase::Matrix3 Irreducible_Sector::direct_to_cartesian(const ModuleBase::Matrix3& d, const ModuleBase::Matrix3& latvec)const + { + return latvec.Inverse() * d * latvec; + } + + std::vector inline get_isymbvk_to_isym_map(const std::vector& bvkgmat, const ModuleSymmetry::Symmetry& symm) + { + auto matequal = [&symm](ModuleBase::Matrix3 a, ModuleBase::Matrix3 b) + { + return (symm.equal(a.e11, b.e11) && symm.equal(a.e12, b.e12) && symm.equal(a.e13, b.e13) && + symm.equal(a.e21, b.e21) && symm.equal(a.e22, b.e22) && symm.equal(a.e23, b.e23) && + symm.equal(a.e31, b.e31) && symm.equal(a.e23, b.e23) && symm.equal(a.e33, b.e33)); + }; + std::vector isymbvk2isym(bvkgmat.size(), -1); + for (int isymbvk = 0;isymbvk < bvkgmat.size();++isymbvk) + { + for (int isym = 0;isym < symm.nrotk;++isym) + { + if (matequal(bvkgmat[isymbvk], symm.gmatrix[isym])) + { + isymbvk2isym[isymbvk] = isym; + break; + } + } + } + return isymbvk2isym; + } + + inline int gcd(const int a, const int b) + { + assert(a > 0 && b > 0); + int c = a % b; + return (c == 0) ? b : gcd(b, c); + } + void Irreducible_Sector::gen_symmetry_BvK(const ModuleSymmetry::Symmetry& symm, const Atom* atoms, const Lattice& lat, const Statistics& st, const TC bvk_period) + { + ModuleBase::TITLE("Irreducible_Sector", "gen_symmetry_BvK"); + auto set_matrix3 = [](const ModuleBase::Vector3& a1, const ModuleBase::Vector3& a2, const ModuleBase::Vector3& a3) + -> ModuleBase::Matrix3 {return ModuleBase::Matrix3(a1.x, a1.y, a1.z, a2.x, a2.y, a2.z, a3.x, a3.y, a3.z);}; + + if (bvk_period[0] == bvk_period[1] && bvk_period[0] == bvk_period[2]) + { //the BvK supercell has the same symmetry as the original cell + this->bvk_nsym_ = symm.nrotk; + this->isymbvk_to_isym_.resize(symm.nrotk); + for (int isym = 0;isym < symm.nrotk;++isym) this->isymbvk_to_isym_[isym] = isym; + return; + } + + // extern lattice to minimal BvK lattice, and set direct coordinates in min BvK lattice + int bvk_gcd = gcd(bvk_period[0], gcd(bvk_period[1], bvk_period[2])); + const TC bvk_min_period = TC({ bvk_period[0] / bvk_gcd, bvk_period[1] / bvk_gcd, bvk_period[2] / bvk_gcd }); + const int bvk_nat = st.nat * bvk_min_period[0] * bvk_min_period[1] * bvk_min_period[2]; + std::vector bvk_na(st.ntype); + std::vector bvk_istart(st.ntype, 0); + int bvk_itmin_start = 0, bvk_itmin_type = 0; + for (int it = 0;it < st.ntype;++it) + { + bvk_na[it] = atoms[it].na * bvk_min_period[0] * bvk_min_period[1] * bvk_min_period[2]; + if (it > 0) bvk_istart[it] = bvk_istart[it - 1] + bvk_na[it - 1]; + if (bvk_na[it] < bvk_na[bvk_itmin_type]) + { + bvk_itmin_type = it; + bvk_itmin_start = bvk_istart[it]; + } + } + + std::vector bvk_dpos(3 * bvk_nat); + std::vector bvk_rot_dpos(3 * bvk_nat); + std::vector order_index(bvk_nat + 2); + ModuleBase::Vector3 a1, a2, a3, s1, s2, s3; // a: to be optimized; s: original + s1 = a1 = lat.a1 * static_cast(bvk_min_period[0]); + s2 = a2 = lat.a2 * static_cast(bvk_min_period[1]); + s3 = a3 = lat.a3 * static_cast(bvk_min_period[2]); + ModuleBase::Matrix3 bvk_min_lat = set_matrix3(s1, s2, s3); + int at = 0; + for (int it = 0; it < st.ntype; ++it) + for (int c1 = 0;c1 < bvk_min_period[0];++c1) + for (int c2 = 0;c2 < bvk_min_period[1];++c2) + for (int c3 = 0;c3 < bvk_min_period[2];++c3) + for (int ia = 0; ia < atoms[it].na; ++ia) + { + bvk_dpos[3 * at] = (static_cast (c1) + atoms[it].taud[ia].x) / static_cast(bvk_min_period[0]); + bvk_dpos[3 * at + 1] = (static_cast (c2) + atoms[it].taud[ia].y) / static_cast(bvk_min_period[1]); + bvk_dpos[3 * at + 2] = (static_cast (c3) + atoms[it].taud[ia].z) / static_cast(bvk_min_period[2]); + for (int k = 0; k < 3; ++k) + { + symm.check_translation(bvk_dpos[3 * at + k], -floor(bvk_dpos[3 * at + k])); + symm.check_boundary(bvk_dpos[3 * at + k]); + } + ++at; + } + + // analyze bravis and generate optimized lattice for minimal BvK lattice + double cel_const[6], pre_const[6]; + int bvk_brav; + std::string bvk_latname; + // bvk_brav = symm.standard_lat(s1, s2, s3, cel_const); //not enough, optimal lattice may change after cell-extension + symm.lattice_type(a1, a2, a3, s1, s2, s3, cel_const, pre_const, bvk_brav, bvk_latname, nullptr, false, nullptr); + ModuleBase::Matrix3 bvk_min_optlat = set_matrix3(a1, a2, a3); + // convert the direct coordinates to the optimized lattice + for (int i = 0;i < bvk_nat;++i) + { + ModuleBase::Vector3 taud(bvk_dpos[3 * i], bvk_dpos[3 * i + 1], bvk_dpos[3 * i + 2]); + taud = taud * bvk_min_lat * bvk_min_optlat.Inverse(); + bvk_dpos[3 * i] = taud.x; + bvk_dpos[3 * i + 1] = taud.y; + bvk_dpos[3 * i + 2] = taud.z; + for (int k = 0; k < 3; ++k) + { + symm.check_translation(bvk_dpos[3 * i + k], -floor(bvk_dpos[3 * i + k])); + symm.check_boundary(bvk_dpos[3 * i + k]); + } + } + + // generate symmetry operation of the BvK lattice using the original optlat-direct coordinates + std::vector bvk_op(48); + int bvk_nop; + symm.setgroup(bvk_op.data(), bvk_nop, bvk_brav); + bvk_op.resize(bvk_nop); + int bvk_npg, bvk_nsg, bvk_pgnum, bvk_sgnum; + std::string bvk_pgname, bvk_sgname; + this->bvk_gmatrix_.resize(48); + this->bvk_gtrans_.resize(48); + symm.getgroup(bvk_npg, bvk_nsg, GlobalV::ofs_running, bvk_nop, + bvk_op.data(), this->bvk_gmatrix_.data(), this->bvk_gtrans_.data(), + bvk_dpos.data(), bvk_rot_dpos.data(), order_index.data(), + bvk_itmin_type, bvk_itmin_start, bvk_istart.data(), bvk_na.data()); + this->bvk_gmatrix_.resize(bvk_nsg); + this->bvk_gtrans_.resize(bvk_nsg); + this->bvk_nsym_ = bvk_nsg; + symm.pointgroup(bvk_npg, bvk_pgnum, bvk_pgname, this->bvk_gmatrix_.data(), GlobalV::ofs_running); + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "POINT GROUP OF BvK SCELL", bvk_pgname); + symm.pointgroup(bvk_nsg, bvk_sgnum, bvk_sgname, this->bvk_gmatrix_.data(), GlobalV::ofs_running); + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "POINT GROUP IN SPACE GROUP OF BvK SCELL", bvk_pgname); + symm.gmatrix_convert_int(this->bvk_gmatrix_.data(), this->bvk_gmatrix_.data(), bvk_nsg, bvk_min_optlat, lat.latvec); + symm.gtrans_convert(this->bvk_gtrans_.data(), this->bvk_gtrans_.data(), bvk_nsg, bvk_min_optlat, lat.latvec); + // get map from bvk-op to original op + this->isymbvk_to_isym_ = get_isymbvk_to_isym_map(this->bvk_gmatrix_, symm); + return; + } + + // std::vector Irreducible_Sector::in_plain(const ModuleSymmetry::Symmetry& symm, const ModuleBase::Matrix3& latvec)const + // { + // // get euler angel of the cartesian gmatrix in optimal lattice + // std::vector gmatc(symm.nrotk); + // symm.gmatrix_convert_int(symm.gmatrix, gmatc.data(), symm.nrotk, latvec, symm.optlat); + // for (auto& g : gmatc) g = direct_to_cartesian(g, symm.optlat); + // std::vector in_plain(symm.nrotk, false); + // for (int i = 0;i < symm.nrotk;++i) + // { + // TCdouble euler_angle = get_euler_angle(gmatc[i]); + // if (symm.equal(euler_angle.y, 0.0) || symm.equal(euler_angle.y, ModuleBase::PI)) in_plain[i] = true; + // } + // return in_plain; + // } + +} \ No newline at end of file diff --git a/source/module_ri/symmetry_rotation.cpp b/source/module_ri/exx_symmetry/symmetry_rotation.cpp similarity index 55% rename from source/module_ri/symmetry_rotation.cpp rename to source/module_ri/exx_symmetry/symmetry_rotation.cpp index b72babe640..ab2a80afe3 100644 --- a/source/module_ri/symmetry_rotation.cpp +++ b/source/module_ri/exx_symmetry/symmetry_rotation.cpp @@ -1,3 +1,4 @@ +#include "symmetry_rotation.h" #include "module_base/constants.h" #include #include "module_base/parallel_reduce.h" @@ -5,7 +6,7 @@ #include "module_base/tool_title.h" #include "module_base/timer.h" #include "module_base/mathzone.h" -#include "symmetry_rotation.h" + #include "module_hamilt_pw/hamilt_pwdft/global.h" namespace ModuleSymmetry @@ -19,14 +20,14 @@ namespace ModuleSymmetry this->nsym_ = ucell.symm.nrotk; this->eps_ = ucell.symm.epsilon; - if (this->invmap_.empty()) + if (this->irs_.invmap_.empty()) { - this->invmap_.resize(ucell.symm.nrotk); - ucell.symm.gmatrix_invmap(ucell.symm.gmatrix, ucell.symm.nrotk, invmap_.data()); + this->irs_.invmap_.resize(ucell.symm.nrotk); + ucell.symm.gmatrix_invmap(ucell.symm.gmatrix, ucell.symm.nrotk, this->irs_.invmap_.data()); } // 1. calculate the rotation matrix in real spherical harmonics representation for each symmetry operation: [T_l (isym)]_mm' std::vector gmatc(nsym_); - for (int i = 0;i < nsym_;++i) gmatc[i] = this->direct_to_cartesian(ucell.symm.gmatrix[i], ucell.latvec); + for (int i = 0;i < nsym_;++i) gmatc[i] = this->irs_.direct_to_cartesian(ucell.symm.gmatrix[i], ucell.latvec); this->cal_rotmat_Slm(gmatc.data(), ucell.lmax); // 2. calculate the rotation matrix in AO-representation for each ibz_kpoint and symmetry operation: M(k, isym) @@ -265,115 +266,42 @@ namespace ModuleSymmetry // set_integer(this->rotmat_Slm_[isym][l]); } } -/* - std::vector euler_angles_test(nsym_); - for (int isym = 0;isym < nsym_;++isym) euler_angles_test[isym] = - get_euler_angle(gmatc[isym].Det() > 0 ? gmatc[isym] : gmatc[isym] * ModuleBase::Matrix3(-1, 0, 0, 0, -1, 0, 0, 0, -1)); + /* + std::vector euler_angles_test(nsym_); + for (int isym = 0;isym < nsym_;++isym) euler_angles_test[isym] = + get_euler_angle(gmatc[isym].Det() > 0 ? gmatc[isym] : gmatc[isym] * ModuleBase::Matrix3(-1, 0, 0, 0, -1, 0, 0, 0, -1)); - auto test_Tmm = [&]()-> void - { - std::ofstream ofs("Tlm.dat"); - for (int isym = 0;isym < nsym_;++isym) - { - ofs << "isym=" << isym << std::endl; - ofs << "gmatrix_cart=" << std::endl; - ofs << gmatc[isym].e11 << " " << gmatc[isym].e12 << " " << gmatc[isym].e13 << std::endl; - ofs << gmatc[isym].e21 << " " << gmatc[isym].e22 << " " << gmatc[isym].e23 << std::endl; - ofs << gmatc[isym].e31 << " " << gmatc[isym].e32 << " " << gmatc[isym].e33 << std::endl; - ofs << "gmatrix_direct=" << std::endl; - ofs << GlobalC::ucell.symm.gmatrix[isym].e11 << " " << GlobalC::ucell.symm.gmatrix[isym].e12 << " " << GlobalC::ucell.symm.gmatrix[isym].e13 << std::endl; - ofs << GlobalC::ucell.symm.gmatrix[isym].e21 << " " << GlobalC::ucell.symm.gmatrix[isym].e22 << " " << GlobalC::ucell.symm.gmatrix[isym].e23 << std::endl; - ofs << GlobalC::ucell.symm.gmatrix[isym].e31 << " " << GlobalC::ucell.symm.gmatrix[isym].e32 << " " << GlobalC::ucell.symm.gmatrix[isym].e33 << std::endl; - ofs << "kgmatrix_direct=" << std::endl; - ofs << GlobalC::ucell.symm.kgmatrix[isym].e11 << " " << GlobalC::ucell.symm.kgmatrix[isym].e12 << " " << GlobalC::ucell.symm.kgmatrix[isym].e13 << std::endl; - ofs << GlobalC::ucell.symm.kgmatrix[isym].e21 << " " << GlobalC::ucell.symm.kgmatrix[isym].e22 << " " << GlobalC::ucell.symm.kgmatrix[isym].e23 << std::endl; - ofs << GlobalC::ucell.symm.kgmatrix[isym].e31 << " " << GlobalC::ucell.symm.kgmatrix[isym].e32 << " " << GlobalC::ucell.symm.kgmatrix[isym].e33 << std::endl; - ofs << "euler_angle/pi: " << euler_angles_test[isym].x / ModuleBase::PI << " " - << euler_angles_test[isym].y / ModuleBase::PI << " " << euler_angles_test[isym].z / ModuleBase::PI << std::endl; - for (int l = 0;l <= lmax;++l) - for (int i = 0;i < 2 * l + 1;++i) + auto test_Tmm = [&]()-> void + { + std::ofstream ofs("Tlm.dat"); + for (int isym = 0;isym < nsym_;++isym) { - for (int j = 0;j < 2 * l + 1;++j) ofs << this->rotmat_Slm_[isym][l](i, j) << " "; - ofs << std::endl; + ofs << "isym=" << isym << std::endl; + ofs << "gmatrix_cart=" << std::endl; + ofs << gmatc[isym].e11 << " " << gmatc[isym].e12 << " " << gmatc[isym].e13 << std::endl; + ofs << gmatc[isym].e21 << " " << gmatc[isym].e22 << " " << gmatc[isym].e23 << std::endl; + ofs << gmatc[isym].e31 << " " << gmatc[isym].e32 << " " << gmatc[isym].e33 << std::endl; + ofs << "gmatrix_direct=" << std::endl; + ofs << GlobalC::ucell.symm.gmatrix[isym].e11 << " " << GlobalC::ucell.symm.gmatrix[isym].e12 << " " << GlobalC::ucell.symm.gmatrix[isym].e13 << std::endl; + ofs << GlobalC::ucell.symm.gmatrix[isym].e21 << " " << GlobalC::ucell.symm.gmatrix[isym].e22 << " " << GlobalC::ucell.symm.gmatrix[isym].e23 << std::endl; + ofs << GlobalC::ucell.symm.gmatrix[isym].e31 << " " << GlobalC::ucell.symm.gmatrix[isym].e32 << " " << GlobalC::ucell.symm.gmatrix[isym].e33 << std::endl; + ofs << "kgmatrix_direct=" << std::endl; + ofs << GlobalC::ucell.symm.kgmatrix[isym].e11 << " " << GlobalC::ucell.symm.kgmatrix[isym].e12 << " " << GlobalC::ucell.symm.kgmatrix[isym].e13 << std::endl; + ofs << GlobalC::ucell.symm.kgmatrix[isym].e21 << " " << GlobalC::ucell.symm.kgmatrix[isym].e22 << " " << GlobalC::ucell.symm.kgmatrix[isym].e23 << std::endl; + ofs << GlobalC::ucell.symm.kgmatrix[isym].e31 << " " << GlobalC::ucell.symm.kgmatrix[isym].e32 << " " << GlobalC::ucell.symm.kgmatrix[isym].e33 << std::endl; + ofs << "euler_angle/pi: " << euler_angles_test[isym].x / ModuleBase::PI << " " + << euler_angles_test[isym].y / ModuleBase::PI << " " << euler_angles_test[isym].z / ModuleBase::PI << std::endl; + for (int l = 0;l <= lmax;++l) + for (int i = 0;i < 2 * l + 1;++i) + { + for (int j = 0;j < 2 * l + 1;++j) ofs << this->rotmat_Slm_[isym][l](i, j) << " "; + ofs << std::endl; + } } - } - ofs.close(); - }; - test_Tmm(); - */ - } - - // Perfoming {R|t} to atom position r in the R=0 lattice, we get Rr+t, which may get out of R=0 lattice, - // whose image in R=0 lattice is r'=Rr+t-O. This function is to get O for each atom and each symmetry operation. - // the range of direct position is [-0.5, 0.5). - TCdouble Symmetry_rotation::get_return_lattice(const Symmetry& symm, - const ModuleBase::Matrix3& gmatd, const TCdouble gtransd, - const TCdouble& posd_a1, const TCdouble& posd_a2)const - { - // auto restrict_center = [&symm](const TCdouble& v) -> TCdouble { - // // in [-0.5, 0.5) - // TCdouble vr; - // vr.x = fmod(v.x + 100.5 + 0.5 * symm.epsilon, 1) - 0.5 - 0.5 * symm.epsilon; - // vr.y = fmod(v.y + 100.5 + 0.5 * symm.epsilon, 1) - 0.5 - 0.5 * symm.epsilon; - // vr.z = fmod(v.z + 100.5 + 0.5 * symm.epsilon, 1) - 0.5 - 0.5 * symm.epsilon; - // if (std::abs(vr.x) < symm.epsilon) vr.x = 0.0; - // if (std::abs(vr.y) < symm.epsilon) vr.y = 0.0; - // if (std::abs(vr.z) < symm.epsilon) vr.z = 0.0; - // return vr; - // }; - auto restrict_center = [&symm](const TCdouble& v) -> TCdouble { - // in [0,1) - TCdouble vr; - vr.x = fmod(v.x + 100 + symm.epsilon, 1) - symm.epsilon; - vr.y = fmod(v.y + 100 + symm.epsilon, 1) - symm.epsilon; - vr.z = fmod(v.z + 100 + symm.epsilon, 1) - symm.epsilon; - if (std::abs(vr.x) < symm.epsilon) vr.x = 0.0; - if (std::abs(vr.y) < symm.epsilon) vr.y = 0.0; - if (std::abs(vr.z) < symm.epsilon) vr.z = 0.0; - return vr; - }; - auto check_integer = [&symm](const double x) -> void { - assert(symm.equal(x, std::round(x))); - }; - TCdouble rotpos1 = restrict_center(posd_a1) * gmatd + restrict_center(gtransd); // row vector - TCdouble return_lattice_double = rotpos1 - restrict_center(posd_a2); -#ifdef __DEBUG - check_integer(return_lattice_double.x); - check_integer(return_lattice_double.y); - check_integer(return_lattice_double.z); -#endif - return TCdouble(std::round(return_lattice_double.x), std::round(return_lattice_double.y), std::round(return_lattice_double.z)); - } - - inline void output_return_lattice(const std::vector>& return_lattice) - { - std::cout << "return lattice:" << std::endl; - for (int iat = 0;iat < return_lattice.size();++iat) - { - std::cout << "atom" << iat << std::endl; - for (int isym = 0;isym < return_lattice[iat].size();++isym) - std::cout << "isym=" << isym << ", return lattice=" << - return_lattice[iat][isym].x << " " << return_lattice[iat][isym].y << " " << return_lattice[iat][isym].z << std::endl; - } - } - - void Symmetry_rotation::get_return_lattice_all(const Symmetry& symm, const Atom* atoms, const Statistics& st) - { - ModuleBase::TITLE("Symmetry_rotation", "get_return_lattice_all"); - this->return_lattice_.resize(st.nat, std::vector(symm.nrotk)); - for (int iat1 = 0;iat1 < st.nat;++iat1) - { - int it = st.iat2it[iat1]; - int ia1 = st.iat2ia[iat1]; - for (int isym = 0;isym < symm.nrotk;++isym) - { - int iat2 = symm.get_rotated_atom(isym, iat1); - int ia2 = st.iat2ia[iat2]; - this->return_lattice_[iat1][isym] = get_return_lattice(symm, symm.gmatrix[isym], symm.gtrans[isym], atoms[it].taud[ia1], atoms[it].taud[ia2]); - } - } - // test: output return_lattice - output_return_lattice(this->return_lattice_); + ofs.close(); + }; + test_Tmm(); + */ } void Symmetry_rotation::set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, @@ -413,7 +341,7 @@ namespace ModuleSymmetry int iat2 = symm.get_rotated_atom(isym, iat1); //iat2=rot(iat1) int ia2 = cell_st.iat2ia[iat2]; // cal phase factor from return lattice: exp(-ik_ibz*O) - double arg = 2 * ModuleBase::PI * kvec_d_ibz * this->return_lattice_[iat1][isym]; + double arg = 2 * ModuleBase::PI * kvec_d_ibz * this->irs_.return_lattice_[iat1][isym]; std::complexphase_factor = std::complex(std::cos(arg), std::sin(arg)); int iw1start = atoms[it].stapos_wf + ia1 * atoms[it].nw; int iw2start = atoms[it].stapos_wf + ia2 * atoms[it].nw; @@ -474,161 +402,40 @@ namespace ModuleSymmetry return DMk; } - ModuleBase::Matrix3 Symmetry_rotation::direct_to_cartesian(const ModuleBase::Matrix3& d, const ModuleBase::Matrix3& latvec)const + std::vector Symmetry_rotation::get_Rs_from_adjacent_list(const UnitCell& ucell, Grid_Driver& gd, const Parallel_Orbitals& pv) const { - return latvec.Inverse() * d * latvec; - } - - std::vector inline get_isymbvk_to_isym_map(const std::vector& bvkgmat, const ModuleSymmetry::Symmetry& symm) - { - auto matequal = [&symm](ModuleBase::Matrix3 a, ModuleBase::Matrix3 b) - { - return (symm.equal(a.e11, b.e11) && symm.equal(a.e12, b.e12) && symm.equal(a.e13, b.e13) && - symm.equal(a.e21, b.e21) && symm.equal(a.e22, b.e22) && symm.equal(a.e23, b.e23) && - symm.equal(a.e31, b.e31) && symm.equal(a.e23, b.e23) && symm.equal(a.e33, b.e33)); - }; - std::vector isymbvk2isym(bvkgmat.size(), -1); - for (int isymbvk = 0;isymbvk < bvkgmat.size();++isymbvk) + // find the union set of Rs for all the atom pairs + std::set Rs_set; + for (int iat1 = 0;iat1 < ucell.nat;++iat1) { - for (int isym = 0;isym < symm.nrotk;++isym) + auto tau1 = ucell.get_tau(iat1); + int it1 = ucell.iat2it[iat1], ia1 = ucell.iat2ia[iat1]; + AdjacentAtomInfo adjs; + gd.Find_atom(ucell, tau1, it1, ia1, &adjs); + for (int ad = 0; ad < adjs.adj_num + 1; ++ad) { - if (matequal(bvkgmat[isymbvk], symm.gmatrix[isym])) + const int it2 = adjs.ntype[ad]; + const int ia2 = adjs.natom[ad]; + int iat2 = ucell.itia2iat(it2, ia2); + if (pv.get_row_size(iat1) && pv.get_col_size(iat2)) { - isymbvk2isym[isymbvk] = isym; - break; + const ModuleBase::Vector3& R_index = adjs.box[ad]; + if (ucell.cal_dtau(iat1, iat2, R_index).norm() * ucell.lat0 + < ucell.atoms[it1].Rcut + ucell.atoms[it2].Rcut) + Rs_set.insert({ R_index.x, R_index.y, R_index.z }); } } } - return isymbvk2isym; + // set to vector + std::vector Rs(Rs_set.size()); + for (auto& R : Rs_set) Rs.push_back(R); + return Rs; } - inline int gcd(const int a, const int b) + std::vector Symmetry_rotation::get_Rs_from_BvK(const K_Vectors& kv) const { - assert(a > 0 && b > 0); - int c = a % b; - return (c == 0) ? b : gcd(b, c); + const TC& period = RI_Util::get_Born_vonKarmen_period(kv); + return RI_Util::get_Born_von_Karmen_cells(period); } - void Symmetry_rotation::gen_symmetry_BvK(const ModuleSymmetry::Symmetry& symm, const Atom* atoms, const Lattice& lat, const Statistics& st, const TC bvk_period) - { - ModuleBase::TITLE("Symmetry_rotation", "gen_symmetry_BvK"); - auto set_matrix3 = [](const ModuleBase::Vector3& a1, const ModuleBase::Vector3& a2, const ModuleBase::Vector3& a3) - -> ModuleBase::Matrix3 {return ModuleBase::Matrix3(a1.x, a1.y, a1.z, a2.x, a2.y, a2.z, a3.x, a3.y, a3.z);}; - - if (bvk_period[0] == bvk_period[1] && bvk_period[0] == bvk_period[2]) - { //the BvK supercell has the same symmetry as the original cell - this->bvk_nsym_ = symm.nrotk; - this->isymbvk_to_isym_.resize(symm.nrotk); - for (int isym = 0;isym < symm.nrotk;++isym) this->isymbvk_to_isym_[isym] = isym; - return; - } - - // extern lattice to minimal BvK lattice, and set direct coordinates in min BvK lattice - int bvk_gcd = gcd(bvk_period[0], gcd(bvk_period[1], bvk_period[2])); - const TC bvk_min_period = TC({ bvk_period[0] / bvk_gcd, bvk_period[1] / bvk_gcd, bvk_period[2] / bvk_gcd }); - const int bvk_nat = st.nat * bvk_min_period[0] * bvk_min_period[1] * bvk_min_period[2]; - std::vector bvk_na(st.ntype); - std::vector bvk_istart(st.ntype, 0); - int bvk_itmin_start = 0, bvk_itmin_type = 0; - for (int it = 0;it < st.ntype;++it) - { - bvk_na[it] = atoms[it].na * bvk_min_period[0] * bvk_min_period[1] * bvk_min_period[2]; - if (it > 0) bvk_istart[it] = bvk_istart[it - 1] + bvk_na[it - 1]; - if (bvk_na[it] < bvk_na[bvk_itmin_type]) - { - bvk_itmin_type = it; - bvk_itmin_start = bvk_istart[it]; - } - } - - std::vector bvk_dpos(3 * bvk_nat); - std::vector bvk_rot_dpos(3 * bvk_nat); - std::vector order_index(bvk_nat + 2); - ModuleBase::Vector3 a1, a2, a3, s1, s2, s3; // a: to be optimized; s: original - s1 = a1 = lat.a1 * static_cast(bvk_min_period[0]); - s2 = a2 = lat.a2 * static_cast(bvk_min_period[1]); - s3 = a3 = lat.a3 * static_cast(bvk_min_period[2]); - ModuleBase::Matrix3 bvk_min_lat = set_matrix3(s1, s2, s3); - int at = 0; - for (int it = 0; it < st.ntype; ++it) - for (int c1 = 0;c1 < bvk_min_period[0];++c1) - for (int c2 = 0;c2 < bvk_min_period[1];++c2) - for (int c3 = 0;c3 < bvk_min_period[2];++c3) - for (int ia = 0; ia < atoms[it].na; ++ia) - { - bvk_dpos[3 * at] = (static_cast (c1) + atoms[it].taud[ia].x) / static_cast(bvk_min_period[0]); - bvk_dpos[3 * at + 1] = (static_cast (c2) + atoms[it].taud[ia].y) / static_cast(bvk_min_period[1]); - bvk_dpos[3 * at + 2] = (static_cast (c3) + atoms[it].taud[ia].z) / static_cast(bvk_min_period[2]); - for (int k = 0; k < 3; ++k) - { - symm.check_translation(bvk_dpos[3 * at + k], -floor(bvk_dpos[3 * at + k])); - symm.check_boundary(bvk_dpos[3 * at + k]); - } - ++at; - } - - // analyze bravis and generate optimized lattice for minimal BvK lattice - double cel_const[6], pre_const[6]; - int bvk_brav; - std::string bvk_latname; - // bvk_brav = symm.standard_lat(s1, s2, s3, cel_const); //not enough, optimal lattice may change after cell-extension - symm.lattice_type(a1, a2, a3, s1, s2, s3, cel_const, pre_const, bvk_brav, bvk_latname, nullptr, false, nullptr); - ModuleBase::Matrix3 bvk_min_optlat = set_matrix3(a1, a2, a3); - // convert the direct coordinates to the optimized lattice - for (int i = 0;i < bvk_nat;++i) - { - ModuleBase::Vector3 taud(bvk_dpos[3 * i], bvk_dpos[3 * i + 1], bvk_dpos[3 * i + 2]); - taud = taud * bvk_min_lat * bvk_min_optlat.Inverse(); - bvk_dpos[3 * i] = taud.x; - bvk_dpos[3 * i + 1] = taud.y; - bvk_dpos[3 * i + 2] = taud.z; - for (int k = 0; k < 3; ++k) - { - symm.check_translation(bvk_dpos[3 * i + k], -floor(bvk_dpos[3 * i + k])); - symm.check_boundary(bvk_dpos[3 * i + k]); - } - } - - // generate symmetry operation of the BvK lattice using the original optlat-direct coordinates - std::vector bvk_op(48); - int bvk_nop; - symm.setgroup(bvk_op.data(), bvk_nop, bvk_brav); - bvk_op.resize(bvk_nop); - int bvk_npg, bvk_nsg, bvk_pgnum, bvk_sgnum; - std::string bvk_pgname, bvk_sgname; - this->bvk_gmatrix_.resize(48); - this->bvk_gtrans_.resize(48); - symm.getgroup(bvk_npg, bvk_nsg, GlobalV::ofs_running, bvk_nop, - bvk_op.data(), this->bvk_gmatrix_.data(), this->bvk_gtrans_.data(), - bvk_dpos.data(), bvk_rot_dpos.data(), order_index.data(), - bvk_itmin_type, bvk_itmin_start, bvk_istart.data(), bvk_na.data()); - this->bvk_gmatrix_.resize(bvk_nsg); - this->bvk_gtrans_.resize(bvk_nsg); - this->bvk_nsym_ = bvk_nsg; - symm.pointgroup(bvk_npg, bvk_pgnum, bvk_pgname, this->bvk_gmatrix_.data(), GlobalV::ofs_running); - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "POINT GROUP OF BvK SCELL", bvk_pgname); - symm.pointgroup(bvk_nsg, bvk_sgnum, bvk_sgname, this->bvk_gmatrix_.data(), GlobalV::ofs_running); - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "POINT GROUP IN SPACE GROUP OF BvK SCELL", bvk_pgname); - symm.gmatrix_convert_int(this->bvk_gmatrix_.data(), this->bvk_gmatrix_.data(), bvk_nsg, bvk_min_optlat, lat.latvec); - symm.gtrans_convert(this->bvk_gtrans_.data(), this->bvk_gtrans_.data(), bvk_nsg, bvk_min_optlat, lat.latvec); - // get map from bvk-op to original op - this->isymbvk_to_isym_ = get_isymbvk_to_isym_map(this->bvk_gmatrix_, symm); - return; - } - - std::vector Symmetry_rotation::in_plain(const ModuleSymmetry::Symmetry& symm, const ModuleBase::Matrix3& latvec)const - { - // get euler angel of the cartesian gmatrix in optimal lattice - std::vector gmatc(symm.nrotk); - symm.gmatrix_convert_int(symm.gmatrix, gmatc.data(), symm.nrotk, latvec, symm.optlat); - for (auto& g : gmatc) g = direct_to_cartesian(g, symm.optlat); - std::vector in_plain(symm.nrotk, false); - for (int i = 0;i < symm.nrotk;++i) - { - TCdouble euler_angle = get_euler_angle(gmatc[i]); - if (symm.equal(euler_angle.y, 0.0) || symm.equal(euler_angle.y, ModuleBase::PI)) in_plain[i] = true; - } - return in_plain; - } - } \ No newline at end of file diff --git a/source/module_ri/symmetry_rotation.h b/source/module_ri/exx_symmetry/symmetry_rotation.h similarity index 58% rename from source/module_ri/symmetry_rotation.h rename to source/module_ri/exx_symmetry/symmetry_rotation.h index aa839d30fe..2067c5f67a 100644 --- a/source/module_ri/symmetry_rotation.h +++ b/source/module_ri/exx_symmetry/symmetry_rotation.h @@ -1,18 +1,10 @@ #pragma once -#include "module_base/abfs-vector3_order.h" -#include "module_base/complexmatrix.h" -#include "module_base/matrix3.h" -#include -#include -#include -#include "module_basis/module_ao/parallel_2d.h" -#include "module_cell/unitcell.h" -#include "module_cell/module_symmetry/symmetry.h" -#include "module_cell/klist.h" +#include "irreducible_sector.h" +#include "module_basis/module_ao/parallel_orbitals.h" #include #include "module_hamilt_lcao/module_hcontainer/hcontainer.h" #include "module_cell/module_neighbor/sltk_grid_driver.h" - + namespace ModuleSymmetry { using Tap = std::pair; @@ -20,49 +12,32 @@ namespace ModuleSymmetry using TapR = std::pair; using TCdouble = Abfs::Vector3_Order; - struct ap_less_func - { - bool operator()(const Tap& lhs, const Tap& rhs) const - { - if (lhs.first < rhs.first)return true; - else if (lhs.first > rhs.first)return false; - else return lhs.second < rhs.second; - } - }; - struct apR_less_func - { - bool operator()(const TapR& lhs, const TapR& rhs) const - { - if (lhs.first < rhs.first)return true; - else if (lhs.first > rhs.first)return false; - else return lhs.second < rhs.second; - } - }; - struct len_less_func - { - int norm2(const TC& R)const - { - return R[0] * R[0] + R[1] * R[1] + R[2] * R[2]; - } - bool operator()(const TC& lhs, const TC& rhs) const - { - if (norm2(lhs) < norm2(rhs))return true; - else if (norm2(lhs) > norm2(rhs))return false; - else return lhs < rhs; - } - }; - class Symmetry_rotation { public: Symmetry_rotation() {}; ~Symmetry_rotation() {}; + //-------------------------------------------------------------------------------- - /// functions to contruct rotation matrix in AO-representation + // getters + const std::map>& get_irreducible_sector()const { return this->irs_.get_irreducible_sector(); } + void find_irreducible_sector(const Symmetry& symm, const Atom* atoms, const Statistics& st, + const std::vector& Rs, const TC& period, const Lattice& lat) + { + this->irs_.find_irreducible_sector(symm, atoms, st, Rs, period, lat); + } + TCdouble get_return_lattice(const Symmetry& symm, + const ModuleBase::Matrix3& gmatd, const TCdouble gtransd, + const TCdouble& posd_a1, const TCdouble& posd_a2)const + { + return this->irs_.get_return_lattice(symm, gmatd, gtransd, posd_a1, posd_a2); + } + //-------------------------------------------------------------------------------- +/// functions to contruct rotation matrix in AO-representation - /// The top-level calculation interface of this class. calculate the rotation matrix in AO representation: M - /// only need once call in each ion step (decided by the configuration) - /// @param kstars equal k points to each ibz-kpont, corresponding to a certain symmetry operations. +/// The top-level calculation interface of this class. calculate the rotation matrix in AO representation: M +/// only need once call in each ion step (decided by the configuration) +/// @param kstars equal k points to each ibz-kpont, corresponding to a certain symmetry operations. void cal_Ms(const K_Vectors& kv, //const std::vector>& kstars, const UnitCell& ucell, const Parallel_2D& pv); @@ -91,14 +66,6 @@ namespace ModuleSymmetry /// T_mm' = [c^\dagger D c]_mm', the rotation matrix in the representation of real sphere harmonics void cal_rotmat_Slm(const ModuleBase::Matrix3* gmatc, const int lmax); - /// Perfoming {R|t} to atom position r in the R=0 lattice, we get Rr+t, which may get out of R=0 lattice, - /// whose image in R=0 lattice is r'=Rr+t-O. This function is to get O for each atom and each symmetry operation. - /// the range of direct position is [-0.5, 0.5). - TCdouble get_return_lattice(const Symmetry& symm, - const ModuleBase::Matrix3& gmatd, const TCdouble gtransd, - const TCdouble& posd_a1, const TCdouble& posd_a2)const; - void get_return_lattice_all(const Symmetry& symm, const Atom* atoms, const Statistics& st); - /// set a block matrix onto a 2d-parallelized matrix(col-maj), at the position (starti, startj) /// if trans=true, the block matrix is transposed before setting void set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, @@ -111,20 +78,8 @@ namespace ModuleSymmetry std::vector> contruct_2d_rot_mat_ao(const Symmetry& symm, const Atom* atoms, const Statistics& cell_st, const TCdouble& kvec_d_ibz, int isym, const Parallel_2D& pv) const; - ModuleBase::Matrix3 direct_to_cartesian(const ModuleBase::Matrix3& d, const ModuleBase::Matrix3& latvec)const; - std::vector>& get_rotmat_Slm() { return this->rotmat_Slm_; } - //-------------------------------------------------------------------------------- - /// The main function to find irreducible sector: {abR} - void find_irreducible_sector(const Symmetry& symm, const Atom* atoms, const Statistics& st, - const std::vector& Rs, const TC& period, const Lattice& lat); - std::vector get_Rs_from_BvK(const K_Vectors& kv)const; - std::vector get_Rs_from_adjacent_list(const UnitCell& ucell, Grid_Driver& gd, const Parallel_Orbitals& pv)const; - const std::map>& get_irreducible_sector()const { return this->irreducible_sector_; } - // const std::map>> convirt_irreducible_sector() {}; - //-------------------------------------------------------------------------------- - //-------------------------------------------------------------------------------- /// The main functions to rotate matrices /// Given H(R) in the irreduceble sector, calculate H(R) for all the atompairs and cells. @@ -151,47 +106,26 @@ namespace ModuleSymmetry //-------------------------------------------------------------------------------- private: - int round2int(const double x)const; - //-------------------------------------------------------------------------------- - /// The sub functions to find irreducible sector: {abR} - - /// gauge='L' means H(R)=; gauge='R' means H(R)=<0|H|R> - /// gauge='L': R'=R+O_1-O_2; gauge='R': R'=R+O_2-O_1 - TC rotate_R_by_formula(const Symmetry& symm, const int isym, const int iat1, const int iat2, const TC& R, const char gauge = 'R')const; - TapR rotate_R_by_formula(const Symmetry& symm, const int isym, const TapR& iapR, const char gauge = 'R')const; - /// gauge='L': tau_a + R - tau_b; gauge='R': tau_a - tau_b - R (direct) - TCdouble get_aRb_direct(const Atom* atoms, const Statistics& st, const int iat1, const int iat2, const TC& R, const char gauge = 'R')const; - TCdouble get_aRb_direct(const Atom* atoms, const Statistics& st, const int iat1, const int iat2, const TCdouble& R, const char gauge = 'R')const; - - // /// find the irreducible atom pairs - // /// algorithm 1: the way finding irreducible k-points - // void find_irreducible_atom_pairs(const Symmetry& symm); - // /// algorithm 2: taking out atom pairs from the initial set - // void find_irreducible_atom_pairs_set(const Symmetry& symm); - // /// double check between the two algorithms - // void test_irreducible_atom_pairs(const Symmetry& symm); - - void output_full_map_to_irreducible_sector(const int nat); - void output_sector_star(); - + std::vector get_Rs_from_BvK(const K_Vectors& kv)const; + std::vector get_Rs_from_adjacent_list(const UnitCell& ucell, Grid_Driver& gd, const Parallel_Orbitals& pv)const; //-------------------------------------------------------------------------------- /// The sub functions to rotate matrices /// mode='H': H_12(R)=T^\dagger(V)H_1'2'(VR+O_1-O_2)T(V) /// mode='D': D_12(R)=T^T(V)D_1'2'(VR+O_1-O_2)T^*(V) template // RI::Tensor type, blas - RI::Tensor rotate_atompair_serial(const RI::Tensor& t, const int isym, + RI::Tensor rotate_atompair_serial(const RI::Tensor& A, const int isym, const Atom& a1, const Atom& a2, const char mode, bool output = false)const; + template // pointer type, blas + void rotate_atompair_serial(Tdata* TAT, const Tdata* A, const int& nw1, const int& nw2, const int isym, + const Atom& a1, const Atom& a2, const char mode)const; template // HContainer type, pblas void rotate_atompair_parallel(const TR* Alocal_in, const int isym, const Atom* atoms, const Statistics& st, const Tap& ap_in, const Tap& ap_out, const char mode, const Parallel_Orbitals& pv, TR* Alocal_out, const bool output = false)const; - //-------------------------------------------------------------------------------- - /// The sub functions judge special symmetry - void gen_symmetry_BvK(const Symmetry& symm, const Atom* atoms, const Lattice& lat, const Statistics& st, const TC bvk_period); - /// whether in 2D plain or not for each symmetry operation - std::vector in_plain(const ModuleSymmetry::Symmetry& symm, const ModuleBase::Matrix3& latvec)const; + template + RI::Tensor set_rotation_matrix(const Atom& a, const int& isym)const; //-------------------------------------------------------------------------------- int nsym_ = 1; @@ -210,30 +144,8 @@ namespace ModuleSymmetry std::vector>>> Ms_; /// irreducible sector - /// irreducible atom pairs: [n_iap][(isym, ap=(iat1, iat2))] - // std::vector> atompair_stars_; - - ///The index range of the orbital matrix to be calculated: irreducible R in irreducible atom pairs - // (including R in other atom pairs that cannot rotate into R_stars_[irreducebule_ap]) - std::map> irreducible_sector_; - - // //[natoms*natoms](R, (isym, irreducible_R)) - // std::vector>> full_map_to_irreducible_sector_; - // (abR) -> (isym, abR) - std::map, apR_less_func> full_map_to_irreducible_sector_; - - // all the {abR}s , where the isym=0 one in each star forms the irreducible sector. - // [irreducible sector size][isym, ((ab),R)] - std::vector> sector_stars_; - - /// the direct lattice vector of {R|t}\tau-\tau' for each atoms and each symmetry operation. [natom][nsym] - std::vector> return_lattice_; - - std::vector invmap_; - std::vector isymbvk_to_isym_; - std::vector bvk_gmatrix_; - std::vector> bvk_gtrans_; - int bvk_nsym_; + Irreducible_Sector irs_; + }; } diff --git a/source/module_ri/symmetry_rotation_R.hpp b/source/module_ri/exx_symmetry/symmetry_rotation_R.hpp similarity index 51% rename from source/module_ri/symmetry_rotation_R.hpp rename to source/module_ri/exx_symmetry/symmetry_rotation_R.hpp index 98720a4597..2742067274 100644 --- a/source/module_ri/symmetry_rotation_R.hpp +++ b/source/module_ri/exx_symmetry/symmetry_rotation_R.hpp @@ -16,7 +16,7 @@ namespace ModuleSymmetry ModuleBase::timer::tick("Symmetry_rotation", "restore_HR"); std::map, RI::Tensor>> HR_full; // openmp slows down this for loop, why? - for (auto& apR_isym_irapR : this->full_map_to_irreducible_sector_) + for (auto& apR_isym_irapR : this->irs_.full_map_to_irreducible_sector_) { const Tap& ap = apR_isym_irapR.first.first; const TC& R = apR_isym_irapR.first.second; @@ -26,8 +26,8 @@ namespace ModuleSymmetry // rotate the matrix and pack data // H_12(R)=T^\dagger(V)H_1'2'(VR+O_1-O_2)T(V) if (HR_irreduceble.find(irap.first) != HR_irreduceble.end() && HR_irreduceble.at(irap.first).find({ irap.second, irR }) != HR_irreduceble.at(irap.first).end()) - HR_full[ap.first][{ap.second, R}] = rotate_atompair_serial(HR_irreduceble.at(irap.first).at({ irap.second, irR }), - isym, atoms[st.iat2it[irap.first]], atoms[st.iat2it[irap.second]], mode); + HR_full[ap.first][{ap.second, R}] = rotate_atompair_serial(HR_irreduceble.at(irap.first).at({ irap.second, irR }), + isym, atoms[st.iat2it[irap.first]], atoms[st.iat2it[irap.second]], mode); else std::cout << "not found: current atom pair =(" << ap.first << "," << ap.second << "), R=(" << R[0] << "," << R[1] << "," << R[2] << "), irreducible atom pair =(" << irap.first << "," << irap.second << "), irR=(" << irR[0] << "," << irR[1] << "," << irR[2] << ")\n"; } @@ -47,63 +47,99 @@ namespace ModuleSymmetry } } + template + inline void set_block(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, + RI::Tensor& obj_tensor) + { // no changing row/col order + for (int i = 0;i < block.nr;++i) + for (int j = 0;j < block.nc;++j) + obj_tensor(starti + i, startj + j) = RI::Global_Func::convert(block(i, j)); + } + + template + RI::Tensor Symmetry_rotation::set_rotation_matrix(const Atom& a, const int& isym)const + { + RI::Tensor T({ static_cast(a.nw), static_cast(a.nw) }); // check if zero + int iw = 0; + while (iw < a.nw) + { + int l = a.iw2l[iw]; + int nm = 2 * l + 1; + set_block(iw, iw, this->rotmat_Slm_[isym][l], T); + iw += nm; + } + return T; + } + + inline void TAT_HR(std::complex* TAT, const std::complex* A, + const RI::Tensor>& T1, const RI::Tensor>& T2) + { + const char notrans = 'N', transpose = 'T', dagger = 'C'; + const std::complex alpha(1.0, 0.0), beta(0.0, 0.0); + // H'^T = T2^T * H^T * T1^* + const int& nw2 = T2.shape[0], & nw1 = T1.shape[0]; + const RI::Shape_Vector& shape = { static_cast(nw1),static_cast(nw2) }; + RI::Tensor> AT2(shape); + zgemm_(¬rans, ¬rans, &nw2, &nw1, &nw2, &alpha, T2.ptr(), &nw2, A, &nw2, &beta, AT2.ptr(), &nw2); + zgemm_(¬rans, &dagger, &nw2, &nw1, &nw1, &alpha, AT2.ptr(), &nw2, T1.ptr(), &nw1, &beta, TAT, &nw2); + // row-maj version + // BlasConnector::gemm(notrans, notrans, nw1, nw2, nw2, + // alpha, A_complex.ptr(), nw2, T2.ptr(), nw2, beta, AT2.ptr(), nw2); + // BlasConnector::gemm(dagger, notrans, nw1, nw2, nw1, + // alpha, T1.ptr(), nw1, AT2.ptr(), nw2, beta, TAT.ptr(), nw2); + } + inline void TAT_HR(double* TAT, const double* A, + const RI::Tensor& T1, const RI::Tensor& T2) + { + const char notrans = 'N', transpose = 'T', dagger = 'C'; + const double alpha(1.0), beta(0.0); + // H'^T = T2^T * H^T * T1^* + const int& nw2 = T2.shape[0], & nw1 = T1.shape[0]; + const RI::Shape_Vector& shape = { static_cast(nw1),static_cast(nw2) }; + RI::Tensor AT2(shape); + dgemm_(¬rans, ¬rans, &nw2, &nw1, &nw2, &alpha, T2.ptr(), &nw2, A, &nw2, &beta, AT2.ptr(), &nw2); + dgemm_(¬rans, &dagger, &nw2, &nw1, &nw1, &alpha, AT2.ptr(), &nw2, T1.ptr(), &nw1, &beta, TAT, &nw2); + } + inline void TAT_DR(std::complex* TAT, const std::complex* A, + const RI::Tensor>& T1, const RI::Tensor>& T2) + { + const char notrans = 'N', transpose = 'T', dagger = 'C'; + const std::complex alpha(1.0, 0.0), beta(0.0, 0.0); + //T2^\dagger * D^T * T1 = [(D^T)^T * (T2^T)^\dagger]^T * (T1^T)^T + const int& nw2 = T2.shape[0], & nw1 = T1.shape[0]; + const RI::Shape_Vector& shape = { static_cast(nw1),static_cast(nw2) }; + RI::Tensor> AT2(shape); + zgemm_(&transpose, &dagger, &nw1, &nw2, &nw2, &alpha, A, &nw2, T2.ptr(), &nw2, &beta, AT2.ptr(), &nw1); + zgemm_(&transpose, &transpose, &nw2, &nw1, &nw1, &alpha, AT2.ptr(), &nw1, T1.ptr(), &nw1, &beta, TAT, &nw2); + } + inline void TAT_DR(double* TAT, const double* A, + const RI::Tensor& T1, const RI::Tensor& T2) + { + const char notrans = 'N', transpose = 'T', dagger = 'C'; + const double alpha(1.0), beta(0.0); + //T2^\dagger * D^T * T1 = [(D^T)^T * (T2^T)^\dagger]^T * (T1^T)^T + const int& nw2 = T2.shape[0], & nw1 = T1.shape[0]; + const RI::Shape_Vector& shape = { static_cast(nw1),static_cast(nw2) }; + RI::Tensor AT2(shape); + dgemm_(&transpose, &dagger, &nw1, &nw2, &nw2, &alpha, A, &nw2, T2.ptr(), &nw2, &beta, AT2.ptr(), &nw1); + dgemm_(&transpose, &transpose, &nw2, &nw1, &nw1, &alpha, AT2.ptr(), &nw1, T1.ptr(), &nw1, &beta, TAT, &nw2); + } + template RI::Tensor Symmetry_rotation::rotate_atompair_serial(const RI::Tensor& A, const int isym, const Atom& a1, const Atom& a2, const char mode, const bool output)const { // due to col-contiguous, actually what we know is T^T and H^T (or D^T), // and what we calculate is(H'^T = T ^ T * H ^ T * T^*) or (D'^T = T ^ \dagger * D ^ T * T) - auto set_block = [](const int starti, const int startj, const ModuleBase::ComplexMatrix& block, - RI::Tensor>& obj_tensor)->void - { // both ComplexMatrix and RI::Tensor are row-major (col-contiguous) - for (int i = 0;i < block.nr;++i) - for (int j = 0;j < block.nc;++j) - obj_tensor(starti + i, startj + j) = block(i, j); - }; - auto set_rotation_matrix = [&, this](const Atom& a) -> RI::Tensor> - { - RI::Tensor> T({ static_cast(a.nw), static_cast(a.nw) }); // check if zero - int iw = 0; - while (iw < a.nw) - { - int l = a.iw2l[iw]; - int nm = 2 * l + 1; - set_block(iw, iw, this->rotmat_Slm_[isym][l], T); - iw += nm; - } - return T; - }; - + assert(mode == 'H' || mode == 'D'); bool sametype = (a1.label == a2.label); assert(A.shape[0] == a1.nw);//col assert(A.shape[1] == a2.nw);//row // contrut T matrix - const RI::Tensor>& T1 = set_rotation_matrix(a1); - const RI::Tensor>& T2 = sametype ? T1 : set_rotation_matrix(a2); - - // A*T_2 (atom 2 is contiguous) - const char notrans = 'N', transpose = 'T', dagger = 'C'; - const std::complex alpha(1.0, 0.0), beta(0.0, 0.0); - const RI::Tensor>& A_complex = RI::Global_Func::convert>(A); - - RI::Tensor> TAT(A.shape); - RI::Tensor> AT2(A.shape); - if (mode == 'H') - { // H'^T = T2^T * H^T * T1^* - zgemm_(¬rans, ¬rans, &a2.nw, &a1.nw, &a2.nw, &alpha, T2.ptr(), &a2.nw, A_complex.ptr(), &a2.nw, &beta, AT2.ptr(), &a2.nw); - zgemm_(¬rans, &dagger, &a2.nw, &a1.nw, &a1.nw, &alpha, AT2.ptr(), &a2.nw, T1.ptr(), &a1.nw, &beta, TAT.ptr(), &a2.nw); - // row-maj version - // BlasConnector::gemm(notrans, notrans, a1.nw, a2.nw, a2.nw, - // alpha, A_complex.ptr(), a2.nw, T2.ptr(), a2.nw, beta, AT2.ptr(), a2.nw); - // BlasConnector::gemm(dagger, notrans, a1.nw, a2.nw, a1.nw, - // alpha, T1.ptr(), a1.nw, AT2.ptr(), a2.nw, beta, TAT.ptr(), a2.nw); - - } - else if (mode == 'D') - { //T2^\dagger * D^T * T1 = [(D^T)^T * (T2^T)^\dagger]^T * (T1^T)^T - zgemm_(&transpose, &dagger, &a1.nw, &a2.nw, &a2.nw, &alpha, A_complex.ptr(), &a2.nw, T2.ptr(), &a2.nw, &beta, AT2.ptr(), &a1.nw); - zgemm_(&transpose, &transpose, &a2.nw, &a1.nw, &a1.nw, &alpha, AT2.ptr(), &a1.nw, T1.ptr(), &a1.nw, &beta, TAT.ptr(), &a2.nw); - } - else throw std::invalid_argument("Symmetry_rotation::rotate_atompair_tensor: invalid mode."); + const RI::Tensor& T1 = this->set_rotation_matrix(a1, isym); + const RI::Tensor& T2 = sametype ? T1 : this->set_rotation_matrix(a2, isym); + // rotate + RI::TensorTAT(A.shape); + (mode == 'H') ? TAT_HR(TAT.ptr(), A.ptr(), T1, T2) : TAT_DR(TAT.ptr(), A.ptr(), T1, T2); if (output) { print_tensor(A, "A"); @@ -111,9 +147,25 @@ namespace ModuleSymmetry print_tensor(T2, "T2"); print_tensor(TAT, "TAT"); } - return RI::Global_Func::convert(TAT); + return TAT; + } + template + void Symmetry_rotation::rotate_atompair_serial(Tdata* TAT, const Tdata* A, + const int& nw1, const int& nw2, const int isym, + const Atom& a1, const Atom& a2, const char mode)const + { // due to col-contiguous, actually what we know is T^T and H^T (or D^T), + // and what we calculate is(H'^T = T ^ T * H ^ T * T^*) or (D'^T = T ^ \dagger * D ^ T * T) + assert(mode == 'H' || mode == 'D'); + bool sametype = (a1.label == a2.label); + assert(nw1 == a1.nw);//col + assert(nw2 == a2.nw);//row + // contrut T matrix + const RI::Tensor& T1 = this->set_rotation_matrix(a1, isym); + const RI::Tensor& T2 = sametype ? T1 : this->set_rotation_matrix(a2, isym); + // rotate + (mode == 'H') ? TAT_HR(TAT, A, T1, T2) : TAT_DR(TAT, A, T1, T2); } - + template void Symmetry_rotation::print_HR(const std::map, RI::Tensor>>& HR, const std::string name, const double& threshold) { @@ -139,7 +191,7 @@ namespace ModuleSymmetry // 1. pick out H(R) in the irreducible sector from full H(R) std::map, RI::Tensor>> HR_irreduceble; - for (auto& irap_Rs : this->irreducible_sector_) + for (auto& irap_Rs : this->irs_.irreducible_sector_) { const Tap& irap = irap_Rs.first; for (auto& irR : irap_Rs.second) diff --git a/source/module_ri/symmetry_rotation_R_hcontainer.hpp b/source/module_ri/exx_symmetry/symmetry_rotation_R_hcontainer.hpp similarity index 96% rename from source/module_ri/symmetry_rotation_R_hcontainer.hpp rename to source/module_ri/exx_symmetry/symmetry_rotation_R_hcontainer.hpp index 781cd7959d..3aef195160 100644 --- a/source/module_ri/symmetry_rotation_R_hcontainer.hpp +++ b/source/module_ri/exx_symmetry/symmetry_rotation_R_hcontainer.hpp @@ -42,14 +42,14 @@ namespace ModuleSymmetry { ModuleBase::TITLE("Symmetry_rotation", "restore_HR"); ModuleBase::timer::tick("Symmetry_rotation", "restore_HR"); - for (auto& apR_isym_irapR : this->full_map_to_irreducible_sector_) + for (auto& apR_isym_irapR : this->irs_.full_map_to_irreducible_sector_) { const Tap& ap = apR_isym_irapR.first.first; const TC& R = apR_isym_irapR.first.second; const int& isym = apR_isym_irapR.second.first; const Tap& irap = apR_isym_irapR.second.second.first; const TC& irR = apR_isym_irapR.second.second.second; - assert(irR == this->rotate_R_by_formula(symm, isym, ap.first, ap.second, R)); + assert(irR == this->irs_.rotate_R(symm, isym, ap.first, ap.second, R)); // get in and out pointer from HContainer const hamilt::AtomPair& irap_hc = HR_irreduceble.get_atom_pair(irap.first, irap.second); const int irR_hc = irap_hc.find_R(irR[0], irR[1], irR[2]); @@ -171,8 +171,8 @@ namespace ModuleSymmetry auto get_irreducible_ijR_info = [&HR_full, this]() -> std::vector { std::vector irreducible_ijR_info; - irreducible_ijR_info.push_back(this->irreducible_sector_.size()); - for (auto& irap_irR : this->irreducible_sector_) + irreducible_ijR_info.push_back(this->irs_.irreducible_sector_.size()); + for (auto& irap_irR : this->irs_.irreducible_sector_) { const int iat1 = irap_irR.first.first, iat2 = irap_irR.first.second; irreducible_ijR_info.insert(irreducible_ijR_info.end(), { iat1, iat2, 0 }); @@ -193,7 +193,7 @@ namespace ModuleSymmetry const std::vector& irreducible_ijR_info = get_irreducible_ijR_info(); hamilt::HContainer HR_irreducible(pv, nullptr, &irreducible_ijR_info); HR_irreducible.set_zero(); - for (auto& irap_irR : this->irreducible_sector_) + for (auto& irap_irR : this->irs_.irreducible_sector_) { const int iat1 = irap_irR.first.first, iat2 = irap_irR.first.second; const hamilt::AtomPair& irap = HR_irreducible.get_atom_pair(iat1, iat2); diff --git a/source/module_ri/exx_symmetry/test/CMakeLists.txt b/source/module_ri/exx_symmetry/test/CMakeLists.txt new file mode 100644 index 0000000000..cf1c1e853c --- /dev/null +++ b/source/module_ri/exx_symmetry/test/CMakeLists.txt @@ -0,0 +1,10 @@ +remove_definitions(-D__DEEPKS) +remove_definitions(-D__CUDA) +remove_definitions(-D__ROCM) +AddTest( + TARGET symmetry_rotation + LIBS base ${math_libs} device symmetry neighbor + SOURCES symmetry_rotation_test.cpp ../symmetry_rotation.cpp ../irreducible_sector.cpp ../irreducible_sector_bvk.cpp + ../../../module_basis/module_ao/parallel_2d.cpp ../../../module_basis/module_ao/parallel_orbitals.cpp + ../../../module_io/output.cpp +) \ No newline at end of file diff --git a/source/module_ri/test/symmetry_rotation_test.cpp b/source/module_ri/exx_symmetry/test/symmetry_rotation_test.cpp similarity index 100% rename from source/module_ri/test/symmetry_rotation_test.cpp rename to source/module_ri/exx_symmetry/test/symmetry_rotation_test.cpp diff --git a/source/module_ri/test/CMakeLists.txt b/source/module_ri/test/CMakeLists.txt index dbd535c5fc..94c25481e3 100644 --- a/source/module_ri/test/CMakeLists.txt +++ b/source/module_ri/test/CMakeLists.txt @@ -5,10 +5,4 @@ AddTest( TARGET dm_mixing_test LIBS base ${math_libs} device SOURCES dm_mixing_test.cpp ../Mix_DMk_2D.cpp ../Mix_Matrix.cpp -) -AddTest( - TARGET symmetry_rotation - LIBS base ${math_libs} device symmetry - SOURCES symmetry_rotation_test.cpp ../symmetry_rotation.cpp ../../module_basis/module_ao/parallel_2d.cpp - ../../module_io/output.cpp ) \ No newline at end of file From b8f826e7851c2d48fa9dd61a8d8ba40c388e17d2 Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Mon, 1 Apr 2024 22:45:53 +0800 Subject: [PATCH 15/19] Cs rotation --- source/module_ri/Exx_LRI.h | 6 +- source/module_ri/Exx_LRI.hpp | 13 +++ source/module_ri/Exx_LRI_interface.hpp | 8 +- .../exx_symmetry/symmetry_rotation.cpp | 9 +- .../exx_symmetry/symmetry_rotation.h | 26 ++++- .../exx_symmetry/symmetry_rotation_R.hpp | 102 +++++++++++++++++- 6 files changed, 153 insertions(+), 11 deletions(-) diff --git a/source/module_ri/Exx_LRI.h b/source/module_ri/Exx_LRI.h index 0e508f4240..577a35da35 100644 --- a/source/module_ri/Exx_LRI.h +++ b/source/module_ri/Exx_LRI.h @@ -18,7 +18,7 @@ #include #include -#include "exx_symmetry/symmetry_rotation.h" +#include "exx_symmetry/symmetry_rotation.h" //tmp class Parallel_Orbitals; @@ -56,12 +56,14 @@ class Exx_LRI void init(const MPI_Comm &mpi_comm_in, const K_Vectors &kv_in); void cal_exx_force(); - void cal_exx_stress(); + void cal_exx_stress(); + std::vector> get_abfs_nchis() const; std::vector< std::map>>> Hexxs; double Eexx; ModuleBase::matrix force_exx; ModuleBase::matrix stress_exx; + private: const Exx_Info::Exx_Info_RI &info; diff --git a/source/module_ri/Exx_LRI.hpp b/source/module_ri/Exx_LRI.hpp index fd1fea9759..f1b4a7934b 100644 --- a/source/module_ri/Exx_LRI.hpp +++ b/source/module_ri/Exx_LRI.hpp @@ -290,5 +290,18 @@ void Exx_LRI::cal_exx_stress() ModuleBase::timer::tick("Exx_LRI", "cal_exx_stress"); } +template +std::vector> Exx_LRI::get_abfs_nchis() const +{ + std::vector> abfs_nchis; + for (const auto& abfs_T : this->abfs) + { + std::vector abfs_nchi_T; + for (const auto& abfs_L : abfs_T) + abfs_nchi_T.push_back(abfs_L.size()); + abfs_nchis.push_back(abfs_nchi_T); + } + return abfs_nchis; +} #endif diff --git a/source/module_ri/Exx_LRI_interface.hpp b/source/module_ri/Exx_LRI_interface.hpp index e798dd56c3..4677e375b7 100644 --- a/source/module_ri/Exx_LRI_interface.hpp +++ b/source/module_ri/Exx_LRI_interface.hpp @@ -52,9 +52,7 @@ void Exx_LRI_Interface::exx_beforescf(const K_Vectors& kv, const Charg XC_Functional::set_xc_type("scan"); } } - - this->exx_ptr->cal_exx_ions(); - + bool test_Cs_rotation = true; // for test // initialize the rotation matrix in AO representation this->exx_spacegroup_symmetry = (GlobalV::NSPIN < 4 && ModuleSymmetry::Symmetry::symm_flag == 1); if (this->exx_spacegroup_symmetry) @@ -62,8 +60,12 @@ void Exx_LRI_Interface::exx_beforescf(const K_Vectors& kv, const Charg const std::array& period = RI_Util::get_Born_vonKarmen_period(kv); this->symrot_.find_irreducible_sector(ucell.symm, ucell.atoms, ucell.st, RI_Util::get_Born_von_Karmen_cells(period), period, ucell.lat); + if (test_Cs_rotation) + this->symrot_.set_Cs_rotation(this->exx_ptr->get_abfs_nchis()); this->symrot_.cal_Ms(kv, ucell, pv); } + + this->exx_ptr->cal_exx_ions(test_Cs_rotation, &this->symrot_); } if (Exx_Abfs::Jle::generate_matrix) diff --git a/source/module_ri/exx_symmetry/symmetry_rotation.cpp b/source/module_ri/exx_symmetry/symmetry_rotation.cpp index ab2a80afe3..4639cd1286 100644 --- a/source/module_ri/exx_symmetry/symmetry_rotation.cpp +++ b/source/module_ri/exx_symmetry/symmetry_rotation.cpp @@ -11,6 +11,13 @@ namespace ModuleSymmetry { + void Symmetry_rotation::set_Cs_rotation(const std::vector>& abfs_l_nchi) + { + this->reduce_Cs_ = true; + this->abfs_l_nchi_ = abfs_l_nchi; + this->abfs_Lmax_ = 0; + for (auto& abfs_T : abfs_l_nchi) this->abfs_Lmax_ = std::max(this->abfs_Lmax_, static_cast(abfs_T.size()) - 1); + } void Symmetry_rotation::cal_Ms(const K_Vectors& kv, //const std::vector>& kstars, const UnitCell& ucell, const Parallel_2D& pv) @@ -28,7 +35,7 @@ namespace ModuleSymmetry // 1. calculate the rotation matrix in real spherical harmonics representation for each symmetry operation: [T_l (isym)]_mm' std::vector gmatc(nsym_); for (int i = 0;i < nsym_;++i) gmatc[i] = this->irs_.direct_to_cartesian(ucell.symm.gmatrix[i], ucell.latvec); - this->cal_rotmat_Slm(gmatc.data(), ucell.lmax); + this->cal_rotmat_Slm(gmatc.data(), reduce_Cs_ ? std::max(this->abfs_Lmax_, ucell.lmax) : ucell.lmax); // 2. calculate the rotation matrix in AO-representation for each ibz_kpoint and symmetry operation: M(k, isym) auto restrict_kpt = [](const TCdouble& kvec, const double& symm_prec) -> TCdouble diff --git a/source/module_ri/exx_symmetry/symmetry_rotation.h b/source/module_ri/exx_symmetry/symmetry_rotation.h index 2067c5f67a..bd48f170e5 100644 --- a/source/module_ri/exx_symmetry/symmetry_rotation.h +++ b/source/module_ri/exx_symmetry/symmetry_rotation.h @@ -33,11 +33,14 @@ namespace ModuleSymmetry return this->irs_.get_return_lattice(symm, gmatd, gtransd, posd_a1, posd_a2); } //-------------------------------------------------------------------------------- -/// functions to contruct rotation matrix in AO-representation + // setters + void set_Cs_rotation(const std::vector>& abfs_l_nchi); + //-------------------------------------------------------------------------------- + /// functions to contruct rotation matrix in AO-representation -/// The top-level calculation interface of this class. calculate the rotation matrix in AO representation: M -/// only need once call in each ion step (decided by the configuration) -/// @param kstars equal k points to each ibz-kpont, corresponding to a certain symmetry operations. + /// The top-level calculation interface of this class. calculate the rotation matrix in AO representation: M + /// only need once call in each ion step (decided by the configuration) + /// @param kstars equal k points to each ibz-kpont, corresponding to a certain symmetry operations. void cal_Ms(const K_Vectors& kv, //const std::vector>& kstars, const UnitCell& ucell, const Parallel_2D& pv); @@ -98,6 +101,9 @@ namespace ModuleSymmetry template // RI::Tensor type, using col-major implementation void test_HR_rotation(const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, const std::map, RI::Tensor>>& HR_full); + template // test the rotation of RI coefficients + void test_Cs_rotation(const Symmetry& symm, const Atom* atoms, const Statistics& st, + const std::map, RI::Tensor>>& Cs_full)const; template // HContainer type, using row-major implementation void test_HR_rotation(const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode, const hamilt::HContainer& HR_full); @@ -124,8 +130,15 @@ namespace ModuleSymmetry void rotate_atompair_parallel(const TR* Alocal_in, const int isym, const Atom* atoms, const Statistics& st, const Tap& ap_in, const Tap& ap_out, const char mode, const Parallel_Orbitals& pv, TR* Alocal_out, const bool output = false)const; + /// rotate a 3-dim C tensor in RI technique + template + RI::Tensor rotate_singleC_serial(const RI::Tensor& C, const int isym, + const Atom& a1, const Atom& a2, const int& type1, bool output = false)const; + template RI::Tensor set_rotation_matrix(const Atom& a, const int& isym)const; + template + RI::Tensor set_rotation_matrix_abf(const int& type, const int& isym)const; //-------------------------------------------------------------------------------- int nsym_ = 1; @@ -134,6 +147,11 @@ namespace ModuleSymmetry bool TRS_first_ = true; //if R(k)=-k, firstly use TRS to restore D(k) from D(R(k)), i.e conjugate D(R(k)). + bool reduce_Cs_ = false; + int abfs_Lmax_ = 0; + + std::vector> abfs_l_nchi_;///< number of abfs for each angular momentum + /// the rotation matrix under the basis of S_l^m. size: [nsym][lmax][nm*nm] std::vector> rotmat_Slm_; // [natom][nsym], phase factor corresponding to a certain kvec_d_ibz diff --git a/source/module_ri/exx_symmetry/symmetry_rotation_R.hpp b/source/module_ri/exx_symmetry/symmetry_rotation_R.hpp index 2742067274..551dd9361b 100644 --- a/source/module_ri/exx_symmetry/symmetry_rotation_R.hpp +++ b/source/module_ri/exx_symmetry/symmetry_rotation_R.hpp @@ -46,6 +46,22 @@ namespace ModuleSymmetry std::cout << std::endl; } } + template + inline void print_tensor3(const RI::Tensor& t, const std::string& name, const double& threshold = 0.0) + { + std::cout << name << ":\n"; + for (int a = 0;a < t.shape[0];++a) + { + std::cout << "abf: " << a << '\n'; + for (int i = 0;i < t.shape[1];++i) + { + for (int j = 0;j < t.shape[2];++j) + std::cout << ((std::abs(t(a, i, j)) > threshold) ? t(a, i, j) : static_cast(0)) << " "; + std::cout << std::endl; + } + std::cout << std::endl; + } + } template inline void set_block(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, @@ -124,7 +140,24 @@ namespace ModuleSymmetry dgemm_(&transpose, &dagger, &nw1, &nw2, &nw2, &alpha, A, &nw2, T2.ptr(), &nw2, &beta, AT2.ptr(), &nw1); dgemm_(&transpose, &transpose, &nw2, &nw1, &nw1, &alpha, AT2.ptr(), &nw1, T1.ptr(), &nw1, &beta, TAT, &nw2); } - + inline void TA_HR(std::complex* TA, const std::complex* A, + const RI::Tensor>& T1, const int& nw12) + { + const char notrans = 'N', transpose = 'T', dagger = 'C'; + const std::complex alpha(1.0, 0.0), beta(0.0, 0.0); + // C'^T = C^T * T1^* + const int& nabf = T1.shape[0]; + zgemm_(¬rans, &dagger, &nw12, &nabf, &nabf, &alpha, A, &nw12, T1.ptr(), &nabf, &beta, TA, &nw12); + } + inline void TA_HR(double* TA, const double* A, + const RI::Tensor& T1, const int& nw12) + { + const char notrans = 'N', transpose = 'T', dagger = 'C'; + const double alpha(1.0), beta(0.0); + // C'^T = C^T * T1^* + const int& nabf = T1.shape[0]; + dgemm_(¬rans, &dagger, &nw12, &nabf, &nabf, &alpha, A, &nw12, T1.ptr(), &nabf, &beta, TA, &nw12); + } template RI::Tensor Symmetry_rotation::rotate_atompair_serial(const RI::Tensor& A, const int isym, const Atom& a1, const Atom& a2, const char mode, const bool output)const @@ -166,6 +199,46 @@ namespace ModuleSymmetry (mode == 'H') ? TAT_HR(TAT, A, T1, T2) : TAT_DR(TAT, A, T1, T2); } + + template + RI::Tensor Symmetry_rotation::set_rotation_matrix_abf(const int& type, const int& isym)const + { + int nabfs = 0; + for (int l = 0;l < this->abfs_l_nchi_[type].size();++l)nabfs += this->abfs_l_nchi_[type][l] * (2 * l + 1); + RI::Tensor T({ static_cast(nabfs), static_cast(nabfs) }); // check if zero + int iw = 0; + for (int L = 0;L < this->abfs_l_nchi_[type].size();++L) + { + int nm = 2 * L + 1; + for (int N = 0;N < this->abfs_l_nchi_[type][L];++N) + { + set_block(iw, iw, this->rotmat_Slm_[isym][L], T); + iw += nm; + std::cout << "L=" << L << ", N=" << N << ", iw=" << iw << "\n"; + } + } + assert(iw == nabfs); + return T; + } + + template + RI::Tensor Symmetry_rotation::rotate_singleC_serial(const RI::Tensor& C, + const int isym, const Atom& a1, const Atom& a2, const int& type1, bool output)const + { + assert(this->reduce_Cs_); + RI::Tensor Cout(C.shape); + assert(C.shape.size() == 3); + const int& slice_size = C.shape[1] * C.shape[2]; + // step 1: multiply 2 AOs' rotation matrices + for (int iabf = 0;iabf < C.shape[0];++iabf) + this->rotate_atompair_serial(Cout.ptr() + iabf * slice_size, C.ptr() + iabf * slice_size, + a1.nw, a2.nw, isym, a1, a2, 'H'); + // step 2: multiply the ABFs' rotation matrix from the left + const RI::Tensor& Tabfs = this->set_rotation_matrix_abf(type1, isym); + TA_HR(Cout.ptr(), Cout.ptr(), Tabfs, slice_size); + return Cout; + } + template void Symmetry_rotation::print_HR(const std::map, RI::Tensor>>& HR, const std::string name, const double& threshold) { @@ -229,4 +302,31 @@ namespace ModuleSymmetry } } + template + void Symmetry_rotation::test_Cs_rotation(const Symmetry& symm, const Atom* atoms, const Statistics& st, + const std::map, RI::Tensor>>& Cs_full)const + { + for (auto& sector_pair : this->irs_.full_map_to_irreducible_sector_) + { + const TapR& apR = sector_pair.first; + const int& isym = sector_pair.second.first; + const TapR& irapR = sector_pair.second.second; + // if (apR.first != irapR.first || apR.second != irapR.second) + if (apR.first != irapR.first) + { + std::cout << "irapR=(" << irapR.first.first << "," << irapR.first.second << "), (" << irapR.second[0] << "," << irapR.second[1] << "," << irapR.second[2] << "):\n"; + std::cout << "apR=(" << apR.first.first << "," << apR.first.second << "), (" << apR.second[0] << "," << apR.second[1] << "," << apR.second[2] << "):\n"; + const RI::Tensor& Cs_ir = Cs_full.at(irapR.first.first).at({ irapR.first.second,irapR.second }); + const RI::Tensor& Cs_ref = Cs_full.at(apR.first.first).at({ apR.first.second,apR.second }); + const RI::Tensor& Cs_rot = this->rotate_singleC_serial(Cs_ir, isym, + atoms[st.iat2it[irapR.first.first]], atoms[st.iat2it[irapR.first.second]], irapR.first.first); + print_tensor3(Cs_rot, "Cs_rot"); + print_tensor3(Cs_ref, "Cs_ref"); + print_tensor3(Cs_ir, "Cs_irreducible"); + exit(0); + } + } + + } + } \ No newline at end of file From aa7e6b7893811f92a0c3ae152fe3127ff56cc202 Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Tue, 2 Apr 2024 02:54:27 +0800 Subject: [PATCH 16/19] mv rotations to LibRI, avoid ComplexMatrix and revert cal_exx_ions --- source/module_ri/Exx_LRI.h | 2 +- source/module_ri/Exx_LRI_interface.hpp | 6 +- .../exx_symmetry/irreducible_sector.h | 1 - .../exx_symmetry/irreducible_sector_bvk.cpp | 2 +- .../exx_symmetry/symmetry_rotation.cpp | 30 +++---- .../exx_symmetry/symmetry_rotation.h | 8 +- .../exx_symmetry/symmetry_rotation_R.hpp | 85 ++----------------- .../test/symmetry_rotation_test.cpp | 10 +-- 8 files changed, 35 insertions(+), 109 deletions(-) diff --git a/source/module_ri/Exx_LRI.h b/source/module_ri/Exx_LRI.h index 577a35da35..bea008713a 100644 --- a/source/module_ri/Exx_LRI.h +++ b/source/module_ri/Exx_LRI.h @@ -18,7 +18,7 @@ #include #include -#include "exx_symmetry/symmetry_rotation.h" //tmp +#include "exx_symmetry/symmetry_rotation.h" class Parallel_Orbitals; diff --git a/source/module_ri/Exx_LRI_interface.hpp b/source/module_ri/Exx_LRI_interface.hpp index 4677e375b7..e1cae02b55 100644 --- a/source/module_ri/Exx_LRI_interface.hpp +++ b/source/module_ri/Exx_LRI_interface.hpp @@ -52,7 +52,6 @@ void Exx_LRI_Interface::exx_beforescf(const K_Vectors& kv, const Charg XC_Functional::set_xc_type("scan"); } } - bool test_Cs_rotation = true; // for test // initialize the rotation matrix in AO representation this->exx_spacegroup_symmetry = (GlobalV::NSPIN < 4 && ModuleSymmetry::Symmetry::symm_flag == 1); if (this->exx_spacegroup_symmetry) @@ -60,12 +59,11 @@ void Exx_LRI_Interface::exx_beforescf(const K_Vectors& kv, const Charg const std::array& period = RI_Util::get_Born_vonKarmen_period(kv); this->symrot_.find_irreducible_sector(ucell.symm, ucell.atoms, ucell.st, RI_Util::get_Born_von_Karmen_cells(period), period, ucell.lat); - if (test_Cs_rotation) - this->symrot_.set_Cs_rotation(this->exx_ptr->get_abfs_nchis()); + // this->symrot_.set_Cs_rotation(this->exx_ptr->get_abfs_nchis()); this->symrot_.cal_Ms(kv, ucell, pv); } - this->exx_ptr->cal_exx_ions(test_Cs_rotation, &this->symrot_); + this->exx_ptr->cal_exx_ions(); } if (Exx_Abfs::Jle::generate_matrix) diff --git a/source/module_ri/exx_symmetry/irreducible_sector.h b/source/module_ri/exx_symmetry/irreducible_sector.h index ed73d8c1b2..ba6818c436 100644 --- a/source/module_ri/exx_symmetry/irreducible_sector.h +++ b/source/module_ri/exx_symmetry/irreducible_sector.h @@ -3,7 +3,6 @@ #include #include #include "module_base/abfs-vector3_order.h" -#include "module_base/complexmatrix.h" #include "module_base/matrix3.h" #include "module_cell/unitcell.h" #include "module_cell/module_symmetry/symmetry.h" diff --git a/source/module_ri/exx_symmetry/irreducible_sector_bvk.cpp b/source/module_ri/exx_symmetry/irreducible_sector_bvk.cpp index 6c40eda06e..4ff7344adb 100644 --- a/source/module_ri/exx_symmetry/irreducible_sector_bvk.cpp +++ b/source/module_ri/exx_symmetry/irreducible_sector_bvk.cpp @@ -134,7 +134,7 @@ namespace ModuleSymmetry symm.pointgroup(bvk_npg, bvk_pgnum, bvk_pgname, this->bvk_gmatrix_.data(), GlobalV::ofs_running); ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "POINT GROUP OF BvK SCELL", bvk_pgname); symm.pointgroup(bvk_nsg, bvk_sgnum, bvk_sgname, this->bvk_gmatrix_.data(), GlobalV::ofs_running); - ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "POINT GROUP IN SPACE GROUP OF BvK SCELL", bvk_pgname); + ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "POINT GROUP IN SPACE GROUP OF BvK SCELL", bvk_sgname); symm.gmatrix_convert_int(this->bvk_gmatrix_.data(), this->bvk_gmatrix_.data(), bvk_nsg, bvk_min_optlat, lat.latvec); symm.gtrans_convert(this->bvk_gtrans_.data(), this->bvk_gtrans_.data(), bvk_nsg, bvk_min_optlat, lat.latvec); // get map from bvk-op to original op diff --git a/source/module_ri/exx_symmetry/symmetry_rotation.cpp b/source/module_ri/exx_symmetry/symmetry_rotation.cpp index 4639cd1286..b530eb1485 100644 --- a/source/module_ri/exx_symmetry/symmetry_rotation.cpp +++ b/source/module_ri/exx_symmetry/symmetry_rotation.cpp @@ -236,11 +236,11 @@ namespace ModuleSymmetry /// T_mm' = [c^\dagger D c]_mm' void Symmetry_rotation::cal_rotmat_Slm(const ModuleBase::Matrix3* gmatc, const int lmax) { - auto set_integer = [](ModuleBase::ComplexMatrix& mat) -> void + auto set_integer = [](RI::Tensor>& mat) -> void { double zero_thres = 1e-10; - for (int i = 0;i < mat.nr;++i) - for (int j = 0;j < mat.nc;++j) + for (int i = 0;i < mat.shape[0];++i) + for (int j = 0;j < mat.shape[1];++j) { if (std::abs(mat(i, j).real() - std::round(mat(i, j).real())) < zero_thres) mat(i, j).real(std::round(mat(i, j).real())); if (std::abs(mat(i, j).imag() - std::round(mat(i, j).imag())) < zero_thres) mat(i, j).imag(std::round(mat(i, j).imag())); @@ -248,14 +248,14 @@ namespace ModuleSymmetry }; this->rotmat_Slm_.resize(nsym_); // c matrix is independent on isym - std::vector c_mm(lmax + 1); + std::vector>> c_mm(lmax + 1); + for (int l = 0;l <= lmax;++l) + c_mm[l] = RI::Tensor>({ size_t(2 * l + 1), size_t(2 * l + 1) }); for (int l = 0;l <= lmax;++l) - { - c_mm[l].create(2 * l + 1, 2 * l + 1); for (int m1 = -l;m1 <= l;++m1) for (int m2 = -l;m2 <= l;++m2) c_mm[l](m2im(m1), m2im(m2)) = ovlp_Ylm_Slm(l, m1, m2); - } + for (int isym = 0;isym < nsym_;++isym) { // if R is a reflection operation, calculate D^l(R)=(-1)^l*D^l(IR), so the euler angle of (IR) is needed. @@ -265,11 +265,11 @@ namespace ModuleSymmetry this->rotmat_Slm_[isym].resize(lmax + 1); for (int l = 0;l <= lmax;++l) {// wigner D matrix - ModuleBase::ComplexMatrix D_mm(2 * l + 1, 2 * l + 1); + RI::Tensor> D_mm({ size_t(2 * l + 1), size_t(2 * l + 1) }); for (int m1 = -l;m1 <= l;++m1) for (int m2 = -l;m2 <= l;++m2) D_mm(m2im(m1), m2im(m2)) = wigner_D(euler_angle, l, m1, m2, (gmatc[isym].Det() < 0)); - this->rotmat_Slm_[isym][l] = transpose(c_mm[l], /*conj=*/true) * D_mm * c_mm[l]; + this->rotmat_Slm_[isym][l] = c_mm[l].dagger() * D_mm * c_mm[l]; // set_integer(this->rotmat_Slm_[isym][l]); } } @@ -311,11 +311,11 @@ namespace ModuleSymmetry */ } - void Symmetry_rotation::set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, + void Symmetry_rotation::set_block_to_mat2d(const int starti, const int startj, const RI::Tensor>& block, std::vector>& obj_mat, const Parallel_2D& pv, const bool trans) const { // caution: ComplaxMatrix is row-major(col-continuous), but obj_mat is col-major(row-continuous) - for (int j = 0;j < block.nr;++j)//outside dimension - for (int i = 0;i < block.nc;++i) //inside dimension + for (int j = 0;j < block.shape[0];++j)//outside dimension + for (int i = 0;i < block.shape[1];++i) //inside dimension if (pv.in_this_processor(starti + i, startj + j)) { int index = pv.global2local_col(startj + j) * pv.get_row_size() + pv.global2local_row(starti + i); @@ -323,11 +323,11 @@ namespace ModuleSymmetry } } - void Symmetry_rotation::set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, + void Symmetry_rotation::set_block_to_mat2d(const int starti, const int startj, const RI::Tensor>& block, std::vector& obj_mat, const Parallel_2D& pv, const bool trans) const { // caution: ComplaxMatrix is row-major(col-continuous), but obj_mat is col-major(row-continuous) - for (int j = 0;j < block.nr;++j)//outside dimension - for (int i = 0;i < block.nc;++i) //inside dimension + for (int j = 0;j < block.shape[0];++j)//outside dimension + for (int i = 0;i < block.shape[1];++i) //inside dimension if (pv.in_this_processor(starti + i, startj + j)) { int index = pv.global2local_col(startj + j) * pv.get_row_size() + pv.global2local_row(starti + i); diff --git a/source/module_ri/exx_symmetry/symmetry_rotation.h b/source/module_ri/exx_symmetry/symmetry_rotation.h index bd48f170e5..f4c8a13e4d 100644 --- a/source/module_ri/exx_symmetry/symmetry_rotation.h +++ b/source/module_ri/exx_symmetry/symmetry_rotation.h @@ -71,9 +71,9 @@ namespace ModuleSymmetry /// set a block matrix onto a 2d-parallelized matrix(col-maj), at the position (starti, startj) /// if trans=true, the block matrix is transposed before setting - void set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, + void set_block_to_mat2d(const int starti, const int startj, const RI::Tensor>& block, std::vector>& obj_mat, const Parallel_2D& pv, const bool trans = false) const; - void set_block_to_mat2d(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, + void set_block_to_mat2d(const int starti, const int startj, const RI::Tensor>& block, std::vector& obj_mat, const Parallel_2D& pv, const bool trans = false) const; /// 2d-block parallized rotation matrix in AO-representation, denoted as M. @@ -81,7 +81,7 @@ namespace ModuleSymmetry std::vector> contruct_2d_rot_mat_ao(const Symmetry& symm, const Atom* atoms, const Statistics& cell_st, const TCdouble& kvec_d_ibz, int isym, const Parallel_2D& pv) const; - std::vector>& get_rotmat_Slm() { return this->rotmat_Slm_; } + std::vector>>>& get_rotmat_Slm() { return this->rotmat_Slm_; } //-------------------------------------------------------------------------------- /// The main functions to rotate matrices @@ -153,7 +153,7 @@ namespace ModuleSymmetry std::vector> abfs_l_nchi_;///< number of abfs for each angular momentum /// the rotation matrix under the basis of S_l^m. size: [nsym][lmax][nm*nm] - std::vector> rotmat_Slm_; + std::vector>>> rotmat_Slm_; // [natom][nsym], phase factor corresponding to a certain kvec_d_ibz // std::vector>> phase_factor_; diff --git a/source/module_ri/exx_symmetry/symmetry_rotation_R.hpp b/source/module_ri/exx_symmetry/symmetry_rotation_R.hpp index 551dd9361b..940cb3b34c 100644 --- a/source/module_ri/exx_symmetry/symmetry_rotation_R.hpp +++ b/source/module_ri/exx_symmetry/symmetry_rotation_R.hpp @@ -4,6 +4,7 @@ #include "module_base/timer.h" #include #include +#include namespace ModuleSymmetry { @@ -64,11 +65,11 @@ namespace ModuleSymmetry } template - inline void set_block(const int starti, const int startj, const ModuleBase::ComplexMatrix& block, + inline void set_block(const int starti, const int startj, const RI::Tensor>& block, RI::Tensor& obj_tensor) { // no changing row/col order - for (int i = 0;i < block.nr;++i) - for (int j = 0;j < block.nc;++j) + for (int i = 0;i < block.shape[0];++i) + for (int j = 0;j < block.shape[1];++j) obj_tensor(starti + i, startj + j) = RI::Global_Func::convert(block(i, j)); } @@ -86,78 +87,6 @@ namespace ModuleSymmetry } return T; } - - inline void TAT_HR(std::complex* TAT, const std::complex* A, - const RI::Tensor>& T1, const RI::Tensor>& T2) - { - const char notrans = 'N', transpose = 'T', dagger = 'C'; - const std::complex alpha(1.0, 0.0), beta(0.0, 0.0); - // H'^T = T2^T * H^T * T1^* - const int& nw2 = T2.shape[0], & nw1 = T1.shape[0]; - const RI::Shape_Vector& shape = { static_cast(nw1),static_cast(nw2) }; - RI::Tensor> AT2(shape); - zgemm_(¬rans, ¬rans, &nw2, &nw1, &nw2, &alpha, T2.ptr(), &nw2, A, &nw2, &beta, AT2.ptr(), &nw2); - zgemm_(¬rans, &dagger, &nw2, &nw1, &nw1, &alpha, AT2.ptr(), &nw2, T1.ptr(), &nw1, &beta, TAT, &nw2); - // row-maj version - // BlasConnector::gemm(notrans, notrans, nw1, nw2, nw2, - // alpha, A_complex.ptr(), nw2, T2.ptr(), nw2, beta, AT2.ptr(), nw2); - // BlasConnector::gemm(dagger, notrans, nw1, nw2, nw1, - // alpha, T1.ptr(), nw1, AT2.ptr(), nw2, beta, TAT.ptr(), nw2); - } - inline void TAT_HR(double* TAT, const double* A, - const RI::Tensor& T1, const RI::Tensor& T2) - { - const char notrans = 'N', transpose = 'T', dagger = 'C'; - const double alpha(1.0), beta(0.0); - // H'^T = T2^T * H^T * T1^* - const int& nw2 = T2.shape[0], & nw1 = T1.shape[0]; - const RI::Shape_Vector& shape = { static_cast(nw1),static_cast(nw2) }; - RI::Tensor AT2(shape); - dgemm_(¬rans, ¬rans, &nw2, &nw1, &nw2, &alpha, T2.ptr(), &nw2, A, &nw2, &beta, AT2.ptr(), &nw2); - dgemm_(¬rans, &dagger, &nw2, &nw1, &nw1, &alpha, AT2.ptr(), &nw2, T1.ptr(), &nw1, &beta, TAT, &nw2); - } - inline void TAT_DR(std::complex* TAT, const std::complex* A, - const RI::Tensor>& T1, const RI::Tensor>& T2) - { - const char notrans = 'N', transpose = 'T', dagger = 'C'; - const std::complex alpha(1.0, 0.0), beta(0.0, 0.0); - //T2^\dagger * D^T * T1 = [(D^T)^T * (T2^T)^\dagger]^T * (T1^T)^T - const int& nw2 = T2.shape[0], & nw1 = T1.shape[0]; - const RI::Shape_Vector& shape = { static_cast(nw1),static_cast(nw2) }; - RI::Tensor> AT2(shape); - zgemm_(&transpose, &dagger, &nw1, &nw2, &nw2, &alpha, A, &nw2, T2.ptr(), &nw2, &beta, AT2.ptr(), &nw1); - zgemm_(&transpose, &transpose, &nw2, &nw1, &nw1, &alpha, AT2.ptr(), &nw1, T1.ptr(), &nw1, &beta, TAT, &nw2); - } - inline void TAT_DR(double* TAT, const double* A, - const RI::Tensor& T1, const RI::Tensor& T2) - { - const char notrans = 'N', transpose = 'T', dagger = 'C'; - const double alpha(1.0), beta(0.0); - //T2^\dagger * D^T * T1 = [(D^T)^T * (T2^T)^\dagger]^T * (T1^T)^T - const int& nw2 = T2.shape[0], & nw1 = T1.shape[0]; - const RI::Shape_Vector& shape = { static_cast(nw1),static_cast(nw2) }; - RI::Tensor AT2(shape); - dgemm_(&transpose, &dagger, &nw1, &nw2, &nw2, &alpha, A, &nw2, T2.ptr(), &nw2, &beta, AT2.ptr(), &nw1); - dgemm_(&transpose, &transpose, &nw2, &nw1, &nw1, &alpha, AT2.ptr(), &nw1, T1.ptr(), &nw1, &beta, TAT, &nw2); - } - inline void TA_HR(std::complex* TA, const std::complex* A, - const RI::Tensor>& T1, const int& nw12) - { - const char notrans = 'N', transpose = 'T', dagger = 'C'; - const std::complex alpha(1.0, 0.0), beta(0.0, 0.0); - // C'^T = C^T * T1^* - const int& nabf = T1.shape[0]; - zgemm_(¬rans, &dagger, &nw12, &nabf, &nabf, &alpha, A, &nw12, T1.ptr(), &nabf, &beta, TA, &nw12); - } - inline void TA_HR(double* TA, const double* A, - const RI::Tensor& T1, const int& nw12) - { - const char notrans = 'N', transpose = 'T', dagger = 'C'; - const double alpha(1.0), beta(0.0); - // C'^T = C^T * T1^* - const int& nabf = T1.shape[0]; - dgemm_(¬rans, &dagger, &nw12, &nabf, &nabf, &alpha, A, &nw12, T1.ptr(), &nabf, &beta, TA, &nw12); - } template RI::Tensor Symmetry_rotation::rotate_atompair_serial(const RI::Tensor& A, const int isym, const Atom& a1, const Atom& a2, const char mode, const bool output)const @@ -172,7 +101,7 @@ namespace ModuleSymmetry const RI::Tensor& T2 = sametype ? T1 : this->set_rotation_matrix(a2, isym); // rotate RI::TensorTAT(A.shape); - (mode == 'H') ? TAT_HR(TAT.ptr(), A.ptr(), T1, T2) : TAT_DR(TAT.ptr(), A.ptr(), T1, T2); + (mode == 'H') ? RI::Sym::T1_HR_T2(TAT.ptr(), A.ptr(), T1, T2) : RI::Sym::T1_DR_T2(TAT.ptr(), A.ptr(), T1, T2); if (output) { print_tensor(A, "A"); @@ -196,7 +125,7 @@ namespace ModuleSymmetry const RI::Tensor& T1 = this->set_rotation_matrix(a1, isym); const RI::Tensor& T2 = sametype ? T1 : this->set_rotation_matrix(a2, isym); // rotate - (mode == 'H') ? TAT_HR(TAT, A, T1, T2) : TAT_DR(TAT, A, T1, T2); + (mode == 'H') ? RI::Sym::T1_HR_T2(TAT, A, T1, T2) : RI::Sym::T1_DR_T2(TAT, A, T1, T2); } @@ -235,7 +164,7 @@ namespace ModuleSymmetry a1.nw, a2.nw, isym, a1, a2, 'H'); // step 2: multiply the ABFs' rotation matrix from the left const RI::Tensor& Tabfs = this->set_rotation_matrix_abf(type1, isym); - TA_HR(Cout.ptr(), Cout.ptr(), Tabfs, slice_size); + RI::Sym::T1_HR(Cout.ptr(), Cout.ptr(), Tabfs, slice_size); return Cout; } diff --git a/source/module_ri/exx_symmetry/test/symmetry_rotation_test.cpp b/source/module_ri/exx_symmetry/test/symmetry_rotation_test.cpp index 3c04c1d7db..33da46f6c3 100644 --- a/source/module_ri/exx_symmetry/test/symmetry_rotation_test.cpp +++ b/source/module_ri/exx_symmetry/test/symmetry_rotation_test.cpp @@ -60,7 +60,7 @@ class SymmetryRotationTest : public testing::Test const int matsize = 5; //2s1p }; -// inline void outmat(ModuleBase::ComplexMatrix& mat, int size, std::string name) +// inline void outmat(RI::Tensor>& mat, int size, std::string name) // { // std::cout << name << std::endl; // for (int i = 0;i < size;++i) @@ -77,7 +77,7 @@ TEST_F(SymmetryRotationTest, Wignerd) } TEST_F(SymmetryRotationTest, WignerD) { - ModuleBase::ComplexMatrix wignerD_p_C41(3, 3); + RI::Tensor> wignerD_p_C41({ 3, 3 }); int l = 1; for (int m1 = -l;m1 <= l;++m1) for (int m2 = -l;m2 <= l;++m2) @@ -104,7 +104,7 @@ TEST_F(SymmetryRotationTest, EulerAngle) TEST_F(SymmetryRotationTest, OvlpYS) { - ModuleBase::ComplexMatrix c_mm_p(3, 3); + RI::Tensor> c_mm_p({ 3, 3 }); int l = 1; for (int m1 = -l;m1 <= l;++m1) for (int m2 = -l;m2 <= l;++m2) @@ -119,7 +119,7 @@ TEST_F(SymmetryRotationTest, OvlpYS) TEST_F(SymmetryRotationTest, RotMat) { symrot.cal_rotmat_Slm(&C41, 1); - ModuleBase::ComplexMatrix& rotmat = symrot.get_rotmat_Slm()[0][1]; + RI::Tensor>& rotmat = symrot.get_rotmat_Slm()[0][1]; int l = 1; for (int m1 = -l;m1 <= l;++m1) for (int m2 = -l;m2 <= l;++m2) @@ -148,7 +148,7 @@ TEST_F(SymmetryRotationTest, SetBlockToMat2d) for (int j = 0;j < pv.get_col_size();++j) for (int i = 0;i < pv.get_row_size();++i) obj_mat[j * pv.get_row_size() + i] = std::complex(static_cast(pv.local2global_row(i)), static_cast(pv.local2global_col(j))); - ModuleBase::ComplexMatrix block(2, 2); + RI::Tensor> block({ 2, 2 }); block(0, 0) = 0; block(0, 1) = -1; block(1, 0) = -2; block(1, 1) = -3; symrot.set_block_to_mat2d(2, 3, block, obj_mat, pv); for (int i = 2;i < 4;++i) From fa66faec30ca39846e5c8b10f18c4d5e7f2a5c24 Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Wed, 10 Apr 2024 13:37:16 +0800 Subject: [PATCH 17/19] fix:ensure the ibz-kpoints are original k-points --- source/module_cell/klist.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/module_cell/klist.cpp b/source/module_cell/klist.cpp index 97565dca3e..003d0da611 100644 --- a/source/module_cell/klist.cpp +++ b/source/module_cell/klist.cpp @@ -878,9 +878,9 @@ void K_Vectors::ibz_kpoint(const ModuleSymmetry::Symmetry& symm, // if really there is no equivalent k point in the list, then add it. if (!already_exist) { - // if it's a new ibz kpoint. - // nkstot_ibz indicate the index of ibz kpoint. - kvec_d_ibz[nkstot_ibz] = kvec_rot; + //if it's a new ibz kpoint. + //nkstot_ibz indicate the index of ibz kpoint. + this->kvec_d_ibz[nkstot_ibz] = kvec_d[i]; // output in kpoints file ibz_index[i] = nkstot_ibz; From c521e26bba307028d5d21be699b5c1f149db9af7 Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Tue, 30 Jul 2024 11:08:26 +0800 Subject: [PATCH 18/19] fix after rebase 0730 --- source/module_base/scalapack_connector.h | 13 ------- source/module_cell/klist.cpp | 12 +++--- source/module_cell/klist.h | 37 +++++++++---------- .../module_cell/module_symmetry/symmetry.cpp | 4 +- source/module_cell/module_symmetry/symmetry.h | 4 +- source/module_io/input_conv.cpp | 2 +- source/module_parameter/input_parameter.h | 2 +- source/module_ri/Exx_LRI_interface.hpp | 10 ++--- .../exx_symmetry/symmetry_rotation.cpp | 6 +-- .../test/symmetry_rotation_test.cpp | 8 +--- 10 files changed, 38 insertions(+), 60 deletions(-) diff --git a/source/module_base/scalapack_connector.h b/source/module_base/scalapack_connector.h index a0bd591f00..8e0798b0d8 100644 --- a/source/module_base/scalapack_connector.h +++ b/source/module_base/scalapack_connector.h @@ -208,19 +208,6 @@ class ScalapackConnector B, &IB, &JB, DESCB, &beta, C, &IC, &JC, DESCC); } - static inline - void gemm( - const char transa, const char transb, - const int M, const int N, const int K, - const double alpha, - const double* A, const int IA, const int JA, const int* DESCA, - const double* B, const int IB, const int JB, const int* DESCB, - const double beta, - double* C, const int IC, const int JC, const int* DESCC) - { - pdgemm_(&transa, &transb, &M, &N, &K, &alpha, A, &IA, &JA, DESCA, - B, &IB, &JB, DESCB, &beta, C, &IC, &JC, DESCC); - } static inline void getrf( const int M, const int N, diff --git a/source/module_cell/klist.cpp b/source/module_cell/klist.cpp index 003d0da611..14ed9487fa 100644 --- a/source/module_cell/klist.cpp +++ b/source/module_cell/klist.cpp @@ -880,7 +880,7 @@ void K_Vectors::ibz_kpoint(const ModuleSymmetry::Symmetry& symm, { //if it's a new ibz kpoint. //nkstot_ibz indicate the index of ibz kpoint. - this->kvec_d_ibz[nkstot_ibz] = kvec_d[i]; + kvec_d_ibz[nkstot_ibz] = kvec_d[i]; // output in kpoints file ibz_index[i] = nkstot_ibz; @@ -938,11 +938,11 @@ void K_Vectors::ibz_kpoint(const ModuleSymmetry::Symmetry& symm, { kvec_rot = kvec_d[i] * kgmatrix[j]; restrict_kpt(kvec_rot); - for (int k = 0; k < this->nkstot_ibz; ++k) + for (int k = 0; k < nkstot_ibz; ++k) { - if (symm.equal(kvec_rot.x, this->kvec_d_ibz[k].x) && - symm.equal(kvec_rot.y, this->kvec_d_ibz[k].y) && - symm.equal(kvec_rot.z, this->kvec_d_ibz[k].z)) + if (symm.equal(kvec_rot.x, kvec_d_ibz[k].x) && + symm.equal(kvec_rot.y, kvec_d_ibz[k].y) && + symm.equal(kvec_rot.z, kvec_d_ibz[k].z)) { isym = j; exist_number = k; @@ -1241,7 +1241,7 @@ void K_Vectors::mpi_k() auto ks = this->kstars[ikibz].begin(); for (int ik = 0;ik < starsize;++ik) { - int isym; + int isym = 0; ModuleBase::Vector3 ks_vec(0, 0, 0); if (GlobalV::MY_RANK == 0) { diff --git a/source/module_cell/klist.h b/source/module_cell/klist.h index 1dbbb2c2fb..3c03e72ec2 100644 --- a/source/module_cell/klist.h +++ b/source/module_cell/klist.h @@ -10,7 +10,7 @@ class K_Vectors { - public: +public: std::vector> kvec_c; /// Cartesian coordinates of k points std::vector> kvec_d; /// Direct coordinates of k points @@ -26,7 +26,6 @@ class K_Vectors /// dim: [iks_ibz][(isym, kvec_d)] std::vector>> kstars; - K_Vectors(); ~K_Vectors(); K_Vectors& operator=(const K_Vectors&) = default; @@ -52,11 +51,11 @@ class K_Vectors * @note Only available for nspin = 1 or 2 or 4. */ void set(const ModuleSymmetry::Symmetry& symm, - const std::string& k_file_name, - const int& nspin, - const ModuleBase::Matrix3& reciprocal_vec, - const ModuleBase::Matrix3& latvec, - std::ofstream& ofs); + const std::string& k_file_name, + const int& nspin, + const ModuleBase::Matrix3& reciprocal_vec, + const ModuleBase::Matrix3& latvec, + std::ofstream& ofs); /** * @brief Generates irreducible k-points in the Brillouin zone considering symmetry operations. @@ -72,10 +71,10 @@ class K_Vectors * @param match A boolean flag that indicates if the results matches the real condition. */ void ibz_kpoint(const ModuleSymmetry::Symmetry& symm, - bool use_symm, - std::string& skpt, - const UnitCell& ucell, - bool& match); + bool use_symm, + std::string& skpt, + const UnitCell& ucell, + bool& match); // LiuXh add 20180515 /** @@ -114,11 +113,11 @@ class K_Vectors * @return int Returns the global index of the k-point. * * @note The function calculates the global index by dividing the total number of k-points (nkstot) by the number of + * process pools (KPAR), and adding the remainder if the process pool ID (MY_POOL) is less than the remainder. * @note The function is declared as inline for efficiency. */ inline int getik_global(const int& ik) const; -<<<<<<< HEAD int get_nks() const { return this->nks; @@ -154,11 +153,11 @@ class K_Vectors this->nkstot_full = value; } - /// dim: [iks_ibz][(isym, kvec_d)] - std::vector>> kstars; - private: ->>>>>>> 627516392 (symmetry rotation for EXX) + int nks; // number of symmetry-reduced k points in this pool(processor, up+dw) + int nkstot; /// number of symmetry-reduced k points in full k mesh + int nkstot_full; /// number of k points before symmetry reduction in full k mesh + int nspin; bool kc_done; bool kd_done; @@ -283,8 +282,8 @@ class K_Vectors * be recalculated. */ void update_use_ibz(const int& nkstot_ibz, - const std::vector>& kvec_d_ibz, - const std::vector& wk_ibz); + const std::vector>& kvec_d_ibz, + const std::vector& wk_ibz); /** * @brief Sets both the direct and Cartesian k-vectors. @@ -405,4 +404,4 @@ inline int K_Vectors::getik_global(const int& ik) const } } -#endif // KVECT_H +#endif // KVECT_H \ No newline at end of file diff --git a/source/module_cell/module_symmetry/symmetry.cpp b/source/module_cell/module_symmetry/symmetry.cpp index aa72f1d584..928f257626 100644 --- a/source/module_cell/module_symmetry/symmetry.cpp +++ b/source/module_cell/module_symmetry/symmetry.cpp @@ -887,7 +887,7 @@ void Symmetry::lattice_type( void Symmetry::getgroup(int& nrot, int& nrotk, std::ofstream& ofs_running, const int& nop, const ModuleBase::Matrix3* symop, ModuleBase::Matrix3* gmatrix, ModuleBase::Vector3* gtrans, - double* pos, double* rotpos, int* index, int itmin_type, int itmin_start, int* istart, int* na)const + double* pos, double* rotpos, int* index, const int itmin_type, const int itmin_start, int* istart, int* na)const { ModuleBase::TITLE("Symmetry", "getgroup"); @@ -990,7 +990,7 @@ void Symmetry::getgroup(int& nrot, int& nrotk, std::ofstream& ofs_running, const } bool Symmetry::checksym(const ModuleBase::Matrix3& s, ModuleBase::Vector3& gtrans, - double* pos, double* rotpos, int* index, int itmin_type, int itmin_start, int* istart, int* na)const + double* pos, double* rotpos, int* index, const int itmin_type, const int itmin_start, int* istart, int* na)const { //---------------------------------------------- // checks whether a point group symmetry element diff --git a/source/module_cell/module_symmetry/symmetry.h b/source/module_cell/module_symmetry/symmetry.h index 885fa73e07..63a2e9d594 100644 --- a/source/module_cell/module_symmetry/symmetry.h +++ b/source/module_cell/module_symmetry/symmetry.h @@ -91,9 +91,9 @@ class Symmetry : public Symmetry_Basic void getgroup(int& nrot, int& nrotk, std::ofstream& ofs_running, const int& nop, const ModuleBase::Matrix3* symop, ModuleBase::Matrix3* gmatrix, ModuleBase::Vector3* gtrans, - double* pos, double* rotpos, int* index, int itmin_type, int itmin_start, int* istart, int* na)const; + double* pos, double* rotpos, int* index, const int itmin_type, const int itmin_start, int* istart, int* na)const; bool checksym(const ModuleBase::Matrix3& s, ModuleBase::Vector3& gtrans, - double* pos, double* rotpos, int* index, int itmin_type, int itmin_start, int* istart, int* na)const; + double* pos, double* rotpos, int* index, const int itmin_type, const int itmin_start, int* istart, int* na)const; /// @brief primitive cell analysis void pricell(double* pos, const Atom* atoms); diff --git a/source/module_io/input_conv.cpp b/source/module_io/input_conv.cpp index e59fbaee08..db0c3adab1 100644 --- a/source/module_io/input_conv.cpp +++ b/source/module_io/input_conv.cpp @@ -496,7 +496,7 @@ void Input_Conv::Convert() GlobalC::exx_info.info_global.separate_loop = PARAM.inp.exx_separate_loop; GlobalC::exx_info.info_global.hybrid_step = PARAM.inp.exx_hybrid_step; GlobalC::exx_info.info_global.mixing_beta_for_loop1 = PARAM.inp.exx_mixing_beta; - GlobalC::exx_info.info_global.exx_symmetry_realspace = INPUT.exx_symmetry_realspace; + GlobalC::exx_info.info_global.exx_symmetry_realspace = PARAM.inp.exx_symmetry_realspace; GlobalC::exx_info.info_lip.lambda = PARAM.inp.exx_lambda; GlobalC::exx_info.info_ri.real_number = std::stoi(PARAM.inp.exx_real_number); diff --git a/source/module_parameter/input_parameter.h b/source/module_parameter/input_parameter.h index 6b9b454daa..471aa950f8 100644 --- a/source/module_parameter/input_parameter.h +++ b/source/module_parameter/input_parameter.h @@ -482,7 +482,7 @@ struct Input_para double exx_opt_orb_ecut = 0.0; ///< the cut-off of plane wave expansion for opt ABFs double exx_opt_orb_tolerence = 0.0; ///< the threshold when solving for the zeros of spherical Bessel ///< functions for opt ABFs - bool exx_symmetry_realspace; ///< true for rotate H(R) and D(k) and false for rotate D(k) only + bool exx_symmetry_realspace = true; ///< whether to reduce the real-space sector in when using symmetry=1 in EXX calculation double rpa_ccp_rmesh_times = 10.0; ///< how many times larger the radial mesh required for ///< calculating Columb potential is to that of atomic orbitals // ============== #Parameters (16.dft+u) ====================== diff --git a/source/module_ri/Exx_LRI_interface.hpp b/source/module_ri/Exx_LRI_interface.hpp index e1cae02b55..14d0a965fa 100644 --- a/source/module_ri/Exx_LRI_interface.hpp +++ b/source/module_ri/Exx_LRI_interface.hpp @@ -101,15 +101,13 @@ void Exx_LRI_Interface::exx_eachiterinit(const elecstate::DensityMatri if (!GlobalC::exx_info.info_global.separate_loop && this->two_level_step) { const bool flag_restart = (iter == 1) ? true : false; - if (this->exx_spacegroup_symmetry) - this->mix_DMk_2D.mix(symrot_.restore_dm(kv, dm.get_DMK_vector(), *dm.get_paraV_pointer()), flag_restart); - else - this->mix_DMk_2D.mix(dm.get_DMK_vector(), flag_restart); + if (this->exx_spacegroup_symmetry) { this->mix_DMk_2D.mix(symrot_.restore_dm(kv, dm.get_DMK_vector(), *dm.get_paraV_pointer()), flag_restart); } + else { this->mix_DMk_2D.mix(dm.get_DMK_vector(), flag_restart); } const std::vector>,RI::Tensor>>> Ds = GlobalV::GAMMA_ONLY_LOCAL ? RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_gamma_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN) : RI_2D_Comm::split_m2D_ktoR(*this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_k_out(), *dm.get_paraV_pointer(), GlobalV::NSPIN, this->exx_spacegroup_symmetry); - if (this->exx_spacegroup_symmetry && GlobalC::exx_info.info_global.symmetry_rotate_realspace) { this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer(), &this->symrot_); } + if (this->exx_spacegroup_symmetry && GlobalC::exx_info.info_global.exx_symmetry_realspace) { this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer(), &this->symrot_); } else { this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer()); } } } @@ -216,7 +214,7 @@ bool Exx_LRI_Interface::exx_after_converge( // this->symrot_.test_HR_rotation(GlobalC::ucell.symm, GlobalC::ucell.atoms, GlobalC::ucell.st, 'H', *(dynamic_cast*>(&hamilt)->getHR())); // exit(0); - if (this->exx_spacegroup_symmetry && GlobalC::exx_info.info_global.symmetry_rotate_realspace) + if (this->exx_spacegroup_symmetry && GlobalC::exx_info.info_global.exx_symmetry_realspace) { this->exx_ptr->cal_exx_elec(Ds, *dm.get_paraV_pointer(), &this->symrot_); // this->symrot_.print_HR(this->exx_ptr->Hexxs[0], "Hexxs_irreducible"); // test diff --git a/source/module_ri/exx_symmetry/symmetry_rotation.cpp b/source/module_ri/exx_symmetry/symmetry_rotation.cpp index b530eb1485..6a78552a32 100644 --- a/source/module_ri/exx_symmetry/symmetry_rotation.cpp +++ b/source/module_ri/exx_symmetry/symmetry_rotation.cpp @@ -92,8 +92,8 @@ namespace ModuleSymmetry }; std::vector>> dm_k_full; int nspin0 = GlobalV::NSPIN == 2 ? 2 : 1; - dm_k_full.reserve(kv.nkstot_full * nspin0); //nkstot_full didn't doubled by spin - int nk = kv.nkstot / nspin0; + dm_k_full.reserve(kv.get_nkstot_full() * nspin0); //nkstot_full didn't doubled by spin + int nk = kv.get_nkstot() / nspin0; for (int is = 0;is < nspin0;++is) for (int ik_ibz = 0;ik_ibz < nk;++ik_ibz) for (auto& isym_kvd : kv.kstars[ik_ibz]) @@ -116,7 +116,7 @@ namespace ModuleSymmetry /* std::ofstream ofs("DM.dat"); int ik = 0; - for (int ikibz = 0;ikibz < kv.nkstot / nspin0;++ikibz) + for (int ikibz = 0;ikibz < kv.get_nkstot() / nspin0;++ikibz) for (auto& isym_kvd : kv.kstars[ikibz]) { ofs << "isym=" << isym_kvd.first << std::endl; diff --git a/source/module_ri/exx_symmetry/test/symmetry_rotation_test.cpp b/source/module_ri/exx_symmetry/test/symmetry_rotation_test.cpp index 33da46f6c3..809a5dfeb7 100644 --- a/source/module_ri/exx_symmetry/test/symmetry_rotation_test.cpp +++ b/source/module_ri/exx_symmetry/test/symmetry_rotation_test.cpp @@ -43,13 +43,7 @@ class SymmetryRotationTest : public testing::Test int myrank, dsize; MPI_Comm_rank(MPI_COMM_WORLD, &myrank); MPI_Comm_size(MPI_COMM_WORLD, &dsize); - pv.set_block_size(1); - pv.set_proc_dim(dsize); - pv.mpi_create_cart(MPI_COMM_WORLD); - std::ofstream ofs; - pv.set_local2global(matsize, matsize, ofs, ofs); - pv.set_desc(matsize, matsize, pv.get_row_size()); - pv.set_global2local(matsize, matsize, true, ofs); + pv.init(matsize, matsize, 1, MPI_COMM_WORLD); } ModuleBase::Matrix3 C41 = ModuleBase::Matrix3(0, 1, 0, -1, 0, 0, 0, 0, 1); std::vector> wigerD_p_C41_ref = { ModuleBase::IMAG_UNIT, 0, 0, 0, 1, 0, 0, 0, -ModuleBase::IMAG_UNIT }; From 42a24111eff82c9640a1100ab1f08463e86cac10 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 04:05:56 +0000 Subject: [PATCH 19/19] [pre-commit.ci lite] apply automatic fixes --- .../exx_symmetry/irreducible_sector.h | 21 +++++++++++-------- .../exx_symmetry/irreducible_sector_bvk.cpp | 20 +++++++++++------- .../exx_symmetry/symmetry_rotation_R.hpp | 18 ++++++++++------ 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/source/module_ri/exx_symmetry/irreducible_sector.h b/source/module_ri/exx_symmetry/irreducible_sector.h index ba6818c436..4770feb980 100644 --- a/source/module_ri/exx_symmetry/irreducible_sector.h +++ b/source/module_ri/exx_symmetry/irreducible_sector.h @@ -22,18 +22,20 @@ namespace ModuleSymmetry { bool operator()(const Tap& lhs, const Tap& rhs) const { - if (lhs.first < rhs.first)return true; - else if (lhs.first > rhs.first)return false; - else return lhs.second < rhs.second; + if (lhs.first < rhs.first) {return true; + } else if (lhs.first > rhs.first) {return false; + } else { return lhs.second < rhs.second; +} } }; struct apR_less_func { bool operator()(const TapR& lhs, const TapR& rhs) const { - if (lhs.first < rhs.first)return true; - else if (lhs.first > rhs.first)return false; - else return lhs.second < rhs.second; + if (lhs.first < rhs.first) {return true; + } else if (lhs.first > rhs.first) {return false; + } else { return lhs.second < rhs.second; +} } }; struct len_less_func @@ -44,9 +46,10 @@ namespace ModuleSymmetry } bool operator()(const TC& lhs, const TC& rhs) const { - if (norm2(lhs) < norm2(rhs))return true; - else if (norm2(lhs) > norm2(rhs))return false; - else return lhs < rhs; + if (norm2(lhs) < norm2(rhs)) {return true; + } else if (norm2(lhs) > norm2(rhs)) {return false; + } else { return lhs < rhs; +} } }; diff --git a/source/module_ri/exx_symmetry/irreducible_sector_bvk.cpp b/source/module_ri/exx_symmetry/irreducible_sector_bvk.cpp index 4ff7344adb..2ed86cb802 100644 --- a/source/module_ri/exx_symmetry/irreducible_sector_bvk.cpp +++ b/source/module_ri/exx_symmetry/irreducible_sector_bvk.cpp @@ -45,7 +45,8 @@ namespace ModuleSymmetry { //the BvK supercell has the same symmetry as the original cell this->bvk_nsym_ = symm.nrotk; this->isymbvk_to_isym_.resize(symm.nrotk); - for (int isym = 0;isym < symm.nrotk;++isym) this->isymbvk_to_isym_[isym] = isym; + for (int isym = 0;isym < symm.nrotk;++isym) { this->isymbvk_to_isym_[isym] = isym; +} return; } @@ -59,7 +60,8 @@ namespace ModuleSymmetry for (int it = 0;it < st.ntype;++it) { bvk_na[it] = atoms[it].na * bvk_min_period[0] * bvk_min_period[1] * bvk_min_period[2]; - if (it > 0) bvk_istart[it] = bvk_istart[it - 1] + bvk_na[it - 1]; + if (it > 0) { bvk_istart[it] = bvk_istart[it - 1] + bvk_na[it - 1]; +} if (bvk_na[it] < bvk_na[bvk_itmin_type]) { bvk_itmin_type = it; @@ -76,10 +78,10 @@ namespace ModuleSymmetry s3 = a3 = lat.a3 * static_cast(bvk_min_period[2]); ModuleBase::Matrix3 bvk_min_lat = set_matrix3(s1, s2, s3); int at = 0; - for (int it = 0; it < st.ntype; ++it) - for (int c1 = 0;c1 < bvk_min_period[0];++c1) - for (int c2 = 0;c2 < bvk_min_period[1];++c2) - for (int c3 = 0;c3 < bvk_min_period[2];++c3) + for (int it = 0; it < st.ntype; ++it) { + for (int c1 = 0;c1 < bvk_min_period[0];++c1) { + for (int c2 = 0;c2 < bvk_min_period[1];++c2) { + for (int c3 = 0;c3 < bvk_min_period[2];++c3) { for (int ia = 0; ia < atoms[it].na; ++ia) { bvk_dpos[3 * at] = (static_cast (c1) + atoms[it].taud[ia].x) / static_cast(bvk_min_period[0]); @@ -92,6 +94,10 @@ namespace ModuleSymmetry } ++at; } +} +} +} +} // analyze bravis and generate optimized lattice for minimal BvK lattice double cel_const[6], pre_const[6]; @@ -157,4 +163,4 @@ namespace ModuleSymmetry // return in_plain; // } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/source/module_ri/exx_symmetry/symmetry_rotation_R.hpp b/source/module_ri/exx_symmetry/symmetry_rotation_R.hpp index 940cb3b34c..af87e32e8c 100644 --- a/source/module_ri/exx_symmetry/symmetry_rotation_R.hpp +++ b/source/module_ri/exx_symmetry/symmetry_rotation_R.hpp @@ -42,8 +42,9 @@ namespace ModuleSymmetry std::cout << name << ":\n"; for (int i = 0;i < t.shape[0];++i) { - for (int j = 0;j < t.shape[1];++j) + for (int j = 0;j < t.shape[1];++j) { std::cout << ((std::abs(t(i, j)) > threshold) ? t(i, j) : static_cast(0)) << " "; +} std::cout << std::endl; } } @@ -56,8 +57,9 @@ namespace ModuleSymmetry std::cout << "abf: " << a << '\n'; for (int i = 0;i < t.shape[1];++i) { - for (int j = 0;j < t.shape[2];++j) + for (int j = 0;j < t.shape[2];++j) { std::cout << ((std::abs(t(a, i, j)) > threshold) ? t(a, i, j) : static_cast(0)) << " "; +} std::cout << std::endl; } std::cout << std::endl; @@ -68,9 +70,11 @@ namespace ModuleSymmetry inline void set_block(const int starti, const int startj, const RI::Tensor>& block, RI::Tensor& obj_tensor) { // no changing row/col order - for (int i = 0;i < block.shape[0];++i) - for (int j = 0;j < block.shape[1];++j) + for (int i = 0;i < block.shape[0];++i) { + for (int j = 0;j < block.shape[1];++j) { obj_tensor(starti + i, startj + j) = RI::Global_Func::convert(block(i, j)); +} +} } template @@ -133,7 +137,8 @@ namespace ModuleSymmetry RI::Tensor Symmetry_rotation::set_rotation_matrix_abf(const int& type, const int& isym)const { int nabfs = 0; - for (int l = 0;l < this->abfs_l_nchi_[type].size();++l)nabfs += this->abfs_l_nchi_[type][l] * (2 * l + 1); + for (int l = 0;l < this->abfs_l_nchi_[type].size();++l) {nabfs += this->abfs_l_nchi_[type][l] * (2 * l + 1); +} RI::Tensor T({ static_cast(nabfs), static_cast(nabfs) }); // check if zero int iw = 0; for (int L = 0;L < this->abfs_l_nchi_[type].size();++L) @@ -159,9 +164,10 @@ namespace ModuleSymmetry assert(C.shape.size() == 3); const int& slice_size = C.shape[1] * C.shape[2]; // step 1: multiply 2 AOs' rotation matrices - for (int iabf = 0;iabf < C.shape[0];++iabf) + for (int iabf = 0;iabf < C.shape[0];++iabf) { this->rotate_atompair_serial(Cout.ptr() + iabf * slice_size, C.ptr() + iabf * slice_size, a1.nw, a2.nw, isym, a1, a2, 'H'); +} // step 2: multiply the ABFs' rotation matrix from the left const RI::Tensor& Tabfs = this->set_rotation_matrix_abf(type1, isym); RI::Sym::T1_HR(Cout.ptr(), Cout.ptr(), Tabfs, slice_size);