diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f85893c47e..015b190affa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ option(ENABLE_MLALGO "Enable the machine learning algorithms" OFF) option(ENABLE_LCAO "Enable LCAO algorithm" ON) option(USE_ELPA "Enable ELPA for LCAO" ON) option(ENABLE_LIBRI "Enable LibRI for hybrid functional" OFF) +option(EXX_DEV "Enable LibRI developing features" OFF) option(ENABLE_LIBCOMM "Enable LibComm" OFF) option(ENABLE_PEXSI "Enable PEXSI for LCAO" OFF) option(ENABLE_DFTD4 "Enable DFT-D4 dispersion correction" OFF) @@ -759,6 +760,9 @@ if(ENABLE_LIBRI) target_link_libraries(${ABACUS_BIN_NAME} ri module_exx_symmetry) add_compile_definitions(__EXX EXX_DM=3 EXX_H_COMM=2 TEST_EXX_LCAO=0 TEST_EXX_RADIAL=1) + if(EXX_DEV) + add_compile_definitions(__EXX_DEV) + endif() endif() if(ENABLE_LIBRI OR DEFINED LIBCOMM_DIR) diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index a91c6dd7530..79a0c2a1e60 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -166,11 +166,23 @@ - [out\_stru](#out_stru) - [out\_level](#out_level) - [out\_mat\_hs](#out_mat_hs) + - [out\_mat\_h\_t](#out_mat_h_t) + - [out\_mat\_h\_vl](#out_mat_h_vl) + - [out\_mat\_h\_vnl](#out_mat_h_vnl) + - [out\_mat\_h\_vh](#out_mat_h_vh) + - [out\_mat\_h\_vxc](#out_mat_h_vxc) + - [out\_mat\_h\_exx](#out_mat_h_exx) - [out\_mat\_hs2](#out_mat_hs2) - [out\_mat\_tk](#out_mat_tk) - [out\_mat\_r](#out_mat_r) - [out\_mat\_t](#out_mat_t) - [out\_mat\_dh](#out_mat_dh) + - [out\_mat\_dh\_t](#out_mat_dh_t) + - [out\_mat\_dh\_vl](#out_mat_dh_vl) + - [out\_mat\_dh\_vnl](#out_mat_dh_vnl) + - [out\_mat\_dh\_vh](#out_mat_dh_vh) + - [out\_mat\_dh\_vxc](#out_mat_dh_vxc) + - [out\_mat\_dh\_exx](#out_mat_dh_exx) - [out\_mat\_ds](#out_mat_ds) - [out\_mat\_xc](#out_mat_xc) - [out\_mat\_xc2](#out_mat_xc2) @@ -1865,7 +1877,7 @@ The corresponding sequence of the orbitals can be seen in Basis Set. - Also controled by out_freq_ion and out_app_flag. + Also controlled by out_freq_ion and out_app_flag. > Note: In the 3.10-LTS version, the file names are WFC_NAO_GAMMA1_ION1.txt and WFC_NAO_K1_ION1.txt, etc. - **Default**: 0 @@ -1926,7 +1938,7 @@ - **Type**: Boolean \[Integer\](optional) - **Availability**: *Numerical atomic orbital basis* -- **Description**: Whether to print the upper triangular part of the Hamiltonian matrices and overlap matrices for each k-point into files in the directory OUT.${suffix}. The second number controls precision. For more information, please refer to hs_matrix.md. Also controled by out_freq_ion and out_app_flag. +- **Description**: Whether to print the upper triangular part of the Hamiltonian matrices and overlap matrices for each k-point into files in the directory OUT.${suffix}. The second number controls precision. For more information, please refer to hs_matrix.md. Also controlled by out_freq_ion and out_app_flag. - For gamma only case: - nspin = 1: hks1_nao.txt for the Hamiltonian matrix and sks1_nao.txt for the overlap matrix; - nspin = 2: hks1_nao.txt and hks2_nao.txt for the Hamiltonian matrix and sks1_nao.txt for the overlap matrix. Note that the code will not output sks2_nao.txt because it is the same as sks1_nao.txt; @@ -1940,6 +1952,54 @@ - **Default**: False 8 - **Unit**: Ry +### out_mat_h_t + +- **Type**: Boolean \[Integer\](optional) +- **Availability**: *Numerical atomic orbital basis (nspin ≠ 4)* +- **Description**: Whether to print the kinetic energy matrix $T_{\mu\nu}(k) = \langle\phi_\mu|\hat{T}|\phi_\nu\rangle(k)$ for each k-point. The output format and file naming (e.g. `tks1_nao.txt`, `tks1k1_nao.txt`) follow [`out_mat_hs`](#out_mat_hs). +- **Default**: False 8 +- **Unit**: Ry + +### out_mat_h_vl + +- **Type**: Boolean \[Integer\](optional) +- **Availability**: *Numerical atomic orbital basis (nspin ≠ 4)* +- **Description**: Whether to print the local pseudopotential matrix $V^L_{\mu\nu}(k) = \langle\phi_\mu|\hat{V}^L|\phi_\nu\rangle(k)$ for each k-point. The output format and file naming (e.g. `vlks1_nao.txt`, `vlks1k1_nao.txt`) follow [`out_mat_hs`](#out_mat_hs). +- **Default**: False 8 +- **Unit**: Ry + +### out_mat_h_vnl + +- **Type**: Boolean \[Integer\](optional) +- **Availability**: *Numerical atomic orbital basis (nspin ≠ 4)* +- **Description**: Whether to print the nonlocal pseudopotential (Kleinman–Bylander) matrix $V^{NL}_{\mu\nu}(k) = \langle\phi_\mu|\hat{V}^{NL}|\phi_\nu\rangle(k)$ for each k-point. The output format and file naming (e.g. `vnlks1_nao.txt`, `vnlks1k1_nao.txt`) follow [`out_mat_hs`](#out_mat_hs). +- **Default**: False 8 +- **Unit**: Ry + +### out_mat_h_vh + +- **Type**: Boolean \[Integer\](optional) +- **Availability**: *Numerical atomic orbital basis (nspin ≠ 4)* +- **Description**: Whether to print the Hartree matrix $V^H_{\mu\nu}(k) = \langle\phi_\mu|\hat{V}^H|\phi_\nu\rangle(k)$ for each k-point. The output format and file naming (e.g. `vhks1_nao.txt`, `vhks1k1_nao.txt`) follow [`out_mat_hs`](#out_mat_hs). +- **Default**: False 8 +- **Unit**: Ry + +### out_mat_h_vxc + +- **Type**: Boolean \[Integer\](optional) +- **Availability**: *Numerical atomic orbital basis (nspin ≠ 4)* +- **Description**: Whether to print the exchange-correlation matrix $V^{XC}_{\mu\nu}(k) = \langle\phi_\mu|\hat{V}^{XC}|\phi_\nu\rangle(k)$ for each k-point. The output format and file naming (e.g. `vxcks1_nao.txt`, `vxcks1k1_nao.txt`) follow [`out_mat_hs`](#out_mat_hs). +- **Default**: False 8 +- **Unit**: Ry + +### out_mat_h_exx + +- **Type**: Boolean \[Integer\](optional) +- **Availability**: *Numerical atomic orbital basis (nspin ≠ 4, hybrid functional only)* +- **Description**: Whether to print the exact-exchange matrix $V^{EXX}_{\mu\nu}(k) = \langle\phi_\mu|\hat{V}^{EXX}|\phi_\nu\rangle(k)$ for each k-point. The output format and file naming (e.g. `vexxks1_nao.txt`, `vexxks1k1_nao.txt`) follow [`out_mat_hs`](#out_mat_hs). Requires a hybrid functional (`cal_exx = true`). +- **Default**: False 8 +- **Unit**: Ry + ### out_mat_hs2 - **Type**: Boolean \[Integer\](optional) @@ -1974,7 +2034,7 @@ - **Type**: Boolean \[Integer\](optional) - **Availability**: *Numerical atomic orbital basis (not gamma-only algorithm)* -- **Description**: Generate files containing the kinetic energy matrix. The format will be the same as the Hamiltonian matrix and overlap matrix as mentioned in out_mat_hs2. The name of the files will be trs1_nao.csr and so on. Also controled by out_freq_ion and out_app_flag. +- **Description**: Generate files containing the kinetic energy matrix. The format will be the same as the Hamiltonian matrix and overlap matrix as mentioned in out_mat_hs2. The name of the files will be trs1_nao.csr and so on. Also controlled by out_freq_ion and out_app_flag. > Note: In the 3.10-LTS version, the file name is data-TR-sparse_SPIN0.csr. - **Default**: False 8 @@ -1983,10 +2043,73 @@ ### out_mat_dh - **Type**: Integer -- **Availability**: *Numerical atomic orbital basis (not gamma-only algorithm)* -- **Description**: Whether to print files containing the derivatives of the Hamiltonian matrix. The format will be the same as the Hamiltonian matrix and overlap matrix as mentioned in out_mat_hs2. The name of the files will be dhrxs1_nao.csr, dhrys1_nao.csr, dhrzs1_nao.csr and so on. Also controled by out_freq_ion and out_app_flag. - +- **Availability**: *Numerical atomic orbital basis* +- **Description**: Whether to print files containing the derivatives of the Hamiltonian matrix $dH(k)/d\tau_I=d\braket{\phi|\hat{H}|\phi}(k)/d\tau_I$ where $\tau_I$ is the Ith atom position with the dense format as `out_mat_dh`. The names are dhk[x/y/z]_iat[I][_ik]_nao.txt. + - See also the term-separated output parameters: [`out_mat_dh_t`](#out_mat_dh_t), [`out_mat_dh_vl`](#out_mat_dh_vl), [`out_mat_dh_vnl`](#out_mat_dh_vnl), [`out_mat_dh_vh`](#out_mat_dh_vh), [`out_mat_dh_vxc`](#out_mat_dh_vxc) and [`out_mat_dh_exx`](#out_mat_dh_exx). + - If not gamma-only, also $\braket{\nabla\phi|\hat{H}\phi}(R)$ of sparse format as `out_mat_hs2` will also be output. The name of the files will be dhrxs1_nao.csr, dhrys1_nao.csr, dhrzs1_nao.csr and so on. Also controlled by out_freq_ion and out_app_flag. > Note: In the 3.10-LTS version, the file name is data-dHRx-sparse_SPIN0.csr and so on. + - **Format**: ` [precision] [iat1 iat2 ...]` + - The first value (0/1) enables or disables output. + - The second optional value sets the output precision (number of significant digits, default: 8). + - Starting from the third value, **1-based atom indices** can be listed to restrict the output to derivatives with respect to those specific atoms only. If no atom indices are given, derivatives are written for all atoms. + + For example, `out_mat_dh 1 8 1 3` writes dH/dR for atoms 1 and 3 only (1-based indexing). + +- **Default**: 0 8 +- **Unit**: Ry/Bohr + +### out_mat_dh_t + +- **Type**: Integer +- **Availability**: *Numerical atomic orbital basis (nspin ≠ 4)* +- **Description**: Whether to print files containing the kinetic energy contribution to the Hamiltonian derivative, see [`out_mat_dh`](#out_mat_dh) for the same format. Output files: dhk[x/y/z]_iat[I][_ik]_nao.txt. + +- **Default**: 0 8 +- **Unit**: Ry/Bohr + +### out_mat_dh_vl + +- **Type**: Integer +- **Availability**: *Numerical atomic orbital basis (nspin ≠ 4)* +- **Description**: Whether to print files containing the local pseudopotential contribution to the Hamiltonian derivative, see [`out_mat_dh`](#out_mat_dh) for the same format. Output files: dvlk[x/y/z]_iat[I][_ik]_nao.txt. + +- **Default**: 0 8 +- **Unit**: Ry/Bohr + +### out_mat_dh_vnl + +- **Type**: Integer +- **Availability**: *Numerical atomic orbital basis (nspin ≠ 4)* +- **Description**: Whether to print files containing the nonlocal pseudopotential contribution to the Hamiltonian derivative, see [`out_mat_dh`](#out_mat_dh) for the same format. Output files: dvnlk[x/y/z]_iat[I][_ik]_nao.txt. + +- **Default**: 0 8 +- **Unit**: Ry/Bohr + +### out_mat_dh_vh + +- **Type**: Integer +- **Availability**: *Numerical atomic orbital basis (nspin ≠ 4)* +- **Description**: Whether to print files containing the Hartree contribution to the Hamiltonian derivative, see [`out_mat_dh`](#out_mat_dh) for the same format. Output files: dvhk[x/y/z]_iat[I][_ik]_nao.txt. + +- **Default**: 0 8 +- **Unit**: Ry/Bohr + +### out_mat_dh_vxc + +- **Type**: Integer +- **Availability**: *Numerical atomic orbital basis (nspin ≠ 4)* +- **Description**: Whether to print files containing the exchange-correlation contribution to the Hamiltonian derivative, see [`out_mat_dh`](#out_mat_dh) for the same format. Output files: dvxck[x/y/z]_iat[I][_ik]_nao.txt. + +- **Default**: 0 8 +- **Unit**: Ry/Bohr + +### out_mat_dh_exx + +- **Type**: Integer +- **Availability**: *Numerical atomic orbital basis, hybrid functional only (nspin ≠ 4)* + - Currently only availablewhen compiled with the personal developing branch of LibRI and -DEXX_DEV flag, waiting for the new release of LibRI to remove the flag. +- **Description**: Whether to print files containing the exact-exchange contribution to the Hamiltonian derivative, see [`out_mat_dh`](#out_mat_dh) for the same format. Output files: dvexxk[x/y/z]_iat[I][_ik]_nao.txt. + - **Default**: 0 8 - **Unit**: Ry/Bohr @@ -1994,7 +2117,7 @@ - **Type**: Boolean \[Integer\](optional) - **Availability**: *Numerical atomic orbital basis (not gamma-only algorithm)* -- **Description**: Whether to print files containing the derivatives of the overlap matrix. The format will be the same as the overlap matrix as mentioned in out_mat_dh. The name of the files will be dsxrs1_nao.csr and so on. Also controled by out_freq_ion and out_app_flag. This feature can be used with calculation get_s. +- **Description**: Whether to print files containing the derivatives of the overlap matrix. The format will be the same as the overlap matrix as mentioned in out_mat_dh. The name of the files will be dsxrs1_nao.csr and so on. Also controlled by out_freq_ion and out_app_flag. This feature can be used with calculation get_s. > Note: In the 3.10-LTS version, the file name is data-dSRx-sparse_SPIN0.csr and so on. - **Default**: False 8 diff --git a/source/source_esolver/esolver_ks_lcao.cpp b/source/source_esolver/esolver_ks_lcao.cpp index ee04d9f1e25..d1b5b2717b5 100644 --- a/source/source_esolver/esolver_ks_lcao.cpp +++ b/source/source_esolver/esolver_ks_lcao.cpp @@ -544,6 +544,7 @@ void ESolver_KS_LCAO::after_scf(UnitCell& ucell, const int istep, const PARAM.inp, this->kv, this->pelec, this->dmat.dm, this->pv, this->gd, this->psi, hamilt_lcao, this->dftu, this->two_center_bundle_, this->orb_, this->pw_wfc, this->pw_rho, this->pw_big, this->sf, + this->pw_rhod, this->locpp.vloc, this->solvent, this->rdmft_solver, this->deepks, this->exx_nao, this->conv_esolver, this->scf_nmax_flag, istep); diff --git a/source/source_estate/init_scf.cpp b/source/source_estate/init_scf.cpp index a86c82b7b0c..783c8fe1a3b 100644 --- a/source/source_estate/init_scf.cpp +++ b/source/source_estate/init_scf.cpp @@ -17,7 +17,10 @@ void init_scf(const UnitCell& ucell, pelec->charge->set_rho_core(ucell, strucfac, numeric); //! renormalize the charge density - pelec->charge->renormalize_rho(); + if(PARAM.inp.init_chg != "dm") + { + pelec->charge->renormalize_rho(); + } //! initialize the potential pelec->pot->init_pot(pelec->charge); diff --git a/source/source_estate/module_charge/charge.cpp b/source/source_estate/module_charge/charge.cpp index 32d0b4f8356..3b540a1a291 100644 --- a/source/source_estate/module_charge/charge.cpp +++ b/source/source_estate/module_charge/charge.cpp @@ -54,7 +54,7 @@ void Charge::set_rhopw(ModulePW::PW_Basis* rhopw_in) } // mohan add 2025-12-02 -bool Charge::kin_density() +bool Charge::kin_density() const { if (XC_Functional::get_ked_flag() || PARAM.inp.out_elf[0] > 0) { diff --git a/source/source_estate/module_charge/charge.h b/source/source_estate/module_charge/charge.h index 9064dfc5fb8..48af8c92412 100644 --- a/source/source_estate/module_charge/charge.h +++ b/source/source_estate/module_charge/charge.h @@ -84,7 +84,7 @@ class Charge const void* wfcpw = nullptr); // mohan add 2025-12-02 - bool kin_density(); + bool kin_density() const; void allocate(const int &nspin_in, const bool kin_den); diff --git a/source/source_estate/module_pot/potential_new.h b/source/source_estate/module_pot/potential_new.h index ca79ca02f63..4281d6e4a0f 100644 --- a/source/source_estate/module_pot/potential_new.h +++ b/source/source_estate/module_pot/potential_new.h @@ -175,6 +175,11 @@ class Potential : public PotBase { return this->rho_basis_; } + // get the local pseudopotential vloc(it, G) table; used by the dH module (out_mat_dh_vl) + const ModuleBase::matrix* get_vloc() const + { + return this->vloc_; + } // What about adding a function to get the wfc? // This is useful for the calculation of the exx energy diff --git a/source/source_io/CMakeLists.txt b/source/source_io/CMakeLists.txt index 6073f10a7df..e6461d11bc4 100644 --- a/source/source_io/CMakeLists.txt +++ b/source/source_io/CMakeLists.txt @@ -82,10 +82,13 @@ if(ENABLE_LCAO) module_mulliken/output_mulliken.cpp module_ml/io_npz.cpp module_hs/cal_pLpR.cpp + module_dhs/write_dH.cpp + module_dhs/write_dH_terms.cpp ) list(APPEND objects_advanced module_unk/unk_overlap_lcao.cpp module_hs/write_HS_R.cpp + module_hs/write_H_terms.cpp module_hs/write_HS_sparse.cpp module_hs/single_R_io.cpp module_hs/cal_r_overlap_R.cpp diff --git a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp index 7318a3f2b7b..385d1134c01 100644 --- a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp +++ b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp @@ -11,6 +11,8 @@ #include "../module_unk/berryphase.h" // use berryphase #include "../module_hs/cal_pLpR.h" // use AngularMomentumCalculator() #include "source_io/module_hs/output_mat_sparse.h" // use ModuleIO::output_mat_sparse() +#include "source_io/module_dhs/write_dH.h" // use ModuleIO::write_dH_components() +#include "source_io/module_hs/write_H_terms.h" // use ModuleIO::write_h_* #include "../module_hs/write_HS_R.h" // use ModuleIO::write_hsr() #include "../module_mulliken/output_mulliken.h" // use cal_mag() #include "../module_wannier/to_wannier90_lcao.h" // use toWannier90_LCAO @@ -52,6 +54,9 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, const ModulePW::PW_Basis* pw_rho, // for berryphase const ModulePW::PW_Basis_Big* pw_big, // for Wannier90 const Structure_Factor& sf, // for Wannier90 + const ModulePW::PW_Basis* pw_rhod, // dense charge grid (for dH veff pots) + const ModuleBase::matrix& vloc, // local pseudopotential (for dH veff pots) + surchem& solvent, // solvent model (for dH veff pots) rdmft::RDMFT& rdmft_solver, // for RDMFT Setup_DeePKS& deepks, Exx_NAO& exx_nao, @@ -229,10 +234,11 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, } //------------------------------------------------------------------ - //! 7b) Output dH, dS, T, r matrices (old sparse path, without H/S) + //! 7b) Output dH, dS, T, r matrices (old sparse path, without H/S), only for multi-k //------------------------------------------------------------------ hamilt::Hamilt* p_ham_tk = static_cast*>(p_hamilt); + if(!PARAM.globalv.gamma_only_local) ModuleIO::output_mat_sparse(inp.out_mat_dh[0], inp.out_mat_ds[0], inp.out_mat_t[0], @@ -248,6 +254,145 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, p_ham_tk, &dftu); + //------------------------------------------------------------------ + //! 7c) Output atomic dH components (dT/dτ, dV^NL/dτ, dV^L/dτ, dV^H/dτ, dV^XC/dτ), only for nspin =1, 2 now + //------------------------------------------------------------------ + if( PARAM.inp.nspin < 4 ) + { + WriteDHParams dh_params; + dh_params.ucell = &ucell; + dh_params.gd = &gd; + dh_params.pv = &pv; + dh_params.two_center_bundle = &two_center_bundle; + dh_params.orb = &orb; + dh_params.kv = &kv; + dh_params.v_eff = &pelec->pot->get_eff_v(); + dh_params.pot = pelec->pot; + dh_params.chg = pelec->charge; + // pelec->pot->get_eff_v() is the SUM V^L + V^H + V^XC; feeding it to cal_dH would + // give the wrong potential for the separated V^L / V^H / V^XC outputs. Build one + // dedicated Potential per term with exactly one component registered (see write_vxc.hpp). + double dh_etxc = 0.0; + double dh_vtxc = 0.0; + elecstate::Potential* pot_vl = nullptr; + elecstate::Potential* pot_vh = nullptr; + elecstate::Potential* pot_vxc = nullptr; + // out_mat_dh (total dH = sum of all terms) needs every veff potential regardless of the + // per-component flags, so allocate all three when it is on; otherwise allocate per flag. + if (inp.out_mat_dh_vl[0] || inp.out_mat_dh[0]) + { + pot_vl = new elecstate::Potential(pw_rhod, pw_rho, &ucell, &vloc, + const_cast(&sf), &solvent, &dh_etxc, &dh_vtxc); + pot_vl->pot_register({"local"}); + pot_vl->update_from_charge(pelec->charge, &ucell); + } + if (inp.out_mat_dh_vh[0] || inp.out_mat_dh[0]) + { + pot_vh = new elecstate::Potential(pw_rhod, pw_rho, &ucell, &vloc, + const_cast(&sf), &solvent, &dh_etxc, &dh_vtxc); + pot_vh->pot_register({"hartree"}); + pot_vh->update_from_charge(pelec->charge, &ucell); + } + if (inp.out_mat_dh_vxc[0] || inp.out_mat_dh[0]) + { + pot_vxc = new elecstate::Potential(pw_rhod, pw_rho, &ucell, &vloc, + const_cast(&sf), &solvent, &dh_etxc, &dh_vtxc); + pot_vxc->pot_register({"xc"}); + pot_vxc->update_from_charge(pelec->charge, &ucell); + } + dh_params.pot_vl = pot_vl; + dh_params.pot_vh = pot_vh; + dh_params.pot_vxc = pot_vxc; + dh_params.iat2iwt = ucell.get_iat2iwt(); + dh_params.nat = ucell.nat; + dh_params.nspin = inp.nspin; + dh_params.istep = istep; + dh_params.gamma_only = gamma_only; + dh_params.append = out_app_flag; + if (PARAM.inp.nspin == 1 || PARAM.inp.nspin == 2) + { + // per-spin DM (1-indexed): nspin=1 -> {spin0}, nspin=2 -> {spin-up, spin-down}. + // The Veff Hellmann-Feynman terms need these (V^H sums spins, V^XC is spin-resolved). + for (int is = 1; is <= PARAM.inp.nspin; ++is) + { + dh_params.dmR.push_back(dm->get_DMR_pointer(is)); + } + } +#ifdef __EXX + // dV^EXX/dR output is wired for the gamma (TK==double) exx interfaces. exd/exc are + // mutually exclusive (real vs complex Hexx); write_dH_exx picks by info_ri.real_number. + if constexpr (std::is_same::value) + { + if (GlobalC::exx_info.info_global.cal_exx) + { + if (exx_nao.exd) { dh_params.exd = exx_nao.exd.get(); } + if (exx_nao.exc) { dh_params.exc = exx_nao.exc.get(); } + } + } +#endif + ModuleIO::write_dH_components(dh_params); + delete pot_vl; + delete pot_vh; + delete pot_vxc; + } + + + //------------------------------------------------------------------ + //! 7d) Output H components (T, Vnl, Vl, Vh, Vxc) + //------------------------------------------------------------------ + { + ModuleIO::WriteHParams h_params; + h_params.ucell = &ucell; + h_params.gd = &gd; + h_params.pv = &pv; + h_params.two_center_bundle = &two_center_bundle; + h_params.orb = &orb; + h_params.kv = &kv; + h_params.pot = pelec->pot; + h_params.chg = pelec->charge; + h_params.rho_basis = pw_rho; + h_params.nrxx = pw_rho->nrxx; + h_params.nspin = nspin; + h_params.istep = istep; + h_params.append = out_app_flag; + h_params.iat2iwt = ucell.get_iat2iwt(); + h_params.nat = ucell.nat; + if (inp.out_mat_h_t[0]) + { + ModuleIO::write_h_t(h_params); + } + if (inp.out_mat_h_vnl[0]) + { + ModuleIO::write_h_vnl(h_params); + } + if (inp.out_mat_h_vl[0]) + { + ModuleIO::write_h_vl(h_params); + } + if (inp.out_mat_h_vh[0]) + { + ModuleIO::write_h_vh(h_params); + } + if (inp.out_mat_h_vxc[0]) + { + ModuleIO::write_h_vxc(h_params); + } +#ifdef __EXX + if (inp.out_mat_h_exx[0] && GlobalC::exx_info.info_global.cal_exx) + { + // V^EXX(R) output is wired for the gamma (TK==double) exx interfaces. + if constexpr (std::is_same::value) + { + if (GlobalC::exx_info.info_global.cal_exx) + { + if (exx_nao.exd) { h_params.exd = exx_nao.exd.get(); } + if (exx_nao.exc) { h_params.exc = exx_nao.exc.get(); } + ModuleIO::write_h_exx(h_params); + } + } + } +#endif + } //------------------------------------------------------------------ //! 8) Output kinetic matrix //------------------------------------------------------------------ @@ -528,6 +673,9 @@ template void ModuleIO::ctrl_scf_lcao( const ModulePW::PW_Basis* pw_rho, // for berryphase const ModulePW::PW_Basis_Big* pw_big, // for Wannier90 const Structure_Factor& sf, // for Wannier90 + const ModulePW::PW_Basis* pw_rhod, // dense charge grid (for dH veff pots) + const ModuleBase::matrix& vloc, // local pseudopotential (for dH veff pots) + surchem& solvent, // solvent model (for dH veff pots) rdmft::RDMFT& rdmft_solver, // for RDMFT Setup_DeePKS& deepks, Exx_NAO& exx_nao, @@ -553,6 +701,9 @@ template void ModuleIO::ctrl_scf_lcao, double>( const ModulePW::PW_Basis* pw_rho, // for berryphase const ModulePW::PW_Basis_Big* pw_big, // for Wannier90 const Structure_Factor& sf, // for Wannier90 + const ModulePW::PW_Basis* pw_rhod, // dense charge grid (for dH veff pots) + const ModuleBase::matrix& vloc, // local pseudopotential (for dH veff pots) + surchem& solvent, // solvent model (for dH veff pots) rdmft::RDMFT, double>& rdmft_solver, // for RDMFT Setup_DeePKS>& deepks, Exx_NAO>& exx_nao, @@ -577,6 +728,9 @@ template void ModuleIO::ctrl_scf_lcao, std::complex const ModulePW::PW_Basis* pw_rho, // for berryphase const ModulePW::PW_Basis_Big* pw_big, // for Wannier90 const Structure_Factor& sf, // for Wannier90 + const ModulePW::PW_Basis* pw_rhod, // dense charge grid (for dH veff pots) + const ModuleBase::matrix& vloc, // local pseudopotential (for dH veff pots) + surchem& solvent, // solvent model (for dH veff pots) rdmft::RDMFT, std::complex>& rdmft_solver, // for RDMFT Setup_DeePKS>& deepks, Exx_NAO>& exx_nao, diff --git a/source/source_io/module_ctrl/ctrl_scf_lcao.h b/source/source_io/module_ctrl/ctrl_scf_lcao.h index ae895f0262f..ab541a93362 100644 --- a/source/source_io/module_ctrl/ctrl_scf_lcao.h +++ b/source/source_io/module_ctrl/ctrl_scf_lcao.h @@ -7,6 +7,7 @@ #include "source_cell/unitcell.h" // use UnitCell #include "source_estate/elecstate.h" // use elecstate::ElecStateLCAO #include "source_estate/module_dm/density_matrix.h" // mohan add 2025-11-04 +#include "source_hamilt/module_surchem/surchem.h" // use surchem (for dH veff pots) #include "source_lcao/hamilt_lcao.h" // use hamilt::HamiltLCAO #include "source_lcao/module_dftu/dftu.h" // mohan add 20251107 #include "source_lcao/module_rdmft/rdmft.h" // use RDMFT codes @@ -37,6 +38,9 @@ void ctrl_scf_lcao(UnitCell& ucell, const ModulePW::PW_Basis* pw_rho, // for berryphase const ModulePW::PW_Basis_Big* pw_big, // for Wannier90 const Structure_Factor& sf, // for Wannier90 + const ModulePW::PW_Basis* pw_rhod, // dense charge grid (for dH veff pots) + const ModuleBase::matrix& vloc, // local pseudopotential (for dH veff pots) + surchem& solvent, // solvent model (for dH veff pots) rdmft::RDMFT& rdmft_solver, // for RDMFT Setup_DeePKS& deepks, Exx_NAO& exx_nao, diff --git a/source/source_io/module_dhs/write_dH.cpp b/source/source_io/module_dhs/write_dH.cpp new file mode 100644 index 00000000000..37a13058552 --- /dev/null +++ b/source/source_io/module_dhs/write_dH.cpp @@ -0,0 +1,189 @@ +#include "write_dH.h" + +#include "source_base/global_function.h" +#include "source_base/timer.h" +#include "source_io/module_hs/write_HS.h" +#include "source_io/module_hs/write_HS_R.h" +#include "source_io/module_output/ucell_io.h" +#include "source_io/module_parameter/parameter.h" +#include "source_lcao/module_hcontainer/hcontainer_funcs.h" +#include "source_lcao/module_hcontainer/output_hcontainer.h" + +#include +#include +#include +#include +#include + +namespace ModuleIO +{ + +void write_dh_perI(WriteDHParams& params, + int ispin, + const std::string& rprefix, + const std::string& kprefix, + const std::string& label, + std::array*>, 3>& g, + const std::vector& atom_filter) +{ + const UnitCell& ucell = *params.ucell; + const Parallel_Orbitals& pv = *params.pv; + const int nat = params.nat; + const int nspin = params.nspin; + const int nbasis = g[0][0]->get_nbasis(); + + const char dirc[3] = { 'x', 'y', 'z' }; + + // k-space (dense, folded like H(k)) parameters + const int nspin_k = (nspin == 2 ? 2 : 1); + const int nks = params.kv->get_nks() / nspin_k; + const int nlocal = PARAM.globalv.nlocal; + const std::string global_out_dir = PARAM.globalv.global_out_dir; + const bool out_app_flag = PARAM.inp.out_app_flag; + const std::string r_dir + = (PARAM.inp.calculation == "md" && !out_app_flag) ? PARAM.globalv.global_matrix_dir : global_out_dir; + +#ifdef __MPI + Parallel_Orbitals serialV; + serialV.init(nbasis, nbasis, nbasis, pv.comm()); + serialV.set_serial(nbasis, nbasis); + serialV.set_atomic_trace(params.iat2iwt, nat, nbasis); +#endif + + const bool filter_atoms = !atom_filter.empty(); + if (filter_atoms) + for (int idx : atom_filter) + if (idx < 0 || idx >= nat) + ModuleBase::WARNING("write_dh_perI", + "atom index " + std::to_string(idx + 1) + " (1-based) is out of range [1, " + + std::to_string(nat) + "] and will be skipped"); + for (int iat = 0; iat < nat; ++iat) + { + if (filter_atoms && std::find(atom_filter.begin(), atom_filter.end(), iat) == atom_filter.end()) + continue; + for (int d = 0; d < 3; ++d) + { + hamilt::HContainer* hR = g[d][iat]; + const std::string tag = std::string(1, dirc[d]) + "_iat" + std::to_string(iat + 1); + + // ---- real space dH(R), CSR (only when also_dhR; dH(k) below is always written) ---- + if (params.also_dhR) + { +#ifdef __MPI + hamilt::HContainer hR_s(&serialV); + hamilt::gatherParallels(*hR, &hR_s, 0); + if (GlobalV::MY_RANK == 0) +#endif + { + std::string fr = r_dir + ModuleIO::dhr_gen_fname(rprefix + tag, ispin, params.append, params.istep); +#ifdef __MPI + ModuleIO::write_hcontainer_csr(fr, &ucell, 8, &hR_s, params.istep, ispin, nspin, label); +#else + ModuleIO::write_hcontainer_csr(fr, &ucell, 8, hR, params.istep, ispin, nspin, label); +#endif + } + } + + // ---- k space dH(k), dense (folded like H(k), comparable to *_nao.txt) ---- + // build the filename directly (filename_output only accepts a fixed property set) +#ifdef __MPI + const bool col_major = ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER(PARAM.inp.ks_solver); + const size_t hk_size = static_cast(pv.get_row_size()) * pv.get_col_size(); +#else + const size_t hk_size = static_cast(nlocal) * nlocal; +#endif + for (int ik = 0; ik < nks; ++ik) + { + std::vector> hk(hk_size, 0); +#ifdef __MPI + if (col_major) + hamilt::folding_HR(*hR, hk.data(), params.kv->kvec_d[ik], pv.get_row_size(), 1); + else + hamilt::folding_HR(*hR, hk.data(), params.kv->kvec_d[ik], pv.get_col_size(), 0); +#else + hamilt::folding_HR(*hR, hk.data(), params.kv->kvec_d[ik], nlocal, 0); +#endif + std::string fk = global_out_dir + kprefix + tag; + if (nks > 1) + { + fk += "_ik" + std::to_string(params.kv->ik2iktot[ik]); + } + fk += "_nao.txt"; + ModuleIO::save_mat(params.istep, + hk.data(), + nlocal, + false, + 8, + false, + out_app_flag, + fk, + pv, + GlobalV::DRANK); + } + } + } +} + +void write_dH_components(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_components"); + ModuleBase::timer::start("ModuleIO", "write_dH_components"); + + // nspin=4 (noncollinear) is not supported: needs complex spinor blocks (HContainer>) + // plus noncollinear Gint kernels that do not exist for the dvlocal/drho paths. + if (PARAM.inp.nspin == 4) + { + ModuleBase::WARNING_QUIT("write_dH_components", + "dH/dR component output (out_mat_dh_*) is not supported for " + "nspin=4 (noncollinear) yet; only nspin=1 and nspin=2."); + } + + GlobalV::ofs_running << " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" << std::endl; + GlobalV::ofs_running << " | |" << std::endl; + GlobalV::ofs_running << " | #Print out dH/dR components# |" << std::endl; + GlobalV::ofs_running << " | |" << std::endl; + GlobalV::ofs_running << " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" << std::endl; + + if (PARAM.inp.out_mat_dh[0]) + { + write_dH_sum(params); + } + + if (PARAM.inp.out_mat_dh_t[0]) + { + write_dH_t(params); + } + + if (PARAM.inp.out_mat_dh_vnl[0]) + { + write_dH_vnl(params); + } + + if (PARAM.inp.out_mat_dh_vl[0]) + { + write_dH_vl(params); + } + + if (PARAM.inp.out_mat_dh_vh[0]) + { + write_dH_vh(params); + write_dH_vh_pulay(params); + } + + if (PARAM.inp.out_mat_dh_vxc[0]) + { + write_dH_vxc(params); + write_dH_vxc_pulay(params); + } + +#ifdef __EXX + if (PARAM.inp.out_mat_dh_exx[0]) + { + write_dH_exx(params); + } +#endif + + ModuleBase::timer::end("ModuleIO", "write_dH_components"); +} + +} // namespace ModuleIO diff --git a/source/source_io/module_dhs/write_dH.h b/source/source_io/module_dhs/write_dH.h new file mode 100644 index 00000000000..870a19f7e30 --- /dev/null +++ b/source/source_io/module_dhs/write_dH.h @@ -0,0 +1,112 @@ +#ifndef WRITE_DH_H +#define WRITE_DH_H + +#include "source_basis/module_nao/two_center_bundle.h" +#include "source_cell/klist.h" +#include "source_cell/module_neighbor/sltk_grid_driver.h" +#include "source_estate/module_pot/potential_new.h" +#include "source_lcao/LCAO_domain.h" +#include "source_lcao/module_hcontainer/hcontainer.h" + +#include +#include +#include + +///for lack of make_unique in c++11 +template +std::unique_ptr make_unique(Args &&... args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} + +template +class Exx_LRI_Interface; + +namespace ModuleIO +{ + +struct WriteDHParams +{ + const UnitCell* ucell = nullptr; + const Grid_Driver* gd = nullptr; + const Parallel_Orbitals* pv = nullptr; + const TwoCenterBundle* two_center_bundle = nullptr; + const LCAO_Orbitals* orb = nullptr; + const K_Vectors* kv = nullptr; + const ModuleBase::matrix* v_eff = nullptr; + const int* iat2iwt = nullptr; + elecstate::Potential* pot = nullptr; + // Dedicated single-component potentials for the Veff-based dH terms. pelec->pot mixes + // V^L + V^H + V^XC in get_eff_v(), so cal_dH would read the wrong potential for the + // separate V^H / V^XC (and V^L) outputs. Each of these is built with exactly one + // component registered ("local" / "hartree" / "xc"); see ctrl_scf_lcao. + elecstate::Potential* pot_vl = nullptr; + elecstate::Potential* pot_vh = nullptr; + elecstate::Potential* pot_vxc = nullptr; + int nat = 0; + int nspin = 1; + int istep = 0; + bool gamma_only = false; + bool append = false; + bool also_dhR = false; // whether to write the real-space dH(R) in addition to the k-space dH(k) + // per-spin real-space DM (size nspin for nspin=1/2). Used by the Veff Hellmann-Feynman + // terms: V^H needs the total density (sum over spins), V^XC the spin-resolved densities. + std::vector*> dmR; + const Charge* chg = nullptr; // ground-state charge for XC Hellmann-Feynman (FDM) +#ifdef __EXX + // gamma (TK==double) exx interfaces used by write_dH_exx; exactly one is set depending on + // GlobalC::exx_info.info_ri.real_number (exd: real Hexx, exc: complex Hexx). + Exx_LRI_Interface* exd = nullptr; + Exx_LRI_Interface>* exc = nullptr; +#endif +}; + +// Returns 0-based atom indices to output (converted from the 1-based user-facing values stored at param[2+]); +// empty vector (param.size() <= 2) means all atoms. Out-of-range checking is done in +// write_dh_perI where nat is available: indices >= nat are warned about and silently skipped. +inline std::vector dh_atom_filter(const std::vector& param) +{ + if (param.size() <= 2) // param elements: [on/off][precition][iat1][iat2][...] + return {}; + return std::vector(param.begin() + 2, param.end()); +} + +// Shared writer for the per-atom-I dH terms. For every differentiated atom I it writes: +// - dH(R) in CSR real-space format ({rprefix}{x,y,z}_iat{I}...) +// - dH(k) dense matrices ({kprefix}{x,y,z}_iat{I}...) folded like H(k), +// so they can be compared directly with the H(k) term matrices (*_nao.txt). +// g[d] are nat per-I HContainers for direction d=0..2 (already filled by an operator's cal_dH). +// atom_filter: if non-empty, only the listed 0-based atom indices are written; empty = all atoms. +void write_dh_perI(WriteDHParams& params, + int ispin, + const std::string& rprefix, + const std::string& kprefix, + const std::string& label, + std::array*>, 3>& g, + const std::vector& atom_filter = {}); + +void write_dH_components(WriteDHParams& params); + +bool write_dH_t(WriteDHParams& params); + +bool write_dH_vnl(WriteDHParams& params); + +bool write_dH_vl(WriteDHParams& params); + +bool write_dH_vh(WriteDHParams& params); + +bool write_dH_vh_pulay(WriteDHParams& params); + +bool write_dH_vxc(WriteDHParams& params); + +bool write_dH_vxc_pulay(WriteDHParams& params); + +bool write_dH_sum(WriteDHParams& params); + +#ifdef __EXX +bool write_dH_exx(WriteDHParams& params); +#endif + +} // namespace ModuleIO + +#endif diff --git a/source/source_io/module_dhs/write_dH_terms.cpp b/source/source_io/module_dhs/write_dH_terms.cpp new file mode 100644 index 00000000000..32d3ba3e316 --- /dev/null +++ b/source/source_io/module_dhs/write_dH_terms.cpp @@ -0,0 +1,477 @@ +#include "source_base/timer.h" +#include "source_io/module_hs/write_HS_R.h" +#include "source_io/module_output/ucell_io.h" +#include "source_io/module_parameter/parameter.h" +#include "source_lcao/module_hcontainer/hcontainer_funcs.h" +#include "source_lcao/module_hcontainer/output_hcontainer.h" +#include "source_lcao/module_operator_lcao/ekinetic.h" +#include "source_lcao/module_operator_lcao/nonlocal.h" +#include "source_lcao/module_operator_lcao/operator_force_stress_utils.h" +#include "source_lcao/module_operator_lcao/veff_lcao.h" +#include "source_lcao/module_gint/gint_interface.h" +#include "source_lcao/module_lr/utils/lr_util_xc.hpp" +#include "source_base/global_variable.h" +#include "source_base/parallel_reduce.h" +#include "write_dH.h" +#ifdef __EXX +#include "source_lcao/module_operator_lcao/op_exx_lcao.h" +#include "source_lcao/module_ri/Exx_LRI_interface.hpp" +#endif + +#include +#include +#include +#include +#include + +namespace ModuleIO +{ + +namespace +{ + + // RAII holder for the per-atom-I dH containers: one HContainer per (atom I, direction d). + // g[d] are raw-pointer views into the owned containers, ready to hand to an +// operator's cal_dH(...) and then to write_dh_perI(...). +struct PerIContainers +{ + std::array>>, 3> owned; + std::array*>, 3> g; + + PerIContainers(const Parallel_Orbitals& pv, int nat) + { + for (int d = 0; d < 3; ++d) + { + owned[d].reserve(nat); + g[d].reserve(nat); + for (int iat = 0; iat < nat; ++iat) + { + owned[d].push_back(make_unique>(&pv)); + g[d].push_back(owned[d].back().get()); + } + } + } +}; + +#ifdef __DEBUG +// Self-validation for cal_gint_drho (otherwise untested). For a symmetric DM the product rule +// gives grad(rho) = sum_{K,L} D[K,L]( (grad phi_K) phi_L + phi_K (grad phi_L) ) +// = 2 * sum_{K,L} D[K,L] (grad phi_K) phi_L = 2 * cal_gint_drho(D). +// We compare 2*cal_gint_drho(D) against the FFT gradient of cal_gint_rho(D) (same density, +// independent operator) and log the max relative deviation under a grep-able key so the +// integrate harness can assert it stays ~0. Cheap: one rho + one drho + one FFT grad. +void validate_gint_drho(const UnitCell& ucell, + elecstate::Potential* pot, + const hamilt::HContainer* dmR) +{ + if (dmR == nullptr) + return; + const ModulePW::PW_Basis* rho_basis = pot->get_rho_basis(); + const int nrxx = rho_basis->nrxx; + std::vector*> dm_vec = {const_cast*>(dmR)}; + + // rho via Gint + std::vector rho(nrxx, 0.0); + double* rho_p[1] = {rho.data()}; + ModuleGint::cal_gint_rho(dm_vec, 1, rho_p, false); + + // grad rho via FFT + std::vector> gradrho(nrxx); + LR_Util::grad(rho.data(), gradrho.data(), *rho_basis, ucell.tpiba); + + // drho via Gint (gradient on the first/row orbital) + std::vector dx(nrxx, 0.0), dy(nrxx, 0.0), dz(nrxx, 0.0); + double* dxp[1] = {dx.data()}; + double* dyp[1] = {dy.data()}; + double* dzp[1] = {dz.data()}; + ModuleGint::cal_gint_drho(dm_vec, 1, dxp, dyp, dzp); + + double maxdev = 0.0, maxref = 0.0; + for (int ir = 0; ir < nrxx; ++ir) + { + const double r[3] = {2.0 * dx[ir], 2.0 * dy[ir], 2.0 * dz[ir]}; + const double g[3] = {gradrho[ir].x, gradrho[ir].y, gradrho[ir].z}; + for (int d = 0; d < 3; ++d) + { + maxdev = std::max(maxdev, std::abs(r[d] - g[d])); + maxref = std::max(maxref, std::abs(g[d])); + } + } +#ifdef __MPI + Parallel_Reduce::reduce_all(maxdev); + Parallel_Reduce::reduce_all(maxref); +#endif + const double reldev = (maxref > 1e-30) ? (maxdev / maxref) : maxdev; + GlobalV::ofs_running << " GINT_DRHO_MAXDEV_REL " << reldev << std::endl; +} +#endif + +// Per-(spin) fillers: build one term's per-atom-I dH containers, no file output. Shared by the +// individual term writers below and by write_dH_sum (which accumulates them). Keeping the +// operator construction in one place avoids duplicating it in the summation path. +void fill_dH_t(WriteDHParams& params, PerIContainers& c) +{ + const UnitCell& ucell = *params.ucell; + const Grid_Driver& gd = *params.gd; + const TwoCenterBundle& two_center_bundle = *params.two_center_bundle; + const std::vector& orb_cutoff = params.orb->cutoffs(); + + hamilt::EKinetic> tmp_ekinetic(nullptr, + params.kv->kvec_d, + nullptr, + &ucell, + orb_cutoff, + &gd, + two_center_bundle.kinetic_orb.get()); + + tmp_ekinetic.cal_dH(c.g); +} + +void fill_dH_vnl(WriteDHParams& params, PerIContainers& c) +{ + const UnitCell& ucell = *params.ucell; + const Grid_Driver& gd = *params.gd; + const TwoCenterBundle& two_center_bundle = *params.two_center_bundle; + const std::vector& orb_cutoff = params.orb->cutoffs(); + + hamilt::Nonlocal> tmp_nonlocal(nullptr, + params.kv->kvec_d, + nullptr, + &ucell, + orb_cutoff, + &gd, + two_center_bundle.overlap_orb_beta.get()); + + tmp_nonlocal.cal_dH(c.g); +} + +void fill_dH_veff(WriteDHParams& params, + elecstate::Potential* pot, + const std::string& hf_type, + int ispin, + PerIContainers& c) +{ + const UnitCell& ucell = *params.ucell; + const Grid_Driver& gd = *params.gd; + const Parallel_Orbitals& pv = *params.pv; + const std::vector& orb_cutoff = params.orb->cutoffs(); + const int nspin = params.nspin; + + hamilt::HContainer hR_dummy(const_cast(&pv)); + + hamilt::Veff> veff(nullptr, + params.kv->kvec_d, + pot, + &hR_dummy, + &ucell, + orb_cutoff, + &gd, + nspin); + + veff.cal_dH(c.g, hf_type, params.dmR, params.chg, ispin); +} + +// Shared driver for the Veff-based terms (V^L, V^H, V^XC), which differ only in the +// Hellmann-Feynman type passed to Veff::cal_dH and in the output prefixes/label. +bool write_dH_veff_term(WriteDHParams& params, + elecstate::Potential* pot, + const std::string& hf_type, + const std::string& rprefix, + const std::string& kprefix, + const std::string& label, + const std::vector& atom_filter = {}) +{ + const UnitCell& ucell = *params.ucell; + const Parallel_Orbitals& pv = *params.pv; + const int nat = ucell.nat; + const int nspin = params.nspin; + +#ifdef __DEBUG + // Validate cal_gint_drho once (it underpins the V^H Hellmann-Feynman term). + if (hf_type == "hartree") + validate_gint_drho(ucell, pot, params.dmR.empty() ? nullptr : params.dmR[0]); +#endif + + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) + { + PerIContainers c(pv, nat); + + fill_dH_veff(params, pot, hf_type, ispin, c); + + ModuleIO::write_dh_perI(params, ispin, rprefix, kprefix, label, c.g, atom_filter); + } + return true; +} + +#ifdef __EXX +// Per-(spin) filler for the EXX dH term. Assumes ex->cal_exx_dHs(...) has already been called +// (it builds dHexxs for all spins at once). Templated on the Hexx tensor data type (double for +// the real interface exd, std::complex for the complex interface exc). +template +void fill_dH_exx(WriteDHParams& params, Exx_LRI_Interface* ex, int ispin, PerIContainers& c) +{ + const UnitCell& ucell = *params.ucell; + const Parallel_Orbitals& pv = *params.pv; + + // OperatorEXX dereferences hR_in in its constructor and reallocates it, so pass a + // throwaway container (its cell_nearest is built from kv and reused for dhR below). + hamilt::HContainer hR_dummy(const_cast(&pv)); + hamilt::OperatorEXX> op_exx(nullptr, &hR_dummy, ucell, *params.kv); + + op_exx.cal_dH(ispin, c.g, ex->get_dHexxs()); +} + +// Shared driver for the EXX dH term. The per-atom-I dH is always written into real +// HContainer (add_HexxR converts Tdata -> double). +template +void write_dH_exx_impl(WriteDHParams& params, Exx_LRI_Interface* ex) +{ + const UnitCell& ucell = *params.ucell; + const Parallel_Orbitals& pv = *params.pv; + const int nat = ucell.nat; + const int nspin = params.nspin; + + // 1+2. build the exx-form per-direction/atom/spin dH (dHexxs) from the current mixed DM + ex->cal_exx_dHs(ucell, pv, nspin); + + const std::vector af = dh_atom_filter(PARAM.inp.out_mat_dh_exx); + // 3+4. convert dHexxs to per-atom-I HContainers and write, one spin channel at a time + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ++ispin) + { + PerIContainers c(pv, nat); + + fill_dH_exx(params, ex, ispin, c); + + ModuleIO::write_dh_perI(params, ispin, "dvexxr", "dvexxk", "dV^EXX", c.g, af); + } +} +#endif + +} // namespace + +bool write_dH_t(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_t"); + ModuleBase::timer::start("ModuleIO", "write_dH_t"); + + const Parallel_Orbitals& pv = *params.pv; + const int nat = params.ucell->nat; + const int nspin = params.nspin; + + const std::vector af_t = dh_atom_filter(PARAM.inp.out_mat_dh_t); + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) + { + // per-atom-I containers: dT_*[iat] = d/dtau_iat + PerIContainers c(pv, nat); + + fill_dH_t(params, c); + + ModuleIO::write_dh_perI(params, ispin, "dtr", "dtk", "dT", c.g, af_t); + } + + ModuleBase::timer::end("ModuleIO", "write_dH_t"); + return true; +} + +bool write_dH_vnl(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_vnl"); + ModuleBase::timer::start("ModuleIO", "write_dH_vnl"); + + const Parallel_Orbitals& pv = *params.pv; + const int nat = params.ucell->nat; + const int nspin = params.nspin; + + const std::vector af_vnl = dh_atom_filter(PARAM.inp.out_mat_dh_vnl); + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) + { + PerIContainers c(pv, nat); + + fill_dH_vnl(params, c); + + ModuleIO::write_dh_perI(params, ispin, "dvnlr", "dvnlk", "dV^NL", c.g, af_vnl); + } + + ModuleBase::timer::end("ModuleIO", "write_dH_vnl"); + return true; +} + +bool write_dH_vl(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_vl"); + ModuleBase::timer::start("ModuleIO", "write_dH_vl"); + + const std::vector af_vl = dh_atom_filter(PARAM.inp.out_mat_dh_vl); + const bool ok = write_dH_veff_term(params, params.pot_vl, "vl", "dvlr", "dvlk", "dV^L", af_vl); + + ModuleBase::timer::end("ModuleIO", "write_dH_vl"); + return ok; +} + +bool write_dH_vh(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_vh"); + ModuleBase::timer::start("ModuleIO", "write_dH_vh"); + + const std::vector af_vh = dh_atom_filter(PARAM.inp.out_mat_dh_vh); + const bool ok = write_dH_veff_term(params, params.pot_vh, "hartree", "dvhr", "dvhk", "dV^H", af_vh); + + ModuleBase::timer::end("ModuleIO", "write_dH_vh"); + return ok; +} + +bool write_dH_vh_pulay(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_vh_pulay"); + ModuleBase::timer::start("ModuleIO", "write_dH_vh_pulay"); + + const std::vector af_vh_pulay = dh_atom_filter(PARAM.inp.out_mat_dh_vh); + const bool ok = write_dH_veff_term(params, params.pot_vh, "none", "dvhr_pulay_", "dvhk_pulay_", "dV^H (Pulay)", af_vh_pulay); + + ModuleBase::timer::end("ModuleIO", "write_dH_vh_pulay"); + return ok; +} + +bool write_dH_vxc(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_vxc"); + ModuleBase::timer::start("ModuleIO", "write_dH_vxc"); + + const std::vector af_vxc = dh_atom_filter(PARAM.inp.out_mat_dh_vxc); + const bool ok = write_dH_veff_term(params, params.pot_vxc, + params.chg ? "xc" : "none", + "dvxcr", "dvxck", "dV^XC", af_vxc); + + ModuleBase::timer::end("ModuleIO", "write_dH_vxc"); + return ok; +} + +bool write_dH_vxc_pulay(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_vxc_pulay"); + ModuleBase::timer::start("ModuleIO", "write_dH_vxc_pulay"); + + const std::vector af_vxc_pulay = dh_atom_filter(PARAM.inp.out_mat_dh_vxc); + const bool ok = write_dH_veff_term(params, params.pot_vxc, "none", "dvxcr_pulay_", "dvxck_pulay_", "dV^XC (Pulay)", af_vxc_pulay); + + ModuleBase::timer::end("ModuleIO", "write_dH_vxc_pulay"); + return ok; +} + +#ifdef __EXX +bool write_dH_exx(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_exx"); + ModuleBase::timer::start("ModuleIO", "write_dH_exx"); + + bool ok = false; + // exd (real Hexx) and exc (complex Hexx) are mutually exclusive; pick by real_number. + if (GlobalC::exx_info.info_ri.real_number) + { + if (params.exd != nullptr) + { + write_dH_exx_impl(params, params.exd); + ok = true; + } + } + else + { + if (params.exc != nullptr) + { + write_dH_exx_impl(params, params.exc); + ok = true; + } + } + + ModuleBase::timer::end("ModuleIO", "write_dH_exx"); + return ok; +} +#endif + +// Total dH = sum of ALL dH terms (dT + dV^NL + dV^L + dV^H + dV^XC, plus dV^EXX when hybrid is +// active), independent of the per-component out_mat_dh_* flags: out_mat_dh on its own yields the +// full sum. Each term is built into its own per-atom-I containers (via the same fillers the +// per-term writers use) and accumulated with HContainer::add_value_union, which unions the +// (generally different) sparsities and sums values. Each term already carries its own sign. +bool write_dH_sum(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_sum"); + ModuleBase::timer::start("ModuleIO", "write_dH_sum"); + + const Parallel_Orbitals& pv = *params.pv; + const int nat = params.ucell->nat; + const int nspin = params.nspin; + +#ifdef __EXX + // EXX (whenever active) is part of the total dH; build dHexxs once up front. + const bool do_exx = (params.exd != nullptr || params.exc != nullptr); + if (do_exx) + { + if (GlobalC::exx_info.info_ri.real_number && params.exd != nullptr) + params.exd->cal_exx_dHs(*params.ucell, pv, nspin); + else if (!GlobalC::exx_info.info_ri.real_number && params.exc != nullptr) + params.exc->cal_exx_dHs(*params.ucell, pv, nspin); + } +#endif + + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ++ispin) + { + PerIContainers sum(pv, nat); + auto accumulate = [&](PerIContainers& term) { + for (int d = 0; d < 3; ++d) + for (int iat = 0; iat < nat; ++iat) + sum.g[d][iat]->add_value_union(*term.g[d][iat]); + }; + + // dT (kinetic) and dV^NL (nonlocal) need no potential. + { + PerIContainers c(pv, nat); + fill_dH_t(params, c); + accumulate(c); + } + { + PerIContainers c(pv, nat); + fill_dH_vnl(params, c); + accumulate(c); + } + // veff terms (potentials are allocated whenever out_mat_dh is on; guard defensively). + if (params.pot_vl != nullptr) + { + PerIContainers c(pv, nat); + fill_dH_veff(params, params.pot_vl, "vl", ispin, c); + accumulate(c); + } + if (params.pot_vh != nullptr) + { + // total dV^H = Hellmann-Feynman part + Pulay part + PerIContainers c(pv, nat); + fill_dH_veff(params, params.pot_vh, "hartree", ispin, c); + accumulate(c); + } + if (params.pot_vxc != nullptr) + { + // total dV^XC = Hellmann-Feynman part + Pulay part + PerIContainers c(pv, nat); + fill_dH_veff(params, params.pot_vxc, params.chg ? "xc" : "none", ispin, c); + accumulate(c); + } +#ifdef __EXX + if (do_exx) + { + PerIContainers c(pv, nat); + if (GlobalC::exx_info.info_ri.real_number && params.exd != nullptr) + fill_dH_exx(params, params.exd, ispin, c); + else if (params.exc != nullptr) + fill_dH_exx(params, params.exc, ispin, c); + accumulate(c); + } +#endif + + ModuleIO::write_dh_perI(params, ispin, "dhr", "dhk", "dH", sum.g, dh_atom_filter(PARAM.inp.out_mat_dh)); + } + + ModuleBase::timer::end("ModuleIO", "write_dH_sum"); + return true; +} + +} // namespace ModuleIO diff --git a/source/source_io/module_hs/output_mat_sparse.cpp b/source/source_io/module_hs/output_mat_sparse.cpp index 9f31352b432..e709590bd8c 100644 --- a/source/source_io/module_hs/output_mat_sparse.cpp +++ b/source/source_io/module_hs/output_mat_sparse.cpp @@ -29,7 +29,7 @@ void output_mat_sparse(const bool& out_mat_dh, output_TR(istep, ucell, pv, HS_Arrays, grid, two_center_bundle, orb); } - //! generate a file containing the derivatives of the Hamiltonian matrix (in Ry/Bohr) + //! generate a file containing the (in Ry/Bohr) if (out_mat_dh) { output_dHR(istep, diff --git a/source/source_io/module_hs/write_H_terms.cpp b/source/source_io/module_hs/write_H_terms.cpp new file mode 100644 index 00000000000..89071785213 --- /dev/null +++ b/source/source_io/module_hs/write_H_terms.cpp @@ -0,0 +1,438 @@ +#include "write_H_terms.h" + +#include "source_base/parallel_reduce.h" +#include "source_base/timer.h" +#include "source_estate/module_pot/H_Hartree_pw.h" +#include "source_hamilt/module_xc/xc_functional.h" +#include "source_io/module_hs/write_HS.h" +#include "source_io/module_hs/write_HS_R.h" +#include "source_io/module_output/filename.h" +#include "source_io/module_output/ucell_io.h" +#include "source_io/module_parameter/parameter.h" +#include "source_lcao/module_gint/gint_interface.h" +#include "source_lcao/module_hcontainer/hcontainer_funcs.h" +#include "source_lcao/module_hcontainer/output_hcontainer.h" +#include "source_lcao/module_operator_lcao/ekinetic.h" +#include "source_lcao/module_operator_lcao/nonlocal.h" +#include "source_lcao/module_operator_lcao/operator_force_stress_utils.h" +#ifdef __EXX +#include "source_lcao/module_operator_lcao/op_exx_lcao.h" +#include "source_lcao/module_ri/Exx_LRI_interface.h" +#include "source_lcao/module_ri/RI_2D_Comm.h" +#endif + +#include +#include + +namespace ModuleIO +{ + +static void setup_veff_hcontainer(hamilt::HContainer& hR, + const UnitCell& ucell, + const Grid_Driver& gd, + const Parallel_Orbitals& pv, + const std::vector& orb_cutoff) +{ + const Parallel_Orbitals* paraV = hR.get_paraV(); + for (int iat1 = 0; iat1 < ucell.nat; iat1++) + { + auto tau1 = ucell.get_tau(iat1); + int T1 = 0, I1 = 0; + ucell.iat2iait(iat1, &I1, &T1); + + AdjacentAtomInfo adjs; + gd.Find_atom(ucell, tau1, T1, I1, &adjs); + + for (int ad = 0; ad < adjs.adj_num + 1; ++ad) + { + const int T2 = adjs.ntype[ad]; + const int I2 = adjs.natom[ad]; + const int iat2 = ucell.itia2iat(T2, I2); + if (paraV->get_row_size(iat1) <= 0 || paraV->get_col_size(iat2) <= 0) + { + continue; + } + const ModuleBase::Vector3& R_index = adjs.box[ad]; + if (ucell.cal_dtau(iat1, iat2, R_index).norm() * ucell.lat0 < orb_cutoff[T1] + orb_cutoff[T2]) + { + hamilt::AtomPair tmp(iat1, iat2, R_index, paraV); + hR.insert_pair(tmp); + } + } + } + hR.allocate(nullptr, true); +} + +static void gather_and_write(const std::string& prefix, + const std::string& label, + hamilt::HContainer& hR, + const UnitCell& ucell, + const Parallel_Orbitals& pv, + const int nspin, + const int ispin, + const int istep, + const bool append, + const int* iat2iwt, + const int nat) +{ + const int nbasis = hR.get_nbasis(); +#ifdef __MPI + Parallel_Orbitals serialV; + serialV.init(nbasis, nbasis, nbasis, pv.comm()); + serialV.set_serial(nbasis, nbasis); + serialV.set_atomic_trace(iat2iwt, nat, nbasis); + hamilt::HContainer hr_serial(&serialV); + hamilt::gatherParallels(hR, &hr_serial, 0); + if (GlobalV::MY_RANK == 0) +#endif + { + std::string fname; + if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) + { + fname = PARAM.globalv.global_matrix_dir + hsr_gen_fname(prefix, ispin, append, istep); + } + else + { + fname = PARAM.globalv.global_out_dir + hsr_gen_fname(prefix, ispin, append, istep); + } +#ifdef __MPI + write_hcontainer_csr(fname, &ucell, 8, &hr_serial, istep, ispin, nspin, label); +#else + write_hcontainer_csr(fname, &ucell, 8, &hR, istep, ispin, nspin, label); +#endif + } +} + +static void write_hk_common(hamilt::HContainer& hR, + const std::string& prefix, + const UnitCell& ucell, + const Parallel_Orbitals& pv, + const K_Vectors& kv, + const int nspin, + const int istep, + const bool append, + const int* iat2iwt, + const int nat) +{ + const int nspin_k = (nspin == 2 ? 2 : 1); + const int nks = kv.get_nks() / nspin_k; + const int nlocal = PARAM.globalv.nlocal; + const bool gamma_only = PARAM.globalv.gamma_only_local; + const std::string global_out_dir = PARAM.globalv.global_out_dir; + const bool out_app_flag = PARAM.inp.out_app_flag; + + for (int ik = 0; ik < nks; ++ik) + { + const ModuleBase::Vector3& kvec_d = kv.kvec_d[ik]; + + std::vector> hk_global(nlocal * nlocal, 0); + hamilt::folding_HR(hR, hk_global.data(), kvec_d, nlocal, 0); + + const int out_label = 1; + std::string fname = ModuleIO::filename_output(global_out_dir, + prefix, + "nao", + ik, + kv.ik2iktot, + nspin, + kv.get_nkstot(), + out_label, + out_app_flag, + gamma_only, + istep); + ModuleIO::save_mat(istep, + hk_global.data(), + nlocal, + false, + 8, + false, + out_app_flag, + fname, + pv, + GlobalV::DRANK); + } +} + +void write_h_t(WriteHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_h_t"); + ModuleBase::timer::start("ModuleIO", "write_h_t"); + + const UnitCell& ucell = *params.ucell; + const Grid_Driver& gd = *params.gd; + const Parallel_Orbitals& pv = *params.pv; + const TwoCenterBundle& two_center_bundle = *params.two_center_bundle; + const LCAO_Orbitals& orb = *params.orb; + const K_Vectors& kv = *params.kv; + const int nspin = params.nspin; + const int istep = params.istep; + const bool append = params.append; + const int* iat2iwt = params.iat2iwt; + const int nat = params.nat; + const bool also_hR = params.also_hR; + + const std::vector& orb_cutoff = orb.cutoffs(); + const int nspin_out = (nspin == 2 ? 2 : 1); + + for (int ispin = 0; ispin < nspin_out; ispin++) + { + hamilt::HContainer hR_tmp(const_cast(&pv)); + + hamilt::EKinetic> + tmp_ekinetic(nullptr, kv.kvec_d, &hR_tmp, &ucell, orb_cutoff, &gd, two_center_bundle.kinetic_orb.get()); + tmp_ekinetic.contributeHR(); + + write_hk_common(hR_tmp, "tk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + + if (also_hR) + { + gather_and_write("t", "T", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + } + } + + ModuleBase::timer::end("ModuleIO", "write_h_t"); +} + +void write_h_vnl(WriteHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_h_vnl"); + ModuleBase::timer::start("ModuleIO", "write_h_vnl"); + + const UnitCell& ucell = *params.ucell; + const Grid_Driver& gd = *params.gd; + const Parallel_Orbitals& pv = *params.pv; + const TwoCenterBundle& two_center_bundle = *params.two_center_bundle; + const LCAO_Orbitals& orb = *params.orb; + const K_Vectors& kv = *params.kv; + const int nspin = params.nspin; + const int istep = params.istep; + const bool append = params.append; + const int* iat2iwt = params.iat2iwt; + const int nat = params.nat; + const bool also_hR = params.also_hR; + + const std::vector& orb_cutoff = orb.cutoffs(); + const int nspin_out = (nspin == 2 ? 2 : 1); + + for (int ispin = 0; ispin < nspin_out; ispin++) + { + hamilt::HContainer hR_tmp(const_cast(&pv)); + + hamilt::Nonlocal> tmp_nonlocal(nullptr, + kv.kvec_d, + &hR_tmp, + &ucell, + orb_cutoff, + &gd, + two_center_bundle.overlap_orb_beta.get()); + tmp_nonlocal.contributeHR(); + + write_hk_common(hR_tmp, "vnlk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + + if (also_hR) + { + gather_and_write("vnl", "V^NL", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + } + } + + ModuleBase::timer::end("ModuleIO", "write_h_vnl"); +} + +void write_h_vl(WriteHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_h_vl"); + ModuleBase::timer::start("ModuleIO", "write_h_vl"); + + const UnitCell& ucell = *params.ucell; + const Grid_Driver& gd = *params.gd; + const Parallel_Orbitals& pv = *params.pv; + const LCAO_Orbitals& orb = *params.orb; + const elecstate::Potential* pot = params.pot; + const K_Vectors& kv = *params.kv; + const int nspin = params.nspin; + const int istep = params.istep; + const bool append = params.append; + const int* iat2iwt = params.iat2iwt; + const int nat = params.nat; + const bool also_hR = params.also_hR; + + const std::vector& orb_cutoff = orb.cutoffs(); + const int nspin_out = (nspin == 2 ? 2 : 1); + + for (int ispin = 0; ispin < nspin_out; ispin++) + { + hamilt::HContainer hR_tmp(const_cast(&pv)); + setup_veff_hcontainer(hR_tmp, ucell, gd, pv, orb_cutoff); + + const double* v_local = pot->get_fixed_v(); // local pp, no Hxc + ModuleGint::cal_gint_vl(v_local, &hR_tmp); + + write_hk_common(hR_tmp, "vlk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + + if (also_hR) + { + gather_and_write("vl", "V^L", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + } + } + + ModuleBase::timer::end("ModuleIO", "write_h_vl"); +} + +void write_h_vh(WriteHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_h_vh"); + ModuleBase::timer::start("ModuleIO", "write_h_vh"); + + const UnitCell& ucell = *params.ucell; + const Grid_Driver& gd = *params.gd; + const Parallel_Orbitals& pv = *params.pv; + const LCAO_Orbitals& orb = *params.orb; + const Charge* chg = params.chg; + const ModulePW::PW_Basis* rho_basis = params.rho_basis; + const K_Vectors& kv = *params.kv; + const int nspin = params.nspin; + const int istep = params.istep; + const bool append = params.append; + const int* iat2iwt = params.iat2iwt; + const int nat = params.nat; + const bool also_hR = params.also_hR; + + const std::vector& orb_cutoff = orb.cutoffs(); + const int nspin_out = (nspin == 2 ? 2 : 1); + + ModuleBase::matrix v_h + = elecstate::H_Hartree_pw::v_hartree(ucell, const_cast(rho_basis), nspin, chg->rho); + + for (int ispin = 0; ispin < nspin_out; ispin++) + { + hamilt::HContainer hR_tmp(const_cast(&pv)); + setup_veff_hcontainer(hR_tmp, ucell, gd, pv, orb_cutoff); + + ModuleGint::cal_gint_vl(&v_h(ispin, 0), &hR_tmp); + + write_hk_common(hR_tmp, "vhk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + + if (also_hR) + { + gather_and_write("vh", "V^H", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + } + } + + ModuleBase::timer::end("ModuleIO", "write_h_vh"); +} + +void write_h_vxc(WriteHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_h_vxc"); + ModuleBase::timer::start("ModuleIO", "write_h_vxc"); + + const UnitCell& ucell = *params.ucell; + const Grid_Driver& gd = *params.gd; + const Parallel_Orbitals& pv = *params.pv; + const LCAO_Orbitals& orb = *params.orb; + const Charge* chg = params.chg; + const int nrxx = params.nrxx; + const K_Vectors& kv = *params.kv; + const int nspin = params.nspin; + const int istep = params.istep; + const bool append = params.append; + const int* iat2iwt = params.iat2iwt; + const int nat = params.nat; + const bool also_hR = params.also_hR; + + const std::vector& orb_cutoff = orb.cutoffs(); + const int nspin_out = (nspin == 2 ? 2 : 1); + + ModuleBase::matrix v_xc; + double etxc, vtxc; + std::tie(etxc, vtxc, v_xc) = XC_Functional::v_xc(nrxx, chg, &ucell); + + for (int ispin = 0; ispin < nspin_out; ispin++) + { + hamilt::HContainer hR_tmp(const_cast(&pv)); + setup_veff_hcontainer(hR_tmp, ucell, gd, pv, orb_cutoff); + + ModuleGint::cal_gint_vl(&v_xc(ispin, 0), &hR_tmp); + + write_hk_common(hR_tmp, "vxck", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + + if (also_hR) + { + gather_and_write("vxc", "V^XC", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + } + } + + ModuleBase::timer::end("ModuleIO", "write_h_vxc"); +} + +#ifdef __EXX +// Build V^EXX(R) for one interface (real or complex Hexx) into real HContainers and write them. +template +static void write_h_exx_impl(const UnitCell& ucell, + const Parallel_Orbitals& pv, + Exx_LRI_Interface* ex, + const K_Vectors& kv, + const int nspin, + const int istep, + const bool append, + const int* iat2iwt, + const int nat, + const bool also_hR) +{ + const auto& Hexxs = ex->get_Hexxs(); // vector over spin of map> + const int nspin_out = (nspin == 2 ? 2 : 1); + const double alpha = GlobalC::exx_info.info_global.hybrid_alpha; + + for (int ispin = 0; ispin < nspin_out; ispin++) + { + hamilt::HContainer hR_tmp(const_cast(&pv)); + // add_HexxR only fills existing matrices, so first allocate the atom-pair structure + // from the exx-form data (native cells, consistent with the nullptr cell_nearest below). + hamilt::reallocate_hcontainer(Hexxs, &hR_tmp); + RI_2D_Comm::add_HexxR(ispin, alpha, Hexxs, pv, PARAM.globalv.npol, hR_tmp, nullptr); + + write_hk_common(hR_tmp, "vexxk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + + if (also_hR) + { + gather_and_write("vexx", "V^EXX", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + } + } +} + +void write_h_exx(WriteHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_h_exx"); + ModuleBase::timer::start("ModuleIO", "write_h_exx"); + + const UnitCell& ucell = *params.ucell; + const Parallel_Orbitals& pv = *params.pv; + const K_Vectors& kv = *params.kv; + const int nspin = params.nspin; + const int istep = params.istep; + const bool append = params.append; + const int* iat2iwt = params.iat2iwt; + const int nat = params.nat; + const bool also_hR = params.also_hR; + + // exd (real Hexx) and exc (complex Hexx) are mutually exclusive; pick by real_number. + if (GlobalC::exx_info.info_ri.real_number) + { + if (params.exd != nullptr) + { + write_h_exx_impl(ucell, pv, params.exd, kv, nspin, istep, append, iat2iwt, nat, also_hR); + } + } + else + { + if (params.exc != nullptr) + { + write_h_exx_impl(ucell, pv, params.exc, kv, nspin, istep, append, iat2iwt, nat, also_hR); + } + } + + ModuleBase::timer::end("ModuleIO", "write_h_exx"); +} +#endif + +} // namespace ModuleIO diff --git a/source/source_io/module_hs/write_H_terms.h b/source/source_io/module_hs/write_H_terms.h new file mode 100644 index 00000000000..05a88c70a63 --- /dev/null +++ b/source/source_io/module_hs/write_H_terms.h @@ -0,0 +1,66 @@ +#ifndef WRITE_H_TERMS_H +#define WRITE_H_TERMS_H + +#include "source_basis/module_nao/two_center_bundle.h" +#include "source_basis/module_pw/pw_basis.h" +#include "source_cell/klist.h" +#include "source_cell/module_neighbor/sltk_grid_driver.h" +#include "source_estate/module_charge/charge.h" +#include "source_estate/module_pot/potential_new.h" +#include "source_lcao/LCAO_domain.h" +#include "source_lcao/module_hcontainer/hcontainer.h" + +#include +#include + +template +class Exx_LRI_Interface; + +namespace ModuleIO +{ + +struct WriteHParams +{ + const UnitCell* ucell = nullptr; + const Grid_Driver* gd = nullptr; + const Parallel_Orbitals* pv = nullptr; + const TwoCenterBundle* two_center_bundle = nullptr; + const LCAO_Orbitals* orb = nullptr; + const K_Vectors* kv = nullptr; + const elecstate::Potential* pot = nullptr; // used by write_h_vl (local pp only) + const Charge* chg = nullptr; // used by write_h_vh, write_h_vxc + const ModulePW::PW_Basis* rho_basis = nullptr; // used by write_h_vh + int nrxx = 0; // used by write_h_vxc + int nspin = 1; + int istep = 0; + bool append = false; + const int* iat2iwt = nullptr; + int nat = 0; + bool also_hR = false; // H(k) is always written; H(R) (CSR) only when this is true +#ifdef __EXX + // gamma (TK==double) exx interfaces used by write_h_exx; exactly one is set depending on + // GlobalC::exx_info.info_ri.real_number (exd: real Hexx, exc: complex Hexx). + Exx_LRI_Interface* exd = nullptr; + Exx_LRI_Interface>* exc = nullptr; +#endif +}; + +void write_h_t(WriteHParams& params); + +void write_h_vnl(WriteHParams& params); + +void write_h_vl(WriteHParams& params); + +void write_h_vh(WriteHParams& params); + +void write_h_vxc(WriteHParams& params); + +#ifdef __EXX +// Build V^EXX(R) into a real HContainer via add_HexxR (from exd/exc->get_Hexxs()) and write it. +// exd (real Hexx) and exc (complex Hexx) are mutually exclusive; picked by info_ri.real_number. +void write_h_exx(WriteHParams& params); +#endif + +} // namespace ModuleIO + +#endif diff --git a/source/source_io/module_output/filename.cpp b/source/source_io/module_output/filename.cpp index 966da0bc8fd..6b95591b2ef 100644 --- a/source/source_io/module_output/filename.cpp +++ b/source/source_io/module_output/filename.cpp @@ -23,7 +23,7 @@ std::string filename_output( // {k(optional)}{k-point index}{g(optional)}{geometry index1}{_basis(nao|pw)} // + {".txt"/".dat"}" - std::set valid_properties = {"wf", "chg", "hk", "sk", "tk", "vxc"}; + std::set valid_properties = { "wf", "chg", "hk", "sk", "tk", "vxc", "vxck", "vlk", "vnlk", "vhk", "vexxk" }; if (valid_properties.find(property) == valid_properties.end()) { ModuleBase::WARNING_QUIT("ModuleIO::filename_output", "unknown property in filename function"); diff --git a/source/source_io/module_parameter/input_parameter.h b/source/source_io/module_parameter/input_parameter.h index acbfeb62bf4..5a02a730075 100644 --- a/source/source_io/module_parameter/input_parameter.h +++ b/source/source_io/module_parameter/input_parameter.h @@ -394,7 +394,19 @@ struct Input_para std::vector out_mat_tk = {0, 8}; ///< output T(k) matrix in local basis. std::vector out_mat_l = {0, 8}; ///< output L matrix in local basis. std::vector out_mat_hs2 = {0, 8}; ///< output H(R) and S(R) matrix with precision + std::vector out_mat_h_t = {0, 8}; ///< output kinetic energy T(R) matrix + std::vector out_mat_h_vnl = {0, 8}; ///< output nonlocal pseudopotential Vnl(R) matrix + std::vector out_mat_h_vl = {0, 8}; ///< output local pseudopotential Vl(R) matrix + std::vector out_mat_h_vh = {0, 8}; ///< output Hartree Vh(R) matrix + std::vector out_mat_h_vxc = {0, 8}; ///< output XC Vxc(R) matrix + std::vector out_mat_h_exx = {0, 8}; ///< output exact-exchange Vexx(R) matrix std::vector out_mat_dh = {0, 8}; ///< output dH/dR matrices with precision + std::vector out_mat_dh_t = { 0, 8 }; ///< output kinetic dH/dR (dT/dR) matrices + std::vector out_mat_dh_vl = { 0, 8 }; ///< output local pseudopotential dH/dR (dV^L/dR) matrices + std::vector out_mat_dh_vnl = { 0, 8 }; ///< output nonlocal pseudopotential dH/dR (dV^NL/dR) matrices + std::vector out_mat_dh_vh = { 0, 8 }; ///< output Hartree dH/dR (dV^H/dR) matrices + std::vector out_mat_dh_vxc = { 0, 8 }; ///< output XC dH/dR (dV^XC/dR) matrices + std::vector out_mat_dh_exx = { 0, 8 }; ///< output exact-exchange dH/dR (dV^EXX/dR) matrices std::vector out_mat_ds = {0, 8}; ///< output dS/dR matrices with precision bool out_mat_xc = false; ///< output exchange-correlation matrix in ///< KS-orbital representation. diff --git a/source/source_io/module_parameter/read_input_item_output.cpp b/source/source_io/module_parameter/read_input_item_output.cpp index 8bc0c895499..217fb9c22cb 100644 --- a/source/source_io/module_parameter/read_input_item_output.cpp +++ b/source/source_io/module_parameter/read_input_item_output.cpp @@ -593,7 +593,7 @@ Also controled by out_freq_ion and out_app_flag. } }; item.check_value = [](const Input_Item& item, const Parameter& para) { - if ((para.inp.out_mat_r[0] || para.inp.out_mat_hs2[0] || para.inp.out_mat_t[0] || para.inp.out_mat_dh[0] + if ((para.inp.out_mat_r[0] || para.inp.out_mat_hs2[0] || para.inp.out_mat_t[0] || para.inp.dm_to_rho) && para.sys.gamma_only_local) { @@ -639,6 +639,7 @@ Also controled by out_freq_ion and out_app_flag. item.category = "Output information"; item.type = "Integer"; item.description = "Whether to print files containing the derivatives of the Hamiltonian matrix. The format will be the same as the Hamiltonian matrix and overlap matrix as mentioned in out_mat_hs2. The name of the files will be dhrxs1_nao.csr, dhrys1_nao.csr, dhrzs1_nao.csr and so on. Also controled by out_freq_ion and out_app_flag." + "\n\nFormat: [precision] [iat1 iat2 ...]. The first value (0/1) enables/disables output. The second optional value sets the output precision (default: 8). Starting from the third value, 1-based atom indices can be listed to restrict output to derivatives with respect to those specific atoms only; if no atom indices are given, all atoms are written." "\n\n[NOTE] In the 3.10-LTS version, the file name is data-dHRx-sparse_SPIN0.csr and so on."; item.default_value = "0 8"; item.unit = "Ry/Bohr"; @@ -653,6 +654,11 @@ Also controled by out_freq_ion and out_app_flag. catch (const std::invalid_argument& e) { ModuleBase::WARNING("Input", "out_mat_dh precision must be an integer, using default 8"); } + for (size_t i = 2; i < count; ++i) + try { para.input.out_mat_dh.push_back(std::stoi(item.str_values[i]) - 1); } + catch (const std::invalid_argument&) { + ModuleBase::WARNING("Input", "out_mat_dh atom index must be an integer, skipping"); + } } catch (const std::invalid_argument& e) { ModuleBase::WARNING("Input", "out_mat_dh enable flag must be 0/1, using default 0"); @@ -664,7 +670,367 @@ Also controled by out_freq_ion and out_app_flag. ModuleBase::WARNING_QUIT("ReadInput", "out_mat_dh is not available for nspin = 4"); } }; - sync_intvec(input.out_mat_dh, 2, 0); + sync_intvec(input.out_mat_dh, para.input.out_mat_dh.size(), 0); + this->add_item(item); + } + { + Input_Item item("out_mat_dh_t"); + item.annotation = "output kinetic energy dH/dR (dT/dR) matrices"; + item.category = "Output information"; + item.type = "Integer"; + item.description = "Whether to print files containing the derivatives of the kinetic energy matrix dT/dR." + "\n\nSee out_mat_dh for format details (enable, precision, atom indices)."; + item.default_value = "0 8"; + item.unit = "Ry/Bohr"; + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + try { + para.input.out_mat_dh_t[0] = assume_as_boolean(item.str_values[0]); + para.input.out_mat_dh_t[1] = 8; + if (count >= 2) try { para.input.out_mat_dh_t[1] = std::stoi(item.str_values[1]); } + catch (const std::invalid_argument&) { + ModuleBase::WARNING("Input", "out_mat_dh_t precision must be an integer, using default 8"); + } + for (size_t i = 2; i < count; ++i) + try { para.input.out_mat_dh_t.push_back(std::stoi(item.str_values[i]) - 1); } + catch (const std::invalid_argument&) { + ModuleBase::WARNING("Input", "out_mat_dh_t atom index must be an integer, skipping"); + } + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_dh_t enable flag must be 0/1, using default 0"); + } + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.out_mat_dh_t[0] && para.input.nspin == 4) + ModuleBase::WARNING_QUIT("ReadInput", "out_mat_dh_t is not available for nspin = 4"); + }; + sync_intvec(input.out_mat_dh_t, para.input.out_mat_dh_t.size(), 0); + this->add_item(item); + } + { + Input_Item item("out_mat_dh_vl"); + item.annotation = "output local pseudopotential dH/dR (dV^L/dR) matrices"; + item.category = "Output information"; + item.type = "Integer"; + item.description = "Whether to print files containing the derivatives of the local pseudopotential matrix dV^L/dR." + "\n\nSee out_mat_dh for format details."; + item.default_value = "0 8"; + item.unit = "Ry/Bohr"; + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + try { + para.input.out_mat_dh_vl[0] = assume_as_boolean(item.str_values[0]); + para.input.out_mat_dh_vl[1] = 8; + if (count >= 2) try { para.input.out_mat_dh_vl[1] = std::stoi(item.str_values[1]); } + catch (const std::invalid_argument&) { + ModuleBase::WARNING("Input", "out_mat_dh_vl precision must be an integer, using default 8"); + } + for (size_t i = 2; i < count; ++i) + try { para.input.out_mat_dh_vl.push_back(std::stoi(item.str_values[i]) - 1); } + catch (const std::invalid_argument&) { + ModuleBase::WARNING("Input", "out_mat_dh_vl atom index must be an integer, skipping"); + } + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_dh_vl enable flag must be 0/1, using default 0"); + } + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.out_mat_dh_vl[0] && para.input.nspin == 4) + ModuleBase::WARNING_QUIT("ReadInput", "out_mat_dh_vl is not available for nspin = 4"); + }; + sync_intvec(input.out_mat_dh_vl, para.input.out_mat_dh_vl.size(), 0); + this->add_item(item); + } + { + Input_Item item("out_mat_dh_vnl"); + item.annotation = "output nonlocal pseudopotential dH/dR (dV^NL/dR) matrices"; + item.category = "Output information"; + item.type = "Integer"; + item.description = "Whether to print files containing the derivatives of the nonlocal pseudopotential matrix dV^NL/dR." + "\n\nSee out_mat_dh for format details."; + item.default_value = "0 8"; + item.unit = "Ry/Bohr"; + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + try { + para.input.out_mat_dh_vnl[0] = assume_as_boolean(item.str_values[0]); + para.input.out_mat_dh_vnl[1] = 8; + if (count >= 2) try { para.input.out_mat_dh_vnl[1] = std::stoi(item.str_values[1]); } + catch (const std::invalid_argument&) { + ModuleBase::WARNING("Input", "out_mat_dh_vnl precision must be an integer, using default 8"); + } + for (size_t i = 2; i < count; ++i) + try { para.input.out_mat_dh_vnl.push_back(std::stoi(item.str_values[i]) - 1); } + catch (const std::invalid_argument&) { + ModuleBase::WARNING("Input", "out_mat_dh_vnl atom index must be an integer, skipping"); + } + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_dh_vnl enable flag must be 0/1, using default 0"); + } + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.out_mat_dh_vnl[0] && para.input.nspin == 4) + ModuleBase::WARNING_QUIT("ReadInput", "out_mat_dh_vnl is not available for nspin = 4"); + }; + sync_intvec(input.out_mat_dh_vnl, para.input.out_mat_dh_vnl.size(), 0); + this->add_item(item); + } + { + Input_Item item("out_mat_dh_vh"); + item.annotation = "output Hartree dH/dR (dV^H/dR) matrices"; + item.category = "Output information"; + item.type = "Integer"; + item.description = "Whether to print files containing the derivatives of the Hartree matrix dV^H/dR." + "\n\nSee out_mat_dh for format details."; + item.default_value = "0 8"; + item.unit = "Ry/Bohr"; + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + try { + para.input.out_mat_dh_vh[0] = assume_as_boolean(item.str_values[0]); + para.input.out_mat_dh_vh[1] = 8; + if (count >= 2) try { para.input.out_mat_dh_vh[1] = std::stoi(item.str_values[1]); } + catch (const std::invalid_argument&) { + ModuleBase::WARNING("Input", "out_mat_dh_vh precision must be an integer, using default 8"); + } + for (size_t i = 2; i < count; ++i) + try { para.input.out_mat_dh_vh.push_back(std::stoi(item.str_values[i]) - 1); } + catch (const std::invalid_argument&) { + ModuleBase::WARNING("Input", "out_mat_dh_vh atom index must be an integer, skipping"); + } + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_dh_vh enable flag must be 0/1, using default 0"); + } + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.out_mat_dh_vh[0] && para.input.nspin == 4) + ModuleBase::WARNING_QUIT("ReadInput", "out_mat_dh_vh is not available for nspin = 4"); + }; + sync_intvec(input.out_mat_dh_vh, para.input.out_mat_dh_vh.size(), 0); + this->add_item(item); + } + { + Input_Item item("out_mat_dh_vxc"); + item.annotation = "output exchange-correlation dH/dR (dV^XC/dR) matrices"; + item.category = "Output information"; + item.type = "Integer"; + item.description = "Whether to print files containing the derivatives of the XC matrix dV^XC/dR." + "\n\nSee out_mat_dh for format details."; + item.default_value = "0 8"; + item.unit = "Ry/Bohr"; + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + try { + para.input.out_mat_dh_vxc[0] = assume_as_boolean(item.str_values[0]); + para.input.out_mat_dh_vxc[1] = 8; + if (count >= 2) try { para.input.out_mat_dh_vxc[1] = std::stoi(item.str_values[1]); } + catch (const std::invalid_argument&) { + ModuleBase::WARNING("Input", "out_mat_dh_vxc precision must be an integer, using default 8"); + } + for (size_t i = 2; i < count; ++i) + try { para.input.out_mat_dh_vxc.push_back(std::stoi(item.str_values[i]) - 1); } + catch (const std::invalid_argument&) { + ModuleBase::WARNING("Input", "out_mat_dh_vxc atom index must be an integer, skipping"); + } + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_dh_vxc enable flag must be 0/1, using default 0"); + } + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.out_mat_dh_vxc[0] && para.input.nspin == 4) + ModuleBase::WARNING_QUIT("ReadInput", "out_mat_dh_vxc is not available for nspin = 4"); + }; + sync_intvec(input.out_mat_dh_vxc, para.input.out_mat_dh_vxc.size(), 0); + this->add_item(item); + } + { + Input_Item item("out_mat_dh_exx"); + item.annotation = "output exact-exchange dH/dR (dV^EXX/dR) matrices"; + item.category = "Output information"; + item.type = "Integer"; + item.description = "Whether to print files containing the derivatives of the exact-exchange matrix dV^EXX/dR." + "\n\nSee out_mat_dh for format details."; + item.default_value = "0 8"; + item.unit = "Ry/Bohr"; + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + try { + para.input.out_mat_dh_exx[0] = assume_as_boolean(item.str_values[0]); + para.input.out_mat_dh_exx[1] = 8; + if (count >= 2) try { para.input.out_mat_dh_exx[1] = std::stoi(item.str_values[1]); } + catch (const std::invalid_argument&) { + ModuleBase::WARNING("Input", "out_mat_dh_exx precision must be an integer, using default 8"); + } + for (size_t i = 2; i < count; ++i) + try { para.input.out_mat_dh_exx.push_back(std::stoi(item.str_values[i]) - 1); } + catch (const std::invalid_argument&) { + ModuleBase::WARNING("Input", "out_mat_dh_exx atom index must be an integer, skipping"); + } + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_dh_exx enable flag must be 0/1, using default 0"); + } + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.out_mat_dh_exx[0] && para.input.nspin == 4) + ModuleBase::WARNING_QUIT("ReadInput", "out_mat_dh_exx is not available for nspin = 4"); + }; + sync_intvec(input.out_mat_dh_exx, para.input.out_mat_dh_exx.size(), 0); + this->add_item(item); + } + { + Input_Item item("out_mat_h_t"); + item.annotation = "output kinetic energy T(R) matrix"; + item.category = "Output information"; + item.type = "Integer"; + item.description = "Whether to print files containing the kinetic energy matrix T(R) in CSR format." + "\n\nSee out_mat_hs2 for format details."; + item.default_value = "0 8"; + item.unit = "Ry"; + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + try { + para.input.out_mat_h_t[0] = assume_as_boolean(item.str_values[0]); + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_h_t enable flag must be 0/1, using default 0"); + } + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.out_mat_h_t[0] && para.input.nspin == 4) + ModuleBase::WARNING_QUIT("ReadInput", "out_mat_h_t is not available for nspin = 4"); + }; + sync_intvec(input.out_mat_h_t, 2, 0); + this->add_item(item); + } + { + Input_Item item("out_mat_h_vnl"); + item.annotation = "output nonlocal pseudopotential Vnl(R) matrix"; + item.category = "Output information"; + item.type = "Integer"; + item.description = "Whether to print files containing the nonlocal pseudopotential matrix Vnl(R) in CSR format." + "\n\nSee out_mat_hs2 for format details."; + item.default_value = "0 8"; + item.unit = "Ry"; + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + try { + para.input.out_mat_h_vnl[0] = assume_as_boolean(item.str_values[0]); + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_h_vnl enable flag must be 0/1, using default 0"); + } + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.out_mat_h_vnl[0] && para.input.nspin == 4) + ModuleBase::WARNING_QUIT("ReadInput", "out_mat_h_vnl is not available for nspin = 4"); + }; + sync_intvec(input.out_mat_h_vnl, 2, 0); + this->add_item(item); + } + { + Input_Item item("out_mat_h_vl"); + item.annotation = "output local pseudopotential Vl(R) matrix"; + item.category = "Output information"; + item.type = "Integer"; + item.description = "Whether to print files containing the local pseudopotential matrix Vl(R) in CSR format." + "\n\nSee out_mat_hs2 for format details."; + item.default_value = "0 8"; + item.unit = "Ry"; + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + try { + para.input.out_mat_h_vl[0] = assume_as_boolean(item.str_values[0]); + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_h_vl enable flag must be 0/1, using default 0"); + } + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.out_mat_h_vl[0] && para.input.nspin == 4) + ModuleBase::WARNING_QUIT("ReadInput", "out_mat_h_vl is not available for nspin = 4"); + }; + sync_intvec(input.out_mat_h_vl, 2, 0); + this->add_item(item); + } + { + Input_Item item("out_mat_h_vh"); + item.annotation = "output Hartree Vh(R) matrix"; + item.category = "Output information"; + item.type = "Integer"; + item.description = "Whether to print files containing the Hartree matrix Vh(R) in CSR format." + "\n\nSee out_mat_hs2 for format details."; + item.default_value = "0 8"; + item.unit = "Ry"; + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + try { + para.input.out_mat_h_vh[0] = assume_as_boolean(item.str_values[0]); + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_h_vh enable flag must be 0/1, using default 0"); + } + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.out_mat_h_vh[0] && para.input.nspin == 4) + ModuleBase::WARNING_QUIT("ReadInput", "out_mat_h_vh is not available for nspin = 4"); + }; + sync_intvec(input.out_mat_h_vh, 2, 0); + this->add_item(item); + } + { + Input_Item item("out_mat_h_vxc"); + item.annotation = "output exchange-correlation Vxc(R) matrix"; + item.category = "Output information"; + item.type = "Integer"; + item.description = "Whether to print files containing the XC matrix Vxc(R) in CSR format." + "\n\nSee out_mat_hs2 for format details."; + item.default_value = "0 8"; + item.unit = "Ry"; + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + try { + para.input.out_mat_h_vxc[0] = assume_as_boolean(item.str_values[0]); + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_h_vxc enable flag must be 0/1, using default 0"); + } + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.out_mat_h_vxc[0] && para.input.nspin == 4) + ModuleBase::WARNING_QUIT("ReadInput", "out_mat_h_vxc is not available for nspin = 4"); + }; + sync_intvec(input.out_mat_h_vxc, 2, 0); + this->add_item(item); + } + { + Input_Item item("out_mat_h_exx"); + item.annotation = "output exact-exchange Vexx(R) matrix"; + item.category = "Output information"; + item.type = "Integer"; + item.description = "Whether to print files containing the exact-exchange matrix Vexx(R) in CSR format." + "\n\nSee out_mat_hs2 for format details."; + item.default_value = "0 8"; + item.unit = "Ry"; + item.read_value = [](const Input_Item& item, Parameter& para) { + const size_t count = item.get_size(); + try { + para.input.out_mat_h_exx[0] = assume_as_boolean(item.str_values[0]); + } + catch (const std::invalid_argument& e) { + ModuleBase::WARNING("Input", "out_mat_h_exx enable flag must be 0/1, using default 0"); + } + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + if (para.input.out_mat_h_exx[0] && para.input.nspin == 4) + ModuleBase::WARNING_QUIT("ReadInput", "out_mat_h_exx is not available for nspin = 4"); + }; + sync_intvec(input.out_mat_h_exx, 2, 0); this->add_item(item); } { diff --git a/source/source_lcao/hamilt_lcao.cpp b/source/source_lcao/hamilt_lcao.cpp index 97858c12d15..ed411a5f97c 100644 --- a/source/source_lcao/hamilt_lcao.cpp +++ b/source/source_lcao/hamilt_lcao.cpp @@ -412,21 +412,6 @@ HamiltLCAO::HamiltLCAO(const UnitCell& ucell, #ifdef __EXX if (GlobalC::exx_info.info_global.cal_exx) { - int* exx_two_level_step = nullptr; - std::vector>>>* Hexxd = nullptr; - std::vector>>>>* Hexxc = nullptr; - - if(GlobalC::exx_info.info_ri.real_number) - { - exx_two_level_step = &exx_nao.exd->two_level_step; - Hexxd = &exx_nao.exd->get_Hexxs(); - } - else - { - exx_two_level_step = &exx_nao.exc->two_level_step; - Hexxc = &exx_nao.exc->get_Hexxs(); - } - // Peize Lin add 2016-12-03 // set xc type before the first cal of xc in pelec->init_scf // and calculate Cs, Vs @@ -437,13 +422,12 @@ HamiltLCAO::HamiltLCAO(const UnitCell& ucell, this->hR, ucell, *this->kv, - Hexxd, - Hexxc, + exx_nao.exd.get(), + exx_nao.exc.get(), Add_Hexx_Type::k, istep, - exx_two_level_step, !GlobalC::restart.info_load.restart_exx - && GlobalC::restart.info_load.load_H); + && GlobalC::restart.info_load.load_H); } else { @@ -451,13 +435,12 @@ HamiltLCAO::HamiltLCAO(const UnitCell& ucell, this->hR, ucell, *kv, - Hexxd, - Hexxc, + exx_nao.exd.get(), + exx_nao.exc.get(), Add_Hexx_Type::R, istep, - exx_two_level_step, !GlobalC::restart.info_load.restart_exx - && GlobalC::restart.info_load.load_H); + && GlobalC::restart.info_load.load_H); } this->getOperator()->add(exx); } diff --git a/source/source_lcao/module_gint/CMakeLists.txt b/source/source_lcao/module_gint/CMakeLists.txt index d9a19c2b022..1955376d727 100644 --- a/source/source_lcao/module_gint/CMakeLists.txt +++ b/source/source_lcao/module_gint/CMakeLists.txt @@ -13,6 +13,7 @@ list(APPEND objects gint_vl_nspin4.cpp gint_vl_metagga_nspin4.cpp gint_rho.cpp + gint_drho.cpp gint_tau.cpp gint_fvl.cpp gint_fvl_meta.cpp diff --git a/source/source_lcao/module_gint/gint_drho.cpp b/source/source_lcao/module_gint/gint_drho.cpp new file mode 100644 index 00000000000..98e4b5f8859 --- /dev/null +++ b/source/source_lcao/module_gint/gint_drho.cpp @@ -0,0 +1,77 @@ +#include "source_base/global_function.h" +#include "gint_drho.h" +#include "gint_common.h" +#include "phi_operator.h" + +namespace ModuleGint +{ + +void Gint_drho::cal_gint() +{ + ModuleBase::TITLE("Gint", "cal_gint_drho"); + ModuleBase::timer::start("Gint", "cal_gint_drho"); + std::vector> dm_gint_vec = init_dm_gint_(); + dm_2d_to_gint(*gint_info_, dm_vec_, dm_gint_vec); + cal_drho_(dm_gint_vec); + ModuleBase::timer::end("Gint", "cal_gint_drho"); +} + +std::vector> Gint_drho::init_dm_gint_() const +{ + std::vector> dm_gint_vec(nspin_); + for (int is = 0; is < nspin_; is++) + { + dm_gint_vec[is] = gint_info_->get_hr(); + } + return dm_gint_vec; +} + +void Gint_drho::cal_drho_(const std::vector>& dm_gint_vec) const +{ +#pragma omp parallel + { + PhiOperator phi_op; + std::vector phi; + std::vector dphi_x; + std::vector dphi_y; + std::vector dphi_z; + std::vector phi_dm; +#pragma omp for schedule(dynamic) + for (int i = 0; i < gint_info_->get_bgrids_num(); i++) + { + const auto& biggrid = gint_info_->get_biggrids()[i]; + if (biggrid->get_atoms().empty()) + { + continue; + } + phi_op.set_bgrid(biggrid); + const int phi_len = phi_op.get_rows() * phi_op.get_cols(); + phi.resize(phi_len); + dphi_x.resize(phi_len); + dphi_y.resize(phi_len); + dphi_z.resize(phi_len); + phi_dm.resize(phi_len); + // phi and its gradient, exactly as in Gint_dvlocal + phi_op.set_phi_dphi(phi.data(), dphi_x.data(), dphi_y.data(), dphi_z.data()); + for (int is = 0; is < nspin_; is++) + { + // contract the gradient orbital (the FIRST/row index of D) with D, then + // dot with the value orbital phi (the second/column index): + // phi_dm[ir,L] = sum_K dphi^d[ir,K] D[K,L] + // drho^d[ir] += sum_L phi[ir,L] phi_dm[ir,L] + // = sum_{K,L} D[K,L] dphi^d_K(ir) phi_L(ir) + // is_symm must stay false here: the symmetric phi_mul_dm fast path folds + // the contraction assuming phi_dot_phi reuses the SAME operand, which is + // not the case once the value orbital (phi) differs from the gradient one. + phi_op.phi_mul_dm(dphi_x.data(), dm_gint_vec[is], false, phi_dm.data()); + phi_op.phi_dot_phi(phi.data(), phi_dm.data(), drho_x_[is]); + phi_op.phi_mul_dm(dphi_y.data(), dm_gint_vec[is], false, phi_dm.data()); + phi_op.phi_dot_phi(phi.data(), phi_dm.data(), drho_y_[is]); + phi_op.phi_mul_dm(dphi_z.data(), dm_gint_vec[is], false, phi_dm.data()); + phi_op.phi_dot_phi(phi.data(), phi_dm.data(), drho_z_[is]); + } + } + } +} + +} diff --git a/source/source_lcao/module_gint/gint_drho.h b/source/source_lcao/module_gint/gint_drho.h new file mode 100644 index 00000000000..e5847de338d --- /dev/null +++ b/source/source_lcao/module_gint/gint_drho.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include "source_lcao/module_hcontainer/hcontainer.h" +#include "gint.h" +#include "gint_info.h" + +namespace ModuleGint +{ + +// Gint_drho integrates, on the real-space grid, the gradient density +// [grad rho]^d(r) = sum_{Kk,Ll} D_{Kk,Ll} (grad^d phi_Kk)(r) phi_Ll(r), d = x,y,z +// i.e. the derivative is taken on the FIRST (row) orbital of the density matrix. +// Pass a symmetrized matrix (D + D^T) to obtain +// [grad rho^S]^d(r) = sum_{Kk,Ll} D_{Kk,Ll} [grad phi_Kk phi_Ll + phi_Kk grad phi_Ll]. +// +// The grid loop / dm-to-gint preparation mirror Gint_rho; the orbital gradient +// (set_phi_dphi) is obtained exactly as in Gint_dvlocal. Everything is fp64 because +// set_phi_dphi only provides double-precision gradients. +// +// The three output buffers are ACCUMULATED into (phi_dot_phi uses +=), so the caller +// must zero-initialize drho_{x,y,z}[is] (each of length nrxx) before calling cal_gint(). +class Gint_drho : public Gint +{ + public: + Gint_drho( + const std::vector*>& dm_vec, + const int nspin, + double** drho_x, + double** drho_y, + double** drho_z) + : dm_vec_(dm_vec), nspin_(nspin), + drho_x_(drho_x), drho_y_(drho_y), drho_z_(drho_z) {} + + void cal_gint(); + + private: + std::vector> init_dm_gint_() const; + + void cal_drho_(const std::vector>& dm_gint_vec) const; + + // input + const std::vector*> dm_vec_; + const int nspin_; + + // output: [grad rho]_{x,y,z}[is](ir), accumulated + double** drho_x_ = nullptr; + double** drho_y_ = nullptr; + double** drho_z_ = nullptr; +}; + +} diff --git a/source/source_lcao/module_gint/gint_dvlocal.cpp b/source/source_lcao/module_gint/gint_dvlocal.cpp index dccad124553..fc32db32539 100644 --- a/source/source_lcao/module_gint/gint_dvlocal.cpp +++ b/source/source_lcao/module_gint/gint_dvlocal.cpp @@ -49,9 +49,11 @@ void Gint_dvlocal::cal_hr_gint_() dphi_z.resize(phi_len); phi_op.set_phi_dphi(phi.data(), dphi_x.data(), dphi_y.data(), dphi_z.data()); phi_op.phi_mul_vldr3(vr_eff_, dr3_, phi.data(), phi_vldr3.data()); - phi_op.phi_mul_phi(phi_vldr3.data(), dphi_x.data(), pvdpRx, PhiOperator::TriPart::Upper); - phi_op.phi_mul_phi(phi_vldr3.data(), dphi_y.data(), pvdpRy, PhiOperator::TriPart::Upper); - phi_op.phi_mul_phi(phi_vldr3.data(), dphi_z.data(), pvdpRz, PhiOperator::TriPart::Upper); + const PhiOperator::TriPart tri + = full_triangle_ ? PhiOperator::TriPart::Full : PhiOperator::TriPart::Upper; + phi_op.phi_mul_phi(phi_vldr3.data(), dphi_x.data(), pvdpRx, tri); + phi_op.phi_mul_phi(phi_vldr3.data(), dphi_y.data(), pvdpRy, tri); + phi_op.phi_mul_phi(phi_vldr3.data(), dphi_z.data(), pvdpRz, tri); } } } diff --git a/source/source_lcao/module_gint/gint_dvlocal.h b/source/source_lcao/module_gint/gint_dvlocal.h index 613976e678f..2adbac08afa 100644 --- a/source/source_lcao/module_gint/gint_dvlocal.h +++ b/source/source_lcao/module_gint/gint_dvlocal.h @@ -16,10 +16,12 @@ class Gint_dvlocal : public Gint Gint_dvlocal( const double* vr_eff, const int nspin, - const int npol) - : vr_eff_(vr_eff), nspin_(nspin), npol_(npol), dr3_(gint_info_->get_mgrid_volume()) + const int npol, + const bool full_triangle = false) + : vr_eff_(vr_eff), nspin_(nspin), npol_(npol), full_triangle_(full_triangle), + dr3_(gint_info_->get_mgrid_volume()) { - assert(nspin_ == 2); // currently only npin == 2 is supported + assert(nspin_ == 1 || nspin_ == 2); // currently only nspin == 1 or 2 is supported } void cal_dvlocal(); @@ -33,6 +35,10 @@ class Gint_dvlocal : public Gint const UnitCell& ucell, const Grid_Driver& gdriver, LCAO_HS_Arrays& hs_arrays); + + HContainer* get_pvdpRx() { return &pvdpRx; } + HContainer* get_pvdpRy() { return &pvdpRy; } + HContainer* get_pvdpRz() { return &pvdpRz; } private: void init_hr_gint_(); @@ -54,6 +60,8 @@ class Gint_dvlocal : public Gint const double* vr_eff_ = nullptr; int nspin_; int npol_; + // if true, fill both triangles of pvdpR (all directed atom pairs); default upper-only + bool full_triangle_ = false; // intermediate variables double dr3_; diff --git a/source/source_lcao/module_gint/gint_interface.cpp b/source/source_lcao/module_gint/gint_interface.cpp index f8b896fe255..21a97e6360f 100644 --- a/source/source_lcao/module_gint/gint_interface.cpp +++ b/source/source_lcao/module_gint/gint_interface.cpp @@ -8,6 +8,7 @@ #include "gint_fvl.h" #include "gint_fvl_meta.h" #include "gint_rho.h" +#include "gint_drho.h" #include "gint_tau.h" #ifdef __CUDA @@ -115,6 +116,18 @@ void cal_gint_rho( } } +void cal_gint_drho( + const std::vector*>& dm_vec, + const int nspin, + double** drho_x, + double** drho_y, + double** drho_z) +{ + // CPU/fp64 only: set_phi_dphi provides double-precision gradients (no GPU/fp32 path). + Gint_drho gint_drho(dm_vec, nspin, drho_x, drho_y, drho_z); + gint_drho.cal_gint(); +} + void cal_gint_tau( const std::vector*>& dm_vec, const int nspin, diff --git a/source/source_lcao/module_gint/gint_interface.h b/source/source_lcao/module_gint/gint_interface.h index cb9112cf4f4..591d9859c59 100644 --- a/source/source_lcao/module_gint/gint_interface.h +++ b/source/source_lcao/module_gint/gint_interface.h @@ -31,7 +31,17 @@ void cal_gint_rho( double **rho, bool is_dm_symm = true); -void cal_gint_tau( +// gradient density on the grid: +// [grad rho]_{x,y,z}[is](ir) += sum_{Kk,Ll} D[Kk,Ll] (grad phi_Kk) phi_Ll +// outputs are accumulated, so zero-initialize drho_{x,y,z}[is] (length nrxx) first. +void cal_gint_drho( + const std::vector*>& dm_vec, + const int nspin, + double** drho_x, + double** drho_y, + double** drho_z); + +void cal_gint_tau( const std::vector*>& dm_vec, const int nspin, double**tau); diff --git a/source/source_lcao/module_hcontainer/hcontainer.cpp b/source/source_lcao/module_hcontainer/hcontainer.cpp index e1d1b909912..e1d408e599e 100644 --- a/source/source_lcao/module_hcontainer/hcontainer.cpp +++ b/source/source_lcao/module_hcontainer/hcontainer.cpp @@ -438,6 +438,81 @@ void HContainer::add(const HContainer& other) } } +// value-add over shared sparsity only: this(i,j,R) += factor * other(i,j,R) +template +void HContainer::add_value_intersection(const HContainer& other, T factor) +{ + for (int iap = 0; iap < this->size_atom_pairs(); ++iap) + { + AtomPair& ap = this->get_atom_pair(iap); + const int i = ap.get_atom_i(); + const int j = ap.get_atom_j(); + if (other.find_pair(i, j) == nullptr) + { + continue; + } + for (int ir = 0; ir < ap.get_R_size(); ++ir) + { + const ModuleBase::Vector3 R = ap.get_R_index(ir); + BaseMatrix* dst = this->find_matrix(i, j, R); + const BaseMatrix* src = other.find_matrix(i, j, R); + if (dst == nullptr || src == nullptr) + { + continue; + } + T* pdst = dst->get_pointer(); + const T* psrc = src->get_pointer(); + if (pdst == nullptr || psrc == nullptr) + { + continue; + } + const int n = dst->get_row_size() * dst->get_col_size(); + for (int k = 0; k < n; ++k) + { + pdst[k] += factor * psrc[k]; + } + } + } +} + +// value-add over union sparsity: build a fresh HContainer covering the union sparsity, +// fill it as result = 1*(*this) + factor*other, then swap it into *this. +// This is necessary because HContainer uses a single contiguous buffer for all R-blocks; +// adding new (i,j,R) entries requires reallocating that buffer. +template +void HContainer::add_value_union(const HContainer& other, T factor) +{ + // 1) Start from a zeroed copy of *this's sparsity (fresh contiguous buffer). + HContainer result(*this, nullptr); + // 2) Extend result's sparsity with any (i,j,R) present in other but not yet in result. + for (int iap = 0; iap < other.size_atom_pairs(); ++iap) + { + AtomPair tmp = other.get_atom_pair(iap); + result.insert_pair(tmp); + } + // 3) Rebuild result's contiguous buffer to cover the full union sparsity (zeroed). + result.allocate(nullptr, true); + // 4) Fill: result = 1*(*this) + factor*other. + result.add_value_intersection(*this, T(1)); + result.add_value_intersection(other, factor); + // 5) Release *this's old buffer and take ownership of result's resources. + if (this->allocated) + { + if (this->allocated_size > 0) + ModuleBase::Memory::record("HContainer", -(long long)this->allocated_size, true); + delete[] this->wrapper_pointer; + } + this->wrapper_pointer = result.wrapper_pointer; + this->allocated = result.allocated; + this->allocated_size = result.allocated_size; + this->atom_pairs = std::move(result.atom_pairs); + this->sparse_ap = std::move(result.sparse_ap); + this->sparse_ap_index = std::move(result.sparse_ap_index); + result.wrapper_pointer = nullptr; + result.allocated = false; + result.allocated_size = 0; +} + template bool HContainer::fix_R(int rx_in, int ry_in, int rz_in) const { diff --git a/source/source_lcao/module_hcontainer/hcontainer.h b/source/source_lcao/module_hcontainer/hcontainer.h index 74e640b83de..a63851aefec 100644 --- a/source/source_lcao/module_hcontainer/hcontainer.h +++ b/source/source_lcao/module_hcontainer/hcontainer.h @@ -284,6 +284,24 @@ class HContainer */ void add(const HContainer& other); + /** + * @brief value-add over the SHARED sparsity only: for every (atom_i, atom_j, R) + * BaseMatrix present in BOTH containers, do + * this(i,j,R) += factor * other(i,j,R). + * Atom-pairs/R-cells that exist only in `other` are ignored (the sparsity of `this` + * is left unchanged). `factor` defaults to 1 (plain add); pass -1 to subtract. + */ + void add_value_intersection(const HContainer& other, T factor = T(1)); + + /** + * @brief value-add over the UNION sparsity: for every (atom_i, atom_j, R) BaseMatrix + * of `other`, ensure it also exists in `this` (insert a zero-initialized shape if + * missing) and then do this(i,j,R) += factor * other(i,j,R). The bare add() only + * unions/copies pair structure; this additionally accumulates values with a scaling + * factor, so it can sum terms with different sparsity (e.g. dH = dT + dVnl + ...). + */ + void add_value_union(const HContainer& other, T factor = T(1)); + // save atom-pair pointers into this->tmp_atom_pairs for selected R index /** * @brief save atom-pair pointers into this->tmp_atom_pairs for selected R index diff --git a/source/source_lcao/module_hcontainer/test/CMakeLists.txt b/source/source_lcao/module_hcontainer/test/CMakeLists.txt index 35d7eb5a7d3..9f79d4d8a6b 100644 --- a/source/source_lcao/module_hcontainer/test/CMakeLists.txt +++ b/source/source_lcao/module_hcontainer/test/CMakeLists.txt @@ -57,5 +57,11 @@ AddTest( install(DIRECTORY support DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +AddTest( + TARGET MODULE_LCAO_hcontainer_add_value_test + LIBS parameter ${math_libs} psi base device + SOURCES test_add_value.cpp ../base_matrix.cpp ../hcontainer.cpp ../atom_pair.cpp + ../../../source_basis/module_ao/parallel_orbitals.cpp tmp_mocks.cpp +) endif() diff --git a/source/source_lcao/module_hcontainer/test/test_add_value.cpp b/source/source_lcao/module_hcontainer/test/test_add_value.cpp new file mode 100644 index 00000000000..2bdd1529f49 --- /dev/null +++ b/source/source_lcao/module_hcontainer/test/test_add_value.cpp @@ -0,0 +1,339 @@ +#include "gtest/gtest.h" +#include "source_lcao/module_hcontainer/hcontainer.h" + +// Tests for add_value_intersection and add_value_union. +// HContainer is built via Parallel_Orbitals (serial): +// nat=2 atoms, atom0: 2 orbitals, atom1: 3 orbitals, nlocal=5 +// All (i,j) pairs at R=(0,0,0) are pre-inserted and zero-allocated. +// Values are written directly via find_matrix/get_atom_pair. +// +// For extra R vectors, register via get_atom_pair(i,j).get_HR_values(rx,ry,rz), +// then call hc->allocate(nullptr, true) once to reallocate (only in that case). + +class AddValueTest : public ::testing::Test +{ + protected: + Parallel_Orbitals paraV; + int iat2iwt[2] = {0, 2}; + + void SetUp() override + { + paraV.set_serial(5, 5); + paraV.set_atomic_trace(iat2iwt, 2, 5); + } + + // Insert all 2*2 pairs at R=(0,0,0) and allocate memory (zero-initialized). + void insert_all_pairs(hamilt::HContainer* hc) + { + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + { + hamilt::AtomPair ap(i, j, 0, 0, 0, ¶V); + hc->insert_pair(ap); + } + hc->allocate(nullptr, true); + } + + // Build an HContainer with only R=(0,0,0), writing the given values into each pair. + // fill: { {i, j, values}, ... } where values.size() == nw(i) * nw(j) + hamilt::HContainer* make_hc( + const std::vector>>& fill) + { + auto* hc = new hamilt::HContainer(¶V); + insert_all_pairs(hc); + for (auto& [i, j, vals] : fill) + { + double* ptr = hc->find_matrix(i, j, 0, 0, 0)->get_pointer(); + for (int k = 0; k < (int)vals.size(); k++) + ptr[k] = vals[k]; + } + return hc; + } + + // Build an HContainer that also has R=(rx,ry,rz) for pair (i,j), with values written. + // Used only for multi-R tests; calls allocate a second time to include the extra R. + hamilt::HContainer* make_hc_multiR( + int i, int j, int rx, int ry, int rz, + const std::vector& vals_000, + const std::vector& vals_R) + { + auto* hc = new hamilt::HContainer(¶V); + insert_all_pairs(hc); + // Register extra R vector + hc->get_atom_pair(i, j).get_HR_values(rx, ry, rz); + // Reallocate so the extra R is included in the wrapper + hc->allocate(nullptr, true); + // Write R=(0,0,0) values + double* p0 = hc->find_matrix(i, j, 0, 0, 0)->get_pointer(); + for (int k = 0; k < (int)vals_000.size(); k++) + p0[k] = vals_000[k]; + // Write extra-R values + double* pR = hc->find_matrix(i, j, rx, ry, rz)->get_pointer(); + for (int k = 0; k < (int)vals_R.size(); k++) + pR[k] = vals_R[k]; + return hc; + } +}; + +// ═══════════════════════════════════════════════════════════════════ +// add_value_intersection tests +// ═══════════════════════════════════════════════════════════════════ + +// 1. Identical sparsity pattern: this += 1.0 * other, each element is the sum of both +TEST_F(AddValueTest, intersection_same_sparsity) +{ + // pair(0,1): 2×3=6 elements; pair(1,0): 3×2=6 elements + auto* dst = make_hc({ + {0, 1, {1, 2, 3, 4, 5, 6}}, + {1, 0, {7, 8, 9, 10, 11, 12}}, + }); + auto* src = make_hc({ + {0, 1, {10, 20, 30, 40, 50, 60}}, + {1, 0, {70, 80, 90, 100, 110, 120}}, + }); + + dst->add_value_intersection(*src, 1.0); + + double* p01 = dst->find_matrix(0, 1, 0, 0, 0)->get_pointer(); + EXPECT_DOUBLE_EQ(p01[0], 11.0); + EXPECT_DOUBLE_EQ(p01[1], 22.0); + EXPECT_DOUBLE_EQ(p01[5], 66.0); + + double* p10 = dst->find_matrix(1, 0, 0, 0, 0)->get_pointer(); + EXPECT_DOUBLE_EQ(p10[0], 77.0); + EXPECT_DOUBLE_EQ(p10[5], 132.0); + + delete dst; + delete src; +} + +// 2. factor parameter: this += 2.0 * other +TEST_F(AddValueTest, intersection_factor) +{ + auto* dst = make_hc({{0, 1, {1, 0, 0, 0, 0, 0}}}); + auto* src = make_hc({{0, 1, {3, 0, 0, 0, 0, 0}}}); + + dst->add_value_intersection(*src, 2.0); + + double* ptr = dst->find_matrix(0, 1, 0, 0, 0)->get_pointer(); + EXPECT_DOUBLE_EQ(ptr[0], 7.0); // 1 + 2*3 = 7 + EXPECT_DOUBLE_EQ(ptr[1], 0.0); + + delete dst; + delete src; +} + +// 3. Negative factor: this += -1.0 * other +TEST_F(AddValueTest, intersection_negative_factor) +{ + auto* dst = make_hc({{0, 1, {10, 20, 30, 40, 50, 60}}}); + auto* src = make_hc({{0, 1, {1, 2, 3, 4, 5, 6}}}); + + dst->add_value_intersection(*src, -1.0); + + double* ptr = dst->find_matrix(0, 1, 0, 0, 0)->get_pointer(); + EXPECT_DOUBLE_EQ(ptr[0], 9.0); + EXPECT_DOUBLE_EQ(ptr[1], 18.0); + EXPECT_DOUBLE_EQ(ptr[5], 54.0); + + delete dst; + delete src; +} + +// 4. other has pairs absent from dst: only the intersection is added; +// values in other for pairs not in dst do not affect dst +TEST_F(AddValueTest, intersection_partial_overlap) +{ + // dst only fills (0,1); (1,0) stays 0 (zero-allocated by make_hc) + auto* dst = make_hc({{0, 1, {1, 2, 3, 4, 5, 6}}}); + // src fills both (0,1) and (1,0) + auto* src = make_hc({ + {0, 1, {10, 20, 30, 40, 50, 60}}, + {1, 0, {99, 99, 99, 99, 99, 99}}, + }); + + dst->add_value_intersection(*src, 1.0); + + // (0,1) should be correctly accumulated + double* p01 = dst->find_matrix(0, 1, 0, 0, 0)->get_pointer(); + EXPECT_DOUBLE_EQ(p01[0], 11.0); + EXPECT_DOUBLE_EQ(p01[5], 66.0); + + // (1,0) exists in dst (zero-initialized); intersection iterates this's pairs, + // so it finds (1,0) in dst and adds src's (1,0) values: 0+99=99 + double* p10 = dst->find_matrix(1, 0, 0, 0, 0)->get_pointer(); + EXPECT_DOUBLE_EQ(p10[0], 99.0); + + delete dst; + delete src; +} + +// 5. Multiple R vectors: only matching (i,j,R) triples are added; R present in dst but not src is unchanged +TEST_F(AddValueTest, intersection_multi_R) +{ + // dst: (0,1) has R=(0,0,0) and R=(1,0,0) + auto* dst = make_hc_multiR(0, 1, 1, 0, 0, + {1, 0, 0, 0, 0, 0}, + {2, 0, 0, 0, 0, 0}); + // src: (0,1) has only R=(0,0,0) + auto* src = make_hc({{0, 1, {10, 0, 0, 0, 0, 0}}}); + + dst->add_value_intersection(*src, 1.0); + + // R=(0,0,0): accumulated + EXPECT_DOUBLE_EQ(dst->find_matrix(0, 1, 0, 0, 0)->get_pointer()[0], 11.0); + // R=(1,0,0): absent in src, so dst value is unchanged + EXPECT_DOUBLE_EQ(dst->find_matrix(0, 1, 1, 0, 0)->get_pointer()[0], 2.0); + + delete dst; + delete src; +} + +// ═══════════════════════════════════════════════════════════════════ +// add_value_union tests +// ═══════════════════════════════════════════════════════════════════ + +// 6. Basic correctness: same sparsity as intersection case should give the same result +// (old code produced all zeros here; correct after bug fix) +TEST_F(AddValueTest, union_basic_sum) +{ + auto* dst = make_hc({{0, 1, {1, 2, 3, 4, 5, 6}}}); + auto* src = make_hc({{0, 1, {10, 20, 30, 40, 50, 60}}}); + + dst->add_value_union(*src, 1.0); + + double* ptr = dst->find_matrix(0, 1, 0, 0, 0)->get_pointer(); + EXPECT_DOUBLE_EQ(ptr[0], 11.0); + EXPECT_DOUBLE_EQ(ptr[1], 22.0); + EXPECT_DOUBLE_EQ(ptr[5], 66.0); + + delete dst; + delete src; +} + +// 7. Core bug regression: other's data must not be corrupted after the call +// (old add_value_union zeroed out other; this test specifically checks the fix) +TEST_F(AddValueTest, union_does_not_corrupt_other) +{ + auto* dst = make_hc({}); // all pairs default to 0 + auto* src = make_hc({{0, 1, {1, 2, 3, 4, 5, 6}}}); + + dst->add_value_union(*src, 1.0); + + // src data must be fully preserved + double* src_ptr = src->find_matrix(0, 1, 0, 0, 0)->get_pointer(); + EXPECT_DOUBLE_EQ(src_ptr[0], 1.0); + EXPECT_DOUBLE_EQ(src_ptr[1], 2.0); + EXPECT_DOUBLE_EQ(src_ptr[5], 6.0); + + // dst should be correctly accumulated + double* dst_ptr = dst->find_matrix(0, 1, 0, 0, 0)->get_pointer(); + EXPECT_DOUBLE_EQ(dst_ptr[0], 1.0); + EXPECT_DOUBLE_EQ(dst_ptr[5], 6.0); + + delete dst; + delete src; +} + +// 8. factor parameter: this += 2.0 * other +TEST_F(AddValueTest, union_factor) +{ + auto* dst = make_hc({{0, 1, {1, 0, 0, 0, 0, 0}}}); + auto* src = make_hc({{0, 1, {3, 0, 0, 0, 0, 0}}}); + + dst->add_value_union(*src, 2.0); + + double* ptr = dst->find_matrix(0, 1, 0, 0, 0)->get_pointer(); + EXPECT_DOUBLE_EQ(ptr[0], 7.0); // 1 + 2*3 = 7 + + delete dst; + delete src; +} + +// 9. Three successive union accumulations: simulates accumulating dH terms as in write_dH_sum; +// also verifies that each term's data is not corrupted after each call +TEST_F(AddValueTest, union_accumulate_three_terms) +{ + auto* sum = make_hc({}); + + auto* t1 = make_hc({{0, 1, {1, 0, 0, 0, 0, 0}}}); + auto* t2 = make_hc({{0, 1, {0, 2, 0, 0, 0, 0}}}); + auto* t3 = make_hc({{0, 1, {0, 0, 3, 0, 0, 0}}}); + + sum->add_value_union(*t1, 1.0); + sum->add_value_union(*t2, 1.0); + sum->add_value_union(*t3, 1.0); + + double* ptr = sum->find_matrix(0, 1, 0, 0, 0)->get_pointer(); + EXPECT_DOUBLE_EQ(ptr[0], 1.0); + EXPECT_DOUBLE_EQ(ptr[1], 2.0); + EXPECT_DOUBLE_EQ(ptr[2], 3.0); + + // Each term's data must remain intact + EXPECT_DOUBLE_EQ(t1->find_matrix(0, 1, 0, 0, 0)->get_pointer()[0], 1.0); + EXPECT_DOUBLE_EQ(t2->find_matrix(0, 1, 0, 0, 0)->get_pointer()[1], 2.0); + EXPECT_DOUBLE_EQ(t3->find_matrix(0, 1, 0, 0, 0)->get_pointer()[2], 3.0); + + delete sum; + delete t1; + delete t2; + delete t3; +} + +// 10. union introduces a new R vector: other has an R absent from dst, which should be inserted and assigned +TEST_F(AddValueTest, union_new_R_from_other) +{ + // dst: (0,1) has only R=(0,0,0), value 1 + auto* dst = make_hc({{0, 1, {1, 0, 0, 0, 0, 0}}}); + // src: (0,1) has R=(0,0,0) and R=(1,0,0) + auto* src = make_hc_multiR(0, 1, 1, 0, 0, + {10, 0, 0, 0, 0, 0}, + {99, 0, 0, 0, 0, 0}); + + dst->add_value_union(*src, 1.0); + + // R=(0,0,0): correctly accumulated + EXPECT_DOUBLE_EQ(dst->find_matrix(0, 1, 0, 0, 0)->get_pointer()[0], 11.0); + + // R=(1,0,0): newly inserted and assigned (0 + 99 = 99) + double* pR = dst->find_matrix(0, 1, 1, 0, 0)->get_pointer(); + EXPECT_NE(pR, nullptr); + EXPECT_DOUBLE_EQ(pR[0], 99.0); + + // src data must not be corrupted + EXPECT_DOUBLE_EQ(src->find_matrix(0, 1, 0, 0, 0)->get_pointer()[0], 10.0); + EXPECT_DOUBLE_EQ(src->find_matrix(0, 1, 1, 0, 0)->get_pointer()[0], 99.0); + + delete dst; + delete src; +} + +// 11. Multiple unions followed by intersection: verifies the two operations compose correctly +TEST_F(AddValueTest, union_then_intersection) +{ + auto* acc = make_hc({}); + auto* t1 = make_hc({{0, 1, {3, 0, 0, 0, 0, 0}}}); + auto* t2 = make_hc({{0, 1, {0, 5, 0, 0, 0, 0}}}); + auto* ref = make_hc({{0, 1, {2, 2, 0, 0, 0, 0}}}); + + acc->add_value_union(*t1, 1.0); + acc->add_value_union(*t2, 1.0); + + // acc = {3, 5, 0, ...}; subtract ref={2,2,...} via intersection + acc->add_value_intersection(*ref, -1.0); + + double* ptr = acc->find_matrix(0, 1, 0, 0, 0)->get_pointer(); + EXPECT_DOUBLE_EQ(ptr[0], 1.0); // 3 - 2 + EXPECT_DOUBLE_EQ(ptr[1], 3.0); // 5 - 2 + + delete acc; + delete t1; + delete t2; + delete ref; +} + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/source/source_lcao/module_operator_lcao/ekinetic.cpp b/source/source_lcao/module_operator_lcao/ekinetic.cpp index 993b7d1ea2d..cc62b96b644 100644 --- a/source/source_lcao/module_operator_lcao/ekinetic.cpp +++ b/source/source_lcao/module_operator_lcao/ekinetic.cpp @@ -259,6 +259,7 @@ void hamilt::EKinetic>::contributeHR() // Include force/stress implementation #include "ekinetic_force_stress.hpp" +#include "ekinetic_dh.hpp" template class hamilt::EKinetic>; template class hamilt::EKinetic, double>>; diff --git a/source/source_lcao/module_operator_lcao/ekinetic.h b/source/source_lcao/module_operator_lcao/ekinetic.h index 916c384a09c..46a77964ee6 100644 --- a/source/source_lcao/module_operator_lcao/ekinetic.h +++ b/source/source_lcao/module_operator_lcao/ekinetic.h @@ -6,6 +6,7 @@ #include "source_cell/unitcell.h" #include "source_lcao/module_operator_lcao/operator_lcao.h" #include "source_lcao/module_hcontainer/hcontainer.h" +#include #include namespace hamilt @@ -75,6 +76,9 @@ class EKinetic> : public OperatorLCAO ModuleBase::matrix& force, ModuleBase::matrix& stress); + // per-atom-I derivative d/dtau_I; one HContainer per atom I (size nat each) + void cal_dH(std::array*>, 3>& dhR); + private: const UnitCell* ucell = nullptr; std::vector orb_cutoff_; diff --git a/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp b/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp new file mode 100644 index 00000000000..0dee60187a4 --- /dev/null +++ b/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp @@ -0,0 +1,165 @@ +#pragma once +#include "ekinetic.h" +#include "operator_force_stress_utils.hpp" +#include "source_base/timer.h" + +namespace hamilt +{ + +template +void EKinetic>::cal_dH(std::array*>, 3>& dhR) +{ + ModuleBase::TITLE("EKinetic", "cal_dH"); + ModuleBase::timer::start("EKinetic", "cal_dH"); + + const int nat = this->ucell->nat; + assert(static_cast(dhR[0].size()) == nat); + const Parallel_Orbitals* paraV = dhR[0][0]->get_paraV(); + const int npol = this->ucell->get_npol(); + + // Pass 1: build the same atom-pair structure in each per-atom-I container + for (int iat1 = 0; iat1 < nat; iat1++) + { + auto tau1 = this->ucell->get_tau(iat1); + int T1 = 0, I1 = 0; + this->ucell->iat2iait(iat1, &I1, &T1); + + AdjacentAtomInfo adjs; + this->gridD->Find_atom(*this->ucell, tau1, T1, I1, &adjs); + + for (int ad = 0; ad < adjs.adj_num + 1; ++ad) + { + const int T2 = adjs.ntype[ad]; + const int I2 = adjs.natom[ad]; + const int iat2 = this->ucell->itia2iat(T2, I2); + const ModuleBase::Vector3& R_index = adjs.box[ad]; + + ModuleBase::Vector3 dtau = this->ucell->cal_dtau(iat1, iat2, R_index); + if (dtau.norm() * this->ucell->lat0 >= this->orb_cutoff_[T1] + this->orb_cutoff_[T2]) + { + continue; + } + + if (paraV->get_row_size(iat1) <= 0 || paraV->get_col_size(iat2) <= 0) + { + continue; + } + + hamilt::AtomPair ap(iat1, iat2, R_index.x, R_index.y, R_index.z, paraV); + for (int iat = 0; iat < nat; ++iat) + { + for (int d = 0; d < 3; ++d) + dhR[d][iat]->insert_pair(ap); + } + } + } + + for (int iat = 0; iat < nat; ++iat) + { + for (int d = 0; d < 3; ++d) + dhR[d][iat]->allocate(nullptr, true); + } + +#pragma omp parallel + { +#pragma omp for schedule(dynamic) + for (int iat1 = 0; iat1 < nat; iat1++) + { + auto tau1 = this->ucell->get_tau(iat1); + int T1 = 0, I1 = 0; + this->ucell->iat2iait(iat1, &I1, &T1); + const Atom& atom1 = this->ucell->atoms[T1]; + + AdjacentAtomInfo adjs; + this->gridD->Find_atom(*this->ucell, tau1, T1, I1, &adjs); + + for (int ad = 0; ad < adjs.adj_num + 1; ++ad) + { + const int T2 = adjs.ntype[ad]; + const int I2 = adjs.natom[ad]; + const int iat2 = this->ucell->itia2iat(T2, I2); + const ModuleBase::Vector3& R_index = adjs.box[ad]; + + ModuleBase::Vector3 dtau = this->ucell->cal_dtau(iat1, iat2, R_index); + if (dtau.norm() * this->ucell->lat0 >= this->orb_cutoff_[T1] + this->orb_cutoff_[T2]) + { + continue; + } + + // d/dtau_I is nonzero only for I in {U=iat1, V=iat2}: + // olm = -> d/dtau_V -> container iat2 + // olm_rev = -> d/dtau_U -> container iat1 + hamilt::BaseMatrix* mtxU[3]; + hamilt::BaseMatrix* mtxV[3]; + for (int d = 0; d < 3; ++d) + { + mtxU[d] = dhR[d][iat1]->find_matrix(iat1, iat2, R_index); + mtxV[d] = dhR[d][iat2]->find_matrix(iat1, iat2, R_index); + } + + if (!mtxU[0] || !mtxU[1] || !mtxU[2] || !mtxV[0] || !mtxV[1] || !mtxV[2]) + { + continue; + } + + double* ptrU[3] = {mtxU[0]->get_pointer(), mtxU[1]->get_pointer(), mtxU[2]->get_pointer()}; + double* ptrV[3] = {mtxV[0]->get_pointer(), mtxV[1]->get_pointer(), mtxV[2]->get_pointer()}; + const int col_size = mtxU[0]->get_col_size(); + + const Atom& atom2 = this->ucell->atoms[T2]; + + auto row_indexes = paraV->get_indexes_row(iat1); + auto col_indexes = paraV->get_indexes_col(iat2); + + if (row_indexes.size() == 0 || col_indexes.size() == 0) + { + continue; + } + + double olm[4] = {0, 0, 0, 0}; + double olm_rev[4] = {0, 0, 0, 0}; + + for (int iw1l = 0; iw1l < row_indexes.size(); iw1l += npol) + { + const int iw1 = row_indexes[iw1l] / npol; + const int L1 = atom1.iw2l[iw1]; + const int N1 = atom1.iw2n[iw1]; + const int m1 = atom1.iw2m[iw1]; + const int M1 = (m1 % 2 == 0) ? -m1 / 2 : (m1 + 1) / 2; + + for (int iw2l = 0; iw2l < col_indexes.size(); iw2l += npol) + { + const int iw2 = col_indexes[iw2l] / npol; + const int L2 = atom2.iw2l[iw2]; + const int N2 = atom2.iw2n[iw2]; + const int m2 = atom2.iw2m[iw2]; + const int M2 = (m2 % 2 == 0) ? -m2 / 2 : (m2 + 1) / 2; + + const ModuleBase::Vector3 dtau_scaled = dtau * this->ucell->lat0; + + this->intor_->calculate(T1, L1, N1, M1, T2, L2, N2, M2, dtau_scaled, nullptr, olm); // + + const ModuleBase::Vector3 dtau_rev = (-1.0) * dtau_scaled; + this->intor_->calculate(T2, L2, N2, M2, T1, L1, N1, M1, dtau_rev, nullptr, olm_rev); // + + const int idx = (iw1l / npol) * col_size + (iw2l / npol); + + // d/dtau_I = - + // but olm directly gives and , + // so we can directly use them without extra negation. + // confirmed against the finite-difference reference. + for (int d = 0; d < 3; ++d) + { + ptrV[d][idx] += olm[d]; + ptrU[d][idx] += olm_rev[d]; + } + } + } + } + } + } + + ModuleBase::timer::end("EKinetic", "cal_dH"); +} + +} // namespace hamilt diff --git a/source/source_lcao/module_operator_lcao/nonlocal.cpp b/source/source_lcao/module_operator_lcao/nonlocal.cpp index 806a45e8d69..754020a32c3 100644 --- a/source/source_lcao/module_operator_lcao/nonlocal.cpp +++ b/source/source_lcao/module_operator_lcao/nonlocal.cpp @@ -324,6 +324,7 @@ void hamilt::Nonlocal>::contributeHR() } #include "nonlocal_force_stress.hpp" +#include "nonlocal_dh.hpp" template class hamilt::Nonlocal>; template class hamilt::Nonlocal, double>>; diff --git a/source/source_lcao/module_operator_lcao/nonlocal.h b/source/source_lcao/module_operator_lcao/nonlocal.h index 9da556b8e3e..dc3cd565740 100644 --- a/source/source_lcao/module_operator_lcao/nonlocal.h +++ b/source/source_lcao/module_operator_lcao/nonlocal.h @@ -7,6 +7,7 @@ #include "source_lcao/module_operator_lcao/operator_lcao.h" #include "source_lcao/module_hcontainer/hcontainer.h" +#include #include #include @@ -60,6 +61,9 @@ class Nonlocal> : public OperatorLCAO ModuleBase::matrix& force, ModuleBase::matrix& stress); + // per-atom-I derivative d/dtau_I; one HContainer per atom I (size nat each) + void cal_dH(std::array*>, 3>& dhR); + virtual void set_HR_fixed(void*) override; private: diff --git a/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp b/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp new file mode 100644 index 00000000000..23afb15feb5 --- /dev/null +++ b/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp @@ -0,0 +1,257 @@ +#pragma once +#include "nonlocal.h" +#include "operator_force_stress_utils.h" +#include "source_base/timer.h" + +namespace hamilt +{ + +template +void Nonlocal>::cal_dH(std::array*>, 3>& dhR) +{ + ModuleBase::TITLE("Nonlocal", "cal_dH"); + ModuleBase::timer::start("Nonlocal", "cal_dH"); + + const int nat = this->ucell->nat; + assert(static_cast(dhR[0].size()) == nat); + const Parallel_Orbitals* paraV = dhR[0][0]->get_paraV(); + const int npol = this->ucell->get_npol(); + + for (int iat0 = 0; iat0 < nat; iat0++) + { + auto tau0 = this->ucell->get_tau(iat0); + int I0 = 0, T0 = 0; + this->ucell->iat2iait(iat0, &I0, &T0); + + AdjacentAtomInfo adjs; + this->gridD->Find_atom(*this->ucell, tau0, T0, I0, &adjs); + + std::vector is_adj(adjs.adj_num + 1, false); + for (int ad = 0; ad < adjs.adj_num + 1; ++ad) + { + const int T1 = adjs.ntype[ad]; + const int I1 = adjs.natom[ad]; + const int iat1 = this->ucell->itia2iat(T1, I1); + const ModuleBase::Vector3& R_index1 = adjs.box[ad]; + if (this->ucell->cal_dtau(iat0, iat1, R_index1).norm() * this->ucell->lat0 + < this->orb_cutoff_[T1] + this->ucell->infoNL.Beta[T0].get_rcut_max()) + { + is_adj[ad] = true; + } + } + + for (int ad1 = 0; ad1 < adjs.adj_num + 1; ++ad1) + { + if (!is_adj[ad1]) + continue; + const int T1 = adjs.ntype[ad1]; + const int I1 = adjs.natom[ad1]; + const int iat1 = this->ucell->itia2iat(T1, I1); + const ModuleBase::Vector3& R_index1 = adjs.box[ad1]; + + for (int ad2 = 0; ad2 < adjs.adj_num + 1; ++ad2) + { + if (!is_adj[ad2]) + continue; + const int T2 = adjs.ntype[ad2]; + const int I2 = adjs.natom[ad2]; + const int iat2 = this->ucell->itia2iat(T2, I2); + const ModuleBase::Vector3& R_index2 = adjs.box[ad2]; + + if (paraV->get_row_size(iat1) <= 0 || paraV->get_col_size(iat2) <= 0) + { + continue; + } + + ModuleBase::Vector3 dR(R_index2.x - R_index1.x, R_index2.y - R_index1.y, R_index2.z - R_index1.z); + + hamilt::AtomPair ap(iat1, iat2, dR.x, dR.y, dR.z, paraV); + for (int iat = 0; iat < nat; ++iat) + { + for (int d = 0; d < 3; ++d) + dhR[d][iat]->insert_pair(ap); + } + } + } + } + + for (int iat = 0; iat < nat; ++iat) + { + for (int d = 0; d < 3; ++d) + dhR[d][iat]->allocate(nullptr, true); + } + +#pragma omp parallel + { +#pragma omp for schedule(dynamic) + for (int iat0 = 0; iat0 < nat; iat0++) + { + auto tau0 = this->ucell->get_tau(iat0); + int I0 = 0, T0 = 0; + this->ucell->iat2iait(iat0, &I0, &T0); + + AdjacentAtomInfo adjs; + this->gridD->Find_atom(*this->ucell, tau0, T0, I0, &adjs); + + std::vector is_adj(adjs.adj_num + 1, false); + for (int ad = 0; ad < adjs.adj_num + 1; ++ad) + { + const int T1 = adjs.ntype[ad]; + const int I1 = adjs.natom[ad]; + const int iat1 = this->ucell->itia2iat(T1, I1); + const ModuleBase::Vector3& R_index1 = adjs.box[ad]; + if (this->ucell->cal_dtau(iat0, iat1, R_index1).norm() * this->ucell->lat0 + < this->orb_cutoff_[T1] + this->ucell->infoNL.Beta[T0].get_rcut_max()) + { + is_adj[ad] = true; + } + } + + std::vector>> nlm_iat0(adjs.adj_num + 1); + + for (int ad = 0; ad < adjs.adj_num + 1; ++ad) + { + if (!is_adj[ad]) + continue; + + const int T1 = adjs.ntype[ad]; + const int I1 = adjs.natom[ad]; + const int iat1 = this->ucell->itia2iat(T1, I1); + const ModuleBase::Vector3& tau1 = adjs.adjacent_tau[ad]; + const Atom* atom1 = &this->ucell->atoms[T1]; + + auto all_indexes = paraV->get_indexes_row(iat1); + auto col_indexes = paraV->get_indexes_col(iat1); + all_indexes.insert(all_indexes.end(), col_indexes.begin(), col_indexes.end()); + std::sort(all_indexes.begin(), all_indexes.end()); + all_indexes.erase(std::unique(all_indexes.begin(), all_indexes.end()), all_indexes.end()); + + for (size_t iw1l = 0; iw1l < all_indexes.size(); iw1l += npol) + { + const int iw1 = all_indexes[iw1l] / npol; + std::vector> nlm; + + OperatorForceStress::OrbitalQuantumNumbers qn1 = OperatorForceStress::get_orbital_qn(*atom1, iw1); + + // = - = + ModuleBase::Vector3 dtau_at = tau0 - tau1; + this->intor_->snap(T1, qn1.L, qn1.N, qn1.M, T0, dtau_at * this->ucell->lat0, true, nlm); + + const size_t length = nlm[0].size(); + std::vector nlm_target(length * 4); + for (size_t index = 0; index < length; index++) + { + for (int n = 0; n < 4; n++) + nlm_target[index + n * length] = nlm[n][index]; + } + nlm_iat0[ad].insert({all_indexes[iw1l], nlm_target}); + } + } + + for (int ad1 = 0; ad1 < adjs.adj_num + 1; ++ad1) + { + if (!is_adj[ad1]) + continue; + const int T1 = adjs.ntype[ad1]; + const int I1 = adjs.natom[ad1]; + const int iat1 = this->ucell->itia2iat(T1, I1); + const ModuleBase::Vector3& R_index1 = adjs.box[ad1]; + + for (int ad2 = 0; ad2 < adjs.adj_num + 1; ++ad2) + { + if (!is_adj[ad2]) + continue; + const int T2 = adjs.ntype[ad2]; + const int I2 = adjs.natom[ad2]; + const int iat2 = this->ucell->itia2iat(T2, I2); + const ModuleBase::Vector3& R_index2 = adjs.box[ad2]; + + ModuleBase::Vector3 dR(R_index2.x - R_index1.x, + R_index2.y - R_index1.y, + R_index2.z - R_index1.z); + + // destination block (iat1,iat2,dR) for the three differentiated atoms: + // iat1 (orbital 1), iat2 (orbital 2), iat0 (projector / Hellmann-Feynman) + hamilt::BaseMatrix* m1[3]; + hamilt::BaseMatrix* m2[3]; + hamilt::BaseMatrix* m0[3]; + for (int d = 0; d < 3; ++d) + { + m1[d] = dhR[d][iat1]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + m2[d] = dhR[d][iat2]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + m0[d] = dhR[d][iat0]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + } + + if (!m1[0] || !m1[1] || !m1[2] || !m2[0] || !m2[1] || !m2[2] || !m0[0] || !m0[1] || !m0[2]) + continue; + + double* p1[3] = {m1[0]->get_pointer(), m1[1]->get_pointer(), m1[2]->get_pointer()}; + double* p2[3] = {m2[0]->get_pointer(), m2[1]->get_pointer(), m2[2]->get_pointer()}; + double* p0[3] = {m0[0]->get_pointer(), m0[1]->get_pointer(), m0[2]->get_pointer()}; + const int col_sz = m1[0]->get_col_size(); + + auto& nlm1_all = nlm_iat0[ad1]; + auto& nlm2_all = nlm_iat0[ad2]; + + auto row_indexes = paraV->get_indexes_row(iat1); + auto col_indexes = paraV->get_indexes_col(iat2); + + for (size_t iw1l = 0; iw1l < row_indexes.size(); iw1l++) + { + auto it1 = nlm1_all.find(row_indexes[iw1l]); + if (it1 == nlm1_all.end()) + continue; + const std::vector& nlm1 = it1->second; + const size_t length = nlm1.size() / 4; + const int iw1_row = static_cast(iw1l); + + for (size_t iw2l = 0; iw2l < col_indexes.size(); iw2l++) + { + auto it2 = nlm2_all.find(col_indexes[iw2l]); + if (it2 == nlm2_all.end()) + continue; + const std::vector& nlm2 = it2->second; + const int iw2_col = static_cast(iw2l); + + // tU = D (orbital 1 moves) + // tV = D (orbital 2 moves) + double tU[3] = {0, 0, 0}; + double tV[3] = {0, 0, 0}; + + for (int no = 0; no < this->ucell->atoms[T0].ncpp.non_zero_count_soc[0]; no++) + { + const int p1_idx = this->ucell->atoms[T0].ncpp.index1_soc[0][no]; + const int p2_idx = this->ucell->atoms[T0].ncpp.index2_soc[0][no]; + const double* tmp_d = nullptr; + this->ucell->atoms[T0].ncpp.get_d(0, p1_idx, p2_idx, tmp_d); + for (int d = 0; d < 3; ++d) + { + tU[d] += nlm1[p1_idx + length * (d + 1)] * nlm2[p2_idx] * (*tmp_d); + tV[d] += nlm1[p1_idx] * nlm2[p2_idx + length * (d + 1)] * (*tmp_d); + } + } + + const int idx = iw1_row * col_sz + iw2_col; + // d/dtau_iat1, d/dtau_iat2, and (translational invariance) d/dtau_iat0 + // dtau=-- + // =- for Hellmann-Feynman terms + for (int d = 0; d < 3; ++d) + { +#pragma omp atomic + p1[d][idx] -= tU[d]; +#pragma omp atomic + p2[d][idx] -= tV[d]; +#pragma omp atomic + p0[d][idx] += tU[d] + tV[d]; + } + } + } + } + } + } + } + + ModuleBase::timer::end("Nonlocal", "cal_dH"); +} + +} // namespace hamilt diff --git a/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp.bak b/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp.bak new file mode 100644 index 00000000000..d247840af0b --- /dev/null +++ b/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp.bak @@ -0,0 +1,256 @@ +#pragma once +#include "nonlocal.h" +#include "operator_force_stress_utils.h" +#include "source_base/timer.h" + +namespace hamilt +{ + +template +void Nonlocal>::cal_dH(std::array*>, 3>& dhR) +{ + ModuleBase::TITLE("Nonlocal", "cal_dH"); + ModuleBase::timer::start("Nonlocal", "cal_dH"); + + const int nat = this->ucell->nat; + assert(static_cast(dhR[0].size()) == nat); + const Parallel_Orbitals* paraV = dhR[0][0]->get_paraV(); + const int npol = this->ucell->get_npol(); + + for (int iat0 = 0; iat0 < nat; iat0++) + { + auto tau0 = this->ucell->get_tau(iat0); + int I0 = 0, T0 = 0; + this->ucell->iat2iait(iat0, &I0, &T0); + + AdjacentAtomInfo adjs; + this->gridD->Find_atom(*this->ucell, tau0, T0, I0, &adjs); + + std::vector is_adj(adjs.adj_num + 1, false); + for (int ad = 0; ad < adjs.adj_num + 1; ++ad) + { + const int T1 = adjs.ntype[ad]; + const int I1 = adjs.natom[ad]; + const int iat1 = this->ucell->itia2iat(T1, I1); + const ModuleBase::Vector3& R_index1 = adjs.box[ad]; + if (this->ucell->cal_dtau(iat0, iat1, R_index1).norm() * this->ucell->lat0 + < this->orb_cutoff_[T1] + this->ucell->infoNL.Beta[T0].get_rcut_max()) + { + is_adj[ad] = true; + } + } + + for (int ad1 = 0; ad1 < adjs.adj_num + 1; ++ad1) + { + if (!is_adj[ad1]) + continue; + const int T1 = adjs.ntype[ad1]; + const int I1 = adjs.natom[ad1]; + const int iat1 = this->ucell->itia2iat(T1, I1); + const ModuleBase::Vector3& R_index1 = adjs.box[ad1]; + + for (int ad2 = 0; ad2 < adjs.adj_num + 1; ++ad2) + { + if (!is_adj[ad2]) + continue; + const int T2 = adjs.ntype[ad2]; + const int I2 = adjs.natom[ad2]; + const int iat2 = this->ucell->itia2iat(T2, I2); + const ModuleBase::Vector3& R_index2 = adjs.box[ad2]; + + if (paraV->get_row_size(iat1) <= 0 || paraV->get_col_size(iat2) <= 0) + { + continue; + } + + ModuleBase::Vector3 dR(R_index2.x - R_index1.x, R_index2.y - R_index1.y, R_index2.z - R_index1.z); + + hamilt::AtomPair ap(iat1, iat2, dR.x, dR.y, dR.z, paraV); + for (int iat = 0; iat < nat; ++iat) + { + for (int d = 0; d < 3; ++d) + dhR[d][iat]->insert_pair(ap); + } + } + } + } + + for (int iat = 0; iat < nat; ++iat) + { + for (int d = 0; d < 3; ++d) + dhR[d][iat]->allocate(nullptr, true); + } + +#pragma omp parallel + { +#pragma omp for schedule(dynamic) + for (int iat0 = 0; iat0 < nat; iat0++) + { + auto tau0 = this->ucell->get_tau(iat0); + int I0 = 0, T0 = 0; + this->ucell->iat2iait(iat0, &I0, &T0); + + AdjacentAtomInfo adjs; + this->gridD->Find_atom(*this->ucell, tau0, T0, I0, &adjs); + + std::vector is_adj(adjs.adj_num + 1, false); + for (int ad = 0; ad < adjs.adj_num + 1; ++ad) + { + const int T1 = adjs.ntype[ad]; + const int I1 = adjs.natom[ad]; + const int iat1 = this->ucell->itia2iat(T1, I1); + const ModuleBase::Vector3& R_index1 = adjs.box[ad]; + if (this->ucell->cal_dtau(iat0, iat1, R_index1).norm() * this->ucell->lat0 + < this->orb_cutoff_[T1] + this->ucell->infoNL.Beta[T0].get_rcut_max()) + { + is_adj[ad] = true; + } + } + + std::vector>> nlm_iat0(adjs.adj_num + 1); + + for (int ad = 0; ad < adjs.adj_num + 1; ++ad) + { + if (!is_adj[ad]) + continue; + + const int T1 = adjs.ntype[ad]; + const int I1 = adjs.natom[ad]; + const int iat1 = this->ucell->itia2iat(T1, I1); + const ModuleBase::Vector3& tau1 = adjs.adjacent_tau[ad]; + const Atom* atom1 = &this->ucell->atoms[T1]; + + auto all_indexes = paraV->get_indexes_row(iat1); + auto col_indexes = paraV->get_indexes_col(iat1); + all_indexes.insert(all_indexes.end(), col_indexes.begin(), col_indexes.end()); + std::sort(all_indexes.begin(), all_indexes.end()); + all_indexes.erase(std::unique(all_indexes.begin(), all_indexes.end()), all_indexes.end()); + + for (size_t iw1l = 0; iw1l < all_indexes.size(); iw1l += npol) + { + const int iw1 = all_indexes[iw1l] / npol; + std::vector> nlm; + + OperatorForceStress::OrbitalQuantumNumbers qn1 = OperatorForceStress::get_orbital_qn(*atom1, iw1); + + ModuleBase::Vector3 dtau_at = tau0 - tau1; + this->intor_->snap(T1, qn1.L, qn1.N, qn1.M, T0, dtau_at * this->ucell->lat0, true, nlm); + + const size_t length = nlm[0].size(); + std::vector nlm_target(length * 4); + for (size_t index = 0; index < length; index++) + { + for (int n = 0; n < 4; n++) + nlm_target[index + n * length] = nlm[n][index]; + } + nlm_iat0[ad].insert({all_indexes[iw1l], nlm_target}); + } + } + + for (int ad1 = 0; ad1 < adjs.adj_num + 1; ++ad1) + { + if (!is_adj[ad1]) + continue; + const int T1 = adjs.ntype[ad1]; + const int I1 = adjs.natom[ad1]; + const int iat1 = this->ucell->itia2iat(T1, I1); + const ModuleBase::Vector3& R_index1 = adjs.box[ad1]; + + for (int ad2 = 0; ad2 < adjs.adj_num + 1; ++ad2) + { + if (!is_adj[ad2]) + continue; + const int T2 = adjs.ntype[ad2]; + const int I2 = adjs.natom[ad2]; + const int iat2 = this->ucell->itia2iat(T2, I2); + const ModuleBase::Vector3& R_index2 = adjs.box[ad2]; + + ModuleBase::Vector3 dR(R_index2.x - R_index1.x, + R_index2.y - R_index1.y, + R_index2.z - R_index1.z); + + // destination block (iat1,iat2,dR) for the three differentiated atoms: + // iat1 (orbital 1), iat2 (orbital 2), iat0 (projector / Hellmann-Feynman) + hamilt::BaseMatrix* m1[3]; + hamilt::BaseMatrix* m2[3]; + hamilt::BaseMatrix* m0[3]; + for (int d = 0; d < 3; ++d) + { + m1[d] = dhR[d][iat1]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + m2[d] = dhR[d][iat2]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + m0[d] = dhR[d][iat0]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + } + + if (!m1[0] || !m1[1] || !m1[2] || !m2[0] || !m2[1] || !m2[2] || !m0[0] || !m0[1] || !m0[2]) + continue; + + double* p1[3] = {m1[0]->get_pointer(), m1[1]->get_pointer(), m1[2]->get_pointer()}; + double* p2[3] = {m2[0]->get_pointer(), m2[1]->get_pointer(), m2[2]->get_pointer()}; + double* p0[3] = {m0[0]->get_pointer(), m0[1]->get_pointer(), m0[2]->get_pointer()}; + const int col_sz = m1[0]->get_col_size(); + + auto& nlm1_all = nlm_iat0[ad1]; + auto& nlm2_all = nlm_iat0[ad2]; + + auto row_indexes = paraV->get_indexes_row(iat1); + auto col_indexes = paraV->get_indexes_col(iat2); + + for (size_t iw1l = 0; iw1l < row_indexes.size(); iw1l++) + { + auto it1 = nlm1_all.find(row_indexes[iw1l]); + if (it1 == nlm1_all.end()) + continue; + const std::vector& nlm1 = it1->second; + const size_t length = nlm1.size() / 4; + const int iw1_row = paraV->global2local_row(row_indexes[iw1l]); + + for (size_t iw2l = 0; iw2l < col_indexes.size(); iw2l++) + { + auto it2 = nlm2_all.find(col_indexes[iw2l]); + if (it2 == nlm2_all.end()) + continue; + const std::vector& nlm2 = it2->second; + const int iw2_col = paraV->global2local_col(col_indexes[iw2l]); + + // tU = D (orbital 1 moves) + // tV = D (orbital 2 moves) + double tU[3] = {0, 0, 0}; + double tV[3] = {0, 0, 0}; + + for (int no = 0; no < this->ucell->atoms[T0].ncpp.non_zero_count_soc[0]; no++) + { + const int p1_idx = this->ucell->atoms[T0].ncpp.index1_soc[0][no]; + const int p2_idx = this->ucell->atoms[T0].ncpp.index2_soc[0][no]; + const double* tmp_d = nullptr; + this->ucell->atoms[T0].ncpp.get_d(0, p1_idx, p2_idx, tmp_d); + for (int d = 0; d < 3; ++d) + { + tU[d] += nlm1[p1_idx + length * (d + 1)] * nlm2[p2_idx] * (*tmp_d); + tV[d] += nlm1[p1_idx] * nlm2[p2_idx + length * (d + 1)] * (*tmp_d); + } + } + + const int idx = iw1_row * col_sz + iw2_col; + // d/dtau_iat1, d/dtau_iat2, and (translational invariance) d/dtau_iat0 + // dtau=-- + // =- for Hellmann-Feynman terms + for (int d = 0; d < 3; ++d) + { +#pragma omp atomic + p1[d][idx] -= tU[d]; +#pragma omp atomic + p2[d][idx] -= tV[d]; +#pragma omp atomic + p0[d][idx] += tU[d] + tV[d]; + } + } + } + } + } + } + } + + ModuleBase::timer::end("Nonlocal", "cal_dH"); +} + +} // namespace hamilt diff --git a/source/source_lcao/module_operator_lcao/op_exx_lcao.h b/source/source_lcao/module_operator_lcao/op_exx_lcao.h index 941d5e088c2..0fa20ae4494 100644 --- a/source/source_lcao/module_operator_lcao/op_exx_lcao.h +++ b/source/source_lcao/module_operator_lcao/op_exx_lcao.h @@ -10,6 +10,10 @@ #include #include +// Forward declaration to avoid circular include (Exx_LRI_interface.hpp includes op_exx_lcao.h) +template +class Exx_LRI_Interface; + namespace hamilt { @@ -33,6 +37,20 @@ class OperatorEXX> : public OperatorLCAO using TAC = std::pair>; public: + /// @brief Full-workflow Constructor that takes Exx_LRI_Interface objects directly. + /// Used in the main project (HamiltLCAO) for both scf and nscf. + OperatorEXX>(HS_Matrix_K* hsk_in, + hamilt::HContainer* hR_in, + const UnitCell& ucell, + const K_Vectors& kv_in, + Exx_LRI_Interface* exd_in, + Exx_LRI_Interface>* exc_in, + Add_Hexx_Type add_hexx_type_in = Add_Hexx_Type::R, + const int istep_in = 0, + const bool restart_in = false); + + /// @brief One-shot operator constructor, only for adding Hexxs, without exd/exc workflow + /// Used in write_Vxc OperatorEXX>( HS_Matrix_K* hsk_in, hamilt::HContainer* hR_in, @@ -40,28 +58,31 @@ class OperatorEXX> : public OperatorLCAO const K_Vectors& kv_in, std::vector>>>* Hexxd_in = nullptr, std::vector>>>>* Hexxc_in = nullptr, - Add_Hexx_Type add_hexx_type_in = Add_Hexx_Type::R, - const int istep_in = 0, - int* two_level_step_in = nullptr, - const bool restart_in = false); + Add_Hexx_Type add_hexx_type_in = Add_Hexx_Type::R); virtual void contributeHk(int ik) override; virtual void contributeHR() override; + template + void cal_dH(const int ispin, + std::array*>, 3>& dhR, + const std::array>>>>, 3>& dHexxs); + private: Add_Hexx_Type add_hexx_type = Add_Hexx_Type::R; int current_spin = 0; bool HR_fixed_done = false; bool initial_gga_done = false; // Taoni Bao add 2026-05-18, to fix RT-TDDFT EXX missing problem in the evolution + /// @brief Non-owning pointers to the EXX interface objects. + /// When set (via the interface-based constructor), Hexxd/Hexxc/two_level_step + /// are sourced from these objects rather than stored as separate members. + Exx_LRI_Interface* exd = nullptr; + Exx_LRI_Interface>* exc = nullptr; + std::vector>>>* Hexxd = nullptr; std::vector>>>>* Hexxc = nullptr; - /// @brief the step of the outer loop. - /// nullptr: no dependence on the number of two_level_step, contributeHk will do enerything normally. - /// 0: the first outer loop. If restart, contributeHk will directly add Hexx to Hloc. else, do nothing. - /// >0: not the first outer loop. contributeHk will do enerything normally. - int* two_level_step = nullptr; /// @brief if restart, read and save Hexx, and directly use it during the first outer loop. bool restart = false; diff --git a/source/source_lcao/module_operator_lcao/op_exx_lcao.hpp b/source/source_lcao/module_operator_lcao/op_exx_lcao.hpp index 8f6f0f832cd..e5e27ba97d7 100644 --- a/source/source_lcao/module_operator_lcao/op_exx_lcao.hpp +++ b/source/source_lcao/module_operator_lcao/op_exx_lcao.hpp @@ -8,6 +8,8 @@ #include "source_io/module_parameter/parameter.h" #include "source_io/module_restart/restart.h" #include "source_io/module_restart/restart_exx_csr.h" +#include "source_lcao/module_hcontainer/read_hcontainer.h" +#include "source_lcao/module_ri/Exx_LRI_interface.h" #include "source_lcao/module_ri/RI_2D_Comm.h" #include "source_lcao/module_rt/td_info.h" @@ -93,24 +95,49 @@ void reallocate_hcontainer(const int nat, template OperatorEXX>::OperatorEXX( HS_Matrix_K* hsk_in, - HContainer* hR_in, - const UnitCell& ucell_in, + hamilt::HContainer* hR_in, + const UnitCell& ucell, const K_Vectors& kv_in, std::vector>>>* Hexxd_in, std::vector>>>>* Hexxc_in, - Add_Hexx_Type add_hexx_type_in, - const int istep, - int* two_level_step_in, - const bool restart_in) - : OperatorLCAO(hsk_in, kv_in.kvec_d, hR_in), ucell(ucell_in), kv(kv_in), Hexxd(Hexxd_in), Hexxc(Hexxc_in), - add_hexx_type(add_hexx_type_in), istep(istep), two_level_step(two_level_step_in), restart(restart_in) + Add_Hexx_Type add_hexx_type_in) + : OperatorLCAO(hsk_in, kv_in.kvec_d, hR_in), ucell(ucell), kv(kv_in), Hexxd(Hexxd_in), Hexxc(Hexxc_in), + add_hexx_type(add_hexx_type_in) { - ModuleBase::TITLE("OperatorEXX", "OperatorEXX"); this->cal_type = calculation_type::lcao_exx; + // This one-shot constructor never builds cell_nearest, so cal_dH() must not use it: + // the (d)Hexxs from LibRI are in native cells, and the dH output mirrors the H-term + // writer (write_h_exx_impl), which also passes a nullptr cell_nearest. + this->use_cell_nearest = false; +} + +template +OperatorEXX>::OperatorEXX(HS_Matrix_K* hsk_in, + HContainer* hR_in, + const UnitCell& ucell_in, + const K_Vectors& kv_in, + Exx_LRI_Interface* exd_in, + Exx_LRI_Interface>* exc_in, + Add_Hexx_Type add_hexx_type_in, + const int istep_in, + const bool restart_in) + : OperatorEXX>(hsk_in, + hR_in, + ucell_in, + kv_in, + exd_in ? &exd_in->get_Hexxs() : nullptr, + exc_in ? &exc_in->get_Hexxs() : nullptr, + add_hexx_type_in) +{ + this->exd = exd_in; + this->exc = exc_in; + const_cast(this->istep) = istep_in; + this->restart = restart_in; + ModuleBase::TITLE("OperatorEXX", "OperatorEXX"); const Parallel_Orbitals* const pv = hR_in->get_paraV(); if (PARAM.inp.calculation == "nscf" && GlobalC::exx_info.info_global.cal_exx) - { // if nscf, read HexxR first and reallocate hR according to the read-in HexxR + { // for nscf, calculate HexxR from the read-in DM, or read HexxR in auto file_name_list_csr = []() -> std::vector { std::vector file_name_list; for (int irank = 0; irank < PARAM.globalv.nproc; ++irank) @@ -143,59 +170,101 @@ OperatorEXX>::OperatorEXX( return true; }; - std::cout << " Attention: The number of MPI processes must be strictly identical between SCF and NSCF when computing exact-exchange." << std::endl; - if (check_exist(file_name_list_csr())) + if (PARAM.inp.init_chg == "dm") { - const std::string file_name_exx_csr - = PARAM.globalv.global_readin_dir + "HexxR" + std::to_string(PARAM.globalv.myrank); - // Read HexxR in CSR format + // 1. cal Cs, Vs if (GlobalC::exx_info.info_ri.real_number) { - ModuleIO::read_Hexxs_csr(file_name_exx_csr, ucell, PARAM.inp.nspin, PARAM.globalv.nlocal, *Hexxd); - if (this->add_hexx_type == Add_Hexx_Type::R) - { - reallocate_hcontainer(*Hexxd, this->hR); - } + this->exd->cal_exx_ions(ucell, PARAM.inp.out_ri_cv); } else { - ModuleIO::read_Hexxs_csr(file_name_exx_csr, ucell, PARAM.inp.nspin, PARAM.globalv.nlocal, *Hexxc); - if (this->add_hexx_type == Add_Hexx_Type::R) - { - reallocate_hcontainer(*Hexxc, this->hR); - } + this->exc->cal_exx_ions(ucell, PARAM.inp.out_ri_cv); } - } - else if (check_exist(file_name_list_cereal())) - { - // Read HexxR in binary format (old version) - const std::string file_name_exx_cereal - = PARAM.globalv.global_readin_dir + "HexxR_" + std::to_string(PARAM.globalv.myrank); - std::ifstream ifs(file_name_exx_cereal, std::ios::binary); - if (!ifs) + + // 2. read DM + const int nspin_dm = (PARAM.inp.nspin == 2) ? 2 : 1; + std::vector*> dmR_vec(nspin_dm); + for (int is = 0; is < nspin_dm; ++is) { - ModuleBase::WARNING_QUIT("OperatorEXX", "Can't open EXX file < " + file_name_exx_cereal + " >."); + const std::string dmfile + = PARAM.globalv.global_readin_dir + "/dmrs" + std::to_string(is + 1) + "_nao.csr"; + dmR_vec[is] = new hamilt::HContainer(const_cast(pv)); + hamilt::Read_HContainer reader_dm(dmR_vec[is], dmfile, PARAM.globalv.nlocal, &ucell); + reader_dm.read(); } + + // 3. DM->Ds->Hexx (do not use symmetry for nscf) + XC_Functional::set_xc_type(ucell.atoms[0].ncpp.xc_func); if (GlobalC::exx_info.info_ri.real_number) { - ModuleIO::read_Hexxs_cereal(file_name_exx_cereal, *Hexxd); - if (this->add_hexx_type == Add_Hexx_Type::R) + const auto& Ds = RI_2D_Comm::dm_container_to_Ds(dmR_vec, ucell, *pv, PARAM.inp.nspin); + this->exd->cal_exx_elec(Ds, ucell, *pv); + } + else + { + const auto& Ds = RI_2D_Comm::dm_container_to_Ds>(dmR_vec, + ucell, + *pv, + PARAM.inp.nspin); + this->exc->cal_exx_elec(Ds, ucell, *pv); + } + } + else // need to read HexxR + { + std::cout << " Attention: The number of MPI processes must be strictly identical between SCF and NSCF when " + "computing exact-exchange." + << std::endl; + if (check_exist(file_name_list_csr())) + { + // read HexxR first and reallocate hR according to the read-in HexxR + const std::string file_name_exx_csr + = PARAM.globalv.global_readin_dir + "HexxR" + std::to_string(PARAM.globalv.myrank); + // Read HexxR in CSR format + if (GlobalC::exx_info.info_ri.real_number) { - reallocate_hcontainer(*Hexxd, this->hR); + ModuleIO::read_Hexxs_csr(file_name_exx_csr, ucell, PARAM.inp.nspin, PARAM.globalv.nlocal, *Hexxd); + } + else + { + ModuleIO::read_Hexxs_csr(file_name_exx_csr, ucell, PARAM.inp.nspin, PARAM.globalv.nlocal, *Hexxc); } } - else + else if (check_exist(file_name_list_cereal())) { - ModuleIO::read_Hexxs_cereal(file_name_exx_cereal, *Hexxc); - if (this->add_hexx_type == Add_Hexx_Type::R) + // Read HexxR in binary format (old version) + const std::string file_name_exx_cereal + = PARAM.globalv.global_readin_dir + "HexxR_" + std::to_string(PARAM.globalv.myrank); + std::ifstream ifs(file_name_exx_cereal, std::ios::binary); + if (!ifs) + { + ModuleBase::WARNING_QUIT("OperatorEXX", "Can't open EXX file < " + file_name_exx_cereal + " >."); + } + if (GlobalC::exx_info.info_ri.real_number) + { + ModuleIO::read_Hexxs_cereal(file_name_exx_cereal, *Hexxd); + } + else { - reallocate_hcontainer(*Hexxc, this->hR); + ModuleIO::read_Hexxs_cereal(file_name_exx_cereal, *Hexxc); } } + else + { + ModuleBase::WARNING_QUIT("OperatorEXX", "Can't open EXX file in " + PARAM.globalv.global_readin_dir); + } } - else + // reallocate hR according to Hexx(R) + if (this->add_hexx_type == Add_Hexx_Type::R) { - ModuleBase::WARNING_QUIT("OperatorEXX", "Can't open EXX file in " + PARAM.globalv.global_readin_dir); + if (GlobalC::exx_info.info_ri.real_number) + { + reallocate_hcontainer(*this->Hexxd, this->hR); + } + else + { + reallocate_hcontainer(*this->Hexxc, this->hR); + } } this->use_cell_nearest = false; } @@ -226,7 +295,6 @@ OperatorEXX>::OperatorEXX( { /// Now only Hexx depends on DM, so we can directly read Hexx to reduce the computational cost. /// If other operators depends on DM, we can also read DM and then calculate the operators to save the /// memory to store operator terms. - assert(this->two_level_step != nullptr); if (this->add_hexx_type == Add_Hexx_Type::k) { @@ -336,7 +404,6 @@ OperatorEXX>::OperatorEXX( } } } - template void OperatorEXX>::contributeHR() { @@ -351,8 +418,11 @@ void OperatorEXX>::contributeHR() // 2. For the first ionic step of SCF, relaxation, or MD: else if (this->istep == 0) { + const int two_level_step + = GlobalC::exx_info.info_ri.real_number ? this->exd->get_two_level_step() : this->exc->get_two_level_step(); + // Check if we are in the pre-convergence stage of the two-level SCF (i.e., the pure GGA loop) - bool in_gga_pre_loop = (this->two_level_step != nullptr && *this->two_level_step == 0); + bool in_gga_pre_loop = (two_level_step == 0); // Check if a high-quality initial guess is missing (neither reading wavefunctions from a file nor restarting) bool lacks_good_guess = (PARAM.inp.init_wfc != "file" && !this->restart); @@ -404,13 +474,21 @@ template void OperatorEXX>::contributeHk(int ik) { ModuleBase::TITLE("OperatorEXX", "constributeHk"); + const bool has_workflow = GlobalC::exx_info.info_ri.real_number ? (this->exd != nullptr) : (this->exc != nullptr); + int two_level_step = 0; + if (has_workflow) + { + two_level_step + = GlobalC::exx_info.info_ri.real_number ? this->exd->get_two_level_step() : this->exc->get_two_level_step(); + } + // Peize Lin add 2016-12-03 // Taoni Bao add 2026-05-15 // In RT-TDDFT, contributeHk is used, but two_level_step is reset to 0 at each ionic step. // In order to add EXX correctly in for istep > 0, this->istep == 0 is needed to avoid skipping EXX calculation. // 1. For NSCF - if (PARAM.inp.calculation == "nscf") + if (PARAM.inp.calculation == "nscf" || !has_workflow) { // Do nothing here, allow the code to proceed and calculate EXX. } @@ -418,13 +496,13 @@ void OperatorEXX>::contributeHk(int ik) else if (this->istep == 0) { // If EXX is once turned on (two_level_step > 0), let OperatorEXX remember this - if (this->two_level_step != nullptr && *this->two_level_step > 0) + if (two_level_step > 0) { this->initial_gga_done = true; } // Check if we are in the pre-convergence stage of the two-level SCF (i.e., the pure GGA loop) - bool in_gga_pre_loop = (this->two_level_step != nullptr && *this->two_level_step == 0); + bool in_gga_pre_loop = (two_level_step == 0); // Check if a high-quality initial guess is missing bool lacks_good_guess = (!this->restart); @@ -441,14 +519,14 @@ void OperatorEXX>::contributeHk(int ik) if (this->add_hexx_type == Add_Hexx_Type::R) { - throw std::invalid_argument("Set Add_Hexx_Type::k to call OperatorEXX::contributeHk()."); + OperatorLCAO::contributeHk(ik); } if (XC_Functional::get_func_type() == 4 || XC_Functional::get_func_type() == 5) { - if (this->restart && this->two_level_step != nullptr) + if (this->restart) { - if (*this->two_level_step == 0) + if (two_level_step == 0) { this->add_loaded_Hexx(ik); return; @@ -506,6 +584,35 @@ void OperatorEXX>::contributeHk(int ik) } } +template +template +void OperatorEXX>::cal_dH( + const int ispin, + std::array*>, 3>& dhR, + const std::array>>>>, 3>& dHexxs) +{ + // dhR is the set of per-atom-I HContainers to fill (not this->hR, which may be a dummy here). + const Parallel_Orbitals* const paraV = dhR[0][0]->get_paraV(); + const RI::Cell_Nearest* const cell_nearest + = this->use_cell_nearest ? &this->cell_nearest : nullptr; + for (int idir = 0; idir < 3; ++idir) + { + for (int iat = 0; iat < ucell.nat; ++iat) + { + // add_HexxR only fills existing matrices, so first allocate the atom-pair + // structure of this per-I container from the exx-form data (same cell mapping). + reallocate_hcontainer(dHexxs[idir][iat], dhR[idir][iat], cell_nearest); + RI_2D_Comm::add_HexxR(ispin, + GlobalC::exx_info.info_global.hybrid_alpha, + dHexxs[idir][iat], + *paraV, + PARAM.globalv.npol, + *dhR[idir][iat], + cell_nearest); + } + } +} + } // namespace hamilt #endif // __EXX #endif // OPEXXLCAO_HPP diff --git a/source/source_lcao/module_operator_lcao/veff_dh.hpp b/source/source_lcao/module_operator_lcao/veff_dh.hpp new file mode 100644 index 00000000000..c5266816e6e --- /dev/null +++ b/source/source_lcao/module_operator_lcao/veff_dh.hpp @@ -0,0 +1,529 @@ +#pragma once +#include "source_base/timer.h" +#include "source_estate/module_charge/charge.h" +#include "source_estate/module_pot/H_Hartree_pw.h" +#include "source_estate/module_pot/pot_xc_fdm.h" +#include "source_lcao/module_gint/gint_dvlocal.h" +#include "source_lcao/module_gint/gint_interface.h" +#include "source_lcao/module_hcontainer/hcontainer_funcs.h" +#include "source_pw/module_pwdft/forces.h" +#include "veff_lcao.h" +#ifdef __MPI +#include +#endif + +namespace hamilt +{ + +template +void Veff>::cal_dH(std::array*>, 3>& dhR, + const std::string& hellmann_feynman_type, + const std::vector*>& dmR, + const Charge* chg, + const int ispin) +{ + ModuleBase::TITLE("Veff", "cal_dH"); + ModuleBase::timer::start("Veff", "cal_dH"); + + const int nat = this->ucell->nat; + assert(static_cast(dhR[0].size()) == nat); + const Parallel_Orbitals* paraV = dhR[0][0]->get_paraV(); + + // Pass 1: discover atom pairs and build the same structure in each per-atom-I container + for (int iat1 = 0; iat1 < nat; iat1++) + { + auto tau1 = this->ucell->get_tau(iat1); + int T1 = 0, I1 = 0; + this->ucell->iat2iait(iat1, &I1, &T1); + + AdjacentAtomInfo adjs; + this->gd->Find_atom(*this->ucell, tau1, T1, I1, &adjs); + + for (int ad = 0; ad < adjs.adj_num + 1; ++ad) + { + const int T2 = adjs.ntype[ad]; + const int I2 = adjs.natom[ad]; + const int iat2 = this->ucell->itia2iat(T2, I2); + if (paraV->get_row_size(iat1) <= 0 || paraV->get_col_size(iat2) <= 0) + { + continue; + } + const ModuleBase::Vector3& R_index = adjs.box[ad]; + if (this->ucell->cal_dtau(iat1, iat2, R_index).norm() * this->ucell->lat0 + < this->orb_cutoff_[T1] + this->orb_cutoff_[T2]) + { + hamilt::AtomPair tmp(iat1, iat2, R_index, paraV); + for (int iat = 0; iat < nat; ++iat) + { + for (int d = 0; d < 3; ++d) + dhR[d][iat]->insert_pair(tmp); + } + } + } + } + + for (int iat = 0; iat < nat; ++iat) + { + for (int d = 0; d < 3; ++d) + dhR[d][iat]->allocate(nullptr, true); + } + + // Pass 2: Pulay term -[ delta_UI + delta_VI ] + // via grid integration. pvdpR[A][B] = (gradient on the 2nd orbital). + { + ModuleBase::timer::start("Veff", "cal_dH_pulay"); + + // term-specific local potential: V^L (fixed local pseudopotential) for "vl", + // otherwise the effective potential ("hartree/xc") of the specified spin channel. + // V^H/V^L are spin-independent so ispin is harmless there. + const double* vr_eff + = (hellmann_feynman_type == "vl") ? this->pot->get_fixed_v() : this->pot->get_eff_v(ispin); + + // full_triangle=true: fill both triangles of pvdpR so that, for every block (U,V), + // both the gradient-on-U and gradient-on-V Pulay terms are available per atom I. + ModuleGint::Gint_dvlocal gint_dv(vr_eff, 1, PARAM.globalv.npol, true); + gint_dv.cal_dvlocal(); + + hamilt::HContainer* pvdpR[3] // grid parallel + = {gint_dv.get_pvdpRx(), gint_dv.get_pvdpRy(), gint_dv.get_pvdpRz()}; + +#ifdef __MPI + int mpi_size = 1; + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); +#endif + for (int I = 0; I < nat; ++I) + { + for (int d = 0; d < 3; ++d) + { + // grid-layout source (same structure as pvdpR), only atom-I blocks filled + hamilt::HContainer gI(*pvdpR[d]); + gI.set_zero(); + + for (int iap = 0; iap < pvdpR[d]->size_atom_pairs(); iap++) + { + const auto& ap = pvdpR[d]->get_atom_pair(iap); + const int iat1 = ap.get_atom_i(); // A + const int iat2 = ap.get_atom_j(); // B + if (iat2 != I) + continue; // gradient on the 2nd orbital => only I=B contributes + + for (int ir = 0; ir < ap.get_R_size(); ir++) + { + const ModuleBase::Vector3 R = ap.get_R_index(ir); + const ModuleBase::Vector3 negR(-R.x, -R.y, -R.z); + + hamilt::BaseMatrix* src = pvdpR[d]->find_matrix(iat1, iat2, R); + // delta_VI (I=B): -pvdpR into block (A,B) + hamilt::BaseMatrix* gV = gI.find_matrix(iat1, iat2, R); + // delta_UI (I=B): -pvdpR^T into block (B,A) + hamilt::BaseMatrix* gU = gI.find_matrix(iat2, iat1, negR); + if (!src || !gV || !gU) + continue; + + const int rowA = src->get_row_size(); + const int colB = src->get_col_size(); + const int colU = gU->get_col_size(); // = nw(A) = rowA + double* psrc = src->get_pointer(); + double* pV = gV->get_pointer(); + double* pU = gU->get_pointer(); + + // pvdpR[A][B] = ; since d_{tau_B}phi_B = -grad phi_B, + // the Pulay contribution to d/dtau_I is -pvdpR + // (sign confirmed against the iat2 finite-difference reference). + for (int a = 0; a < rowA; ++a) + { + for (int b = 0; b < colB; ++b) + { + const double val = psrc[a * colB + b]; + pV[a * colB + b] -= val; // block (A,B)[a,b] (delta_VI) + pU[b * colU + a] -= val; // block (B,A)[b,a] (delta_UI, transpose) + } + } + } + } + + // grid -> 2D: sum across ranks and scatter into the 2D-distributed container +#ifdef __MPI + if (mpi_size > 1) + { + hamilt::transferSerials2Parallels(gI, dhR[d][I]); + } + else + { + dhR[d][I]->add(gI); + } +#else + dhR[d][I]->add(gI); +#endif + } + } + + ModuleBase::timer::end("Veff", "cal_dH_pulay"); + } + + // Pass 3: Hellmann-Feynman term + if (hellmann_feynman_type == "none") + { + // do nothing + } + else if (hellmann_feynman_type == "vl") + { + ModuleBase::timer::start("Veff", "cal_dH_hf_vl"); + + // PW-side machinery reused from the effective potential + const ModulePW::PW_Basis* rho_basis = this->pot->get_rho_basis(); + const ModuleBase::matrix& vloc = *this->pot->get_vloc(); + + // a charge buffer to hold the orbital-pair density rho(r) = phi_Umu * phi_Vnu + Charge chr; + chr.set_rhopw(const_cast(rho_basis)); + chr.allocate(PARAM.inp.nspin, false); + + // cal_force_loc returns the local Hellmann-Feynman force on every atom: + // F_I = -Omega * sum_G e^{iG.tau_I} iG . V^{L,Z_I}(G) rho*(G) + Forces f_pw(nat); + ModuleBase::matrix forcelc(nat, 3); + + // delta-density-matrix: it must carry the FULL neighbour structure (cal_gint_rho looks + // up every overlapping atom pair on the grid), all values zero. We mirror the per-I + // structure and toggle a single element on/off to realize D=delta_{Umu}delta_{Vnu}. + hamilt::HContainer dm(paraV); + for (int iap = 0; iap < dhR[0][0]->size_atom_pairs(); ++iap) + { + dm.insert_pair(dhR[0][0]->get_atom_pair(iap)); + } + dm.allocate(nullptr, true); + std::vector*> dm_vec = {&dm}; + + const int* iat2iwt = this->ucell->get_iat2iwt(); + for (int iat1 = 0; iat1 < nat; iat1++) + { + auto tau1 = this->ucell->get_tau(iat1); + int T1 = 0, I1 = 0; + this->ucell->iat2iait(iat1, &I1, &T1); + + AdjacentAtomInfo adjs; + this->gd->Find_atom(*this->ucell, tau1, T1, I1, &adjs); + + for (int ad = 0; ad < adjs.adj_num + 1; ++ad) + { + const int T2 = adjs.ntype[ad]; + const int I2 = adjs.natom[ad]; + const int iat2 = this->ucell->itia2iat(T2, I2); + const ModuleBase::Vector3& R_index = adjs.box[ad]; + + ModuleBase::Vector3 dtau = this->ucell->cal_dtau(iat1, iat2, R_index); + if (dtau.norm() * this->ucell->lat0 + >= this->orb_cutoff_[T1] + this->orb_cutoff_[T2]) + continue; + + // The delta-DM density (cal_gint_rho) and the PW force (cal_force_loc) are both + // collective MPI operations and must be called in lockstep on all ranks. + // Therefore we iterate GLOBAL orbital pairs (iw1,iw2) to avoid deadlock. + // The one-hot DM element is set only on the rank that owns it under the 2D block-cyclic layout, + // and the resulting force is written into dhR on that same owning rank. + const int nw1 = this->ucell->atoms[T1].nw * PARAM.globalv.npol; + const int nw2 = this->ucell->atoms[T2].nw * PARAM.globalv.npol; + const int gr0 = iat2iwt[iat1]; + const int gc0 = iat2iwt[iat2]; + + // Does this rank store the (iat1,iat2,R) sub-block at all? If so, cache the + // owner-only pointers (identical for every orbital pair within the block). + const bool owns_block = (paraV->get_row_size(iat1) > 0 && paraV->get_col_size(iat2) > 0); + double* dm_ptr = nullptr; + int col_size = 0; + // save the address of the (iat1,iat2,R) block in each dhR[d][iat] for quick access within the loop + std::vector dst[3]; + if (owns_block) + { + hamilt::BaseMatrix* dm_mat = dm.find_matrix(iat1, iat2, R_index); + dm_ptr = dm_mat ? dm_mat->get_pointer() : nullptr; + col_size = dm_mat ? dm_mat->get_col_size() : 0; + for (int d = 0; d < 3; ++d) + dst[d].assign(nat, nullptr); + for (int iat = 0; iat < nat; ++iat) + for (int d = 0; d < 3; ++d) + { + hamilt::BaseMatrix* m = dhR[d][iat]->find_matrix(iat1, iat2, R_index); + dst[d][iat] = m ? m->get_pointer() : nullptr; + } + } + + for (int iw1 = 0; iw1 < nw1; ++iw1) + { + const int lr = paraV->global2local_row(gr0 + iw1); + for (int iw2 = 0; iw2 < nw2; ++iw2) + { + const int lc = paraV->global2local_col(gc0 + iw2); + // this matrix element is owned iff both its row and col are local here + const bool owned = owns_block && dm_ptr && lr >= 0 && lc >= 0; + + int idx = 0; + if (owned) + { + const int br = lr - paraV->atom_begin_row[iat1]; + const int bc = lc - paraV->atom_begin_col[iat2]; + idx = br * col_size + bc; + // delta-density-matrix D_{Ii,Jj} = delta_{Ii,Umu} delta_{Jj,Vnu} + dm_ptr[idx] = 1.0; + } + + // (collective: same call count on every rank, = NLOCAL^2) + // the result element (forcelc) is the same on every rank, + // but only stored into dhR on the rank that owns the orbital pair (Umu,Vnu) + + // effective charge density rho(r) = phi_Umu(r) * phi_Vnu(r) by Gint + for (int is = 0; is < PARAM.inp.nspin; ++is) + ModuleBase::GlobalFunc::ZEROS(chr.rho[is], chr.nrxx); + ModuleGint::cal_gint_rho(dm_vec, 1, chr.rho, false); + + // Hellmann-Feynman local force on every atom I from this pair density + forcelc.zero_out(); + f_pw.cal_force_loc(*this->ucell, forcelc, rho_basis, vloc, &chr); + + // cal_force_loc returns F_I = -d E_loc/d tau_I, hence the matrix element + // = -F_I + // (sign confirmed against central finite-difference of the V^L matrix for iat2) + if (owned) + { + for (int iat = 0; iat < nat; ++iat) + for (int d = 0; d < 3; ++d) + if (dst[d][iat]) + dst[d][iat][idx] -= forcelc(iat, d); + + // reset the delta element back to zero for the next orbital pair + dm_ptr[idx] = 0.0; + } + } + } + } + } + ModuleBase::timer::end("Veff", "cal_dH_hf_vl"); + } + else if (hellmann_feynman_type == "hartree") + { + ModuleBase::timer::start("Veff", "cal_dH_hf_vh"); + + // Hellmann-Feynman Hartree term: the matrix element also + // depends on tau_I through rho (the basis on atom I that builds the density moves): + // d_{tau_I,d} V^H_{mu,nu}|HF = INT phi_mu phi_nu V^H[ d_{tau_I,d} rho ] + // with d_{tau_I,d} rho = -[grad rho]^{S,delta}_{I,d}, + // [grad rho]^{S,delta}_{I,d}(r) = sum_{Kk,Ll} delta_{KI} (D_{Kk,Ll}+D_{Ll,Kk}) + // (grad^d phi_Kk)(r) phi_Ll(r). + // Hence the HF contribution is -. + assert(!dmR.empty() && dmR[0] != nullptr); + + const ModulePW::PW_Basis* rho_basis = this->pot->get_rho_basis(); + const int nrxx = rho_basis->nrxx; + + // single total-density channel for the gradient density on the grid + std::vector drho[3] = {std::vector(nrxx), + std::vector(nrxx), + std::vector(nrxx)}; + + for (int I = 0; I < nat; ++I) + { + // Set M^I = delta_{KI} (D + D^T): the rows on atom I carry the symmetrized DM, + // every other block is zero. The full neighbour structure of D must be kept + // (cal_gint_drho/dm_2d_to_gint looks up every overlapping pair), so we mirror + // D's atom pairs and only fill the atom-I rows. + // Block (I,L,R) value = D(I,L,R) + D(L,I,-R)^T. For the collinear DM (nspin 1/2, + // the only case routed here) DMK is Hermitian, so cal_DMR yields the exact symmetry + // D(L,I,-R)[l,k] = D(I,L,R)[k,l]; hence the symmetrized block is simply 2*D(I,L,R). + // We use only the *local* block D(I,L,R): the reverse pair (L,I,-R) lives on a + // different rank under 2D block-cyclic, so reading it directly (the old code) silently + // dropped the D^T term in MPI. 2*D(I,L,R) is local and parallel-correct. + hamilt::HContainer mI(paraV); + for (int iap = 0; iap < dmR[0]->size_atom_pairs(); ++iap) + { + mI.insert_pair(dmR[0]->get_atom_pair(iap)); + } + mI.allocate(nullptr, true); + + for (int iap = 0; iap < mI.size_atom_pairs(); ++iap) + { + auto& ap = mI.get_atom_pair(iap); + if (ap.get_atom_i() != I) + { + continue; // rows not on atom I stay zero (delta_{KI}) + } + const int L = ap.get_atom_j(); + for (int ir = 0; ir < ap.get_R_size(); ++ir) + { + const ModuleBase::Vector3 R = ap.get_R_index(ir); + const ModuleBase::Vector3 negR(-R.x, -R.y, -R.z); + (void)negR; + hamilt::BaseMatrix* dst = mI.find_matrix(I, L, R); + const int nrow = dst->get_row_size(); + const int ncol = dst->get_col_size(); + double* pdst = dst->get_pointer(); + for (int a = 0; a < nrow; ++a) + for (int b = 0; b < ncol; ++b) + pdst[a * ncol + b] = 0.0; + // M^I(I,L,R) = D + D^T = 2*D(I,L,R) (DMR symmetry, see above). V^H depends on + // the TOTAL density, so for nspin=2 sum both spin DMs: D = sum_s D^s. + for (int s = 0; s < (int)dmR.size(); ++s) + { + // D^s(I,L,R) is the same (locally-owned) 2D block as mI(I,L,R) + const hamilt::BaseMatrix* d_il = dmR[s]->find_matrix(I, L, R); + if (d_il == nullptr) { continue; } + const double* psrc = d_il->get_pointer(); + for (int a = 0; a < nrow; ++a) + for (int b = 0; b < ncol; ++b) + pdst[a * ncol + b] += 2.0 * psrc[a * ncol + b]; + } + } + } + + // [grad rho]^{S,delta}_{I,d} on the real-space grid (accumulated -> zero first) + for (int d = 0; d < 3; ++d) + ModuleBase::GlobalFunc::ZEROS(drho[d].data(), nrxx); + double* drho_x_p[1] = {drho[0].data()}; + double* drho_y_p[1] = {drho[1].data()}; + double* drho_z_p[1] = {drho[2].data()}; + std::vector*> dm_vec = {&mI}; + ModuleGint::cal_gint_drho(dm_vec, 1, drho_x_p, drho_y_p, drho_z_p); + + for (int d = 0; d < 3; ++d) + { + // Hartree potential of the gradient density (treated as a charge density) + double* rho_ptr[1] = {drho[d].data()}; + ModuleBase::matrix vh = elecstate::H_Hartree_pw::v_hartree( + *this->ucell, const_cast(rho_basis), 1, rho_ptr); + + // AO matrix elements on the same per-I sparsity + hamilt::HContainer* dpI = dhR[d][I]; + hamilt::HContainer hR_hf(paraV); + for (int iap = 0; iap < dpI->size_atom_pairs(); ++iap) + { + hR_hf.insert_pair(dpI->get_atom_pair(iap)); + } + hR_hf.allocate(nullptr, true); + ModuleGint::cal_gint_vl(&vh(0, 0), &hR_hf); + + // d_{tau_I,d} V^H|HF = - + dpI->add_value_intersection(hR_hf, -1.0); + } + } + ModuleBase::timer::end("Veff", "cal_dH_hf_vh"); + } + else if (hellmann_feynman_type == "xc") + { + ModuleBase::timer::start("Veff", "cal_dH_hf_xc"); + + assert(chg != nullptr && !dmR.empty()); + + const ModulePW::PW_Basis* rho_basis = this->pot->get_rho_basis(); + const int nrxx = rho_basis->nrxx; + + // finite-difference XC: delta V^XC(r) = V^XC[rho0 + drho](r) - V^XC[rho0](r) + elecstate::PotXC_FDM dvxcr_fdm_op(rho_basis, chg, this->ucell); + + std::vector chg_drho(3); + for (int d = 0; d < 3; ++d) + { + chg_drho[d].set_rhopw(const_cast(rho_basis)); + chg_drho[d].allocate(chg->nspin, false); + + } + + for (int I = 0; I < nat; ++I) + { + // [grad rho^s]^{S,delta}_{I,d} on the real-space grid, one channel per spin s. + // chg_drho is allocated once and reused across I; cal_gint_drho ACCUMULATES + // (see Gint_drho), so zero every spin channel per atom (mirrors the Hartree branch). + for (int d = 0; d < 3; ++d) + for (int is = 0; is < chg->nspin; ++is) + ModuleBase::GlobalFunc::ZEROS(chg_drho[d].rho[is], nrxx); + + // V^XC is spin-resolved for nspin=2; the FDM perturbation needs BOTH spin gradient + // densities because the kernel couples spins (dV^XC_s = sum_s' f_{ss'} drho_s'). + // Build M^I_s = 2*delta_{KI}*D^s(I,L,R) per spin and integrate into density channel s. + for (int s = 0; s < chg->nspin; ++s) + { + const hamilt::HContainer* dms = dmR[s]; + + hamilt::HContainer mI(paraV); + for (int iap = 0; iap < dms->size_atom_pairs(); ++iap) + { + mI.insert_pair(dms->get_atom_pair(iap)); + } + mI.allocate(nullptr, true); + + for (int iap = 0; iap < mI.size_atom_pairs(); ++iap) + { + auto& ap = mI.get_atom_pair(iap); + if (ap.get_atom_i() != I) + { + continue; + } + const int L = ap.get_atom_j(); + for (int ir = 0; ir < ap.get_R_size(); ++ir) + { + const ModuleBase::Vector3 R = ap.get_R_index(ir); + hamilt::BaseMatrix* dst = mI.find_matrix(I, L, R); + const hamilt::BaseMatrix* d_il = dms->find_matrix(I, L, R); + const int nrow = dst->get_row_size(); + const int ncol = dst->get_col_size(); + double* pdst = dst->get_pointer(); + for (int a = 0; a < nrow; ++a) + { + for (int b = 0; b < ncol; ++b) + { + pdst[a * ncol + b] = (d_il ? 2.0 * d_il->get_pointer()[a * ncol + b] : 0.0); + } + } + } + } + + std::vector*> dm_vec = {&mI}; + double* drho_x[1] = {chg_drho[0].rho[s]}; + double* drho_y[1] = {chg_drho[1].rho[s]}; + double* drho_z[1] = {chg_drho[2].rho[s]}; + ModuleGint::cal_gint_drho(dm_vec, 1, drho_x, drho_y, drho_z); + } + + for (int d = 0; d < 3; ++d) + { + // FDM is exact only for an infinitesimal perturbation: V^XC is non-linear, so + // V^XC[rho0+drho]-V^XC[rho0] with the FULL drho is polluted by O(drho^2) and + // higher terms. Scale the perturbation by a small lambda before the FDM call and + // divide the result back after, isolating the linear response + // delta V^XC = INT f^XC drho (-> matches the small-displacement FD reference). + const double lambda = 1e-4; + for (int is = 0; is < chg->nspin; ++is) + for (int ir = 0; ir < nrxx; ++ir) + chg_drho[d].rho[is][ir] *= lambda; + + // delta V^XC from the (scaled) density perturbation drho[d] + ModuleBase::matrix dvxcr(chg->nspin, nrxx); + dvxcr.zero_out(); + dvxcr_fdm_op.cal_v_eff(&chg_drho[d], this->ucell, dvxcr); + dvxcr *= (1.0 / lambda); + + // AO matrix elements + hamilt::HContainer* dpI = dhR[d][I]; + hamilt::HContainer hR_hf(paraV); + for (int iap = 0; iap < dpI->size_atom_pairs(); ++iap) + { + hR_hf.insert_pair(dpI->get_atom_pair(iap)); + } + hR_hf.allocate(nullptr, true); + // project the OUTPUT spin channel's delta V^XC (row ispin) into AO basis + ModuleGint::cal_gint_vl(&dvxcr(ispin, 0), &hR_hf); + + // d_{tau_I,d} V^XC|HF = - + dpI->add_value_intersection(hR_hf, -1.0); + } + } + ModuleBase::timer::end("Veff", "cal_dH_hf_xc"); + } + else + { + // Unsupported Hellmann-Feynman type + std::cerr << "Unsupported Hellmann-Feynman type: " << hellmann_feynman_type << std::endl; + } + ModuleBase::timer::end("Veff", "cal_dH"); +} + +} // namespace hamilt diff --git a/source/source_lcao/module_operator_lcao/veff_lcao.cpp b/source/source_lcao/module_operator_lcao/veff_lcao.cpp index 27d2ff6c19d..88c8e117d80 100644 --- a/source/source_lcao/module_operator_lcao/veff_lcao.cpp +++ b/source/source_lcao/module_operator_lcao/veff_lcao.cpp @@ -1,4 +1,5 @@ #include "veff_lcao.h" +#include "veff_dh.hpp" #include "source_base/timer.h" #include "source_io/module_parameter/parameter.h" #include "source_base/tool_title.h" diff --git a/source/source_lcao/module_operator_lcao/veff_lcao.h b/source/source_lcao/module_operator_lcao/veff_lcao.h index 9f06348333f..bccc503da3c 100644 --- a/source/source_lcao/module_operator_lcao/veff_lcao.h +++ b/source/source_lcao/module_operator_lcao/veff_lcao.h @@ -5,6 +5,8 @@ #include "operator_lcao.h" #include "source_cell/module_neighbor/sltk_grid_driver.h" #include "source_cell/unitcell.h" +#include +#include #include namespace hamilt @@ -57,6 +59,15 @@ class Veff> : public OperatorLCAO * grid integration is used to calculate the contribution Hamiltonian of effective potential */ virtual void contributeHR() override; + + // per-atom-I derivative d/dtau_I; one HContainer per atom I (size nat each). + // Includes the Pulay term (-) for all types, plus the Hellmann-Feynman + // term for "vl"; "none" gives Pulay only (V^XC), "hartree" is deferred. + void cal_dH(std::array*>, 3>& dhR, + const std::string& hellmann_feynman_type = "none", + const std::vector*>& dmR = {}, + const Charge* chg = nullptr, + const int ispin = 0); const UnitCell* ucell = nullptr; const Grid_Driver* gd = nullptr; diff --git a/source/source_lcao/module_ri/Exx_LRI.h b/source/source_lcao/module_ri/Exx_LRI.h index b25958ad65f..43ce130a1e3 100644 --- a/source/source_lcao/module_ri/Exx_LRI.h +++ b/source/source_lcao/module_ri/Exx_LRI.h @@ -92,14 +92,18 @@ class Exx_LRI const Parallel_Orbitals& pv, const ModuleSymmetry::Symmetry_rotation* p_symrot = nullptr); void cal_exx_force(const int& nat); - void cal_exx_stress(const double& omega, const double& lat0); + void cal_exx_stress(const double& omega, const double& lat0); + void cal_exx_dHs(const std::vector>>>& Ds, + const UnitCell& ucell, + const Parallel_Orbitals& pv); void reset_Cs(const std::map>>& Cs_in) { this->exx_lri.set_Cs(Cs_in, this->info.C_threshold); } void reset_Vs(const std::map>>& Vs_in) { this->exx_lri.set_Vs(Vs_in, this->info.V_threshold); } //std::vector> get_abfs_nchis() const; - std::vector< std::map>>> Hexxs; - double Eexx; + std::vector< std::map>>> Hexxs; + std::array>>>>, 3> dHexxs; // direction, atom, spin, (i,j,R) + double Eexx; ModuleBase::matrix force_exx; ModuleBase::matrix stress_exx; diff --git a/source/source_lcao/module_ri/Exx_LRI.hpp b/source/source_lcao/module_ri/Exx_LRI.hpp index 405b245e941..e4f8a6dbd02 100644 --- a/source/source_lcao/module_ri/Exx_LRI.hpp +++ b/source/source_lcao/module_ri/Exx_LRI.hpp @@ -190,6 +190,7 @@ void Exx_LRI::cal_exx_ions(const UnitCell& ucell, std::map>> Vs; std::map, Ndim>>> dVs; + const bool cal_dCV = PARAM.inp.cal_force || PARAM.inp.cal_stress || PARAM.inp.out_mat_dh_exx[0]; for(const auto &settings_list : this->coulomb_settings) { std::map>> @@ -225,7 +226,7 @@ void Exx_LRI::cal_exx_ions(const UnitCell& ucell, } Vs = Vs.empty() ? Vs_temp : LRI_CV_Tools::add(Vs, Vs_temp); - if(PARAM.inp.cal_force || PARAM.inp.cal_stress) + if (cal_dCV) { std::map, Ndim>>> dVs_temp = this->exx_objs[settings_list.first].cv.cal_dVs(ucell, @@ -239,7 +240,7 @@ void Exx_LRI::cal_exx_ions(const UnitCell& ucell, { LRI_CV_Tools::write_Vs_abf(Vs, PARAM.globalv.global_out_dir + "Vs"); } this->exx_lri.set_Vs(std::move(Vs), this->info.V_threshold); - if(PARAM.inp.cal_force || PARAM.inp.cal_stress) + if (cal_dCV) { std::array>>, Ndim> dVs_order = LRI_CV_Tools::change_order(std::move(dVs)); @@ -266,13 +267,13 @@ void Exx_LRI::cal_exx_ions(const UnitCell& ucell, Cs_dCs = this->exx_objs[settings_list.first].cv.cal_Cs_dCs( ucell, list_As_Cs.first, list_As_Cs.second[0], - {{"cal_dC",PARAM.inp.cal_force||PARAM.inp.cal_stress}, + { {"cal_dC",cal_dCV}, {"writable_Cws",true}, {"writable_dCws",true}, {"writable_Vws",false}, {"writable_dVws",false}}); std::map>> &Cs_temp = std::get<0>(Cs_dCs); this->exx_objs[settings_list.first].cv.Cws = LRI_CV_Tools::get_CVws(ucell,Cs_temp); Cs = Cs.empty() ? Cs_temp : LRI_CV_Tools::add(Cs, Cs_temp); - if(PARAM.inp.cal_force || PARAM.inp.cal_stress) + if (cal_dCV) { std::map, 3>>> &dCs_temp = std::get<1>(Cs_dCs); this->exx_objs[settings_list.first].cv.dCws = LRI_CV_Tools::get_dCVws(ucell,dCs_temp); @@ -284,7 +285,7 @@ void Exx_LRI::cal_exx_ions(const UnitCell& ucell, { LRI_CV_Tools::write_Cs_ao(Cs, PARAM.globalv.global_out_dir + "Cs"); } this->exx_lri.set_Cs(std::move(Cs), this->info.C_threshold); - if(PARAM.inp.cal_force || PARAM.inp.cal_stress) + if (cal_dCV) { std::array>>, Ndim> dCs_order = LRI_CV_Tools::change_order(std::move(dCs)); @@ -907,6 +908,82 @@ void Exx_LRI::cal_exx_stress(const double& omega, const double& lat0) ModuleBase::timer::end("Exx_LRI", "cal_exx_stress"); } +template +void Exx_LRI::cal_exx_dHs(const std::vector>>>& Ds, + const UnitCell& ucell, + const Parallel_Orbitals& pv) +{ + ModuleBase::TITLE("Exx_LRI", "cal_exx_dHs"); + ModuleBase::timer::start("Exx_LRI", "cal_exx_dHs"); +#ifdef __EXX_DEV + + const std::vector, std::set>> judge = RI_2D_Comm::get_2D_judge(ucell, pv); + + const int nspin = PARAM.inp.nspin; + // dHexxs is indexed [direction(3)][atom][spin]; std::array has no resize(), so size the + // atom/spin dimensions explicitly before filling them below. + for (int ipos = 0; ipos < 3; ++ipos) + { + this->dHexxs[ipos].resize(ucell.nat); + for (int iat = 0; iat < ucell.nat; ++iat) + { + this->dHexxs[ipos][iat].resize(nspin); + } + } + for (int is = 0; is < nspin; ++is) + { + using namespace RI::Map_Operator; + + const std::string suffix = std::to_string(is); // the same as cal_force/cal_stress case + + this->exx_lri.set_Ds(Ds[is], this->info.dm_threshold, suffix); + this->exx_lri.cal_dHs({ "","",suffix,"","" }); // get lri-distributed exx_lri.dHs (all 3 directions) + // postprocess exx_lri.dHs[x/y/z] + for (int ipos = 0; ipos < 3; ++ipos) + { + // 1. Pulay terms: regroup by the differentiated atom: relative row/col [0]/[1] to absolute [0, nat-1] + std::vector>>> dHs_ipos_ispin(ucell.nat); + // dHs[ipos][0]: derivative w.r.t. the first (row) atom -> group by the row atom + for (const auto& item : this->exx_lri.dHs[ipos][0]) + { + const TA iat = item.first; + dHs_ipos_ispin[iat] = dHs_ipos_ispin[iat] + + std::map>>{ item }; + } + // dHs[ipos][1]: derivative w.r.t. the second (col) atom -> group each (col,R) entry by its col atom + for (const auto& row_item : this->exx_lri.dHs[ipos][1]) + { + const TA iat_row = row_item.first; + for (const auto& col_item : row_item.second) + { + const TA iat_col = col_item.first.first; // col atom (TA) of the TAC key + // Accumulate, do NOT drop on key collision: + // when iat_col==iat_row==I, directly insert would make col_item lost. + const auto ins = dHs_ipos_ispin[iat_col][iat_row].insert(col_item); + if (!ins.second) + ins.first->second = ins.first->second + col_item.second; + } + } + // 2. add Hellmann-Feynman terms and convert to 2D-distribution for abacus + for (int iat = 0; iat < ucell.nat; ++iat) + { + dHs_ipos_ispin[iat] = dHs_ipos_ispin[iat] + this->exx_lri.dHs_HF[ipos][iat]; + dHs_ipos_ispin[iat] = RI::Communicate_Tensors_Map_Judge::comm_map2_first( + this->mpi_comm, std::move(dHs_ipos_ispin[iat]), std::get<0>(judge[is]), std::get<1>(judge[is])); + this->dHexxs[ipos][iat][is] = dHs_ipos_ispin[iat]; + // Reuse the same post-processing as the Hexx writer (general nspin=1,2,4 factor) + // -1 factor compared to cal_force (F=-dE/dτ) is already included in LibRI's cal_dHs function. + this->post_process_Hexx(this->dHexxs[ipos][iat][is]); + } + } + } + ModuleBase::timer::end("Exx_LRI", "cal_exx_dHs"); +#else + ModuleBase::WARNING_QUIT("cal_exx_dHs","Compile with the developing version of LibRI and -DEXX_DEV flag to calculate dHexx."); +#endif +} + + /* template std::vector> Exx_LRI::get_abfs_nchis() const diff --git a/source/source_lcao/module_ri/Exx_LRI_interface.h b/source/source_lcao/module_ri/Exx_LRI_interface.h index 55ca9312daf..8aa22f1a461 100644 --- a/source/source_lcao/module_ri/Exx_LRI_interface.h +++ b/source/source_lcao/module_ri/Exx_LRI_interface.h @@ -53,6 +53,11 @@ class Exx_LRI_Interface double &get_Eexx() const { return this->exx_ptr->Eexx; } ModuleBase::matrix &get_force() const { return this->exx_ptr->force_exx; } ModuleBase::matrix &get_stress() const { return this->exx_ptr->stress_exx; } + auto& get_dHexxs() const { return this->exx_ptr->dHexxs; } + int get_two_level_step() const + { + return this->two_level_step; + } // Processes in ESolver_KS_LCAO /// @brief in init: Exx_LRI::init() @@ -76,6 +81,14 @@ class Exx_LRI_Interface /// @brief: in cal_exx_stress: Exx_LRI::cal_exx_stress() void cal_exx_stress(const double& omega, const double& lat0); + /// @brief: in cal_exx_dHs: Exx_LRI::cal_exx_dHs() + void cal_exx_dHs(const std::vector>>>& Ds, + const UnitCell& ucell, + const Parallel_Orbitals& pv); + + /// @brief build the exx-form dH (dHexxs) from the current mixed DM (for dH/dR output) + void cal_exx_dHs(const UnitCell& ucell, const Parallel_Orbitals& pv, const int nspin); + // Processes in ESolver_KS_LCAO /// @brief in before_all_runners: set symmetry according to irreducible k-points /// since k-points are not reduced again after the variation of the cell and exx-symmetry must be consistent with k-points. @@ -117,6 +130,10 @@ class Exx_LRI_Interface const double& etot, const double& scf_ene_thr); + /// @brief the step of the outer loop. + /// nullptr: no dependence on the number of two_level_step, contributeHk will do enerything normally. + /// 0: the first outer loop. If restart, contributeHk will directly add Hexx to Hloc. else, do nothing. + /// >0: not the first outer loop. contributeHk will do enerything normally. int two_level_step = 0; double etot_last_outer_loop = 0.0; elecstate::DensityMatrix* dm_last_step; @@ -136,6 +153,7 @@ class Exx_LRI_Interface bool elec = false; bool force = false; bool stress = false; + bool dHs = false; }; Flag_Finish flag_finish; }; diff --git a/source/source_lcao/module_ri/Exx_LRI_interface.hpp b/source/source_lcao/module_ri/Exx_LRI_interface.hpp index 5272cb7b10b..961dcbae11b 100644 --- a/source/source_lcao/module_ri/Exx_LRI_interface.hpp +++ b/source/source_lcao/module_ri/Exx_LRI_interface.hpp @@ -1,22 +1,21 @@ #ifndef EXX_LRI_INTERFACE_HPP #define EXX_LRI_INTERFACE_HPP -#include "source_io/module_parameter/parameter.h" - #include "Exx_LRI_interface.h" -#include "source_lcao/module_ri/exx_abfs-jle.h" -#include "source_lcao/module_operator_lcao/op_exx_lcao.h" -#include "source_base/parallel_common.h" #include "source_base/formatter.h" - -#include "source_io/module_output/csr_reader.h" -#include "source_io/module_hs/write_HS_sparse.h" +#include "source_base/parallel_common.h" #include "source_estate/elecstate_lcao.h" #include "source_hamilt/module_xc/exx_info.h" // use GlobalC::exx_info +#include "source_hamilt/module_xc/xc_functional.h" +#include "source_io/module_hs/write_HS_sparse.h" +#include "source_io/module_output/csr_reader.h" +#include "source_io/module_parameter/parameter.h" #include "source_io/module_restart/restart.h" +#include "source_lcao/module_operator_lcao/op_exx_lcao.h" +#include "source_lcao/module_ri/exx_abfs-jle.h" -#include #include #include +#include template void Exx_LRI_Interface::init(const MPI_Comm &mpi_comm, @@ -98,6 +97,35 @@ void Exx_LRI_Interface::cal_exx_stress(const double& omega, const doub this->flag_finish.stress = true; } +template +void Exx_LRI_Interface::cal_exx_dHs(const std::vector>>>& Ds, + const UnitCell& ucell, + const Parallel_Orbitals& pv) +{ + ModuleBase::TITLE("Exx_LRI_Interface", "cal_exx_dHs"); + if (!this->flag_finish.init || !this->flag_finish.ions) + { + throw std::runtime_error("Exx init unfinished when " + std::string(__FILE__) + " line " + std::to_string(__LINE__)); + } + + this->exx_ptr->cal_exx_dHs(Ds, ucell, pv); + + this->flag_finish.dHs = true; +} + +template +void Exx_LRI_Interface::cal_exx_dHs(const UnitCell& ucell, + const Parallel_Orbitals& pv, + const int nspin) +{ + // build D(R) from the current mixed D(k) (mirrors the Ds construction in exx_iter_finish) + const std::vector>>> Ds + = PARAM.globalv.gamma_only_local + ? RI_2D_Comm::split_m2D_ktoR(ucell, *this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_gamma_out(), pv, nspin) + : RI_2D_Comm::split_m2D_ktoR(ucell, *this->exx_ptr->p_kv, this->mix_DMk_2D.get_DMk_k_out(), pv, nspin, this->exx_spacegroup_symmetry); + this->cal_exx_dHs(Ds, ucell, pv); +} + template void Exx_LRI_Interface::exx_before_all_runners( const K_Vectors& kv, diff --git a/source/source_lcao/module_ri/RI_2D_Comm.h b/source/source_lcao/module_ri/RI_2D_Comm.h index 001f8969b57..c5f8d5c259e 100644 --- a/source/source_lcao/module_ri/RI_2D_Comm.h +++ b/source/source_lcao/module_ri/RI_2D_Comm.h @@ -105,6 +105,18 @@ extern std::vector>>> split_m2D_kto const double mixing_beta, const std::string mixing_mode); + // DM(R) format conversion: the real-space (DM(R)) counterpart of split_m2D_ktoR, + // and the inverse of add_HexxR. dm_container is DensityMatrix::get_DMR_vector(): + // nspin==1 : size 1 (container 0 -> spin-block 0) + // nspin==2 : size 2 (container is -> spin-block is) + // nspin==4 : size 1 (container 0 holds the 2x2 npol blocks -> spin-blocks 0,1,2,3) + template + extern std::vector>>> dm_container_to_Ds( + const std::vector*>& dm_container, + const UnitCell& ucell, + const Parallel_Orbitals& pv, + const int nspin); + //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 UnitCell& ucell,const int& iwt); diff --git a/source/source_lcao/module_ri/RI_2D_Comm.hpp b/source/source_lcao/module_ri/RI_2D_Comm.hpp index 9d322672375..8fd4d16bfa7 100644 --- a/source/source_lcao/module_ri/RI_2D_Comm.hpp +++ b/source/source_lcao/module_ri/RI_2D_Comm.hpp @@ -490,6 +490,86 @@ void RI_2D_Comm::add_HexxR( ModuleBase::timer::end("RI_2D_Comm", "add_HexxR"); } +// DM(R) format conversion: HContainer -> Ds (atom-pair / cell map). +// This is the real-space (DM(R)) counterpart of split_m2D_ktoR (which converts DM(k)), +// and the inverse of add_HexxR (which converts Ds -> HContainer); it therefore reuses the +// exact same atom/orbital/spin-block index mapping as add_HexxR. +// dm_container is the DM(R) vector returned by DensityMatrix::get_DMR_vector(): +// nspin==1 : size 1 (container 0 -> spin-block 0) +// nspin==2 : size 2 (container is -> spin-block is) +// nspin==4 : size 1 (container 0 holds the 2x2 npol blocks -> spin-blocks 0,1,2,3) +template +auto RI_2D_Comm::dm_container_to_Ds( + const std::vector*>& dm_container, + const UnitCell& ucell, + const Parallel_Orbitals& pv, + const int nspin) +-> std::vector>>> +{ + ModuleBase::TITLE("RI_2D_Comm", "dm_container_to_Ds"); + ModuleBase::timer::start("RI_2D_Comm", "dm_container_to_Ds"); + + const int npol = (nspin == 4) ? 2 : 1; + // same spin prefactor as split_m2D_ktoR: DM(R) carries the full (spin-summed) occupation, + // while Ds is the single-spin-channel density matrix + const double SPIN_multiple = std::map{ {1, 0.5}, {2, 1}, {4, 1} }.at(nspin); + + std::vector>>> Ds(nspin); + + for (int ic = 0; ic < static_cast(dm_container.size()); ++ic) + { + const hamilt::HContainer& dmR = *dm_container[ic]; + // spin-blocks carried by this container (cf. add_HexxR's is_list) + const std::vector is_list = (nspin == 4) + ? std::vector{ 0, 1, 2, 3 } + : std::vector{ ic }; + for (int iap = 0; iap < static_cast(dmR.size_atom_pairs()); ++iap) + { + const hamilt::AtomPair& ap = dmR.get_atom_pair(iap); + const int iat0 = ap.get_atom_i(); + const int iat1 = ap.get_atom_j(); + const int it0 = ucell.iat2it[iat0]; + const int it1 = ucell.iat2it[iat1]; + const std::vector row_indexes = pv.get_indexes_row(iat0); + const std::vector col_indexes = pv.get_indexes_col(iat1); + for (int iR = 0; iR < ap.get_R_size(); ++iR) + { + const ModuleBase::Vector3 R_index = ap.get_R_index(iR); + const TC cell = { R_index.x, R_index.y, R_index.z }; + const hamilt::BaseMatrix* const dm_mat = ap.find_matrix(R_index); + if (dm_mat == nullptr) { continue; } + for (const int is_b : is_list) + { + int is0_b = 0, is1_b = 0; + std::tie(is0_b, is1_b) = RI_2D_Comm::split_is_block(is_b); + RI::Tensor& D = Ds[is_b][iat0][{iat1, cell}]; + if (D.empty()) + { + D = RI::Tensor( + { static_cast(ucell.atoms[it0].nw), + static_cast(ucell.atoms[it1].nw) }); + } + for (int lw0_b = 0; lw0_b < static_cast(row_indexes.size()); lw0_b += npol) + { + const int gw0 = row_indexes[lw0_b] / npol; + const int lw0 = (npol == 2) ? (lw0_b + is0_b) : lw0_b; + for (int lw1_b = 0; lw1_b < static_cast(col_indexes.size()); lw1_b += npol) + { + const int gw1 = col_indexes[lw1_b] / npol; + const int lw1 = (npol == 2) ? (lw1_b + is1_b) : lw1_b; + D(gw0, gw1) = RI::Global_Func::convert( + SPIN_multiple * dm_mat->get_value(lw0, lw1)); + } + } + } + } + } + } + + ModuleBase::timer::end("RI_2D_Comm", "dm_container_to_Ds"); + return Ds; +} + template std::map> RI_2D_Comm::comm_map2_first(const MPI_Comm& mpi_comm, const std::map>& Ds_in, diff --git a/source/source_lcao/setup_exx.cpp b/source/source_lcao/setup_exx.cpp index f552ed06dff..623125d28c9 100644 --- a/source/source_lcao/setup_exx.cpp +++ b/source/source_lcao/setup_exx.cpp @@ -59,6 +59,22 @@ void Exx_NAO::before_runner( } } } + else if (inp.calculation == "nscf" && inp.init_chg == "dm") + { + // init exx integration tables for Cs/Vs, but not use symmetry for nscf + if (GlobalC::exx_info.info_global.cal_exx) + { + if (GlobalC::exx_info.info_ri.real_number) + { + this->exd->init(MPI_COMM_WORLD, ucell, kv, orb); + } + else + { + this->exc->init(MPI_COMM_WORLD, ucell, kv, orb); + } + } + } + #endif } diff --git a/source/source_lcao/spar_dh.cpp b/source/source_lcao/spar_dh.cpp index f1d8900c9b0..4fc011c1199 100644 --- a/source/source_lcao/spar_dh.cpp +++ b/source/source_lcao/spar_dh.cpp @@ -16,7 +16,7 @@ void sparse_format::cal_dS(const UnitCell& ucell, ModuleBase::TITLE("sparse_format", "cal_dS"); sparse_format::set_R_range(HS_Arrays.all_R_coor, grid); -const int nnr = pv.nnr; +const int nnr = PARAM.globalv.gamma_only_local ? pv.nloc : pv.nnr; ForceStressArrays fsr_dh; fsr_dh.DHloc_fixedR_x = new double[nnr]; @@ -64,7 +64,7 @@ void sparse_format::cal_dH(const UnitCell& ucell, sparse_format::set_R_range(HS_Arrays.all_R_coor, grid); - const int nnr = pv.nnr; + const int nnr = PARAM.globalv.gamma_only_local ? pv.nloc : pv.nnr; ForceStressArrays fsr_dh; diff --git a/source/source_pw/module_pwdft/forces.h b/source/source_pw/module_pwdft/forces.h index b71e9c6a385..3a229fc3964 100644 --- a/source/source_pw/module_pwdft/forces.h +++ b/source/source_pw/module_pwdft/forces.h @@ -16,12 +16,17 @@ class pseudopot_cell_vnl; +// forward declaration so that the dH module (out_mat_dh_vl) can reuse cal_force_loc +namespace hamilt { template class Veff; } + template class Forces { public: template friend class Force_Stress_LCAO; + template + friend class hamilt::Veff; /* This routine is a driver routine which compute the forces * acting on the atoms, the complete forces in plane waves * is computed from 4 main parts diff --git a/tests/02_NAO_Gamma/CASES_CPU.txt b/tests/02_NAO_Gamma/CASES_CPU.txt index 662e0e09915..b7313ff1fe6 100644 --- a/tests/02_NAO_Gamma/CASES_CPU.txt +++ b/tests/02_NAO_Gamma/CASES_CPU.txt @@ -27,6 +27,7 @@ scf_out_dm scf_out_hk scf_out_hk_spin2 scf_out_hxc +scf_out_dh scf_out_mul scf_out_mul_spin2 scf_out_wf diff --git a/tests/02_NAO_Gamma/scf_out_dh/INPUT b/tests/02_NAO_Gamma/scf_out_dh/INPUT new file mode 100644 index 00000000000..b496a977b2e --- /dev/null +++ b/tests/02_NAO_Gamma/scf_out_dh/INPUT @@ -0,0 +1,34 @@ +INPUT_PARAMETERS +suffix autotest +calculation scf + +nbands 4 +symmetry 0 +pseudo_dir ../../PP_ORB +orbital_dir ../../PP_ORB +gamma_only 1 + +ecutwfc 20 +scf_thr 1e-5 +scf_nmax 100 + +basis_type lcao +smearing_method gauss +smearing_sigma 0.002 + +mixing_type broyden +mixing_beta 0.7 +mixing_gg0 0 + +ks_solver scalapack_gvx +bx 2 +by 2 +bz 2 + +out_mat_dh 1 8 2 +out_mat_dh_t 1 8 2 +out_mat_dh_vnl 1 8 2 +out_mat_dh_vl 1 8 2 +out_mat_dh_vh 1 8 2 +out_mat_dh_vxc 1 8 2 + diff --git a/tests/02_NAO_Gamma/scf_out_dh/STRU b/tests/02_NAO_Gamma/scf_out_dh/STRU new file mode 100644 index 00000000000..5df0c1da5e0 --- /dev/null +++ b/tests/02_NAO_Gamma/scf_out_dh/STRU @@ -0,0 +1,22 @@ +ATOMIC_SPECIES +H 1.00794 H_ONCV_PBE-1.0.upf upf201 + +NUMERICAL_ORBITAL +H_gga_6au_60Ry_2s1p.orb + +LATTICE_CONSTANT +1.889726 + +LATTICE_VECTORS +20 0 0 +0 20 0 +0 0 20 + +ATOMIC_POSITIONS +Cartesian + +H #label +0 #magnetism +2 #number of atoms +0 0 0 +0 0 0.74 diff --git a/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dhkz_iat2_nao.txt b/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dhkz_iat2_nao.txt new file mode 100644 index 00000000000..5919bafdf7f --- /dev/null +++ b/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dhkz_iat2_nao.txt @@ -0,0 +1,37 @@ +#------------------------------------------------------------------------ +# ionic step 1 +# filename OUT.autotest/dhkz_iat2_nao.txt +# gamma only 0 +# rows 10 +# columns 10 +#------------------------------------------------------------------------ +Row 1 + (-5.53239936e-02,0.00000000e+00) (1.49944506e-01,0.00000000e+00) (3.48565728e-01,0.00000000e+00) (-1.03748456e-14,0.00000000e+00) (9.68059185e-14,0.00000000e+00) (1.08199334e-01,0.00000000e+00) (3.05832028e-01,0.00000000e+00) (2.22097339e-01,0.00000000e+00) + (7.14758943e-15,0.00000000e+00) (7.92413148e-15,0.00000000e+00) +Row 2 + (1.49944506e-01,0.00000000e+00) (-1.58650926e-01,0.00000000e+00) (2.45285064e-01,0.00000000e+00) (-8.94402760e-14,0.00000000e+00) (6.60222258e-14,0.00000000e+00) (3.05877419e-01,0.00000000e+00) (-1.43230862e-01,0.00000000e+00) (9.47655272e-01,0.00000000e+00) + (-5.11568908e-14,0.00000000e+00) (1.21155740e-14,0.00000000e+00) +Row 3 + (3.48565728e-01,0.00000000e+00) (2.45285064e-01,0.00000000e+00) (3.12338838e-01,0.00000000e+00) (-3.75482750e-14,0.00000000e+00) (-5.83576357e-14,0.00000000e+00) (-2.22583656e-01,0.00000000e+00) (-9.47281471e-01,0.00000000e+00) (-4.63163535e-01,0.00000000e+00) + (-1.24428767e-14,0.00000000e+00) (4.83729716e-15,0.00000000e+00) +Row 4 + (-1.04871960e-14,0.00000000e+00) (-8.94229559e-14,0.00000000e+00) (-3.75422035e-14,0.00000000e+00) (-1.32869749e-01,0.00000000e+00) (8.67777842e-14,0.00000000e+00) (6.45889701e-15,0.00000000e+00) (-4.92201993e-14,0.00000000e+00) (2.96255779e-14,0.00000000e+00) + (-1.25906071e+00,0.00000000e+00) (2.88757891e-14,0.00000000e+00) +Row 5 + (9.68106348e-14,0.00000000e+00) (6.60066810e-14,0.00000000e+00) (-5.83593705e-14,0.00000000e+00) (8.67777834e-14,0.00000000e+00) (-1.32869749e-01,0.00000000e+00) (2.65882294e-14,0.00000000e+00) (-1.70006613e-14,0.00000000e+00) (-3.03147811e-14,0.00000000e+00) + (2.88632506e-14,0.00000000e+00) (-1.25906071e+00,0.00000000e+00) +Row 6 + (1.08199334e-01,0.00000000e+00) (3.05877419e-01,0.00000000e+00) (-2.22583656e-01,0.00000000e+00) (6.45889701e-15,0.00000000e+00) (2.65882294e-14,0.00000000e+00) (-5.54332893e-02,0.00000000e+00) (1.50721174e-01,0.00000000e+00) (-3.46868413e-01,0.00000000e+00) + (-1.77005805e-14,0.00000000e+00) (2.36894279e-14,0.00000000e+00) +Row 7 + (3.05832028e-01,0.00000000e+00) (-1.43230862e-01,0.00000000e+00) (-9.47281471e-01,0.00000000e+00) (-4.92201993e-14,0.00000000e+00) (-1.70006613e-14,0.00000000e+00) (1.50721174e-01,0.00000000e+00) (-1.61557136e-01,0.00000000e+00) (-2.48328511e-01,0.00000000e+00) + (-1.13654227e-13,0.00000000e+00) (6.48555768e-14,0.00000000e+00) +Row 8 + (2.22097339e-01,0.00000000e+00) (9.47655272e-01,0.00000000e+00) (-4.63163535e-01,0.00000000e+00) (2.96255779e-14,0.00000000e+00) (-3.03147811e-14,0.00000000e+00) (-3.46868413e-01,0.00000000e+00) (-2.48328511e-01,0.00000000e+00) (3.05196081e-01,0.00000000e+00) + (-2.36668382e-15,0.00000000e+00) (1.32803830e-15,0.00000000e+00) +Row 9 + (7.14758943e-15,0.00000000e+00) (-5.11568908e-14,0.00000000e+00) (-1.24428767e-14,0.00000000e+00) (-1.25906071e+00,0.00000000e+00) (2.88632506e-14,0.00000000e+00) (-1.76795470e-14,0.00000000e+00) (-1.13658618e-13,0.00000000e+00) (-2.34413242e-15,0.00000000e+00) + (-1.40224044e-01,0.00000000e+00) (-2.31370288e-14,0.00000000e+00) +Row 10 + (7.92413148e-15,0.00000000e+00) (1.21155740e-14,0.00000000e+00) (4.83729716e-15,0.00000000e+00) (2.88757891e-14,0.00000000e+00) (-1.25906071e+00,0.00000000e+00) (2.36884522e-14,0.00000000e+00) (6.48587210e-14,0.00000000e+00) (1.31543445e-15,0.00000000e+00) + (-2.31404982e-14,0.00000000e+00) (-1.40224044e-01,0.00000000e+00) diff --git a/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dtkz_iat2_nao.txt b/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dtkz_iat2_nao.txt new file mode 100644 index 00000000000..17c349cbc21 --- /dev/null +++ b/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dtkz_iat2_nao.txt @@ -0,0 +1,37 @@ +#------------------------------------------------------------------------ +# ionic step 1 +# filename OUT.autotest/dtkz_iat2_nao.txt +# gamma only 0 +# rows 10 +# columns 10 +#------------------------------------------------------------------------ +Row 1 + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (-5.35767394e-01,0.00000000e+00) (-6.58867703e-01,0.00000000e+00) (7.99568993e-01,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 2 + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (-6.58867703e-01,0.00000000e+00) (-1.12164140e+00,0.00000000e+00) (1.91616413e+00,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 3 + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (-7.99568993e-01,0.00000000e+00) (-1.91616413e+00,0.00000000e+00) (-1.27732722e+00,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 4 + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) + (-1.87585319e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 5 + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (-1.87585319e+00,0.00000000e+00) +Row 6 + (-5.35767394e-01,0.00000000e+00) (-6.58867703e-01,0.00000000e+00) (-7.99568993e-01,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 7 + (-6.58867703e-01,0.00000000e+00) (-1.12164140e+00,0.00000000e+00) (-1.91616413e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 8 + (7.99568993e-01,0.00000000e+00) (1.91616413e+00,0.00000000e+00) (-1.27732722e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 9 + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (-1.87585319e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 10 + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (-1.87585319e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) diff --git a/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvhkz_iat2_nao.txt b/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvhkz_iat2_nao.txt new file mode 100644 index 00000000000..6e063d3183c --- /dev/null +++ b/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvhkz_iat2_nao.txt @@ -0,0 +1,37 @@ +#------------------------------------------------------------------------ +# ionic step 1 +# filename OUT.autotest/dvhkz_iat2_nao.txt +# gamma only 0 +# rows 10 +# columns 10 +#------------------------------------------------------------------------ +Row 1 + (-8.09803466e-01,0.00000000e+00) (-3.52562171e-01,0.00000000e+00) (-5.67265560e-02,0.00000000e+00) (1.44936655e-16,0.00000000e+00) (3.00544230e-17,0.00000000e+00) (-1.27789525e+00,0.00000000e+00) (-7.05046238e-01,0.00000000e+00) (6.52475503e-01,0.00000000e+00) + (-8.41642165e-16,0.00000000e+00) (-2.40976374e-16,0.00000000e+00) +Row 2 + (-3.52562171e-01,0.00000000e+00) (-5.98769454e-01,0.00000000e+00) (-5.29545246e-02,0.00000000e+00) (2.50755634e-16,0.00000000e+00) (-6.52147607e-17,0.00000000e+00) (-7.05042918e-01,0.00000000e+00) (-1.04119279e+00,0.00000000e+00) (1.19739335e+00,0.00000000e+00) + (1.04807585e-15,0.00000000e+00) (3.45218866e-19,0.00000000e+00) +Row 3 + (-5.67265560e-02,0.00000000e+00) (-5.29545246e-02,0.00000000e+00) (-7.39922971e-01,0.00000000e+00) (-1.51978887e-17,0.00000000e+00) (-1.28727832e-18,0.00000000e+00) (-6.52314825e-01,0.00000000e+00) (-1.19798962e+00,0.00000000e+00) (-1.33667241e+00,0.00000000e+00) + (7.60578941e-17,0.00000000e+00) (9.15448328e-17,0.00000000e+00) +Row 4 + (9.63643973e-17,0.00000000e+00) (2.36879540e-16,0.00000000e+00) (-1.51974651e-17,0.00000000e+00) (-7.52525293e-01,0.00000000e+00) (1.89662853e-17,0.00000000e+00) (7.27456055e-16,0.00000000e+00) (1.11222350e-15,0.00000000e+00) (2.55688542e-17,0.00000000e+00) + (-1.39234564e+00,0.00000000e+00) (4.31402417e-17,0.00000000e+00) +Row 5 + (3.00544230e-17,0.00000000e+00) (-6.52139136e-17,0.00000000e+00) (-1.28727832e-18,0.00000000e+00) (1.89662853e-17,0.00000000e+00) (-7.52525293e-01,0.00000000e+00) (-3.15475601e-16,0.00000000e+00) (1.59251300e-16,0.00000000e+00) (1.33603036e-16,0.00000000e+00) + (3.62014536e-17,0.00000000e+00) (-1.39234564e+00,0.00000000e+00) +Row 6 + (-1.27789525e+00,0.00000000e+00) (-7.05042918e-01,0.00000000e+00) (-6.52314825e-01,0.00000000e+00) (7.27456055e-16,0.00000000e+00) (-3.15475601e-16,0.00000000e+00) (-8.09802902e-01,0.00000000e+00) (-3.52559499e-01,0.00000000e+00) (5.67057894e-02,0.00000000e+00) + (8.97391773e-17,0.00000000e+00) (-7.12832683e-17,0.00000000e+00) +Row 7 + (-7.05046238e-01,0.00000000e+00) (-1.04119279e+00,0.00000000e+00) (-1.19798962e+00,0.00000000e+00) (1.11222350e-15,0.00000000e+00) (1.59251300e-16,0.00000000e+00) (-3.52559499e-01,0.00000000e+00) (-5.98768242e-01,0.00000000e+00) (5.30132510e-02,0.00000000e+00) + (2.32696329e-16,0.00000000e+00) (5.81770486e-17,0.00000000e+00) +Row 8 + (6.52475503e-01,0.00000000e+00) (1.19739335e+00,0.00000000e+00) (-1.33667241e+00,0.00000000e+00) (2.55688542e-17,0.00000000e+00) (1.33603036e-16,0.00000000e+00) (5.67057894e-02,0.00000000e+00) (5.30132510e-02,0.00000000e+00) (-7.39941593e-01,0.00000000e+00) + (1.85771182e-15,0.00000000e+00) (9.62500594e-17,0.00000000e+00) +Row 9 + (-8.41642165e-16,0.00000000e+00) (1.04807585e-15,0.00000000e+00) (7.60578941e-17,0.00000000e+00) (-1.39234564e+00,0.00000000e+00) (3.62014536e-17,0.00000000e+00) (8.28002834e-17,0.00000000e+00) (2.32696329e-16,0.00000000e+00) (1.86811847e-15,0.00000000e+00) + (-7.52526366e-01,0.00000000e+00) (-1.15393972e-16,0.00000000e+00) +Row 10 + (-2.40976374e-16,0.00000000e+00) (3.45218866e-19,0.00000000e+00) (9.15448328e-17,0.00000000e+00) (4.31402417e-17,0.00000000e+00) (-1.39234564e+00,0.00000000e+00) (-7.82763723e-17,0.00000000e+00) (5.82304116e-17,0.00000000e+00) (8.58425656e-17,0.00000000e+00) + (-1.15394395e-16,0.00000000e+00) (-7.52526366e-01,0.00000000e+00) diff --git a/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvlkz_iat2_nao.txt b/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvlkz_iat2_nao.txt new file mode 100644 index 00000000000..390fbbcf1fe --- /dev/null +++ b/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvlkz_iat2_nao.txt @@ -0,0 +1,37 @@ +#------------------------------------------------------------------------ +# ionic step 1 +# filename OUT.autotest/dvlkz_iat2_nao.txt +# gamma only 0 +# rows 10 +# columns 10 +#------------------------------------------------------------------------ +Row 1 + (6.03754626e-01,0.00000000e+00) (4.03189513e-01,0.00000000e+00) (3.22761881e-01,0.00000000e+00) (-9.63901752e-18,0.00000000e+00) (-1.00422371e-17,0.00000000e+00) (1.48514001e+00,0.00000000e+00) (1.27301126e+00,0.00000000e+00) (-9.51549644e-01,0.00000000e+00) + (2.48592257e-16,0.00000000e+00) (-1.70374775e-16,0.00000000e+00) +Row 2 + (4.03189513e-01,0.00000000e+00) (3.70053497e-01,0.00000000e+00) (2.42564683e-01,0.00000000e+00) (-8.14541117e-18,0.00000000e+00) (-7.59066138e-18,0.00000000e+00) (1.27305265e+00,0.00000000e+00) (1.54802029e+00,0.00000000e+00) (-1.66183984e+00,0.00000000e+00) + (7.21925323e-16,0.00000000e+00) (9.11804995e-18,0.00000000e+00) +Row 3 + (3.22761881e-01,0.00000000e+00) (2.42564683e-01,0.00000000e+00) (8.20071779e-01,0.00000000e+00) (-6.33992039e-18,0.00000000e+00) (-6.45757703e-18,0.00000000e+00) (9.51162877e-01,0.00000000e+00) (1.66182802e+00,0.00000000e+00) (1.62268911e+00,0.00000000e+00) + (3.65210379e-16,0.00000000e+00) (-1.92253070e-17,0.00000000e+00) +Row 4 + (-9.63901752e-18,0.00000000e+00) (-8.14541117e-18,0.00000000e+00) (-6.33992039e-18,0.00000000e+00) (4.94169867e-01,0.00000000e+00) (-2.47592199e-18,0.00000000e+00) (-4.49440819e-16,0.00000000e+00) (4.80951783e-16,0.00000000e+00) (-2.03411987e-16,0.00000000e+00) + (1.55875775e+00,0.00000000e+00) (5.65054247e-17,0.00000000e+00) +Row 5 + (-1.00422371e-17,0.00000000e+00) (-7.59066138e-18,0.00000000e+00) (-6.45757703e-18,0.00000000e+00) (-2.47592199e-18,0.00000000e+00) (4.94169867e-01,0.00000000e+00) (-4.82623163e-16,0.00000000e+00) (-3.58631026e-16,0.00000000e+00) (1.98083732e-16,0.00000000e+00) + (5.68011439e-17,0.00000000e+00) (1.55875775e+00,0.00000000e+00) +Row 6 + (1.48514001e+00,0.00000000e+00) (1.27305265e+00,0.00000000e+00) (9.51162877e-01,0.00000000e+00) (-4.49440819e-16,0.00000000e+00) (-4.82623163e-16,0.00000000e+00) (6.03844409e-01,0.00000000e+00) (4.03355505e-01,0.00000000e+00) (-3.22147586e-01,0.00000000e+00) + (-9.14447091e-16,0.00000000e+00) (-1.20174341e-16,0.00000000e+00) +Row 7 + (1.27301126e+00,0.00000000e+00) (1.54802029e+00,0.00000000e+00) (1.66182802e+00,0.00000000e+00) (4.80951783e-16,0.00000000e+00) (-3.58631026e-16,0.00000000e+00) (4.03355505e-01,0.00000000e+00) (3.70384008e-01,0.00000000e+00) (-2.41410143e-01,0.00000000e+00) + (6.76544813e-17,0.00000000e+00) (-4.65004301e-17,0.00000000e+00) +Row 8 + (-9.51549644e-01,0.00000000e+00) (-1.66183984e+00,0.00000000e+00) (1.62268911e+00,0.00000000e+00) (-2.03411987e-16,0.00000000e+00) (1.98083732e-16,0.00000000e+00) (-3.22147586e-01,0.00000000e+00) (-2.41410143e-01,0.00000000e+00) (8.19267897e-01,0.00000000e+00) + (3.06359408e-16,0.00000000e+00) (-4.60377909e-16,0.00000000e+00) +Row 9 + (2.48592257e-16,0.00000000e+00) (7.21925323e-16,0.00000000e+00) (3.65210379e-16,0.00000000e+00) (1.55875775e+00,0.00000000e+00) (5.68011439e-17,0.00000000e+00) (-9.14447091e-16,0.00000000e+00) (6.76544813e-17,0.00000000e+00) (3.06359408e-16,0.00000000e+00) + (4.94211725e-01,0.00000000e+00) (-9.04548285e-17,0.00000000e+00) +Row 10 + (-1.70374775e-16,0.00000000e+00) (9.11804995e-18,0.00000000e+00) (-1.92253070e-17,0.00000000e+00) (5.65054247e-17,0.00000000e+00) (1.55875775e+00,0.00000000e+00) (-1.20174341e-16,0.00000000e+00) (-4.65004301e-17,0.00000000e+00) (-4.60377909e-16,0.00000000e+00) + (-9.04548285e-17,0.00000000e+00) (4.94211725e-01,0.00000000e+00) diff --git a/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvnlkz_iat2_nao.txt b/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvnlkz_iat2_nao.txt new file mode 100644 index 00000000000..cb09923c1fe --- /dev/null +++ b/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvnlkz_iat2_nao.txt @@ -0,0 +1,37 @@ +#------------------------------------------------------------------------ +# ionic step 1 +# filename OUT.autotest/dvnlkz_iat2_nao.txt +# gamma only 0 +# rows 10 +# columns 10 +#------------------------------------------------------------------------ +Row 1 + (1.92878931e-02,0.00000000e+00) (1.13147191e-02,0.00000000e+00) (4.28327385e-02,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (6.37879670e-02,0.00000000e+00) (7.89171042e-02,0.00000000e+00) (-8.20063413e-02,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 2 + (1.13147191e-02,0.00000000e+00) (-1.83454509e-03,0.00000000e+00) (2.18777381e-02,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (7.89171042e-02,0.00000000e+00) (9.76602990e-02,0.00000000e+00) (-1.02993153e-01,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 3 + (4.28327385e-02,0.00000000e+00) (2.18777381e-02,0.00000000e+00) (9.56644563e-02,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (8.20063413e-02,0.00000000e+00) (1.02993153e-01,0.00000000e+00) (0.00000000e+00,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 4 + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 5 + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 6 + (6.37879670e-02,0.00000000e+00) (7.89171042e-02,0.00000000e+00) (8.20063413e-02,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (1.92878931e-02,0.00000000e+00) (1.13147191e-02,0.00000000e+00) (-4.28327385e-02,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 7 + (7.89171042e-02,0.00000000e+00) (9.76602990e-02,0.00000000e+00) (1.02993153e-01,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (1.13147191e-02,0.00000000e+00) (-1.83454509e-03,0.00000000e+00) (-2.18777381e-02,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 8 + (-8.20063413e-02,0.00000000e+00) (-1.02993153e-01,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (-4.28327385e-02,0.00000000e+00) (-2.18777381e-02,0.00000000e+00) (9.56644563e-02,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 9 + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) +Row 10 + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) + (0.00000000e+00,0.00000000e+00) (0.00000000e+00,0.00000000e+00) diff --git a/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvxckz_iat2_nao.txt b/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvxckz_iat2_nao.txt new file mode 100644 index 00000000000..b7785784c23 --- /dev/null +++ b/tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvxckz_iat2_nao.txt @@ -0,0 +1,37 @@ +#------------------------------------------------------------------------ +# ionic step 1 +# filename OUT.autotest/dvxckz_iat2_nao.txt +# gamma only 0 +# rows 10 +# columns 10 +#------------------------------------------------------------------------ +Row 1 + (1.31436954e-01,0.00000000e+00) (8.80024452e-02,0.00000000e+00) (3.96976644e-02,0.00000000e+00) (-1.04521339e-14,0.00000000e+00) (9.67646600e-14,0.00000000e+00) (3.72934005e-01,0.00000000e+00) (3.17817605e-01,0.00000000e+00) (-1.96391171e-01,0.00000000e+00) + (7.59294673e-15,0.00000000e+00) (8.33325498e-15,0.00000000e+00) +Row 2 + (8.80024452e-02,0.00000000e+00) (7.18995755e-02,0.00000000e+00) (3.37971674e-02,0.00000000e+00) (-8.96187917e-14,0.00000000e+00) (6.60742059e-14,0.00000000e+00) (3.17818283e-01,0.00000000e+00) (3.73922747e-01,0.00000000e+00) (-4.01069217e-01,0.00000000e+00) + (-5.30519162e-14,0.00000000e+00) (1.20989238e-14,0.00000000e+00) +Row 3 + (3.96976644e-02,0.00000000e+00) (3.37971674e-02,0.00000000e+00) (1.36525573e-01,0.00000000e+00) (-3.75296984e-14,0.00000000e+00) (-5.83383333e-14,0.00000000e+00) (1.96130944e-01,0.00000000e+00) (4.02051112e-01,0.00000000e+00) (5.28146983e-01,0.00000000e+00) + (-1.31240410e-14,0.00000000e+00) (4.83568124e-15,0.00000000e+00) +Row 4 + (-1.04746853e-14,0.00000000e+00) (-8.96187917e-14,0.00000000e+00) (-3.75305658e-14,0.00000000e+00) (1.25485678e-01,0.00000000e+00) (8.67285163e-14,0.00000000e+00) (6.05907612e-15,0.00000000e+00) (-5.09040255e-14,0.00000000e+00) (2.97094970e-14,0.00000000e+00) + (4.50380361e-01,0.00000000e+00) (2.86731204e-14,0.00000000e+00) +Row 5 + (9.67694305e-14,0.00000000e+00) (6.60655323e-14,0.00000000e+00) (-5.83478743e-14,0.00000000e+00) (8.67198427e-14,0.00000000e+00) (1.25485678e-01,0.00000000e+00) (2.73628420e-14,0.00000000e+00) (-1.66664778e-14,0.00000000e+00) (-3.07102502e-14,0.00000000e+00) + (2.86756137e-14,0.00000000e+00) (4.50380361e-01,0.00000000e+00) +Row 6 + (3.72934005e-01,0.00000000e+00) (3.17818283e-01,0.00000000e+00) (1.96130944e-01,0.00000000e+00) (6.05907612e-15,0.00000000e+00) (2.73628420e-14,0.00000000e+00) (1.31237310e-01,0.00000000e+00) (8.86104491e-02,0.00000000e+00) (-3.85938779e-02,0.00000000e+00) + (-1.69809821e-14,0.00000000e+00) (2.38505835e-14,0.00000000e+00) +Row 7 + (3.17817605e-01,0.00000000e+00) (3.73922747e-01,0.00000000e+00) (4.02051112e-01,0.00000000e+00) (-5.09040255e-14,0.00000000e+00) (-1.66664778e-14,0.00000000e+00) (8.86104491e-02,0.00000000e+00) (6.86616431e-02,0.00000000e+00) (-3.80538803e-02,0.00000000e+00) + (-1.14021153e-13,0.00000000e+00) (6.48015052e-14,0.00000000e+00) +Row 8 + (-1.96391171e-01,0.00000000e+00) (-4.01069217e-01,0.00000000e+00) (5.28146983e-01,0.00000000e+00) (2.97094970e-14,0.00000000e+00) (-3.07102502e-14,0.00000000e+00) (-3.85938779e-02,0.00000000e+00) (-3.80538803e-02,0.00000000e+00) (1.30205320e-01,0.00000000e+00) + (-4.12771764e-15,0.00000000e+00) (1.52752355e-15,0.00000000e+00) +Row 9 + (7.59294673e-15,0.00000000e+00) (-5.30519162e-14,0.00000000e+00) (-1.31240410e-14,0.00000000e+00) (4.50380361e-01,0.00000000e+00) (2.86756137e-14,0.00000000e+00) (-1.69706822e-14,0.00000000e+00) (-1.14021587e-13,0.00000000e+00) (-4.14245601e-15,0.00000000e+00) + (1.18090597e-01,0.00000000e+00) (-2.30634479e-14,0.00000000e+00) +Row 10 + (8.33325498e-15,0.00000000e+00) (1.20989238e-14,0.00000000e+00) (4.83568124e-15,0.00000000e+00) (2.86731204e-14,0.00000000e+00) (4.50380361e-01,0.00000000e+00) (2.38393069e-14,0.00000000e+00) (6.47939157e-14,0.00000000e+00) (1.53318850e-15,0.00000000e+00) + (-2.30627973e-14,0.00000000e+00) (1.18090597e-01,0.00000000e+00) diff --git a/tests/02_NAO_Gamma/scf_out_dh/result.ref b/tests/02_NAO_Gamma/scf_out_dh/result.ref new file mode 100644 index 00000000000..52631e61b51 --- /dev/null +++ b/tests/02_NAO_Gamma/scf_out_dh/result.ref @@ -0,0 +1,8 @@ +etotref -31.60025033377112 +etotperatomref -15.8001251669 +Compare_dhkz_iat2_nao_pass 0 +Compare_dtkz_iat2_nao_pass 0 +Compare_dvhkz_iat2_nao_pass 0 +Compare_dvlkz_iat2_nao_pass 0 +Compare_dvnlkz_iat2_nao_pass 0 +Compare_dvxckz_iat2_nao_pass 0 diff --git a/tests/03_NAO_multik/scf_in_dmr_GaAs/result.ref b/tests/03_NAO_multik/scf_in_dmr_GaAs/result.ref index 59b71894975..89671237c8b 100644 --- a/tests/03_NAO_multik/scf_in_dmr_GaAs/result.ref +++ b/tests/03_NAO_multik/scf_in_dmr_GaAs/result.ref @@ -1,5 +1,5 @@ -etotref -5069.1660720303607377 -etotperatomref -2534.5830360152 -totalforceref 89.291634 -totalstressref 2011.565088 +etotref -5069.1660719143756069 +etotperatomref -2534.5830359572 +totalforceref 89.291628 +totalstressref 2011.565086 totaltimeref 0.33 diff --git a/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkx_iat1_ik0_nao.txt b/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkx_iat1_ik0_nao.txt new file mode 100644 index 00000000000..842c77f3406 --- /dev/null +++ b/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkx_iat1_ik0_nao.txt @@ -0,0 +1,46 @@ +#------------------------------------------------------------------------ +# ionic step 1 +# filename OUT.autotest/dhkx_iat1_ik0_nao.txt +# gamma only 0 +# rows 13 +# columns 13 +#------------------------------------------------------------------------ +Row 1 + (-2.12008022e-05,0.00000000e+00) (6.78611551e-05,0.00000000e+00) (4.96686906e-14,0.00000000e+00) (1.72417113e-03,0.00000000e+00) (-1.97083544e-14,0.00000000e+00) (2.94984166e-14,0.00000000e+00) (2.75880257e-03,0.00000000e+00) (-1.28997390e-14,0.00000000e+00) + (1.56194509e-05,0.00000000e+00) (4.13844113e-14,0.00000000e+00) (2.92166028e-14,0.00000000e+00) (-2.70536825e-05,0.00000000e+00) (-1.08423632e-14,0.00000000e+00) +Row 2 + (6.78611551e-05,0.00000000e+00) (-5.57970727e-04,0.00000000e+00) (3.03879992e-14,0.00000000e+00) (3.23767801e-03,0.00000000e+00) (-1.97488000e-14,0.00000000e+00) (6.24318868e-15,0.00000000e+00) (-6.42813142e-03,0.00000000e+00) (-1.35210417e-16,0.00000000e+00) + (-7.85946556e-05,0.00000000e+00) (2.26379384e-14,0.00000000e+00) (1.34189581e-14,0.00000000e+00) (1.36129937e-04,0.00000000e+00) (2.07018557e-14,0.00000000e+00) +Row 3 + (4.96566043e-14,0.00000000e+00) (3.03992749e-14,0.00000000e+00) (-2.79235818e-05,0.00000000e+00) (2.70041058e-14,0.00000000e+00) (2.90552250e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (1.18389311e-14,0.00000000e+00) (2.15549830e-14,0.00000000e+00) + (5.32819412e-14,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) (-1.93364216e-14,0.00000000e+00) (-1.90133199e-15,0.00000000e+00) (-1.91402601e-14,0.00000000e+00) +Row 4 + (1.72417113e-03,0.00000000e+00) (3.23767801e-03,0.00000000e+00) (2.70041058e-14,0.00000000e+00) (-9.27107580e-05,0.00000000e+00) (-1.08810586e-14,0.00000000e+00) (1.11024313e-14,0.00000000e+00) (3.01690807e-04,0.00000000e+00) (1.03116660e-14,0.00000000e+00) + (-1.75478128e-03,0.00000000e+00) (1.45046845e-14,0.00000000e+00) (-1.89273686e-14,0.00000000e+00) (3.03937033e-03,0.00000000e+00) (-3.96172199e-14,0.00000000e+00) +Row 5 + (-1.97135592e-14,0.00000000e+00) (-1.97340244e-14,0.00000000e+00) (2.90552256e-14,0.00000000e+00) (-1.08810582e-14,0.00000000e+00) (-2.79235818e-05,0.00000000e+00) (2.15843904e-14,0.00000000e+00) (8.86989396e-15,0.00000000e+00) (1.10978663e-04,0.00000000e+00) + (2.39079905e-15,0.00000000e+00) (-1.91274800e-14,0.00000000e+00) (1.86066645e-14,0.00000000e+00) (-1.31885922e-14,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) +Row 6 + (2.94923434e-14,0.00000000e+00) (6.24430672e-15,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (1.10990169e-14,0.00000000e+00) (2.15822220e-14,0.00000000e+00) (-3.72087074e-04,0.00000000e+00) (-3.68270065e-15,0.00000000e+00) (2.52144049e-14,0.00000000e+00) + (4.35662689e-14,0.00000000e+00) (1.05517226e-03,0.00000000e+00) (-4.39291373e-14,0.00000000e+00) (-9.61206397e-15,0.00000000e+00) (-2.35764729e-15,0.00000000e+00) +Row 7 + (2.75880257e-03,0.00000000e+00) (-6.42813142e-03,0.00000000e+00) (1.18407221e-14,0.00000000e+00) (3.01690807e-04,0.00000000e+00) (8.88247049e-15,0.00000000e+00) (-3.68140468e-15,0.00000000e+00) (-1.08973807e-03,0.00000000e+00) (-4.02981610e-14,0.00000000e+00) + (-2.95724945e-03,0.00000000e+00) (-8.19745419e-15,0.00000000e+00) (-2.46725136e-15,0.00000000e+00) (5.12210629e-03,0.00000000e+00) (1.50447246e-14,0.00000000e+00) +Row 8 + (-1.29006066e-14,0.00000000e+00) (-1.43020893e-16,0.00000000e+00) (2.15443866e-14,0.00000000e+00) (1.03259767e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (2.52163598e-14,0.00000000e+00) (-4.02929576e-14,0.00000000e+00) (-3.72087074e-04,0.00000000e+00) + (-1.94635131e-14,0.00000000e+00) (-2.53863341e-15,0.00000000e+00) (1.10467874e-14,0.00000000e+00) (2.53053110e-14,0.00000000e+00) (1.05517226e-03,0.00000000e+00) +Row 9 + (1.56194509e-05,0.00000000e+00) (-7.85946556e-05,0.00000000e+00) (5.32805318e-14,0.00000000e+00) (-1.75478128e-03,0.00000000e+00) (2.39036537e-15,0.00000000e+00) (4.35666822e-14,0.00000000e+00) (-2.95724945e-03,0.00000000e+00) (-1.94641637e-14,0.00000000e+00) + (-4.65206284e-05,0.00000000e+00) (-1.85562028e-15,0.00000000e+00) (-2.31042831e-15,0.00000000e+00) (3.68908596e-05,0.00000000e+00) (-3.96529441e-15,0.00000000e+00) +Row 10 + (4.13740013e-14,0.00000000e+00) (2.26379452e-14,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) (1.45046843e-14,0.00000000e+00) (-1.91240387e-14,0.00000000e+00) (1.05517226e-03,0.00000000e+00) (-8.21217637e-15,0.00000000e+00) (-2.53473134e-15,0.00000000e+00) + (-1.86544543e-15,0.00000000e+00) (-9.79208642e-05,0.00000000e+00) (-3.05054256e-14,0.00000000e+00) (2.46416004e-14,0.00000000e+00) (1.59961094e-14,0.00000000e+00) +Row 11 + (2.92131581e-14,0.00000000e+00) (1.34155454e-14,0.00000000e+00) (-1.93424957e-14,0.00000000e+00) (-1.89273827e-14,0.00000000e+00) (1.86075189e-14,0.00000000e+00) (-4.39291271e-14,0.00000000e+00) (-2.46811745e-15,0.00000000e+00) (1.10489562e-14,0.00000000e+00) + (-2.31030973e-15,0.00000000e+00) (-3.04880788e-14,0.00000000e+00) (-3.88951514e-05,0.00000000e+00) (-1.18667053e-14,0.00000000e+00) (2.34828500e-14,0.00000000e+00) +Row 12 + (-2.70536825e-05,0.00000000e+00) (1.36129937e-04,0.00000000e+00) (-1.90783329e-15,0.00000000e+00) (3.03937033e-03,0.00000000e+00) (-1.31913202e-14,0.00000000e+00) (-9.60587936e-15,0.00000000e+00) (5.12210629e-03,0.00000000e+00) (2.53089244e-14,0.00000000e+00) + (3.68908596e-05,0.00000000e+00) (2.46324998e-14,0.00000000e+00) (-1.18609290e-14,0.00000000e+00) (-8.91185238e-05,0.00000000e+00) (-2.12390877e-14,0.00000000e+00) +Row 13 + (-1.08527854e-14,0.00000000e+00) (2.07296360e-14,0.00000000e+00) (-1.91376606e-14,0.00000000e+00) (-3.96432406e-14,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) (-2.35501641e-15,0.00000000e+00) (1.50230338e-14,0.00000000e+00) (1.05517226e-03,0.00000000e+00) + (-3.96567366e-15,0.00000000e+00) (1.59770271e-14,0.00000000e+00) (2.34845854e-14,0.00000000e+00) (-2.12319325e-14,0.00000000e+00) (-9.79208642e-05,0.00000000e+00) diff --git a/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkx_iat1_ik1_nao.txt b/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkx_iat1_ik1_nao.txt new file mode 100644 index 00000000000..48c64df8e16 --- /dev/null +++ b/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkx_iat1_ik1_nao.txt @@ -0,0 +1,46 @@ +#------------------------------------------------------------------------ +# ionic step 1 +# filename OUT.autotest/dhkx_iat1_ik1_nao.txt +# gamma only 0 +# rows 13 +# columns 13 +#------------------------------------------------------------------------ +Row 1 + (-2.12008022e-05,0.00000000e+00) (6.78611551e-05,0.00000000e+00) (4.96686906e-14,0.00000000e+00) (1.72417113e-03,0.00000000e+00) (-1.97083544e-14,0.00000000e+00) (2.94984166e-14,0.00000000e+00) (2.75880257e-03,0.00000000e+00) (-1.28997390e-14,0.00000000e+00) + (1.56194509e-05,0.00000000e+00) (4.13844113e-14,0.00000000e+00) (2.92166028e-14,0.00000000e+00) (-2.70536825e-05,0.00000000e+00) (-1.08423632e-14,0.00000000e+00) +Row 2 + (6.78611551e-05,0.00000000e+00) (-5.57970727e-04,0.00000000e+00) (3.03879992e-14,0.00000000e+00) (3.23767801e-03,0.00000000e+00) (-1.97488000e-14,0.00000000e+00) (6.24318868e-15,0.00000000e+00) (-6.42813142e-03,0.00000000e+00) (-1.35210417e-16,0.00000000e+00) + (-7.85946556e-05,0.00000000e+00) (2.26379384e-14,0.00000000e+00) (1.34189581e-14,0.00000000e+00) (1.36129937e-04,0.00000000e+00) (2.07018557e-14,0.00000000e+00) +Row 3 + (4.96566043e-14,0.00000000e+00) (3.03992749e-14,0.00000000e+00) (-2.79235818e-05,0.00000000e+00) (2.70041058e-14,0.00000000e+00) (2.90552250e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (1.18389311e-14,0.00000000e+00) (2.15549830e-14,0.00000000e+00) + (5.32819412e-14,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) (-1.93364216e-14,0.00000000e+00) (-1.90133199e-15,0.00000000e+00) (-1.91402601e-14,0.00000000e+00) +Row 4 + (1.72417113e-03,0.00000000e+00) (3.23767801e-03,0.00000000e+00) (2.70041058e-14,0.00000000e+00) (-9.27107580e-05,0.00000000e+00) (-1.08810586e-14,0.00000000e+00) (1.11024313e-14,0.00000000e+00) (3.01690807e-04,0.00000000e+00) (1.03116660e-14,0.00000000e+00) + (-1.75478128e-03,0.00000000e+00) (1.45046845e-14,0.00000000e+00) (-1.89273686e-14,0.00000000e+00) (3.03937033e-03,0.00000000e+00) (-3.96172199e-14,0.00000000e+00) +Row 5 + (-1.97135592e-14,0.00000000e+00) (-1.97340244e-14,0.00000000e+00) (2.90552256e-14,0.00000000e+00) (-1.08810582e-14,0.00000000e+00) (-2.79235818e-05,0.00000000e+00) (2.15843904e-14,0.00000000e+00) (8.86989396e-15,0.00000000e+00) (1.10978663e-04,0.00000000e+00) + (2.39079905e-15,0.00000000e+00) (-1.91274800e-14,0.00000000e+00) (1.86066645e-14,0.00000000e+00) (-1.31885922e-14,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) +Row 6 + (2.94923434e-14,0.00000000e+00) (6.24430672e-15,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (1.10990169e-14,0.00000000e+00) (2.15822220e-14,0.00000000e+00) (-3.72087074e-04,0.00000000e+00) (-3.68270065e-15,0.00000000e+00) (2.52144049e-14,0.00000000e+00) + (4.35662689e-14,0.00000000e+00) (1.05517226e-03,0.00000000e+00) (-4.39291373e-14,0.00000000e+00) (-9.61206397e-15,0.00000000e+00) (-2.35764729e-15,0.00000000e+00) +Row 7 + (2.75880257e-03,0.00000000e+00) (-6.42813142e-03,0.00000000e+00) (1.18407221e-14,0.00000000e+00) (3.01690807e-04,0.00000000e+00) (8.88247049e-15,0.00000000e+00) (-3.68140468e-15,0.00000000e+00) (-1.08973807e-03,0.00000000e+00) (-4.02981610e-14,0.00000000e+00) + (-2.95724945e-03,0.00000000e+00) (-8.19745419e-15,0.00000000e+00) (-2.46725136e-15,0.00000000e+00) (5.12210629e-03,0.00000000e+00) (1.50447246e-14,0.00000000e+00) +Row 8 + (-1.29006066e-14,0.00000000e+00) (-1.43020893e-16,0.00000000e+00) (2.15443866e-14,0.00000000e+00) (1.03259767e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (2.52163598e-14,0.00000000e+00) (-4.02929576e-14,0.00000000e+00) (-3.72087074e-04,0.00000000e+00) + (-1.94635131e-14,0.00000000e+00) (-2.53863341e-15,0.00000000e+00) (1.10467874e-14,0.00000000e+00) (2.53053110e-14,0.00000000e+00) (1.05517226e-03,0.00000000e+00) +Row 9 + (1.56194509e-05,0.00000000e+00) (-7.85946556e-05,0.00000000e+00) (5.32805318e-14,0.00000000e+00) (-1.75478128e-03,0.00000000e+00) (2.39036537e-15,0.00000000e+00) (4.35666822e-14,0.00000000e+00) (-2.95724945e-03,0.00000000e+00) (-1.94641637e-14,0.00000000e+00) + (-4.65206284e-05,0.00000000e+00) (-1.85562028e-15,0.00000000e+00) (-2.31042831e-15,0.00000000e+00) (3.68908596e-05,0.00000000e+00) (-3.96529441e-15,0.00000000e+00) +Row 10 + (4.13740013e-14,0.00000000e+00) (2.26379452e-14,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) (1.45046843e-14,0.00000000e+00) (-1.91240387e-14,0.00000000e+00) (1.05517226e-03,0.00000000e+00) (-8.21217637e-15,0.00000000e+00) (-2.53473134e-15,0.00000000e+00) + (-1.86544543e-15,0.00000000e+00) (-9.79208642e-05,0.00000000e+00) (-3.05054256e-14,0.00000000e+00) (2.46416004e-14,0.00000000e+00) (1.59961094e-14,0.00000000e+00) +Row 11 + (2.92131581e-14,0.00000000e+00) (1.34155454e-14,0.00000000e+00) (-1.93424957e-14,0.00000000e+00) (-1.89273827e-14,0.00000000e+00) (1.86075189e-14,0.00000000e+00) (-4.39291271e-14,0.00000000e+00) (-2.46811745e-15,0.00000000e+00) (1.10489562e-14,0.00000000e+00) + (-2.31030973e-15,0.00000000e+00) (-3.04880788e-14,0.00000000e+00) (-3.88951514e-05,0.00000000e+00) (-1.18667053e-14,0.00000000e+00) (2.34828500e-14,0.00000000e+00) +Row 12 + (-2.70536825e-05,0.00000000e+00) (1.36129937e-04,0.00000000e+00) (-1.90783329e-15,0.00000000e+00) (3.03937033e-03,0.00000000e+00) (-1.31913202e-14,0.00000000e+00) (-9.60587936e-15,0.00000000e+00) (5.12210629e-03,0.00000000e+00) (2.53089244e-14,0.00000000e+00) + (3.68908596e-05,0.00000000e+00) (2.46324998e-14,0.00000000e+00) (-1.18609290e-14,0.00000000e+00) (-8.91185238e-05,0.00000000e+00) (-2.12390877e-14,0.00000000e+00) +Row 13 + (-1.08527854e-14,0.00000000e+00) (2.07296360e-14,0.00000000e+00) (-1.91376606e-14,0.00000000e+00) (-3.96432406e-14,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) (-2.35501641e-15,0.00000000e+00) (1.50230338e-14,0.00000000e+00) (1.05517226e-03,0.00000000e+00) + (-3.96567366e-15,0.00000000e+00) (1.59770271e-14,0.00000000e+00) (2.34845854e-14,0.00000000e+00) (-2.12319325e-14,0.00000000e+00) (-9.79208642e-05,0.00000000e+00) diff --git a/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhky_iat1_ik0_nao.txt b/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhky_iat1_ik0_nao.txt new file mode 100644 index 00000000000..fc70c1e73e4 --- /dev/null +++ b/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhky_iat1_ik0_nao.txt @@ -0,0 +1,46 @@ +#------------------------------------------------------------------------ +# ionic step 1 +# filename OUT.autotest/dhky_iat1_ik0_nao.txt +# gamma only 0 +# rows 13 +# columns 13 +#------------------------------------------------------------------------ +Row 1 + (-2.12008021e-05,0.00000000e+00) (6.78611552e-05,0.00000000e+00) (-2.25914027e-14,0.00000000e+00) (4.28045398e-14,0.00000000e+00) (1.72417113e-03,0.00000000e+00) (-3.58867067e-14,0.00000000e+00) (1.78678312e-14,0.00000000e+00) (2.75880257e-03,0.00000000e+00) + (1.56194509e-05,0.00000000e+00) (2.13742110e-14,0.00000000e+00) (2.62503271e-14,0.00000000e+00) (2.70536825e-05,0.00000000e+00) (-2.33338772e-14,0.00000000e+00) +Row 2 + (6.78611552e-05,0.00000000e+00) (-5.57970727e-04,0.00000000e+00) (-3.75953750e-14,0.00000000e+00) (3.78058862e-14,0.00000000e+00) (3.23767801e-03,0.00000000e+00) (-1.22002405e-14,0.00000000e+00) (-9.93106222e-15,0.00000000e+00) (-6.42813142e-03,0.00000000e+00) + (-7.85946556e-05,0.00000000e+00) (1.81086119e-14,0.00000000e+00) (4.94058446e-15,0.00000000e+00) (-1.36129937e-04,0.00000000e+00) (4.31702696e-15,0.00000000e+00) +Row 3 + (-2.25974742e-14,0.00000000e+00) (-3.75832162e-14,0.00000000e+00) (-2.79235817e-05,0.00000000e+00) (2.23885912e-14,0.00000000e+00) (2.75004220e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (2.04581902e-14,0.00000000e+00) (1.43068938e-14,0.00000000e+00) + (6.41824603e-14,0.00000000e+00) (5.01453571e-14,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) (-4.12835846e-14,0.00000000e+00) (-9.87784677e-15,0.00000000e+00) +Row 4 + (4.27993628e-14,0.00000000e+00) (3.77979172e-14,0.00000000e+00) (2.23878323e-14,0.00000000e+00) (-2.79235817e-05,0.00000000e+00) (-5.15163485e-14,0.00000000e+00) (2.05290058e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (-3.53274126e-14,0.00000000e+00) + (-3.51995489e-15,0.00000000e+00) (-1.01853314e-13,0.00000000e+00) (-9.83736988e-15,0.00000000e+00) (6.53093434e-14,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) +Row 5 + (1.72417113e-03,0.00000000e+00) (3.23767801e-03,0.00000000e+00) (2.74901220e-14,0.00000000e+00) (-5.15146138e-14,0.00000000e+00) (-9.27107579e-05,0.00000000e+00) (1.44913170e-14,0.00000000e+00) (-4.37091469e-14,0.00000000e+00) (3.01690807e-04,0.00000000e+00) + (-1.75478128e-03,0.00000000e+00) (-9.71548483e-15,0.00000000e+00) (-1.97363642e-14,0.00000000e+00) (-3.03937033e-03,0.00000000e+00) (-8.37477618e-15,0.00000000e+00) +Row 6 + (-3.58846468e-14,0.00000000e+00) (-1.21943862e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (2.05271624e-14,0.00000000e+00) (1.44983640e-14,0.00000000e+00) (-3.72087074e-04,0.00000000e+00) (1.12450906e-14,0.00000000e+00) (2.57539590e-14,0.00000000e+00) + (6.28431324e-15,0.00000000e+00) (1.10256469e-14,0.00000000e+00) (1.05517226e-03,0.00000000e+00) (-1.58304490e-14,0.00000000e+00) (5.97553910e-16,0.00000000e+00) +Row 7 + (1.78899489e-14,0.00000000e+00) (-9.92564110e-15,0.00000000e+00) (2.04601148e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (-4.37057859e-14,0.00000000e+00) (1.12398051e-14,0.00000000e+00) (-3.72087074e-04,0.00000000e+00) (-7.96420638e-14,0.00000000e+00) + (-2.26020365e-14,0.00000000e+00) (-7.07654505e-14,0.00000000e+00) (4.92871110e-16,0.00000000e+00) (5.76126160e-14,0.00000000e+00) (1.05517226e-03,0.00000000e+00) +Row 8 + (2.75880257e-03,0.00000000e+00) (-6.42813142e-03,0.00000000e+00) (1.43104722e-14,0.00000000e+00) (-3.53098486e-14,0.00000000e+00) (3.01690807e-04,0.00000000e+00) (2.57575907e-14,0.00000000e+00) (-7.96415217e-14,0.00000000e+00) (-1.08973807e-03,0.00000000e+00) + (-2.95724945e-03,0.00000000e+00) (8.10518764e-16,0.00000000e+00) (-3.92318646e-14,0.00000000e+00) (-5.12210629e-03,0.00000000e+00) (-9.11681734e-15,0.00000000e+00) +Row 9 + (1.56194509e-05,0.00000000e+00) (-7.85946556e-05,0.00000000e+00) (6.41811862e-14,0.00000000e+00) (-3.52515902e-15,0.00000000e+00) (-1.75478128e-03,0.00000000e+00) (6.28263103e-15,0.00000000e+00) (-2.26004914e-14,0.00000000e+00) (-2.95724945e-03,0.00000000e+00) + (-4.65206284e-05,0.00000000e+00) (-8.11120545e-15,0.00000000e+00) (-1.46289147e-14,0.00000000e+00) (-3.68908595e-05,0.00000000e+00) (-7.26228653e-15,0.00000000e+00) +Row 10 + (2.13746718e-14,0.00000000e+00) (1.81108613e-14,0.00000000e+00) (5.01428363e-14,0.00000000e+00) (-1.01844315e-13,0.00000000e+00) (-9.71553909e-15,0.00000000e+00) (1.10191421e-14,0.00000000e+00) (-7.07641496e-14,0.00000000e+00) (8.06181902e-16,0.00000000e+00) + (-8.10816956e-15,0.00000000e+00) (-3.88951514e-05,0.00000000e+00) (-4.30593520e-14,0.00000000e+00) (1.70042662e-14,0.00000000e+00) (2.82526861e-14,0.00000000e+00) +Row 11 + (2.62607355e-14,0.00000000e+00) (4.94084842e-15,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) (-9.83216568e-15,0.00000000e+00) (-1.97389662e-14,0.00000000e+00) (1.05517226e-03,0.00000000e+00) (4.89401716e-16,0.00000000e+00) (-3.92292631e-14,0.00000000e+00) + (-1.46271801e-14,0.00000000e+00) (-4.30580511e-14,0.00000000e+00) (-9.79208641e-05,0.00000000e+00) (-1.25520263e-14,0.00000000e+00) (1.13846481e-14,0.00000000e+00) +Row 12 + (2.70536825e-05,0.00000000e+00) (-1.36129937e-04,0.00000000e+00) (-4.12841267e-14,0.00000000e+00) (6.53175833e-14,0.00000000e+00) (-3.03937033e-03,0.00000000e+00) (-1.58286060e-14,0.00000000e+00) (5.76176033e-14,0.00000000e+00) (-5.12210629e-03,0.00000000e+00) + (-3.68908595e-05,0.00000000e+00) (1.70108256e-14,0.00000000e+00) (-1.25468222e-14,0.00000000e+00) (-8.91185237e-05,0.00000000e+00) (-3.70477123e-14,0.00000000e+00) +Row 13 + (-2.33530133e-14,0.00000000e+00) (4.32849245e-15,0.00000000e+00) (-9.88462300e-15,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) (-8.33650384e-15,0.00000000e+00) (6.00210099e-16,0.00000000e+00) (1.05517226e-03,0.00000000e+00) (-9.09079644e-15,0.00000000e+00) + (-7.28223593e-15,0.00000000e+00) (2.82421693e-14,0.00000000e+00) (1.13820461e-14,0.00000000e+00) (-3.70233177e-14,0.00000000e+00) (-9.79208642e-05,0.00000000e+00) diff --git a/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhky_iat1_ik1_nao.txt b/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhky_iat1_ik1_nao.txt new file mode 100644 index 00000000000..8669c62087e --- /dev/null +++ b/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhky_iat1_ik1_nao.txt @@ -0,0 +1,46 @@ +#------------------------------------------------------------------------ +# ionic step 1 +# filename OUT.autotest/dhky_iat1_ik1_nao.txt +# gamma only 0 +# rows 13 +# columns 13 +#------------------------------------------------------------------------ +Row 1 + (-2.12008021e-05,0.00000000e+00) (6.78611552e-05,0.00000000e+00) (-2.25914027e-14,0.00000000e+00) (4.28045398e-14,0.00000000e+00) (1.72417113e-03,0.00000000e+00) (-3.58867067e-14,0.00000000e+00) (1.78678312e-14,0.00000000e+00) (2.75880257e-03,0.00000000e+00) + (1.56194509e-05,0.00000000e+00) (2.13742110e-14,0.00000000e+00) (2.62503271e-14,0.00000000e+00) (2.70536825e-05,0.00000000e+00) (-2.33338772e-14,0.00000000e+00) +Row 2 + (6.78611552e-05,0.00000000e+00) (-5.57970727e-04,0.00000000e+00) (-3.75953750e-14,0.00000000e+00) (3.78058862e-14,0.00000000e+00) (3.23767801e-03,0.00000000e+00) (-1.22002405e-14,0.00000000e+00) (-9.93106222e-15,0.00000000e+00) (-6.42813142e-03,0.00000000e+00) + (-7.85946556e-05,0.00000000e+00) (1.81086119e-14,0.00000000e+00) (4.94058446e-15,0.00000000e+00) (-1.36129937e-04,0.00000000e+00) (4.31702696e-15,0.00000000e+00) +Row 3 + (-2.25974742e-14,0.00000000e+00) (-3.75832162e-14,0.00000000e+00) (-2.79235817e-05,0.00000000e+00) (2.23885912e-14,0.00000000e+00) (2.75004220e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (2.04581902e-14,0.00000000e+00) (1.43068938e-14,0.00000000e+00) + (6.41824603e-14,0.00000000e+00) (5.01453571e-14,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) (-4.12835846e-14,0.00000000e+00) (-9.87784677e-15,0.00000000e+00) +Row 4 + (4.27993628e-14,0.00000000e+00) (3.77979172e-14,0.00000000e+00) (2.23878323e-14,0.00000000e+00) (-2.79235817e-05,0.00000000e+00) (-5.15163485e-14,0.00000000e+00) (2.05290058e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (-3.53274126e-14,0.00000000e+00) + (-3.51995489e-15,0.00000000e+00) (-1.01853314e-13,0.00000000e+00) (-9.83736988e-15,0.00000000e+00) (6.53093434e-14,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) +Row 5 + (1.72417113e-03,0.00000000e+00) (3.23767801e-03,0.00000000e+00) (2.74901220e-14,0.00000000e+00) (-5.15146138e-14,0.00000000e+00) (-9.27107579e-05,0.00000000e+00) (1.44913170e-14,0.00000000e+00) (-4.37091469e-14,0.00000000e+00) (3.01690807e-04,0.00000000e+00) + (-1.75478128e-03,0.00000000e+00) (-9.71548483e-15,0.00000000e+00) (-1.97363642e-14,0.00000000e+00) (-3.03937033e-03,0.00000000e+00) (-8.37477618e-15,0.00000000e+00) +Row 6 + (-3.58846468e-14,0.00000000e+00) (-1.21943862e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (2.05271624e-14,0.00000000e+00) (1.44983640e-14,0.00000000e+00) (-3.72087074e-04,0.00000000e+00) (1.12450906e-14,0.00000000e+00) (2.57539590e-14,0.00000000e+00) + (6.28431324e-15,0.00000000e+00) (1.10256469e-14,0.00000000e+00) (1.05517226e-03,0.00000000e+00) (-1.58304490e-14,0.00000000e+00) (5.97553910e-16,0.00000000e+00) +Row 7 + (1.78899489e-14,0.00000000e+00) (-9.92564110e-15,0.00000000e+00) (2.04601148e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (-4.37057859e-14,0.00000000e+00) (1.12398051e-14,0.00000000e+00) (-3.72087074e-04,0.00000000e+00) (-7.96420638e-14,0.00000000e+00) + (-2.26020365e-14,0.00000000e+00) (-7.07654505e-14,0.00000000e+00) (4.92871110e-16,0.00000000e+00) (5.76126160e-14,0.00000000e+00) (1.05517226e-03,0.00000000e+00) +Row 8 + (2.75880257e-03,0.00000000e+00) (-6.42813142e-03,0.00000000e+00) (1.43104722e-14,0.00000000e+00) (-3.53098486e-14,0.00000000e+00) (3.01690807e-04,0.00000000e+00) (2.57575907e-14,0.00000000e+00) (-7.96415217e-14,0.00000000e+00) (-1.08973807e-03,0.00000000e+00) + (-2.95724945e-03,0.00000000e+00) (8.10518764e-16,0.00000000e+00) (-3.92318646e-14,0.00000000e+00) (-5.12210629e-03,0.00000000e+00) (-9.11681734e-15,0.00000000e+00) +Row 9 + (1.56194509e-05,0.00000000e+00) (-7.85946556e-05,0.00000000e+00) (6.41811862e-14,0.00000000e+00) (-3.52515902e-15,0.00000000e+00) (-1.75478128e-03,0.00000000e+00) (6.28263103e-15,0.00000000e+00) (-2.26004914e-14,0.00000000e+00) (-2.95724945e-03,0.00000000e+00) + (-4.65206284e-05,0.00000000e+00) (-8.11120545e-15,0.00000000e+00) (-1.46289147e-14,0.00000000e+00) (-3.68908595e-05,0.00000000e+00) (-7.26228653e-15,0.00000000e+00) +Row 10 + (2.13746718e-14,0.00000000e+00) (1.81108613e-14,0.00000000e+00) (5.01428363e-14,0.00000000e+00) (-1.01844315e-13,0.00000000e+00) (-9.71553909e-15,0.00000000e+00) (1.10191421e-14,0.00000000e+00) (-7.07641496e-14,0.00000000e+00) (8.06181902e-16,0.00000000e+00) + (-8.10816956e-15,0.00000000e+00) (-3.88951514e-05,0.00000000e+00) (-4.30593520e-14,0.00000000e+00) (1.70042662e-14,0.00000000e+00) (2.82526861e-14,0.00000000e+00) +Row 11 + (2.62607355e-14,0.00000000e+00) (4.94084842e-15,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) (-9.83216568e-15,0.00000000e+00) (-1.97389662e-14,0.00000000e+00) (1.05517226e-03,0.00000000e+00) (4.89401716e-16,0.00000000e+00) (-3.92292631e-14,0.00000000e+00) + (-1.46271801e-14,0.00000000e+00) (-4.30580511e-14,0.00000000e+00) (-9.79208641e-05,0.00000000e+00) (-1.25520263e-14,0.00000000e+00) (1.13846481e-14,0.00000000e+00) +Row 12 + (2.70536825e-05,0.00000000e+00) (-1.36129937e-04,0.00000000e+00) (-4.12841267e-14,0.00000000e+00) (6.53175833e-14,0.00000000e+00) (-3.03937033e-03,0.00000000e+00) (-1.58286060e-14,0.00000000e+00) (5.76176033e-14,0.00000000e+00) (-5.12210629e-03,0.00000000e+00) + (-3.68908595e-05,0.00000000e+00) (1.70108256e-14,0.00000000e+00) (-1.25468222e-14,0.00000000e+00) (-8.91185237e-05,0.00000000e+00) (-3.70477123e-14,0.00000000e+00) +Row 13 + (-2.33530133e-14,0.00000000e+00) (4.32849245e-15,0.00000000e+00) (-9.88462300e-15,0.00000000e+00) (-8.48984556e-04,0.00000000e+00) (-8.33650384e-15,0.00000000e+00) (6.00210099e-16,0.00000000e+00) (1.05517226e-03,0.00000000e+00) (-9.09079644e-15,0.00000000e+00) + (-7.28223593e-15,0.00000000e+00) (2.82421693e-14,0.00000000e+00) (1.13820461e-14,0.00000000e+00) (-3.70233177e-14,0.00000000e+00) (-9.79208642e-05,0.00000000e+00) diff --git a/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkz_iat1_ik0_nao.txt b/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkz_iat1_ik0_nao.txt new file mode 100644 index 00000000000..f97f74184fc --- /dev/null +++ b/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkz_iat1_ik0_nao.txt @@ -0,0 +1,46 @@ +#------------------------------------------------------------------------ +# ionic step 1 +# filename OUT.autotest/dhkz_iat1_ik0_nao.txt +# gamma only 0 +# rows 13 +# columns 13 +#------------------------------------------------------------------------ +Row 1 + (-2.12008021e-05,0.00000000e+00) (6.78611551e-05,0.00000000e+00) (-1.72417113e-03,0.00000000e+00) (1.49853909e-14,0.00000000e+00) (-1.32194823e-15,0.00000000e+00) (-2.75880257e-03,0.00000000e+00) (-2.39331641e-14,0.00000000e+00) (1.29570494e-14,0.00000000e+00) + (-3.12389017e-05,0.00000000e+00) (-4.26175775e-15,0.00000000e+00) (-1.82293609e-14,0.00000000e+00) (5.57296702e-15,0.00000000e+00) (-4.50789763e-14,0.00000000e+00) +Row 2 + (6.78611551e-05,0.00000000e+00) (-5.57970727e-04,0.00000000e+00) (-3.23767801e-03,0.00000000e+00) (-4.86416060e-16,0.00000000e+00) (1.27018298e-15,0.00000000e+00) (6.42813142e-03,0.00000000e+00) (-3.32683726e-14,0.00000000e+00) (-3.69901684e-15,0.00000000e+00) + (1.57189311e-04,0.00000000e+00) (6.56400815e-15,0.00000000e+00) (1.44806852e-16,0.00000000e+00) (2.46893435e-14,0.00000000e+00) (-7.62336540e-15,0.00000000e+00) +Row 3 + (-1.72417113e-03,0.00000000e+00) (-3.23767801e-03,0.00000000e+00) (-9.27107579e-05,0.00000000e+00) (5.16299535e-15,0.00000000e+00) (-1.89531670e-14,0.00000000e+00) (3.01690807e-04,0.00000000e+00) (8.95769994e-15,0.00000000e+00) (-1.05416869e-14,0.00000000e+00) + (-3.50956255e-03,0.00000000e+00) (-1.27929414e-14,0.00000000e+00) (1.09143934e-14,0.00000000e+00) (-3.71210940e-14,0.00000000e+00) (-5.16144763e-14,0.00000000e+00) +Row 4 + (1.49975339e-14,0.00000000e+00) (-4.80344952e-16,0.00000000e+00) (5.16212843e-15,0.00000000e+00) (-2.79235816e-05,0.00000000e+00) (-6.58487499e-14,0.00000000e+00) (7.39242291e-16,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (-5.45887440e-14,0.00000000e+00) + (-3.92015982e-14,0.00000000e+00) (8.48984556e-04,0.00000000e+00) (-5.18557397e-14,0.00000000e+00) (3.64619221e-14,0.00000000e+00) (1.16305758e-14,0.00000000e+00) +Row 5 + (-1.32888701e-15,0.00000000e+00) (1.27538737e-15,0.00000000e+00) (-1.89531669e-14,0.00000000e+00) (-6.58496173e-14,0.00000000e+00) (-2.79235817e-05,0.00000000e+00) (-1.04707370e-14,0.00000000e+00) (-5.46163595e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) + (1.59090581e-14,0.00000000e+00) (-5.17365472e-14,0.00000000e+00) (8.48984556e-04,0.00000000e+00) (2.86639926e-14,0.00000000e+00) (1.86336662e-14,0.00000000e+00) +Row 6 + (-2.75880257e-03,0.00000000e+00) (6.42813142e-03,0.00000000e+00) (3.01690807e-04,0.00000000e+00) (7.31435611e-16,0.00000000e+00) (-1.04703035e-14,0.00000000e+00) (-1.08973807e-03,0.00000000e+00) (1.42286485e-15,0.00000000e+00) (-2.07232067e-14,0.00000000e+00) + (-5.91449889e-03,0.00000000e+00) (-5.68576655e-14,0.00000000e+00) (-6.84424824e-15,0.00000000e+00) (-2.77203516e-14,0.00000000e+00) (-2.84971223e-14,0.00000000e+00) +Row 7 + (-2.39318628e-14,0.00000000e+00) (-3.32705418e-14,0.00000000e+00) (8.94425636e-15,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (-5.46139739e-14,0.00000000e+00) (1.42893426e-15,0.00000000e+00) (-3.72087074e-04,0.00000000e+00) (-8.74729049e-14,0.00000000e+00) + (-3.89062080e-14,0.00000000e+00) (-1.05517226e-03,0.00000000e+00) (-2.87374924e-14,0.00000000e+00) (7.59572829e-15,0.00000000e+00) (3.04616182e-14,0.00000000e+00) +Row 8 + (1.29609521e-14,0.00000000e+00) (-3.70206044e-15,0.00000000e+00) (-1.05564311e-14,0.00000000e+00) (-5.45846241e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (-2.07232075e-14,0.00000000e+00) (-8.74746392e-14,0.00000000e+00) (-3.72087074e-04,0.00000000e+00) + (-1.31223587e-14,0.00000000e+00) (-2.87283884e-14,0.00000000e+00) (-1.05517226e-03,0.00000000e+00) (1.47950884e-14,0.00000000e+00) (2.93373522e-15,0.00000000e+00) +Row 9 + (-3.12389017e-05,0.00000000e+00) (1.57189311e-04,0.00000000e+00) (-3.50956255e-03,0.00000000e+00) (-3.92123317e-14,0.00000000e+00) (1.58976740e-14,0.00000000e+00) (-5.91449889e-03,0.00000000e+00) (-3.89080508e-14,0.00000000e+00) (-1.31209501e-14,0.00000000e+00) + (-1.10417471e-04,0.00000000e+00) (-1.32748205e-14,0.00000000e+00) (-3.01174164e-14,0.00000000e+00) (4.74289832e-15,0.00000000e+00) (-1.79543413e-14,0.00000000e+00) +Row 10 + (-4.34328975e-15,0.00000000e+00) (6.57268389e-15,0.00000000e+00) (-1.27946768e-14,0.00000000e+00) (8.48984556e-04,0.00000000e+00) (-5.17495576e-14,0.00000000e+00) (-5.68576653e-14,0.00000000e+00) (-1.05517226e-03,0.00000000e+00) (-2.87279548e-14,0.00000000e+00) + (-1.32193098e-14,0.00000000e+00) (-9.79208641e-05,0.00000000e+00) (-6.89880813e-14,0.00000000e+00) (3.47559974e-15,0.00000000e+00) (-7.15928944e-15,0.00000000e+00) +Row 11 + (-1.82224217e-14,0.00000000e+00) (1.43077210e-16,0.00000000e+00) (1.09178636e-14,0.00000000e+00) (-5.18514029e-14,0.00000000e+00) (8.48984556e-04,0.00000000e+00) (-6.84424909e-15,0.00000000e+00) (-2.87361914e-14,0.00000000e+00) (-1.05517226e-03,0.00000000e+00) + (-3.01260902e-14,0.00000000e+00) (-6.89776732e-14,0.00000000e+00) (-9.79208641e-05,0.00000000e+00) (-6.52317482e-15,0.00000000e+00) (1.60327315e-15,0.00000000e+00) +Row 12 + (5.57531895e-15,0.00000000e+00) (2.46895150e-14,0.00000000e+00) (-3.71212307e-14,0.00000000e+00) (3.64593200e-14,0.00000000e+00) (2.86663783e-14,0.00000000e+00) (-2.77029559e-14,0.00000000e+00) (7.59778829e-15,0.00000000e+00) (1.47938958e-14,0.00000000e+00) + (4.74032589e-15,0.00000000e+00) (3.47776814e-15,0.00000000e+00) (-6.52339157e-15,0.00000000e+00) (-2.52216807e-05,0.00000000e+00) (-4.00550304e-14,0.00000000e+00) +Row 13 + (-4.50945887e-14,0.00000000e+00) (-7.63117229e-15,0.00000000e+00) (-5.15780474e-14,0.00000000e+00) (1.16253716e-14,0.00000000e+00) (1.86380029e-14,0.00000000e+00) (-2.84979896e-14,0.00000000e+00) (3.04776644e-14,0.00000000e+00) (2.92549505e-15,0.00000000e+00) + (-1.79609406e-14,0.00000000e+00) (-7.15582010e-15,0.00000000e+00) (1.59286514e-15,0.00000000e+00) (-4.00527109e-14,0.00000000e+00) (-3.88951514e-05,0.00000000e+00) diff --git a/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkz_iat1_ik1_nao.txt b/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkz_iat1_ik1_nao.txt new file mode 100644 index 00000000000..95ad8e96c48 --- /dev/null +++ b/tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkz_iat1_ik1_nao.txt @@ -0,0 +1,46 @@ +#------------------------------------------------------------------------ +# ionic step 1 +# filename OUT.autotest/dhkz_iat1_ik1_nao.txt +# gamma only 0 +# rows 13 +# columns 13 +#------------------------------------------------------------------------ +Row 1 + (-2.12008021e-05,0.00000000e+00) (6.78611551e-05,0.00000000e+00) (-1.72417113e-03,0.00000000e+00) (1.49853909e-14,0.00000000e+00) (-1.32194823e-15,0.00000000e+00) (-2.75880257e-03,0.00000000e+00) (-2.39331641e-14,0.00000000e+00) (1.29570494e-14,0.00000000e+00) + (-3.12389017e-05,0.00000000e+00) (-4.26175775e-15,0.00000000e+00) (-1.82293609e-14,0.00000000e+00) (5.57296702e-15,0.00000000e+00) (-4.50789763e-14,0.00000000e+00) +Row 2 + (6.78611551e-05,0.00000000e+00) (-5.57970727e-04,0.00000000e+00) (-3.23767801e-03,0.00000000e+00) (-4.86416060e-16,0.00000000e+00) (1.27018298e-15,0.00000000e+00) (6.42813142e-03,0.00000000e+00) (-3.32683726e-14,0.00000000e+00) (-3.69901684e-15,0.00000000e+00) + (1.57189311e-04,0.00000000e+00) (6.56400815e-15,0.00000000e+00) (1.44806852e-16,0.00000000e+00) (2.46893435e-14,0.00000000e+00) (-7.62336540e-15,0.00000000e+00) +Row 3 + (-1.72417113e-03,0.00000000e+00) (-3.23767801e-03,0.00000000e+00) (-9.27107579e-05,0.00000000e+00) (5.16299535e-15,0.00000000e+00) (-1.89531670e-14,0.00000000e+00) (3.01690807e-04,0.00000000e+00) (8.95769994e-15,0.00000000e+00) (-1.05416869e-14,0.00000000e+00) + (-3.50956255e-03,0.00000000e+00) (-1.27929414e-14,0.00000000e+00) (1.09143934e-14,0.00000000e+00) (-3.71210940e-14,0.00000000e+00) (-5.16144763e-14,0.00000000e+00) +Row 4 + (1.49975339e-14,0.00000000e+00) (-4.80344952e-16,0.00000000e+00) (5.16212843e-15,0.00000000e+00) (-2.79235816e-05,0.00000000e+00) (-6.58487499e-14,0.00000000e+00) (7.39242291e-16,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (-5.45887440e-14,0.00000000e+00) + (-3.92015982e-14,0.00000000e+00) (8.48984556e-04,0.00000000e+00) (-5.18557397e-14,0.00000000e+00) (3.64619221e-14,0.00000000e+00) (1.16305758e-14,0.00000000e+00) +Row 5 + (-1.32888701e-15,0.00000000e+00) (1.27538737e-15,0.00000000e+00) (-1.89531669e-14,0.00000000e+00) (-6.58496173e-14,0.00000000e+00) (-2.79235817e-05,0.00000000e+00) (-1.04707370e-14,0.00000000e+00) (-5.46163595e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) + (1.59090581e-14,0.00000000e+00) (-5.17365472e-14,0.00000000e+00) (8.48984556e-04,0.00000000e+00) (2.86639926e-14,0.00000000e+00) (1.86336662e-14,0.00000000e+00) +Row 6 + (-2.75880257e-03,0.00000000e+00) (6.42813142e-03,0.00000000e+00) (3.01690807e-04,0.00000000e+00) (7.31435611e-16,0.00000000e+00) (-1.04703035e-14,0.00000000e+00) (-1.08973807e-03,0.00000000e+00) (1.42286485e-15,0.00000000e+00) (-2.07232067e-14,0.00000000e+00) + (-5.91449889e-03,0.00000000e+00) (-5.68576655e-14,0.00000000e+00) (-6.84424824e-15,0.00000000e+00) (-2.77203516e-14,0.00000000e+00) (-2.84971223e-14,0.00000000e+00) +Row 7 + (-2.39318628e-14,0.00000000e+00) (-3.32705418e-14,0.00000000e+00) (8.94425636e-15,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (-5.46139739e-14,0.00000000e+00) (1.42893426e-15,0.00000000e+00) (-3.72087074e-04,0.00000000e+00) (-8.74729049e-14,0.00000000e+00) + (-3.89062080e-14,0.00000000e+00) (-1.05517226e-03,0.00000000e+00) (-2.87374924e-14,0.00000000e+00) (7.59572829e-15,0.00000000e+00) (3.04616182e-14,0.00000000e+00) +Row 8 + (1.29609521e-14,0.00000000e+00) (-3.70206044e-15,0.00000000e+00) (-1.05564311e-14,0.00000000e+00) (-5.45846241e-14,0.00000000e+00) (1.10978663e-04,0.00000000e+00) (-2.07232075e-14,0.00000000e+00) (-8.74746392e-14,0.00000000e+00) (-3.72087074e-04,0.00000000e+00) + (-1.31223587e-14,0.00000000e+00) (-2.87283884e-14,0.00000000e+00) (-1.05517226e-03,0.00000000e+00) (1.47950884e-14,0.00000000e+00) (2.93373522e-15,0.00000000e+00) +Row 9 + (-3.12389017e-05,0.00000000e+00) (1.57189311e-04,0.00000000e+00) (-3.50956255e-03,0.00000000e+00) (-3.92123317e-14,0.00000000e+00) (1.58976740e-14,0.00000000e+00) (-5.91449889e-03,0.00000000e+00) (-3.89080508e-14,0.00000000e+00) (-1.31209501e-14,0.00000000e+00) + (-1.10417471e-04,0.00000000e+00) (-1.32748205e-14,0.00000000e+00) (-3.01174164e-14,0.00000000e+00) (4.74289832e-15,0.00000000e+00) (-1.79543413e-14,0.00000000e+00) +Row 10 + (-4.34328975e-15,0.00000000e+00) (6.57268389e-15,0.00000000e+00) (-1.27946768e-14,0.00000000e+00) (8.48984556e-04,0.00000000e+00) (-5.17495576e-14,0.00000000e+00) (-5.68576653e-14,0.00000000e+00) (-1.05517226e-03,0.00000000e+00) (-2.87279548e-14,0.00000000e+00) + (-1.32193098e-14,0.00000000e+00) (-9.79208641e-05,0.00000000e+00) (-6.89880813e-14,0.00000000e+00) (3.47559974e-15,0.00000000e+00) (-7.15928944e-15,0.00000000e+00) +Row 11 + (-1.82224217e-14,0.00000000e+00) (1.43077210e-16,0.00000000e+00) (1.09178636e-14,0.00000000e+00) (-5.18514029e-14,0.00000000e+00) (8.48984556e-04,0.00000000e+00) (-6.84424909e-15,0.00000000e+00) (-2.87361914e-14,0.00000000e+00) (-1.05517226e-03,0.00000000e+00) + (-3.01260902e-14,0.00000000e+00) (-6.89776732e-14,0.00000000e+00) (-9.79208641e-05,0.00000000e+00) (-6.52317482e-15,0.00000000e+00) (1.60327315e-15,0.00000000e+00) +Row 12 + (5.57531895e-15,0.00000000e+00) (2.46895150e-14,0.00000000e+00) (-3.71212307e-14,0.00000000e+00) (3.64593200e-14,0.00000000e+00) (2.86663783e-14,0.00000000e+00) (-2.77029559e-14,0.00000000e+00) (7.59778829e-15,0.00000000e+00) (1.47938958e-14,0.00000000e+00) + (4.74032589e-15,0.00000000e+00) (3.47776814e-15,0.00000000e+00) (-6.52339157e-15,0.00000000e+00) (-2.52216807e-05,0.00000000e+00) (-4.00550304e-14,0.00000000e+00) +Row 13 + (-4.50945887e-14,0.00000000e+00) (-7.63117229e-15,0.00000000e+00) (-5.15780474e-14,0.00000000e+00) (1.16253716e-14,0.00000000e+00) (1.86380029e-14,0.00000000e+00) (-2.84979896e-14,0.00000000e+00) (3.04776644e-14,0.00000000e+00) (2.92549505e-15,0.00000000e+00) + (-1.79609406e-14,0.00000000e+00) (-7.15582010e-15,0.00000000e+00) (1.59286514e-15,0.00000000e+00) (-4.00527109e-14,0.00000000e+00) (-3.88951514e-05,0.00000000e+00) diff --git a/tests/03_NAO_multik/scf_out_dh_t/result.ref b/tests/03_NAO_multik/scf_out_dh_t/result.ref index f2b39592614..86aafccd6be 100644 --- a/tests/03_NAO_multik/scf_out_dh_t/result.ref +++ b/tests/03_NAO_multik/scf_out_dh_t/result.ref @@ -4,4 +4,10 @@ ComparerTR_pass 0 ComparerdHRx_pass 0 ComparerdHRy_pass 0 ComparerdHRz_pass 0 +Compare_dhkx_iat1_ik0_nao_pass 0 +Compare_dhky_iat1_ik0_nao_pass 0 +Compare_dhkz_iat1_ik0_nao_pass 0 +Compare_dhkx_iat1_ik1_nao_pass 0 +Compare_dhky_iat1_ik1_nao_pass 0 +Compare_dhkz_iat1_ik1_nao_pass 0 totaltimeref 0.39079 diff --git a/tests/integrate/tools/catch_properties.sh b/tests/integrate/tools/catch_properties.sh index 21d3bb70cce..f13639d58c5 100755 --- a/tests/integrate/tools/catch_properties.sh +++ b/tests/integrate/tools/catch_properties.sh @@ -451,10 +451,10 @@ if ! test -z "$has_mat_syns" && [ $has_mat_syns == 1 ]; then fi #----------------------------------- -# matrix +# matrix #----------------------------------- #echo $has_mat_dh -if ! test -z "$has_mat_dh" && [ $has_mat_dh == 1 ]; then +if ! test -z "$has_mat_dh" && [ $has_mat_dh == 1 ] && [ $gamma_only != 1 ]; then python3 $COMPARE_SCRIPT dhrxs1_nao.csr.ref OUT.autotest/dhrxs1_nao.csr 8 echo "ComparerdHRx_pass $?" >>$1 python3 $COMPARE_SCRIPT dhrys1_nao.csr.ref OUT.autotest/dhrys1_nao.csr 8 @@ -463,6 +463,20 @@ if ! test -z "$has_mat_dh" && [ $has_mat_dh == 1 ]; then echo "ComparerdHRz_pass $?" >>$1 fi +#----------------------------------- +# d (k) matrix +#----------------------------------- +#echo $has_mat_dh_terms +if ! test -z "$has_mat_dh" && [ $has_mat_dh == 1 ]; then + shopt -s nullglob + for reffile in dhk_ref/*.txt; do + fname=$(basename "$reffile") + key=$(sanitize_result_key "Compare_${fname%.txt}") + record_compare_result "$1" "${key}_pass" "$reffile" "OUT.autotest/$fname" 8 + done + shopt -u nullglob +fi + #--------------------------------------- # Charge density #---------------------------------------