From 966dd2b82e441e40b1ae0a146fe5c6f64a13004f Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Wed, 20 May 2026 20:34:03 +0800 Subject: [PATCH 01/13] initial version of writing H and dH terms (except exx) --- source/source_io/CMakeLists.txt | 7 + .../source_io/module_ctrl/ctrl_scf_lcao.cpp | 58 +++ source/source_io/module_dhs/write_dH.cpp | 142 +++++++ source/source_io/module_dhs/write_dH.h | 51 +++ source/source_io/module_dhs/write_dH_t.cpp | 96 +++++ source/source_io/module_dhs/write_dH_vh.cpp | 82 ++++ source/source_io/module_dhs/write_dH_vl.cpp | 178 +++++++++ source/source_io/module_dhs/write_dH_vnl.cpp | 94 +++++ source/source_io/module_dhs/write_dH_vxc.cpp | 82 ++++ source/source_io/module_hs/write_H_terms.cpp | 354 ++++++++++++++++++ source/source_io/module_hs/write_H_terms.h | 87 +++++ source/source_io/module_output/filename.cpp | 2 +- .../module_parameter/input_parameter.h | 10 + .../read_input_item_output.cpp | 252 ++++++++++++- .../module_operator_lcao/ekinetic.cpp | 1 + .../module_operator_lcao/ekinetic.h | 4 + .../module_operator_lcao/ekinetic_dh.hpp | 151 ++++++++ .../module_operator_lcao/nonlocal.cpp | 1 + .../module_operator_lcao/nonlocal.h | 4 + .../module_operator_lcao/nonlocal_dh.hpp | 233 ++++++++++++ source/source_lcao/spar_dh.cpp | 4 +- .../02_NAO_Gamma/scf_out_dh/genref_diff/INPUT | 44 +++ .../02_NAO_Gamma/scf_out_dh/genref_diff/STRU | 22 ++ 23 files changed, 1955 insertions(+), 4 deletions(-) create mode 100644 source/source_io/module_dhs/write_dH.cpp create mode 100644 source/source_io/module_dhs/write_dH.h create mode 100644 source/source_io/module_dhs/write_dH_t.cpp create mode 100644 source/source_io/module_dhs/write_dH_vh.cpp create mode 100644 source/source_io/module_dhs/write_dH_vl.cpp create mode 100644 source/source_io/module_dhs/write_dH_vnl.cpp create mode 100644 source/source_io/module_dhs/write_dH_vxc.cpp create mode 100644 source/source_io/module_hs/write_H_terms.cpp create mode 100644 source/source_io/module_hs/write_H_terms.h create mode 100644 source/source_lcao/module_operator_lcao/ekinetic_dh.hpp create mode 100644 source/source_lcao/module_operator_lcao/nonlocal_dh.hpp create mode 100644 tests/02_NAO_Gamma/scf_out_dh/genref_diff/INPUT create mode 100644 tests/02_NAO_Gamma/scf_out_dh/genref_diff/STRU diff --git a/source/source_io/CMakeLists.txt b/source/source_io/CMakeLists.txt index 6073f10a7df..37b0261812c 100644 --- a/source/source_io/CMakeLists.txt +++ b/source/source_io/CMakeLists.txt @@ -82,10 +82,17 @@ 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_t.cpp + module_dhs/write_dH_vnl.cpp + module_dhs/write_dH_vl.cpp + module_dhs/write_dH_vh.cpp + module_dhs/write_dH_vxc.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..5b146225970 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 @@ -248,6 +250,62 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, p_ham_tk, &dftu); + //------------------------------------------------------------------ + //! 7c) Output dH components (dT/dR, dV^NL/dR, dV^L/dR, dV^H/dR, dV^XC/dR) + //------------------------------------------------------------------ + { + 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.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) + { + dh_params.dmR = dm->get_DMR_pointer(1); + } + ModuleIO::write_dH_components(dh_params); + } + + + //------------------------------------------------------------------ + //! 7d) Output H components (T, Vnl, Vl, Vh, Vxc) + //------------------------------------------------------------------ + { + if (inp.out_mat_h_t[0]) + { + ModuleIO::write_h_t(ucell, gd, pv, two_center_bundle, orb, kv, nspin, istep, out_app_flag, + ucell.get_iat2iwt(), ucell.nat); + } + if (inp.out_mat_h_vnl[0]) + { + ModuleIO::write_h_vnl(ucell, gd, pv, two_center_bundle, orb, kv, nspin, istep, out_app_flag, + ucell.get_iat2iwt(), ucell.nat); + } + if (inp.out_mat_h_vl[0]) + { + ModuleIO::write_h_vl(ucell, gd, pv, orb, pelec->pot, nspin, istep, out_app_flag, + ucell.get_iat2iwt(), ucell.nat, kv); + } + if (inp.out_mat_h_vh[0]) + { + ModuleIO::write_h_vh(ucell, gd, pv, orb, pelec->charge, pw_rho, nspin, istep, out_app_flag, + ucell.get_iat2iwt(), ucell.nat, kv); + } + if (inp.out_mat_h_vxc[0]) + { + ModuleIO::write_h_vxc(ucell, gd, pv, orb, pelec->charge, pw_rho->nrxx, nspin, istep, + out_app_flag, ucell.get_iat2iwt(), ucell.nat, kv); + } + } //------------------------------------------------------------------ //! 8) Output kinetic matrix //------------------------------------------------------------------ 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..b88651d883e --- /dev/null +++ b/source/source_io/module_dhs/write_dH.cpp @@ -0,0 +1,142 @@ +#include "write_dH.h" + +#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 +#include + +namespace ModuleIO +{ + +bool any_dh_term_enabled() +{ + return PARAM.inp.out_mat_dh_t[0] || PARAM.inp.out_mat_dh_vl[0] || PARAM.inp.out_mat_dh_vnl[0] + || PARAM.inp.out_mat_dh_vh[0] || PARAM.inp.out_mat_dh_vxc[0]; +} + +void write_dH_components(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_components"); + ModuleBase::timer::start("ModuleIO", "write_dH_components"); + + if (!any_dh_term_enabled()) + { + ModuleBase::timer::end("ModuleIO", "write_dH_components"); + return; + } + + 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_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); + } + + if (PARAM.inp.out_mat_dh_vxc[0]) + { + write_dH_vxc(params); + } + + if (PARAM.inp.out_mat_dh[0] && any_dh_term_enabled()) + { + write_dH_sum(params); + } + + ModuleBase::timer::end("ModuleIO", "write_dH_components"); +} + +bool write_dH_sum(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_sum"); + ModuleBase::timer::start("ModuleIO", "write_dH_sum"); + + const UnitCell& ucell = *params.ucell; + const Parallel_Orbitals& pv = *params.pv; + const int nat = ucell.nat; + const int nspin = params.nspin; + + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) + { + hamilt::HContainer dH_sum_x(&pv); + hamilt::HContainer dH_sum_y(&pv); + hamilt::HContainer dH_sum_z(&pv); + dH_sum_x.set_zero(); + dH_sum_y.set_zero(); + dH_sum_z.set_zero(); + + const int nbasis = dH_sum_x.get_nbasis(); + +#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); + + hamilt::HContainer dH_x_s(&serialV); + hamilt::HContainer dH_y_s(&serialV); + hamilt::HContainer dH_z_s(&serialV); + hamilt::gatherParallels(dH_sum_x, &dH_x_s, 0); + hamilt::gatherParallels(dH_sum_y, &dH_y_s, 0); + hamilt::gatherParallels(dH_sum_z, &dH_z_s, 0); + + if (GlobalV::MY_RANK == 0) +#endif + { + std::string fname_x = ModuleIO::dhr_gen_fname("dhrx", ispin, params.append, params.istep); + std::string fname_y = ModuleIO::dhr_gen_fname("dhry", ispin, params.append, params.istep); + std::string fname_z = ModuleIO::dhr_gen_fname("dhrz", ispin, params.append, params.istep); + + if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) + { + fname_x = PARAM.globalv.global_matrix_dir + fname_x; + fname_y = PARAM.globalv.global_matrix_dir + fname_y; + fname_z = PARAM.globalv.global_matrix_dir + fname_z; + } + else + { + fname_x = PARAM.globalv.global_out_dir + fname_x; + fname_y = PARAM.globalv.global_out_dir + fname_y; + fname_z = PARAM.globalv.global_out_dir + fname_z; + } + +#ifdef __MPI + ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dH_x_s, params.istep, ispin, nspin, "dH_sum"); + ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dH_y_s, params.istep, ispin, nspin, "dH_sum"); + ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dH_z_s, params.istep, ispin, nspin, "dH_sum"); +#else + ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dH_sum_x, params.istep, ispin, nspin, "dH_sum"); + ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dH_sum_y, params.istep, ispin, nspin, "dH_sum"); + ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dH_sum_z, params.istep, ispin, nspin, "dH_sum"); +#endif + } + } + + ModuleBase::timer::end("ModuleIO", "write_dH_sum"); + return true; +} + +} // 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..1e4e57e3504 --- /dev/null +++ b/source/source_io/module_dhs/write_dH.h @@ -0,0 +1,51 @@ +#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_lcao/LCAO_domain.h" +#include "source_lcao/module_hcontainer/hcontainer.h" + +#include + +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; + int nat = 0; + int nspin = 1; + int istep = 0; + bool gamma_only = false; + bool append = false; + const hamilt::HContainer* dmR = nullptr; +}; + +bool any_dh_term_enabled(); + +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_vxc(WriteDHParams& params); + +bool write_dH_sum(WriteDHParams& params); + +} // namespace ModuleIO + +#endif diff --git a/source/source_io/module_dhs/write_dH_t.cpp b/source/source_io/module_dhs/write_dH_t.cpp new file mode 100644 index 00000000000..7def2ed5fbe --- /dev/null +++ b/source/source_io/module_dhs/write_dH_t.cpp @@ -0,0 +1,96 @@ +#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/operator_force_stress_utils.h" +#include "write_dH.h" + +namespace ModuleIO +{ + +bool write_dH_t(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_t"); + ModuleBase::timer::start("ModuleIO", "write_dH_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 int nat = ucell.nat; + const int nspin = params.nspin; + const std::vector& orb_cutoff = orb.cutoffs(); + + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) + { + hamilt::HContainer dT_x(&pv); + hamilt::HContainer dT_y(&pv); + hamilt::HContainer dT_z(&pv); + + hamilt::EKinetic> tmp_ekinetic(nullptr, + params.kv->kvec_d, + nullptr, + &ucell, + orb_cutoff, + &gd, + two_center_bundle.kinetic_orb.get()); + + tmp_ekinetic.cal_dH(&dT_x, &dT_y, &dT_z); + + const int nbasis = dT_x.get_nbasis(); + +#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); + + hamilt::HContainer dT_x_serial(&serialV); + hamilt::HContainer dT_y_serial(&serialV); + hamilt::HContainer dT_z_serial(&serialV); + hamilt::gatherParallels(dT_x, &dT_x_serial, 0); + hamilt::gatherParallels(dT_y, &dT_y_serial, 0); + hamilt::gatherParallels(dT_z, &dT_z_serial, 0); + + if (GlobalV::MY_RANK == 0) +#endif + { + std::string fname_x = ModuleIO::dhr_gen_fname("dtrx", ispin, params.append, params.istep); + std::string fname_y = ModuleIO::dhr_gen_fname("dtry", ispin, params.append, params.istep); + std::string fname_z = ModuleIO::dhr_gen_fname("dtrz", ispin, params.append, params.istep); + + if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) + { + fname_x = PARAM.globalv.global_matrix_dir + fname_x; + fname_y = PARAM.globalv.global_matrix_dir + fname_y; + fname_z = PARAM.globalv.global_matrix_dir + fname_z; + } + else + { + fname_x = PARAM.globalv.global_out_dir + fname_x; + fname_y = PARAM.globalv.global_out_dir + fname_y; + fname_z = PARAM.globalv.global_out_dir + fname_z; + } + +#ifdef __MPI + ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dT_x_serial, params.istep, ispin, nspin, "dT"); + ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dT_y_serial, params.istep, ispin, nspin, "dT"); + ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dT_z_serial, params.istep, ispin, nspin, "dT"); +#else + ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dT_x, params.istep, ispin, nspin, "dT"); + ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dT_y, params.istep, ispin, nspin, "dT"); + ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dT_z, params.istep, ispin, nspin, "dT"); +#endif + } + } + + ModuleBase::timer::end("ModuleIO", "write_dH_t"); + return true; +} + +} // namespace ModuleIO diff --git a/source/source_io/module_dhs/write_dH_vh.cpp b/source/source_io/module_dhs/write_dH_vh.cpp new file mode 100644 index 00000000000..c786701dde8 --- /dev/null +++ b/source/source_io/module_dhs/write_dH_vh.cpp @@ -0,0 +1,82 @@ +#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 "write_dH.h" + +namespace ModuleIO +{ + +bool write_dH_vh(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_vh"); + ModuleBase::timer::start("ModuleIO", "write_dH_vh"); + + const UnitCell& ucell = *params.ucell; + const Parallel_Orbitals& pv = *params.pv; + const int nat = ucell.nat; + const int nspin = params.nspin; + + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) + { + hamilt::HContainer dVh_x(&pv); + hamilt::HContainer dVh_y(&pv); + hamilt::HContainer dVh_z(&pv); + dVh_x.set_zero(); + dVh_y.set_zero(); + dVh_z.set_zero(); + + const int nbasis = dVh_x.get_nbasis(); + +#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); + + hamilt::HContainer dVh_x_s(&serialV); + hamilt::HContainer dVh_y_s(&serialV); + hamilt::HContainer dVh_z_s(&serialV); + hamilt::gatherParallels(dVh_x, &dVh_x_s, 0); + hamilt::gatherParallels(dVh_y, &dVh_y_s, 0); + hamilt::gatherParallels(dVh_z, &dVh_z_s, 0); + + if (GlobalV::MY_RANK == 0) +#endif + { + std::string fname_x = ModuleIO::dhr_gen_fname("dvhrx", ispin, params.append, params.istep); + std::string fname_y = ModuleIO::dhr_gen_fname("dvhry", ispin, params.append, params.istep); + std::string fname_z = ModuleIO::dhr_gen_fname("dvhrz", ispin, params.append, params.istep); + + if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) + { + fname_x = PARAM.globalv.global_matrix_dir + fname_x; + fname_y = PARAM.globalv.global_matrix_dir + fname_y; + fname_z = PARAM.globalv.global_matrix_dir + fname_z; + } + else + { + fname_x = PARAM.globalv.global_out_dir + fname_x; + fname_y = PARAM.globalv.global_out_dir + fname_y; + fname_z = PARAM.globalv.global_out_dir + fname_z; + } + +#ifdef __MPI + ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVh_x_s, params.istep, ispin, nspin, "dV^H"); + ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVh_y_s, params.istep, ispin, nspin, "dV^H"); + ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVh_z_s, params.istep, ispin, nspin, "dV^H"); +#else + ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVh_x, params.istep, ispin, nspin, "dV^H"); + ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVh_y, params.istep, ispin, nspin, "dV^H"); + ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVh_z, params.istep, ispin, nspin, "dV^H"); +#endif + } + } + + ModuleBase::timer::end("ModuleIO", "write_dH_vh"); + return true; +} + +} // namespace ModuleIO diff --git a/source/source_io/module_dhs/write_dH_vl.cpp b/source/source_io/module_dhs/write_dH_vl.cpp new file mode 100644 index 00000000000..408203ddf00 --- /dev/null +++ b/source/source_io/module_dhs/write_dH_vl.cpp @@ -0,0 +1,178 @@ +#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_gint/gint_interface.h" +#include "source_lcao/module_gint/phi_operator.h" +#include "source_lcao/module_hcontainer/hcontainer_funcs.h" +#include "source_lcao/module_hcontainer/output_hcontainer.h" +#include "source_lcao/module_operator_lcao/operator_force_stress_utils.h" +#include "write_dH.h" + +#include + +#ifdef _OPENMP +#include +#endif + +namespace ModuleIO +{ + +static void write_dH_vl_pulay(const WriteDHParams& params, + int ispin, + hamilt::HContainer& dVl_x, + hamilt::HContainer& dVl_y, + hamilt::HContainer& dVl_z) +{ + const UnitCell& ucell = *params.ucell; + const Grid_Driver& gd = *params.gd; + const Parallel_Orbitals& pv = *params.pv; + const LCAO_Orbitals& orb = *params.orb; + const std::vector& orb_cutoff = orb.cutoffs(); + const int nat = ucell.nat; + const int npol = ucell.get_npol(); + +#pragma omp parallel for schedule(dynamic) + for (int iat = 0; iat < nat; iat++) + { + const int T1 = ucell.iat2it[iat]; + const int I1 = ucell.iat2ia[iat]; + const ModuleBase::Vector3& tau1 = ucell.atoms[T1].tau[I1]; + const Atom* atom1 = &ucell.atoms[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); + const ModuleBase::Vector3& tau2 = adjs.adjacent_tau[ad]; + const Atom* atom2 = &ucell.atoms[T2]; + + ModuleBase::Vector3 dtau = tau2 - tau1; + double dist = dtau.norm() * ucell.lat0; + double cutoff = orb_cutoff[T1] + orb_cutoff[T2]; + + if (dist >= cutoff) + continue; + + ModuleBase::Vector3 R_idx(adjs.box[ad].x, adjs.box[ad].y, adjs.box[ad].z); + + hamilt::BaseMatrix* mtx_x = dVl_x.find_matrix(iat, iat2, R_idx.x, R_idx.y, R_idx.z); + hamilt::BaseMatrix* mtx_y = dVl_y.find_matrix(iat, iat2, R_idx.x, R_idx.y, R_idx.z); + hamilt::BaseMatrix* mtx_z = dVl_z.find_matrix(iat, iat2, R_idx.x, R_idx.y, R_idx.z); + + if (!mtx_x || !mtx_y || !mtx_z) + continue; + + double* ptr_x = mtx_x->get_pointer(); + double* ptr_y = mtx_y->get_pointer(); + double* ptr_z = mtx_z->get_pointer(); + const int row_sz = mtx_x->get_row_size(); + const int col_sz = mtx_x->get_col_size(); + + for (int ii = 0; ii < atom1->nw * npol; ii++) + { + const int iw1_all = ucell.itiaiw2iwt(T1, I1, ii / npol); + if (pv.global2local_row(iw1_all) < 0) + continue; + const int iw1_row = pv.global2local_row(iw1_all); + + for (int jj = 0; jj < atom2->nw * npol; jj++) + { + const int iw2_all = ucell.itiaiw2iwt(T2, I2, jj / npol); + if (pv.global2local_col(iw2_all) < 0) + continue; + const int iw2_col = pv.global2local_col(iw2_all); + + int idx = iw1_row * col_sz + iw2_col; + + // Contribution from atom1's orbitals: - + // This is the Pulay term which needs grid integration + // Placeholder: store zero for now + ptr_x[idx] += 0.0; + ptr_y[idx] += 0.0; + ptr_z[idx] += 0.0; + } + } + } + } +} + +bool write_dH_vl(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_vl"); + ModuleBase::timer::start("ModuleIO", "write_dH_vl"); + + const UnitCell& ucell = *params.ucell; + const Parallel_Orbitals& pv = *params.pv; + const int nat = ucell.nat; + const int nspin = params.nspin; + + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) + { + hamilt::HContainer dVl_x(&pv); + hamilt::HContainer dVl_y(&pv); + hamilt::HContainer dVl_z(&pv); + dVl_x.set_zero(); + dVl_y.set_zero(); + dVl_z.set_zero(); + + // Compute Pulay term via grid integration + write_dH_vl_pulay(params, ispin, dVl_x, dVl_y, dVl_z); + + const int nbasis = dVl_x.get_nbasis(); + + // Write to CSR files +#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); + + hamilt::HContainer dVl_x_s(&serialV); + hamilt::HContainer dVl_y_s(&serialV); + hamilt::HContainer dVl_z_s(&serialV); + hamilt::gatherParallels(dVl_x, &dVl_x_s, 0); + hamilt::gatherParallels(dVl_y, &dVl_y_s, 0); + hamilt::gatherParallels(dVl_z, &dVl_z_s, 0); + + if (GlobalV::MY_RANK == 0) +#endif + { + std::string fname_x = ModuleIO::dhr_gen_fname("dvlrx", ispin, params.append, params.istep); + std::string fname_y = ModuleIO::dhr_gen_fname("dvlry", ispin, params.append, params.istep); + std::string fname_z = ModuleIO::dhr_gen_fname("dvlrz", ispin, params.append, params.istep); + + if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) + { + fname_x = PARAM.globalv.global_matrix_dir + fname_x; + fname_y = PARAM.globalv.global_matrix_dir + fname_y; + fname_z = PARAM.globalv.global_matrix_dir + fname_z; + } + else + { + fname_x = PARAM.globalv.global_out_dir + fname_x; + fname_y = PARAM.globalv.global_out_dir + fname_y; + fname_z = PARAM.globalv.global_out_dir + fname_z; + } + +#ifdef __MPI + ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVl_x_s, params.istep, ispin, nspin, "dV^L"); + ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVl_y_s, params.istep, ispin, nspin, "dV^L"); + ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVl_z_s, params.istep, ispin, nspin, "dV^L"); +#else + ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVl_x, params.istep, ispin, nspin, "dV^L"); + ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVl_y, params.istep, ispin, nspin, "dV^L"); + ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVl_z, params.istep, ispin, nspin, "dV^L"); +#endif + } + } + + ModuleBase::timer::end("ModuleIO", "write_dH_vl"); + return true; +} + +} // namespace ModuleIO diff --git a/source/source_io/module_dhs/write_dH_vnl.cpp b/source/source_io/module_dhs/write_dH_vnl.cpp new file mode 100644 index 00000000000..2d93e9512ea --- /dev/null +++ b/source/source_io/module_dhs/write_dH_vnl.cpp @@ -0,0 +1,94 @@ +#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/nonlocal.h" +#include "source_lcao/module_operator_lcao/operator_force_stress_utils.h" +#include "write_dH.h" + +namespace ModuleIO +{ + +bool write_dH_vnl(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_vnl"); + ModuleBase::timer::start("ModuleIO", "write_dH_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 int nat = ucell.nat; + const int nspin = params.nspin; + const std::vector& orb_cutoff = params.orb->cutoffs(); + + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) + { + hamilt::HContainer dVnl_x(&pv); + hamilt::HContainer dVnl_y(&pv); + hamilt::HContainer dVnl_z(&pv); + + 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(&dVnl_x, &dVnl_y, &dVnl_z); + + const int nbasis = dVnl_x.get_nbasis(); + +#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); + + hamilt::HContainer dVnl_x_s(&serialV); + hamilt::HContainer dVnl_y_s(&serialV); + hamilt::HContainer dVnl_z_s(&serialV); + hamilt::gatherParallels(dVnl_x, &dVnl_x_s, 0); + hamilt::gatherParallels(dVnl_y, &dVnl_y_s, 0); + hamilt::gatherParallels(dVnl_z, &dVnl_z_s, 0); + + if (GlobalV::MY_RANK == 0) +#endif + { + std::string fname_x = ModuleIO::dhr_gen_fname("dvnlrx", ispin, params.append, params.istep); + std::string fname_y = ModuleIO::dhr_gen_fname("dvnlry", ispin, params.append, params.istep); + std::string fname_z = ModuleIO::dhr_gen_fname("dvnlrz", ispin, params.append, params.istep); + + if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) + { + fname_x = PARAM.globalv.global_matrix_dir + fname_x; + fname_y = PARAM.globalv.global_matrix_dir + fname_y; + fname_z = PARAM.globalv.global_matrix_dir + fname_z; + } + else + { + fname_x = PARAM.globalv.global_out_dir + fname_x; + fname_y = PARAM.globalv.global_out_dir + fname_y; + fname_z = PARAM.globalv.global_out_dir + fname_z; + } + +#ifdef __MPI + ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVnl_x_s, params.istep, ispin, nspin, "dV^NL"); + ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVnl_y_s, params.istep, ispin, nspin, "dV^NL"); + ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVnl_z_s, params.istep, ispin, nspin, "dV^NL"); +#else + ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVnl_x, params.istep, ispin, nspin, "dV^NL"); + ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVnl_y, params.istep, ispin, nspin, "dV^NL"); + ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVnl_z, params.istep, ispin, nspin, "dV^NL"); +#endif + } + } + + ModuleBase::timer::end("ModuleIO", "write_dH_vnl"); + return true; +} + +} // namespace ModuleIO diff --git a/source/source_io/module_dhs/write_dH_vxc.cpp b/source/source_io/module_dhs/write_dH_vxc.cpp new file mode 100644 index 00000000000..6192b31cdf4 --- /dev/null +++ b/source/source_io/module_dhs/write_dH_vxc.cpp @@ -0,0 +1,82 @@ +#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 "write_dH.h" + +namespace ModuleIO +{ + +bool write_dH_vxc(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_vxc"); + ModuleBase::timer::start("ModuleIO", "write_dH_vxc"); + + const UnitCell& ucell = *params.ucell; + const Parallel_Orbitals& pv = *params.pv; + const int nat = ucell.nat; + const int nspin = params.nspin; + + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) + { + hamilt::HContainer dVxc_x(&pv); + hamilt::HContainer dVxc_y(&pv); + hamilt::HContainer dVxc_z(&pv); + dVxc_x.set_zero(); + dVxc_y.set_zero(); + dVxc_z.set_zero(); + + const int nbasis = dVxc_x.get_nbasis(); + +#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); + + hamilt::HContainer dVxc_x_s(&serialV); + hamilt::HContainer dVxc_y_s(&serialV); + hamilt::HContainer dVxc_z_s(&serialV); + hamilt::gatherParallels(dVxc_x, &dVxc_x_s, 0); + hamilt::gatherParallels(dVxc_y, &dVxc_y_s, 0); + hamilt::gatherParallels(dVxc_z, &dVxc_z_s, 0); + + if (GlobalV::MY_RANK == 0) +#endif + { + std::string fname_x = ModuleIO::dhr_gen_fname("dvxcrx", ispin, params.append, params.istep); + std::string fname_y = ModuleIO::dhr_gen_fname("dvxcry", ispin, params.append, params.istep); + std::string fname_z = ModuleIO::dhr_gen_fname("dvxcrz", ispin, params.append, params.istep); + + if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) + { + fname_x = PARAM.globalv.global_matrix_dir + fname_x; + fname_y = PARAM.globalv.global_matrix_dir + fname_y; + fname_z = PARAM.globalv.global_matrix_dir + fname_z; + } + else + { + fname_x = PARAM.globalv.global_out_dir + fname_x; + fname_y = PARAM.globalv.global_out_dir + fname_y; + fname_z = PARAM.globalv.global_out_dir + fname_z; + } + +#ifdef __MPI + ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVxc_x_s, params.istep, ispin, nspin, "dV^XC"); + ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVxc_y_s, params.istep, ispin, nspin, "dV^XC"); + ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVxc_z_s, params.istep, ispin, nspin, "dV^XC"); +#else + ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVxc_x, params.istep, ispin, nspin, "dV^XC"); + ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVxc_y, params.istep, ispin, nspin, "dV^XC"); + ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVxc_z, params.istep, ispin, nspin, "dV^XC"); +#endif + } + } + + ModuleBase::timer::end("ModuleIO", "write_dH_vxc"); + return true; +} + +} // namespace ModuleIO 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..bd7d64f1c85 --- /dev/null +++ b/source/source_io/module_hs/write_H_terms.cpp @@ -0,0 +1,354 @@ +#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" + +#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); + std::cout << "hk term fname = " << fname << std::endl; + ModuleIO::save_mat(istep, + hk_global.data(), + nlocal, + false, + 8, + false, + out_app_flag, + fname, + pv, + GlobalV::DRANK); + } +} + +void write_h_t(const UnitCell& ucell, + const Grid_Driver& gd, + const Parallel_Orbitals& pv, + const TwoCenterBundle& two_center_bundle, + const LCAO_Orbitals& orb, + const K_Vectors& kv, + const int nspin, + const int istep, + const bool append, + const int* iat2iwt, + const int nat, + const bool also_hk) +{ + ModuleBase::TITLE("ModuleIO", "write_h_t"); + ModuleBase::timer::start("ModuleIO", "write_h_t"); + + 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(); + + gather_and_write("t", "T", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + + if (also_hk) + { + write_hk_common(hR_tmp, "tk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + } + } + + ModuleBase::timer::end("ModuleIO", "write_h_t"); +} + +void write_h_vnl(const UnitCell& ucell, + const Grid_Driver& gd, + const Parallel_Orbitals& pv, + const TwoCenterBundle& two_center_bundle, + const LCAO_Orbitals& orb, + const K_Vectors& kv, + const int nspin, + const int istep, + const bool append, + const int* iat2iwt, + const int nat, + const bool also_hk) +{ + ModuleBase::TITLE("ModuleIO", "write_h_vnl"); + ModuleBase::timer::start("ModuleIO", "write_h_vnl"); + + 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(); + + gather_and_write("vnl", "V^NL", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + + if (also_hk) + { + write_hk_common(hR_tmp, "vnlk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + } + } + + ModuleBase::timer::end("ModuleIO", "write_h_vnl"); +} + +void write_h_vl(const UnitCell& ucell, + const Grid_Driver& gd, + const Parallel_Orbitals& pv, + const LCAO_Orbitals& orb, + const elecstate::Potential* pot, + const int nspin, + const int istep, + const bool append, + const int* iat2iwt, + const int nat, + const K_Vectors& kv, + const bool also_hk) +{ + ModuleBase::TITLE("ModuleIO", "write_h_vl"); + ModuleBase::timer::start("ModuleIO", "write_h_vl"); + + 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(); + ModuleGint::cal_gint_vl(v_local, &hR_tmp); + + gather_and_write("vl", "V^L", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + + if (also_hk) + { + write_hk_common(hR_tmp, "vlk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + } + } + + ModuleBase::timer::end("ModuleIO", "write_h_vl"); +} + +void write_h_vh(const UnitCell& ucell, + const Grid_Driver& gd, + const Parallel_Orbitals& pv, + const LCAO_Orbitals& orb, + const Charge* chg, + const ModulePW::PW_Basis* rho_basis, + const int nspin, + const int istep, + const bool append, + const int* iat2iwt, + const int nat, + const K_Vectors& kv, + const bool also_hk) +{ + ModuleBase::TITLE("ModuleIO", "write_h_vh"); + ModuleBase::timer::start("ModuleIO", "write_h_vh"); + + 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); + + gather_and_write("vh", "V^H", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + + if (also_hk) + { + write_hk_common(hR_tmp, "vhk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + } + } + + ModuleBase::timer::end("ModuleIO", "write_h_vh"); +} + +void write_h_vxc(const UnitCell& ucell, + const Grid_Driver& gd, + const Parallel_Orbitals& pv, + const LCAO_Orbitals& orb, + const Charge* chg, + const int nrxx, + const int nspin, + const int istep, + const bool append, + const int* iat2iwt, + const int nat, + const K_Vectors& kv, + const bool also_hk) +{ + ModuleBase::TITLE("ModuleIO", "write_h_vxc"); + ModuleBase::timer::start("ModuleIO", "write_h_vxc"); + + 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); + + gather_and_write("vxc", "V^XC", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + + if (also_hk) + { + write_hk_common(hR_tmp, "vxck", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + } + } + + ModuleBase::timer::end("ModuleIO", "write_h_vxc"); +} + +} // 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..f1434486d54 --- /dev/null +++ b/source/source_io/module_hs/write_H_terms.h @@ -0,0 +1,87 @@ +#ifndef WRITE_HS_R_TERMS_H +#define WRITE_HS_R_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 + +namespace ModuleIO +{ + +void write_h_t(const UnitCell& ucell, + const Grid_Driver& gd, + const Parallel_Orbitals& pv, + const TwoCenterBundle& two_center_bundle, + const LCAO_Orbitals& orb, + const K_Vectors& kv, + const int nspin, + const int istep, + const bool append, + const int* iat2iwt, + const int nat, + const bool also_hk = true); + +void write_h_vnl(const UnitCell& ucell, + const Grid_Driver& gd, + const Parallel_Orbitals& pv, + const TwoCenterBundle& two_center_bundle, + const LCAO_Orbitals& orb, + const K_Vectors& kv, + const int nspin, + const int istep, + const bool append, + const int* iat2iwt, + const int nat, + const bool also_hk = true); + +void write_h_vl(const UnitCell& ucell, + const Grid_Driver& gd, + const Parallel_Orbitals& pv, + const LCAO_Orbitals& orb, + const elecstate::Potential* pot, + const int nspin, + const int istep, + const bool append, + const int* iat2iwt, + const int nat, + const K_Vectors& kv, + const bool also_hk = true); + +void write_h_vh(const UnitCell& ucell, + const Grid_Driver& gd, + const Parallel_Orbitals& pv, + const LCAO_Orbitals& orb, + const Charge* chg, + const ModulePW::PW_Basis* rho_basis, + const int nspin, + const int istep, + const bool append, + const int* iat2iwt, + const int nat, + const K_Vectors& kv, + const bool also_hk = true); + +void write_h_vxc(const UnitCell& ucell, + const Grid_Driver& gd, + const Parallel_Orbitals& pv, + const LCAO_Orbitals& orb, + const Charge* chg, + const int nrxx, + const int nspin, + const int istep, + const bool append, + const int* iat2iwt, + const int nat, + const K_Vectors& kv, + const bool also_hk = true); + +} // namespace ModuleIO + +#endif diff --git a/source/source_io/module_output/filename.cpp b/source/source_io/module_output/filename.cpp index 966da0bc8fd..b9c06b93898 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" }; 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..426b4a7e5d0 100644 --- a/source/source_io/module_parameter/input_parameter.h +++ b/source/source_io/module_parameter/input_parameter.h @@ -394,7 +394,17 @@ 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_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_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..a64cb4931da 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) { @@ -667,6 +667,256 @@ Also controled by out_freq_ion and out_app_flag. sync_intvec(input.out_mat_dh, 2, 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. The first value controls output (0/1), and optional subsequent values specify which atoms to compute derivatives for." + "\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_t[0] = assume_as_boolean(item.str_values[0]); + } + 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, 2, 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]); + } + 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, 2, 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]); + } + 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, 2, 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]); + } + 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, 2, 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]); + } + 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, 2, 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_ds"); item.annotation = "output of derivative of S(R) matrix"; 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..473bca65ba0 100644 --- a/source/source_lcao/module_operator_lcao/ekinetic.h +++ b/source/source_lcao/module_operator_lcao/ekinetic.h @@ -75,6 +75,10 @@ class EKinetic> : public OperatorLCAO ModuleBase::matrix& force, ModuleBase::matrix& stress); + void cal_dH(hamilt::HContainer* dhR_x, + hamilt::HContainer* dhR_y, + hamilt::HContainer* dhR_z); + 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..75545c63ae3 --- /dev/null +++ b/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp @@ -0,0 +1,151 @@ +#pragma once +#include "ekinetic.h" +#include "operator_force_stress_utils.hpp" +#include "source_base/timer.h" + +namespace hamilt +{ + +template +void EKinetic>::cal_dH(hamilt::HContainer* dhR_x, + hamilt::HContainer* dhR_y, + hamilt::HContainer* dhR_z) +{ + ModuleBase::TITLE("EKinetic", "cal_dH"); + ModuleBase::timer::start("EKinetic", "cal_dH"); + + const Parallel_Orbitals* paraV = dhR_x->get_paraV(); + const int npol = this->ucell->get_npol(); + + const int nat = this->ucell->nat; + + 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); + dhR_x->insert_pair(ap); + dhR_y->insert_pair(ap); + dhR_z->insert_pair(ap); + } + } + + dhR_x->allocate(nullptr, true); + dhR_y->allocate(nullptr, true); + dhR_z->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; + } + + hamilt::BaseMatrix* mtx_x = dhR_x->find_matrix(iat1, iat2, R_index); + hamilt::BaseMatrix* mtx_y = dhR_y->find_matrix(iat1, iat2, R_index); + hamilt::BaseMatrix* mtx_z = dhR_z->find_matrix(iat1, iat2, R_index); + + if (!mtx_x || !mtx_y || !mtx_z) + { + continue; + } + + double* ptr_x = mtx_x->get_pointer(); + double* ptr_y = mtx_y->get_pointer(); + double* ptr_z = mtx_z->get_pointer(); + const int row_size = mtx_x->get_row_size(); + const int col_size = mtx_x->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); + + ptr_x[idx] += olm[1] + olm_rev[1]; + ptr_y[idx] += olm[2] + olm_rev[2]; + ptr_z[idx] += olm[3] + olm_rev[3]; + } + } + } + } + } + + 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..d50e0e9c0ba 100644 --- a/source/source_lcao/module_operator_lcao/nonlocal.h +++ b/source/source_lcao/module_operator_lcao/nonlocal.h @@ -60,6 +60,10 @@ class Nonlocal> : public OperatorLCAO ModuleBase::matrix& force, ModuleBase::matrix& stress); + void cal_dH(hamilt::HContainer* dhR_x, + hamilt::HContainer* dhR_y, + hamilt::HContainer* dhR_z); + 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..5d66a256a1c --- /dev/null +++ b/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp @@ -0,0 +1,233 @@ +#pragma once +#include "nonlocal.h" +#include "operator_force_stress_utils.h" +#include "source_base/timer.h" + +namespace hamilt +{ + +template +void Nonlocal>::cal_dH(hamilt::HContainer* dhR_x, + hamilt::HContainer* dhR_y, + hamilt::HContainer* dhR_z) +{ + ModuleBase::TITLE("Nonlocal", "cal_dH"); + ModuleBase::timer::start("Nonlocal", "cal_dH"); + + const Parallel_Orbitals* paraV = dhR_x->get_paraV(); + const int npol = this->ucell->get_npol(); + + const int nat = this->ucell->nat; + + 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); + dhR_x->insert_pair(ap); + dhR_y->insert_pair(ap); + dhR_z->insert_pair(ap); + } + } + } + + dhR_x->allocate(nullptr, true); + dhR_y->allocate(nullptr, true); + dhR_z->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); + + hamilt::BaseMatrix* mtx_x = dhR_x->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + hamilt::BaseMatrix* mtx_y = dhR_y->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + hamilt::BaseMatrix* mtx_z = dhR_z->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + + if (!mtx_x || !mtx_y || !mtx_z) + continue; + + double* ptr_x = mtx_x->get_pointer(); + double* ptr_y = mtx_y->get_pointer(); + double* ptr_z = mtx_z->get_pointer(); + const int row_sz = mtx_x->get_row_size(); + const int col_sz = mtx_x->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]); + + std::vector nlm_tmp(3, 0.0); + + for (int no = 0; no < this->ucell->atoms[T0].ncpp.non_zero_count_soc[0]; no++) + { + const int p1 = this->ucell->atoms[T0].ncpp.index1_soc[0][no]; + const int p2 = this->ucell->atoms[T0].ncpp.index2_soc[0][no]; + const double* tmp_d = nullptr; + this->ucell->atoms[T0].ncpp.get_d(0, p1, p2, tmp_d); + nlm_tmp[0] += nlm1[p1 + length] * nlm2[p2] * (*tmp_d); + nlm_tmp[1] += nlm1[p1 + length * 2] * nlm2[p2] * (*tmp_d); + nlm_tmp[2] += nlm1[p1 + length * 3] * nlm2[p2] * (*tmp_d); + } + + int idx = iw1_row * col_sz + iw2_col; + ptr_x[idx] += nlm_tmp[0]; + ptr_y[idx] += nlm_tmp[1]; + ptr_z[idx] += nlm_tmp[2]; + } + } + } + } + } + } + + ModuleBase::timer::end("Nonlocal", "cal_dH"); +} + +} // namespace hamilt 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/tests/02_NAO_Gamma/scf_out_dh/genref_diff/INPUT b/tests/02_NAO_Gamma/scf_out_dh/genref_diff/INPUT new file mode 100644 index 00000000000..fdb9d0fd57b --- /dev/null +++ b/tests/02_NAO_Gamma/scf_out_dh/genref_diff/INPUT @@ -0,0 +1,44 @@ +INPUT_PARAMETERS +#Parameters (1.General) +suffix autotest +calculation scf + +nbands 4 +symmetry 1 +pseudo_dir ../../PP_ORB +orbital_dir ../../PP_ORB + +gamma_only 1 + +#Parameters (2.Iteration) +ecutwfc 20 +scf_thr 1e-8 +scf_nmax 100 + + +#Parameters (3.Basis) +basis_type lcao + +#Parameters (4.Smearing) +smearing_method gauss +smearing_sigma 0.002 + +out_mat_xc 1 +out_mat_xc2 1 +out_eband_terms 1 + +#Parameters (5.Mixing) +mixing_type broyden +mixing_beta 0.7 +mixing_gg0 1.5 + +ks_solver scalapack_gvx + +bx 2 +by 2 +bz 2 + + +out_mat_dh 1 +out_mat_dh_t 1 +out_mat_dh_vnl 1 \ No newline at end of file diff --git a/tests/02_NAO_Gamma/scf_out_dh/genref_diff/STRU b/tests/02_NAO_Gamma/scf_out_dh/genref_diff/STRU new file mode 100644 index 00000000000..5df0c1da5e0 --- /dev/null +++ b/tests/02_NAO_Gamma/scf_out_dh/genref_diff/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 From 2402a636b5f24d01b3d1c232bf28df89c03d5b94 Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Mon, 1 Jun 2026 16:17:46 +0800 Subject: [PATCH 02/13] correct 1-electron terms: T, Vl, Vnl --- .../source_estate/module_pot/potential_new.h | 5 + source/source_io/CMakeLists.txt | 6 +- .../source_io/module_ctrl/ctrl_scf_lcao.cpp | 1 + source/source_io/module_dhs/write_dH.cpp | 91 ++++++ source/source_io/module_dhs/write_dH.h | 16 ++ source/source_io/module_dhs/write_dH_t.cpp | 96 ------- .../source_io/module_dhs/write_dH_terms.cpp | 193 +++++++++++++ source/source_io/module_dhs/write_dH_vh.cpp | 82 ------ source/source_io/module_dhs/write_dH_vl.cpp | 178 ------------ source/source_io/module_dhs/write_dH_vnl.cpp | 94 ------ source/source_io/module_dhs/write_dH_vxc.cpp | 82 ------ .../source_lcao/module_gint/gint_dvlocal.cpp | 8 +- source/source_lcao/module_gint/gint_dvlocal.h | 14 +- .../module_operator_lcao/ekinetic.h | 7 +- .../module_operator_lcao/ekinetic_dh.hpp | 74 +++-- .../module_operator_lcao/nonlocal.h | 7 +- .../module_operator_lcao/nonlocal_dh.hpp | 102 +++++-- .../module_operator_lcao/veff_dh.hpp | 267 ++++++++++++++++++ .../module_operator_lcao/veff_lcao.cpp | 1 + .../module_operator_lcao/veff_lcao.h | 9 + source/source_pw/module_pwdft/forces.h | 5 + 21 files changed, 734 insertions(+), 604 deletions(-) delete mode 100644 source/source_io/module_dhs/write_dH_t.cpp create mode 100644 source/source_io/module_dhs/write_dH_terms.cpp delete mode 100644 source/source_io/module_dhs/write_dH_vh.cpp delete mode 100644 source/source_io/module_dhs/write_dH_vl.cpp delete mode 100644 source/source_io/module_dhs/write_dH_vnl.cpp delete mode 100644 source/source_io/module_dhs/write_dH_vxc.cpp create mode 100644 source/source_lcao/module_operator_lcao/veff_dh.hpp 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 37b0261812c..e6461d11bc4 100644 --- a/source/source_io/CMakeLists.txt +++ b/source/source_io/CMakeLists.txt @@ -83,11 +83,7 @@ if(ENABLE_LCAO) module_ml/io_npz.cpp module_hs/cal_pLpR.cpp module_dhs/write_dH.cpp - module_dhs/write_dH_t.cpp - module_dhs/write_dH_vnl.cpp - module_dhs/write_dH_vl.cpp - module_dhs/write_dH_vh.cpp - module_dhs/write_dH_vxc.cpp + module_dhs/write_dH_terms.cpp ) list(APPEND objects_advanced module_unk/unk_overlap_lcao.cpp diff --git a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp index 5b146225970..5e9fd5e6ee9 100644 --- a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp +++ b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp @@ -262,6 +262,7 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, dh_params.orb = &orb; dh_params.kv = &kv; dh_params.v_eff = &pelec->pot->get_eff_v(); + dh_params.pot = pelec->pot; dh_params.iat2iwt = ucell.get_iat2iwt(); dh_params.nat = ucell.nat; dh_params.nspin = inp.nspin; diff --git a/source/source_io/module_dhs/write_dH.cpp b/source/source_io/module_dhs/write_dH.cpp index b88651d883e..a90c1f6b414 100644 --- a/source/source_io/module_dhs/write_dH.cpp +++ b/source/source_io/module_dhs/write_dH.cpp @@ -1,18 +1,104 @@ #include "write_dH.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 namespace ModuleIO { +void write_dh_perI(WriteDHParams& params, + int ispin, + const std::string& rprefix, + const std::string& kprefix, + const std::string& label, + std::vector*>& gx, + std::vector*>& gy, + std::vector*>& gz) +{ + const UnitCell& ucell = *params.ucell; + const Parallel_Orbitals& pv = *params.pv; + const int nat = params.nat; + const int nspin = params.nspin; + const int nbasis = gx[0]->get_nbasis(); + + const char dirc[3] = {'x', 'y', 'z'}; + std::vector*>* g[3] = {&gx, &gy, &gz}; + + // 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 + + for (int iat = 0; iat < nat; ++iat) + { + 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 ---- +#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) + for (int ik = 0; ik < nks; ++ik) + { + std::vector> hk(static_cast(nlocal) * nlocal, 0); + hamilt::folding_HR(*hR, hk.data(), params.kv->kvec_d[ik], nlocal, 0); + 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); + } + } + } +} + bool any_dh_term_enabled() { return PARAM.inp.out_mat_dh_t[0] || PARAM.inp.out_mat_dh_vl[0] || PARAM.inp.out_mat_dh_vnl[0] @@ -88,6 +174,11 @@ bool write_dH_sum(WriteDHParams& params) dH_sum_y.set_zero(); dH_sum_z.set_zero(); + if (dH_sum_x.size_atom_pairs() == 0) + { + continue; + } + const int nbasis = dH_sum_x.get_nbasis(); #ifdef __MPI diff --git a/source/source_io/module_dhs/write_dH.h b/source/source_io/module_dhs/write_dH.h index 1e4e57e3504..a15d2096f49 100644 --- a/source/source_io/module_dhs/write_dH.h +++ b/source/source_io/module_dhs/write_dH.h @@ -4,6 +4,7 @@ #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" @@ -22,6 +23,7 @@ struct WriteDHParams const K_Vectors* kv = nullptr; const ModuleBase::matrix* v_eff = nullptr; const int* iat2iwt = nullptr; + elecstate::Potential* pot = nullptr; int nat = 0; int nspin = 1; int istep = 0; @@ -32,6 +34,20 @@ struct WriteDHParams bool any_dh_term_enabled(); +// 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). +// gx/gy/gz are nat per-I HContainers (already filled by an operator's cal_dH). +void write_dh_perI(WriteDHParams& params, + int ispin, + const std::string& rprefix, + const std::string& kprefix, + const std::string& label, + std::vector*>& gx, + std::vector*>& gy, + std::vector*>& gz); + void write_dH_components(WriteDHParams& params); bool write_dH_t(WriteDHParams& params); diff --git a/source/source_io/module_dhs/write_dH_t.cpp b/source/source_io/module_dhs/write_dH_t.cpp deleted file mode 100644 index 7def2ed5fbe..00000000000 --- a/source/source_io/module_dhs/write_dH_t.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#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/operator_force_stress_utils.h" -#include "write_dH.h" - -namespace ModuleIO -{ - -bool write_dH_t(WriteDHParams& params) -{ - ModuleBase::TITLE("ModuleIO", "write_dH_t"); - ModuleBase::timer::start("ModuleIO", "write_dH_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 int nat = ucell.nat; - const int nspin = params.nspin; - const std::vector& orb_cutoff = orb.cutoffs(); - - for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) - { - hamilt::HContainer dT_x(&pv); - hamilt::HContainer dT_y(&pv); - hamilt::HContainer dT_z(&pv); - - hamilt::EKinetic> tmp_ekinetic(nullptr, - params.kv->kvec_d, - nullptr, - &ucell, - orb_cutoff, - &gd, - two_center_bundle.kinetic_orb.get()); - - tmp_ekinetic.cal_dH(&dT_x, &dT_y, &dT_z); - - const int nbasis = dT_x.get_nbasis(); - -#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); - - hamilt::HContainer dT_x_serial(&serialV); - hamilt::HContainer dT_y_serial(&serialV); - hamilt::HContainer dT_z_serial(&serialV); - hamilt::gatherParallels(dT_x, &dT_x_serial, 0); - hamilt::gatherParallels(dT_y, &dT_y_serial, 0); - hamilt::gatherParallels(dT_z, &dT_z_serial, 0); - - if (GlobalV::MY_RANK == 0) -#endif - { - std::string fname_x = ModuleIO::dhr_gen_fname("dtrx", ispin, params.append, params.istep); - std::string fname_y = ModuleIO::dhr_gen_fname("dtry", ispin, params.append, params.istep); - std::string fname_z = ModuleIO::dhr_gen_fname("dtrz", ispin, params.append, params.istep); - - if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) - { - fname_x = PARAM.globalv.global_matrix_dir + fname_x; - fname_y = PARAM.globalv.global_matrix_dir + fname_y; - fname_z = PARAM.globalv.global_matrix_dir + fname_z; - } - else - { - fname_x = PARAM.globalv.global_out_dir + fname_x; - fname_y = PARAM.globalv.global_out_dir + fname_y; - fname_z = PARAM.globalv.global_out_dir + fname_z; - } - -#ifdef __MPI - ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dT_x_serial, params.istep, ispin, nspin, "dT"); - ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dT_y_serial, params.istep, ispin, nspin, "dT"); - ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dT_z_serial, params.istep, ispin, nspin, "dT"); -#else - ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dT_x, params.istep, ispin, nspin, "dT"); - ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dT_y, params.istep, ispin, nspin, "dT"); - ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dT_z, params.istep, ispin, nspin, "dT"); -#endif - } - } - - ModuleBase::timer::end("ModuleIO", "write_dH_t"); - return true; -} - -} // namespace ModuleIO 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..3bb5bfbc6be --- /dev/null +++ b/source/source_io/module_dhs/write_dH_terms.cpp @@ -0,0 +1,193 @@ +#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 "write_dH.h" + +#include +#include + +namespace ModuleIO +{ + +namespace +{ + +// RAII holder for the per-atom-I dH containers: one (dx, dy, dz) HContainer per atom I. +// gx/gy/gz 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::vector>> ox, oy, oz; + std::vector*> gx, gy, gz; + + PerIContainers(const Parallel_Orbitals& pv, int nat) + { + ox.reserve(nat); + oy.reserve(nat); + oz.reserve(nat); + gx.reserve(nat); + gy.reserve(nat); + gz.reserve(nat); + for (int iat = 0; iat < nat; ++iat) + { + ox.push_back(std::make_unique>(&pv)); + oy.push_back(std::make_unique>(&pv)); + oz.push_back(std::make_unique>(&pv)); + gx.push_back(ox.back().get()); + gy.push_back(oy.back().get()); + gz.push_back(oz.back().get()); + } + } +}; + +// 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, + const std::string& hf_type, + const std::string& rprefix, + const std::string& kprefix, + const std::string& label) +{ + 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 nat = ucell.nat; + const int nspin = params.nspin; + + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) + { + hamilt::HContainer hR_dummy(const_cast(&pv)); + + hamilt::Veff> veff(nullptr, + params.kv->kvec_d, + params.pot, + &hR_dummy, + &ucell, + orb_cutoff, + &gd, + nspin); + + PerIContainers c(pv, nat); + + veff.cal_dH(c.gx, c.gy, c.gz, hf_type); + + ModuleIO::write_dh_perI(params, ispin, rprefix, kprefix, label, c.gx, c.gy, c.gz); + } + return true; +} + +} // namespace + +bool write_dH_t(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_t"); + ModuleBase::timer::start("ModuleIO", "write_dH_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 int nat = ucell.nat; + const int nspin = params.nspin; + const std::vector& orb_cutoff = orb.cutoffs(); + + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) + { + // per-atom-I containers: dT_*[iat] = d/dtau_iat + PerIContainers c(pv, nat); + + 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.gx, c.gy, c.gz); + + ModuleIO::write_dh_perI(params, ispin, "dtr", "dtk", "dT", c.gx, c.gy, c.gz); + } + + 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 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 int nat = ucell.nat; + const int nspin = params.nspin; + const std::vector& orb_cutoff = params.orb->cutoffs(); + + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) + { + PerIContainers c(pv, nat); + + 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.gx, c.gy, c.gz); + + ModuleIO::write_dh_perI(params, ispin, "dvnlr", "dvnlk", "dV^NL", c.gx, c.gy, c.gz); + } + + 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 bool ok = write_dH_veff_term(params, "vl", "dvlr", "dvlk", "dV^L"); + + 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 bool ok = write_dH_veff_term(params, "hartree", "dvhr", "dvhk", "dV^H"); + + ModuleBase::timer::end("ModuleIO", "write_dH_vh"); + return ok; +} + +bool write_dH_vxc(WriteDHParams& params) +{ + ModuleBase::TITLE("ModuleIO", "write_dH_vxc"); + ModuleBase::timer::start("ModuleIO", "write_dH_vxc"); + + const bool ok = write_dH_veff_term(params, "none", "dvxcr", "dvxck", "dV^XC"); + + ModuleBase::timer::end("ModuleIO", "write_dH_vxc"); + return ok; +} + +} // namespace ModuleIO diff --git a/source/source_io/module_dhs/write_dH_vh.cpp b/source/source_io/module_dhs/write_dH_vh.cpp deleted file mode 100644 index c786701dde8..00000000000 --- a/source/source_io/module_dhs/write_dH_vh.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#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 "write_dH.h" - -namespace ModuleIO -{ - -bool write_dH_vh(WriteDHParams& params) -{ - ModuleBase::TITLE("ModuleIO", "write_dH_vh"); - ModuleBase::timer::start("ModuleIO", "write_dH_vh"); - - const UnitCell& ucell = *params.ucell; - const Parallel_Orbitals& pv = *params.pv; - const int nat = ucell.nat; - const int nspin = params.nspin; - - for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) - { - hamilt::HContainer dVh_x(&pv); - hamilt::HContainer dVh_y(&pv); - hamilt::HContainer dVh_z(&pv); - dVh_x.set_zero(); - dVh_y.set_zero(); - dVh_z.set_zero(); - - const int nbasis = dVh_x.get_nbasis(); - -#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); - - hamilt::HContainer dVh_x_s(&serialV); - hamilt::HContainer dVh_y_s(&serialV); - hamilt::HContainer dVh_z_s(&serialV); - hamilt::gatherParallels(dVh_x, &dVh_x_s, 0); - hamilt::gatherParallels(dVh_y, &dVh_y_s, 0); - hamilt::gatherParallels(dVh_z, &dVh_z_s, 0); - - if (GlobalV::MY_RANK == 0) -#endif - { - std::string fname_x = ModuleIO::dhr_gen_fname("dvhrx", ispin, params.append, params.istep); - std::string fname_y = ModuleIO::dhr_gen_fname("dvhry", ispin, params.append, params.istep); - std::string fname_z = ModuleIO::dhr_gen_fname("dvhrz", ispin, params.append, params.istep); - - if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) - { - fname_x = PARAM.globalv.global_matrix_dir + fname_x; - fname_y = PARAM.globalv.global_matrix_dir + fname_y; - fname_z = PARAM.globalv.global_matrix_dir + fname_z; - } - else - { - fname_x = PARAM.globalv.global_out_dir + fname_x; - fname_y = PARAM.globalv.global_out_dir + fname_y; - fname_z = PARAM.globalv.global_out_dir + fname_z; - } - -#ifdef __MPI - ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVh_x_s, params.istep, ispin, nspin, "dV^H"); - ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVh_y_s, params.istep, ispin, nspin, "dV^H"); - ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVh_z_s, params.istep, ispin, nspin, "dV^H"); -#else - ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVh_x, params.istep, ispin, nspin, "dV^H"); - ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVh_y, params.istep, ispin, nspin, "dV^H"); - ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVh_z, params.istep, ispin, nspin, "dV^H"); -#endif - } - } - - ModuleBase::timer::end("ModuleIO", "write_dH_vh"); - return true; -} - -} // namespace ModuleIO diff --git a/source/source_io/module_dhs/write_dH_vl.cpp b/source/source_io/module_dhs/write_dH_vl.cpp deleted file mode 100644 index 408203ddf00..00000000000 --- a/source/source_io/module_dhs/write_dH_vl.cpp +++ /dev/null @@ -1,178 +0,0 @@ -#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_gint/gint_interface.h" -#include "source_lcao/module_gint/phi_operator.h" -#include "source_lcao/module_hcontainer/hcontainer_funcs.h" -#include "source_lcao/module_hcontainer/output_hcontainer.h" -#include "source_lcao/module_operator_lcao/operator_force_stress_utils.h" -#include "write_dH.h" - -#include - -#ifdef _OPENMP -#include -#endif - -namespace ModuleIO -{ - -static void write_dH_vl_pulay(const WriteDHParams& params, - int ispin, - hamilt::HContainer& dVl_x, - hamilt::HContainer& dVl_y, - hamilt::HContainer& dVl_z) -{ - const UnitCell& ucell = *params.ucell; - const Grid_Driver& gd = *params.gd; - const Parallel_Orbitals& pv = *params.pv; - const LCAO_Orbitals& orb = *params.orb; - const std::vector& orb_cutoff = orb.cutoffs(); - const int nat = ucell.nat; - const int npol = ucell.get_npol(); - -#pragma omp parallel for schedule(dynamic) - for (int iat = 0; iat < nat; iat++) - { - const int T1 = ucell.iat2it[iat]; - const int I1 = ucell.iat2ia[iat]; - const ModuleBase::Vector3& tau1 = ucell.atoms[T1].tau[I1]; - const Atom* atom1 = &ucell.atoms[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); - const ModuleBase::Vector3& tau2 = adjs.adjacent_tau[ad]; - const Atom* atom2 = &ucell.atoms[T2]; - - ModuleBase::Vector3 dtau = tau2 - tau1; - double dist = dtau.norm() * ucell.lat0; - double cutoff = orb_cutoff[T1] + orb_cutoff[T2]; - - if (dist >= cutoff) - continue; - - ModuleBase::Vector3 R_idx(adjs.box[ad].x, adjs.box[ad].y, adjs.box[ad].z); - - hamilt::BaseMatrix* mtx_x = dVl_x.find_matrix(iat, iat2, R_idx.x, R_idx.y, R_idx.z); - hamilt::BaseMatrix* mtx_y = dVl_y.find_matrix(iat, iat2, R_idx.x, R_idx.y, R_idx.z); - hamilt::BaseMatrix* mtx_z = dVl_z.find_matrix(iat, iat2, R_idx.x, R_idx.y, R_idx.z); - - if (!mtx_x || !mtx_y || !mtx_z) - continue; - - double* ptr_x = mtx_x->get_pointer(); - double* ptr_y = mtx_y->get_pointer(); - double* ptr_z = mtx_z->get_pointer(); - const int row_sz = mtx_x->get_row_size(); - const int col_sz = mtx_x->get_col_size(); - - for (int ii = 0; ii < atom1->nw * npol; ii++) - { - const int iw1_all = ucell.itiaiw2iwt(T1, I1, ii / npol); - if (pv.global2local_row(iw1_all) < 0) - continue; - const int iw1_row = pv.global2local_row(iw1_all); - - for (int jj = 0; jj < atom2->nw * npol; jj++) - { - const int iw2_all = ucell.itiaiw2iwt(T2, I2, jj / npol); - if (pv.global2local_col(iw2_all) < 0) - continue; - const int iw2_col = pv.global2local_col(iw2_all); - - int idx = iw1_row * col_sz + iw2_col; - - // Contribution from atom1's orbitals: - - // This is the Pulay term which needs grid integration - // Placeholder: store zero for now - ptr_x[idx] += 0.0; - ptr_y[idx] += 0.0; - ptr_z[idx] += 0.0; - } - } - } - } -} - -bool write_dH_vl(WriteDHParams& params) -{ - ModuleBase::TITLE("ModuleIO", "write_dH_vl"); - ModuleBase::timer::start("ModuleIO", "write_dH_vl"); - - const UnitCell& ucell = *params.ucell; - const Parallel_Orbitals& pv = *params.pv; - const int nat = ucell.nat; - const int nspin = params.nspin; - - for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) - { - hamilt::HContainer dVl_x(&pv); - hamilt::HContainer dVl_y(&pv); - hamilt::HContainer dVl_z(&pv); - dVl_x.set_zero(); - dVl_y.set_zero(); - dVl_z.set_zero(); - - // Compute Pulay term via grid integration - write_dH_vl_pulay(params, ispin, dVl_x, dVl_y, dVl_z); - - const int nbasis = dVl_x.get_nbasis(); - - // Write to CSR files -#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); - - hamilt::HContainer dVl_x_s(&serialV); - hamilt::HContainer dVl_y_s(&serialV); - hamilt::HContainer dVl_z_s(&serialV); - hamilt::gatherParallels(dVl_x, &dVl_x_s, 0); - hamilt::gatherParallels(dVl_y, &dVl_y_s, 0); - hamilt::gatherParallels(dVl_z, &dVl_z_s, 0); - - if (GlobalV::MY_RANK == 0) -#endif - { - std::string fname_x = ModuleIO::dhr_gen_fname("dvlrx", ispin, params.append, params.istep); - std::string fname_y = ModuleIO::dhr_gen_fname("dvlry", ispin, params.append, params.istep); - std::string fname_z = ModuleIO::dhr_gen_fname("dvlrz", ispin, params.append, params.istep); - - if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) - { - fname_x = PARAM.globalv.global_matrix_dir + fname_x; - fname_y = PARAM.globalv.global_matrix_dir + fname_y; - fname_z = PARAM.globalv.global_matrix_dir + fname_z; - } - else - { - fname_x = PARAM.globalv.global_out_dir + fname_x; - fname_y = PARAM.globalv.global_out_dir + fname_y; - fname_z = PARAM.globalv.global_out_dir + fname_z; - } - -#ifdef __MPI - ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVl_x_s, params.istep, ispin, nspin, "dV^L"); - ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVl_y_s, params.istep, ispin, nspin, "dV^L"); - ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVl_z_s, params.istep, ispin, nspin, "dV^L"); -#else - ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVl_x, params.istep, ispin, nspin, "dV^L"); - ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVl_y, params.istep, ispin, nspin, "dV^L"); - ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVl_z, params.istep, ispin, nspin, "dV^L"); -#endif - } - } - - ModuleBase::timer::end("ModuleIO", "write_dH_vl"); - return true; -} - -} // namespace ModuleIO diff --git a/source/source_io/module_dhs/write_dH_vnl.cpp b/source/source_io/module_dhs/write_dH_vnl.cpp deleted file mode 100644 index 2d93e9512ea..00000000000 --- a/source/source_io/module_dhs/write_dH_vnl.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#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/nonlocal.h" -#include "source_lcao/module_operator_lcao/operator_force_stress_utils.h" -#include "write_dH.h" - -namespace ModuleIO -{ - -bool write_dH_vnl(WriteDHParams& params) -{ - ModuleBase::TITLE("ModuleIO", "write_dH_vnl"); - ModuleBase::timer::start("ModuleIO", "write_dH_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 int nat = ucell.nat; - const int nspin = params.nspin; - const std::vector& orb_cutoff = params.orb->cutoffs(); - - for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) - { - hamilt::HContainer dVnl_x(&pv); - hamilt::HContainer dVnl_y(&pv); - hamilt::HContainer dVnl_z(&pv); - - 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(&dVnl_x, &dVnl_y, &dVnl_z); - - const int nbasis = dVnl_x.get_nbasis(); - -#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); - - hamilt::HContainer dVnl_x_s(&serialV); - hamilt::HContainer dVnl_y_s(&serialV); - hamilt::HContainer dVnl_z_s(&serialV); - hamilt::gatherParallels(dVnl_x, &dVnl_x_s, 0); - hamilt::gatherParallels(dVnl_y, &dVnl_y_s, 0); - hamilt::gatherParallels(dVnl_z, &dVnl_z_s, 0); - - if (GlobalV::MY_RANK == 0) -#endif - { - std::string fname_x = ModuleIO::dhr_gen_fname("dvnlrx", ispin, params.append, params.istep); - std::string fname_y = ModuleIO::dhr_gen_fname("dvnlry", ispin, params.append, params.istep); - std::string fname_z = ModuleIO::dhr_gen_fname("dvnlrz", ispin, params.append, params.istep); - - if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) - { - fname_x = PARAM.globalv.global_matrix_dir + fname_x; - fname_y = PARAM.globalv.global_matrix_dir + fname_y; - fname_z = PARAM.globalv.global_matrix_dir + fname_z; - } - else - { - fname_x = PARAM.globalv.global_out_dir + fname_x; - fname_y = PARAM.globalv.global_out_dir + fname_y; - fname_z = PARAM.globalv.global_out_dir + fname_z; - } - -#ifdef __MPI - ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVnl_x_s, params.istep, ispin, nspin, "dV^NL"); - ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVnl_y_s, params.istep, ispin, nspin, "dV^NL"); - ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVnl_z_s, params.istep, ispin, nspin, "dV^NL"); -#else - ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVnl_x, params.istep, ispin, nspin, "dV^NL"); - ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVnl_y, params.istep, ispin, nspin, "dV^NL"); - ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVnl_z, params.istep, ispin, nspin, "dV^NL"); -#endif - } - } - - ModuleBase::timer::end("ModuleIO", "write_dH_vnl"); - return true; -} - -} // namespace ModuleIO diff --git a/source/source_io/module_dhs/write_dH_vxc.cpp b/source/source_io/module_dhs/write_dH_vxc.cpp deleted file mode 100644 index 6192b31cdf4..00000000000 --- a/source/source_io/module_dhs/write_dH_vxc.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#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 "write_dH.h" - -namespace ModuleIO -{ - -bool write_dH_vxc(WriteDHParams& params) -{ - ModuleBase::TITLE("ModuleIO", "write_dH_vxc"); - ModuleBase::timer::start("ModuleIO", "write_dH_vxc"); - - const UnitCell& ucell = *params.ucell; - const Parallel_Orbitals& pv = *params.pv; - const int nat = ucell.nat; - const int nspin = params.nspin; - - for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) - { - hamilt::HContainer dVxc_x(&pv); - hamilt::HContainer dVxc_y(&pv); - hamilt::HContainer dVxc_z(&pv); - dVxc_x.set_zero(); - dVxc_y.set_zero(); - dVxc_z.set_zero(); - - const int nbasis = dVxc_x.get_nbasis(); - -#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); - - hamilt::HContainer dVxc_x_s(&serialV); - hamilt::HContainer dVxc_y_s(&serialV); - hamilt::HContainer dVxc_z_s(&serialV); - hamilt::gatherParallels(dVxc_x, &dVxc_x_s, 0); - hamilt::gatherParallels(dVxc_y, &dVxc_y_s, 0); - hamilt::gatherParallels(dVxc_z, &dVxc_z_s, 0); - - if (GlobalV::MY_RANK == 0) -#endif - { - std::string fname_x = ModuleIO::dhr_gen_fname("dvxcrx", ispin, params.append, params.istep); - std::string fname_y = ModuleIO::dhr_gen_fname("dvxcry", ispin, params.append, params.istep); - std::string fname_z = ModuleIO::dhr_gen_fname("dvxcrz", ispin, params.append, params.istep); - - if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) - { - fname_x = PARAM.globalv.global_matrix_dir + fname_x; - fname_y = PARAM.globalv.global_matrix_dir + fname_y; - fname_z = PARAM.globalv.global_matrix_dir + fname_z; - } - else - { - fname_x = PARAM.globalv.global_out_dir + fname_x; - fname_y = PARAM.globalv.global_out_dir + fname_y; - fname_z = PARAM.globalv.global_out_dir + fname_z; - } - -#ifdef __MPI - ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVxc_x_s, params.istep, ispin, nspin, "dV^XC"); - ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVxc_y_s, params.istep, ispin, nspin, "dV^XC"); - ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVxc_z_s, params.istep, ispin, nspin, "dV^XC"); -#else - ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dVxc_x, params.istep, ispin, nspin, "dV^XC"); - ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dVxc_y, params.istep, ispin, nspin, "dV^XC"); - ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dVxc_z, params.istep, ispin, nspin, "dV^XC"); -#endif - } - } - - ModuleBase::timer::end("ModuleIO", "write_dH_vxc"); - return true; -} - -} // namespace ModuleIO 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_operator_lcao/ekinetic.h b/source/source_lcao/module_operator_lcao/ekinetic.h index 473bca65ba0..afe4af35c8d 100644 --- a/source/source_lcao/module_operator_lcao/ekinetic.h +++ b/source/source_lcao/module_operator_lcao/ekinetic.h @@ -75,9 +75,10 @@ class EKinetic> : public OperatorLCAO ModuleBase::matrix& force, ModuleBase::matrix& stress); - void cal_dH(hamilt::HContainer* dhR_x, - hamilt::HContainer* dhR_y, - hamilt::HContainer* dhR_z); + // per-atom-I derivative d/dtau_I; one HContainer per atom I (size nat each) + void cal_dH(std::vector*>& dhR_x, + std::vector*>& dhR_y, + std::vector*>& dhR_z); private: const UnitCell* ucell = nullptr; diff --git a/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp b/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp index 75545c63ae3..c97cd84cbdf 100644 --- a/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp +++ b/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp @@ -7,18 +7,19 @@ namespace hamilt { template -void EKinetic>::cal_dH(hamilt::HContainer* dhR_x, - hamilt::HContainer* dhR_y, - hamilt::HContainer* dhR_z) +void EKinetic>::cal_dH(std::vector*>& dhR_x, + std::vector*>& dhR_y, + std::vector*>& dhR_z) { ModuleBase::TITLE("EKinetic", "cal_dH"); ModuleBase::timer::start("EKinetic", "cal_dH"); - const Parallel_Orbitals* paraV = dhR_x->get_paraV(); - const int npol = this->ucell->get_npol(); - const int nat = this->ucell->nat; + assert(static_cast(dhR_x.size()) == nat); + const Parallel_Orbitals* paraV = dhR_x[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); @@ -47,15 +48,21 @@ void EKinetic>::cal_dH(hamilt::HContainer* dhR_x, } hamilt::AtomPair ap(iat1, iat2, R_index.x, R_index.y, R_index.z, paraV); - dhR_x->insert_pair(ap); - dhR_y->insert_pair(ap); - dhR_z->insert_pair(ap); + for (int iat = 0; iat < nat; ++iat) + { + dhR_x[iat]->insert_pair(ap); + dhR_y[iat]->insert_pair(ap); + dhR_z[iat]->insert_pair(ap); + } } } - dhR_x->allocate(nullptr, true); - dhR_y->allocate(nullptr, true); - dhR_z->allocate(nullptr, true); + for (int iat = 0; iat < nat; ++iat) + { + dhR_x[iat]->allocate(nullptr, true); + dhR_y[iat]->allocate(nullptr, true); + dhR_z[iat]->allocate(nullptr, true); + } #pragma omp parallel { @@ -83,20 +90,28 @@ void EKinetic>::cal_dH(hamilt::HContainer* dhR_x, continue; } - hamilt::BaseMatrix* mtx_x = dhR_x->find_matrix(iat1, iat2, R_index); - hamilt::BaseMatrix* mtx_y = dhR_y->find_matrix(iat1, iat2, R_index); - hamilt::BaseMatrix* mtx_z = dhR_z->find_matrix(iat1, iat2, R_index); - - if (!mtx_x || !mtx_y || !mtx_z) + // 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_x = dhR_x[iat1]->find_matrix(iat1, iat2, R_index); + hamilt::BaseMatrix* mtxU_y = dhR_y[iat1]->find_matrix(iat1, iat2, R_index); + hamilt::BaseMatrix* mtxU_z = dhR_z[iat1]->find_matrix(iat1, iat2, R_index); + hamilt::BaseMatrix* mtxV_x = dhR_x[iat2]->find_matrix(iat1, iat2, R_index); + hamilt::BaseMatrix* mtxV_y = dhR_y[iat2]->find_matrix(iat1, iat2, R_index); + hamilt::BaseMatrix* mtxV_z = dhR_z[iat2]->find_matrix(iat1, iat2, R_index); + + if (!mtxU_x || !mtxU_y || !mtxU_z || !mtxV_x || !mtxV_y || !mtxV_z) { continue; } - double* ptr_x = mtx_x->get_pointer(); - double* ptr_y = mtx_y->get_pointer(); - double* ptr_z = mtx_z->get_pointer(); - const int row_size = mtx_x->get_row_size(); - const int col_size = mtx_x->get_col_size(); + double* ptrU_x = mtxU_x->get_pointer(); + double* ptrU_y = mtxU_y->get_pointer(); + double* ptrU_z = mtxU_z->get_pointer(); + double* ptrV_x = mtxV_x->get_pointer(); + double* ptrV_y = mtxV_y->get_pointer(); + double* ptrV_z = mtxV_z->get_pointer(); + const int col_size = mtxU_x->get_col_size(); const Atom& atom2 = this->ucell->atoms[T2]; @@ -136,9 +151,18 @@ void EKinetic>::cal_dH(hamilt::HContainer* dhR_x, const int idx = (iw1l / npol) * col_size + (iw2l / npol); - ptr_x[idx] += olm[1] + olm_rev[1]; - ptr_y[idx] += olm[2] + olm_rev[2]; - ptr_z[idx] += olm[3] + olm_rev[3]; + // calculate() writes the spatial gradient (d/dx,d/dy,d/dz) into + // grad_out[0..2] (here olm[0..2]); olm[3] is unused. + // d/dtau_I = - (dtau = -grad); sign + // confirmed against the finite-difference reference. + // d/dtau_V (I = iat2) + ptrV_x[idx] -= olm[0]; + ptrV_y[idx] -= olm[1]; + ptrV_z[idx] -= olm[2]; + // d/dtau_U (I = iat1) + ptrU_x[idx] -= olm_rev[0]; + ptrU_y[idx] -= olm_rev[1]; + ptrU_z[idx] -= olm_rev[2]; } } } diff --git a/source/source_lcao/module_operator_lcao/nonlocal.h b/source/source_lcao/module_operator_lcao/nonlocal.h index d50e0e9c0ba..1a1e9f510f2 100644 --- a/source/source_lcao/module_operator_lcao/nonlocal.h +++ b/source/source_lcao/module_operator_lcao/nonlocal.h @@ -60,9 +60,10 @@ class Nonlocal> : public OperatorLCAO ModuleBase::matrix& force, ModuleBase::matrix& stress); - void cal_dH(hamilt::HContainer* dhR_x, - hamilt::HContainer* dhR_y, - hamilt::HContainer* dhR_z); + // per-atom-I derivative d/dtau_I; one HContainer per atom I (size nat each) + void cal_dH(std::vector*>& dhR_x, + std::vector*>& dhR_y, + std::vector*>& dhR_z); virtual void set_HR_fixed(void*) override; diff --git a/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp b/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp index 5d66a256a1c..2b2a9a9da8f 100644 --- a/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp +++ b/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp @@ -7,17 +7,17 @@ namespace hamilt { template -void Nonlocal>::cal_dH(hamilt::HContainer* dhR_x, - hamilt::HContainer* dhR_y, - hamilt::HContainer* dhR_z) +void Nonlocal>::cal_dH(std::vector*>& dhR_x, + std::vector*>& dhR_y, + std::vector*>& dhR_z) { ModuleBase::TITLE("Nonlocal", "cal_dH"); ModuleBase::timer::start("Nonlocal", "cal_dH"); - const Parallel_Orbitals* paraV = dhR_x->get_paraV(); - const int npol = this->ucell->get_npol(); - const int nat = this->ucell->nat; + assert(static_cast(dhR_x.size()) == nat); + const Parallel_Orbitals* paraV = dhR_x[0]->get_paraV(); + const int npol = this->ucell->get_npol(); for (int iat0 = 0; iat0 < nat; iat0++) { @@ -68,16 +68,22 @@ void Nonlocal>::cal_dH(hamilt::HContainer* dhR_x, 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); - dhR_x->insert_pair(ap); - dhR_y->insert_pair(ap); - dhR_z->insert_pair(ap); + for (int iat = 0; iat < nat; ++iat) + { + dhR_x[iat]->insert_pair(ap); + dhR_y[iat]->insert_pair(ap); + dhR_z[iat]->insert_pair(ap); + } } } } - dhR_x->allocate(nullptr, true); - dhR_y->allocate(nullptr, true); - dhR_z->allocate(nullptr, true); + for (int iat = 0; iat < nat; ++iat) + { + dhR_x[iat]->allocate(nullptr, true); + dhR_y[iat]->allocate(nullptr, true); + dhR_z[iat]->allocate(nullptr, true); + } #pragma omp parallel { @@ -167,18 +173,31 @@ void Nonlocal>::cal_dH(hamilt::HContainer* dhR_x, R_index2.y - R_index1.y, R_index2.z - R_index1.z); - hamilt::BaseMatrix* mtx_x = dhR_x->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); - hamilt::BaseMatrix* mtx_y = dhR_y->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); - hamilt::BaseMatrix* mtx_z = dhR_z->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); - - if (!mtx_x || !mtx_y || !mtx_z) + // destination block (iat1,iat2,dR) for the three differentiated atoms: + // iat1 (orbital 1), iat2 (orbital 2), iat0 (projector / Hellmann-Feynman) + hamilt::BaseMatrix* m1_x = dhR_x[iat1]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + hamilt::BaseMatrix* m1_y = dhR_y[iat1]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + hamilt::BaseMatrix* m1_z = dhR_z[iat1]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + hamilt::BaseMatrix* m2_x = dhR_x[iat2]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + hamilt::BaseMatrix* m2_y = dhR_y[iat2]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + hamilt::BaseMatrix* m2_z = dhR_z[iat2]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + hamilt::BaseMatrix* m0_x = dhR_x[iat0]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + hamilt::BaseMatrix* m0_y = dhR_y[iat0]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + hamilt::BaseMatrix* m0_z = dhR_z[iat0]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); + + if (!m1_x || !m1_y || !m1_z || !m2_x || !m2_y || !m2_z || !m0_x || !m0_y || !m0_z) continue; - double* ptr_x = mtx_x->get_pointer(); - double* ptr_y = mtx_y->get_pointer(); - double* ptr_z = mtx_z->get_pointer(); - const int row_sz = mtx_x->get_row_size(); - const int col_sz = mtx_x->get_col_size(); + double* p1_x = m1_x->get_pointer(); + double* p1_y = m1_y->get_pointer(); + double* p1_z = m1_z->get_pointer(); + double* p2_x = m2_x->get_pointer(); + double* p2_y = m2_y->get_pointer(); + double* p2_z = m2_z->get_pointer(); + double* p0_x = m0_x->get_pointer(); + double* p0_y = m0_y->get_pointer(); + double* p0_z = m0_z->get_pointer(); + const int col_sz = m1_x->get_col_size(); auto& nlm1_all = nlm_iat0[ad1]; auto& nlm2_all = nlm_iat0[ad2]; @@ -203,7 +222,10 @@ void Nonlocal>::cal_dH(hamilt::HContainer* dhR_x, const std::vector& nlm2 = it2->second; const int iw2_col = paraV->global2local_col(col_indexes[iw2l]); - std::vector nlm_tmp(3, 0.0); + // 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++) { @@ -211,15 +233,35 @@ void Nonlocal>::cal_dH(hamilt::HContainer* dhR_x, const int p2 = this->ucell->atoms[T0].ncpp.index2_soc[0][no]; const double* tmp_d = nullptr; this->ucell->atoms[T0].ncpp.get_d(0, p1, p2, tmp_d); - nlm_tmp[0] += nlm1[p1 + length] * nlm2[p2] * (*tmp_d); - nlm_tmp[1] += nlm1[p1 + length * 2] * nlm2[p2] * (*tmp_d); - nlm_tmp[2] += nlm1[p1 + length * 3] * nlm2[p2] * (*tmp_d); + for (int d = 0; d < 3; ++d) + { + tU[d] += nlm1[p1 + length * (d + 1)] * nlm2[p2] * (*tmp_d); + tV[d] += nlm1[p1] * nlm2[p2 + length * (d + 1)] * (*tmp_d); + } } - int idx = iw1_row * col_sz + iw2_col; - ptr_x[idx] += nlm_tmp[0]; - ptr_y[idx] += nlm_tmp[1]; - ptr_z[idx] += nlm_tmp[2]; + 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 +#pragma omp atomic + p1_x[idx] -= tU[0]; +#pragma omp atomic + p1_y[idx] -= tU[1]; +#pragma omp atomic + p1_z[idx] -= tU[2]; +#pragma omp atomic + p2_x[idx] -= tV[0]; +#pragma omp atomic + p2_y[idx] -= tV[1]; +#pragma omp atomic + p2_z[idx] -= tV[2]; +#pragma omp atomic + p0_x[idx] += tU[0] + tV[0]; +#pragma omp atomic + p0_y[idx] += tU[1] + tV[1]; +#pragma omp atomic + p0_z[idx] += tU[2] + tV[2]; } } } 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..0801a492dc7 --- /dev/null +++ b/source/source_lcao/module_operator_lcao/veff_dh.hpp @@ -0,0 +1,267 @@ +#pragma once +#include "veff_lcao.h" +#include "source_base/timer.h" +#include "source_lcao/module_gint/gint_dvlocal.h" +#include "source_lcao/module_gint/gint_interface.h" +#include "source_estate/module_charge/charge.h" +#include "source_pw/module_pwdft/forces.h" + +namespace hamilt +{ + +template +void Veff>::cal_dH(std::vector*>& dhR_perI_x, + std::vector*>& dhR_perI_y, + std::vector*>& dhR_perI_z, + const std::string& hellmann_feynman_type) +{ + ModuleBase::TITLE("Veff", "cal_dH"); + ModuleBase::timer::start("Veff", "cal_dH"); + + const int nat = this->ucell->nat; + assert(static_cast(dhR_perI_x.size()) == nat); + const Parallel_Orbitals* paraV = dhR_perI_x[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) + { + dhR_perI_x[iat]->insert_pair(tmp); + dhR_perI_y[iat]->insert_pair(tmp); + dhR_perI_z[iat]->insert_pair(tmp); + } + } + } + } + + for (int iat = 0; iat < nat; ++iat) + { + dhR_perI_x[iat]->allocate(nullptr, true); + dhR_perI_y[iat]->allocate(nullptr, true); + dhR_perI_z[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 (used by "none"/"hartree" placeholders). + const double* vr_eff + = (hellmann_feynman_type == "vl") ? this->pot->get_fixed_v() : this->pot->get_eff_v(0); + + // 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, this->nspin, PARAM.globalv.npol, true); + gint_dv.cal_dvlocal(); + + hamilt::HContainer* pvdpR[3] + = {gint_dv.get_pvdpRx(), gint_dv.get_pvdpRy(), gint_dv.get_pvdpRz()}; + std::vector*>* perI[3] = {&dhR_perI_x, &dhR_perI_y, &dhR_perI_z}; + + for (int iap = 0; iap < pvdpR[0]->size_atom_pairs(); iap++) + { + const auto& ap = pvdpR[0]->get_atom_pair(iap); + const int iat1 = ap.get_atom_i(); // A + const int iat2 = ap.get_atom_j(); // B + + 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); + + for (int d = 0; d < 3; ++d) + { + hamilt::BaseMatrix* src = pvdpR[d]->find_matrix(iat1, iat2, R); + // delta_VI (I=B): -pvdpR into block (A,B) of container B + hamilt::BaseMatrix* dV = (*perI[d])[iat2]->find_matrix(iat1, iat2, R); + // delta_UI (I=B): -pvdpR^T into block (B,A) of container B + hamilt::BaseMatrix* dU = (*perI[d])[iat2]->find_matrix(iat2, iat1, negR); + if (!src || !dV || !dU) + continue; + + const int rowA = src->get_row_size(); + const int colB = src->get_col_size(); + double* psrc = src->get_pointer(); + double* pV = dV->get_pointer(); + double* pU = dU->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 * rowA + a] -= val; // block (B,A)[b,a] (delta_UI, transpose) + } + } + } + } + } + + ModuleBase::timer::end("Veff", "cal_dH_pulay"); + } + + // Pass 3: Hellmann-Feynman term + if (hellmann_feynman_type == "none") + { + // V^XC has no Hellmann-Feynman term (V^XC(r) does not depend on atomic positions) + } + 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_perI_x[0]->size_atom_pairs(); ++iap) + { + dm.insert_pair(dhR_perI_x[0]->get_atom_pair(iap)); + } + dm.allocate(nullptr, true); + std::vector*> dm_vec = {&dm}; + + 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; + + 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; + + // cache the destination pointers of this (iat1, iat2, R) block for every atom I + std::vector dst_x(nat, nullptr); + std::vector dst_y(nat, nullptr); + std::vector dst_z(nat, nullptr); + int col_size = 0; + bool ok = true; + for (int iat = 0; iat < nat; ++iat) + { + hamilt::BaseMatrix* mx = dhR_perI_x[iat]->find_matrix(iat1, iat2, R_index); + hamilt::BaseMatrix* my = dhR_perI_y[iat]->find_matrix(iat1, iat2, R_index); + hamilt::BaseMatrix* mz = dhR_perI_z[iat]->find_matrix(iat1, iat2, R_index); + if (!mx || !my || !mz) + { + ok = false; + break; + } + dst_x[iat] = mx->get_pointer(); + dst_y[iat] = my->get_pointer(); + dst_z[iat] = mz->get_pointer(); + col_size = mx->get_col_size(); + } + if (!ok) + continue; + + double* dm_ptr = dm.find_matrix(iat1, iat2, R_index)->get_pointer(); + + for (int iw1l = 0; iw1l < static_cast(row_indexes.size()); ++iw1l) + { + for (int iw2l = 0; iw2l < static_cast(col_indexes.size()); ++iw2l) + { + const int idx = iw1l * col_size + iw2l; + + // delta-density-matrix D_{Ii,Jj} = delta_{Ii,Umu} delta_{Jj,Vnu} + dm_ptr[idx] = 1.0; + + // 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) + for (int iat = 0; iat < nat; ++iat) + { + dst_x[iat][idx] -= forcelc(iat, 0); + dst_y[iat][idx] -= forcelc(iat, 1); + dst_z[iat][idx] -= forcelc(iat, 2); + } + + // 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"); + // HF hartree term: 4-center ERIs with gradient — deferred + ModuleBase::timer::end("Veff", "cal_dH_hf_vh"); + } + 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..cf630a9729b 100644 --- a/source/source_lcao/module_operator_lcao/veff_lcao.h +++ b/source/source_lcao/module_operator_lcao/veff_lcao.h @@ -5,6 +5,7 @@ #include "operator_lcao.h" #include "source_cell/module_neighbor/sltk_grid_driver.h" #include "source_cell/unitcell.h" +#include #include namespace hamilt @@ -57,6 +58,14 @@ 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::vector*>& dhR_perI_x, + std::vector*>& dhR_perI_y, + std::vector*>& dhR_perI_z, + const std::string& hellmann_feynman_type = "none"); const UnitCell* ucell = nullptr; const Grid_Driver* gd = nullptr; 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 From 3bbf1e7bb2177b2c45e9efbe684218d3bca81ec0 Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Tue, 2 Jun 2026 01:33:05 +0800 Subject: [PATCH 03/13] fix pot register --- source/source_esolver/esolver_ks_lcao.cpp | 1 + .../source_io/module_ctrl/ctrl_scf_lcao.cpp | 47 +++++++++++++++++++ source/source_io/module_ctrl/ctrl_scf_lcao.h | 4 ++ source/source_io/module_dhs/write_dH.h | 7 +++ .../source_io/module_dhs/write_dH_terms.cpp | 9 ++-- source/source_io/module_hs/write_H_terms.cpp | 2 +- .../module_operator_lcao/veff_dh.hpp | 2 +- 7 files changed, 66 insertions(+), 6 deletions(-) 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_io/module_ctrl/ctrl_scf_lcao.cpp b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp index 5e9fd5e6ee9..c485b54b2fe 100644 --- a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp +++ b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp @@ -54,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, @@ -263,6 +266,38 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, dh_params.kv = &kv; dh_params.v_eff = &pelec->pot->get_eff_v(); dh_params.pot = pelec->pot; + // 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; + if (inp.out_mat_dh_vl[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]) + { + 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]) + { + 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; @@ -274,6 +309,9 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, dh_params.dmR = dm->get_DMR_pointer(1); } ModuleIO::write_dH_components(dh_params); + delete pot_vl; + delete pot_vh; + delete pot_vxc; } @@ -587,6 +625,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, @@ -612,6 +653,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, @@ -636,6 +680,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.h b/source/source_io/module_dhs/write_dH.h index a15d2096f49..7f5b124b83a 100644 --- a/source/source_io/module_dhs/write_dH.h +++ b/source/source_io/module_dhs/write_dH.h @@ -24,6 +24,13 @@ struct WriteDHParams 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; diff --git a/source/source_io/module_dhs/write_dH_terms.cpp b/source/source_io/module_dhs/write_dH_terms.cpp index 3bb5bfbc6be..eedd38aa398 100644 --- a/source/source_io/module_dhs/write_dH_terms.cpp +++ b/source/source_io/module_dhs/write_dH_terms.cpp @@ -50,6 +50,7 @@ struct PerIContainers // 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, @@ -68,7 +69,7 @@ bool write_dH_veff_term(WriteDHParams& params, hamilt::Veff> veff(nullptr, params.kv->kvec_d, - params.pot, + pot, &hR_dummy, &ucell, orb_cutoff, @@ -162,7 +163,7 @@ bool write_dH_vl(WriteDHParams& params) ModuleBase::TITLE("ModuleIO", "write_dH_vl"); ModuleBase::timer::start("ModuleIO", "write_dH_vl"); - const bool ok = write_dH_veff_term(params, "vl", "dvlr", "dvlk", "dV^L"); + const bool ok = write_dH_veff_term(params, params.pot_vl, "vl", "dvlr", "dvlk", "dV^L"); ModuleBase::timer::end("ModuleIO", "write_dH_vl"); return ok; @@ -173,7 +174,7 @@ bool write_dH_vh(WriteDHParams& params) ModuleBase::TITLE("ModuleIO", "write_dH_vh"); ModuleBase::timer::start("ModuleIO", "write_dH_vh"); - const bool ok = write_dH_veff_term(params, "hartree", "dvhr", "dvhk", "dV^H"); + const bool ok = write_dH_veff_term(params, params.pot_vh, "hartree", "dvhr", "dvhk", "dV^H"); ModuleBase::timer::end("ModuleIO", "write_dH_vh"); return ok; @@ -184,7 +185,7 @@ bool write_dH_vxc(WriteDHParams& params) ModuleBase::TITLE("ModuleIO", "write_dH_vxc"); ModuleBase::timer::start("ModuleIO", "write_dH_vxc"); - const bool ok = write_dH_veff_term(params, "none", "dvxcr", "dvxck", "dV^XC"); + const bool ok = write_dH_veff_term(params, params.pot_vxc, "none", "dvxcr", "dvxck", "dV^XC"); ModuleBase::timer::end("ModuleIO", "write_dH_vxc"); return ok; diff --git a/source/source_io/module_hs/write_H_terms.cpp b/source/source_io/module_hs/write_H_terms.cpp index bd7d64f1c85..7bce4039543 100644 --- a/source/source_io/module_hs/write_H_terms.cpp +++ b/source/source_io/module_hs/write_H_terms.cpp @@ -254,7 +254,7 @@ void write_h_vl(const UnitCell& ucell, 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(); + const double* v_local = pot->get_fixed_v(); // local pp, no Hxc ModuleGint::cal_gint_vl(v_local, &hR_tmp); gather_and_write("vl", "V^L", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); diff --git a/source/source_lcao/module_operator_lcao/veff_dh.hpp b/source/source_lcao/module_operator_lcao/veff_dh.hpp index 0801a492dc7..774e7015d04 100644 --- a/source/source_lcao/module_operator_lcao/veff_dh.hpp +++ b/source/source_lcao/module_operator_lcao/veff_dh.hpp @@ -69,7 +69,7 @@ void Veff>::cal_dH(std::vector*> ModuleBase::timer::start("Veff", "cal_dH_pulay"); // term-specific local potential: V^L (fixed local pseudopotential) for "vl", - // otherwise the effective potential (used by "none"/"hartree" placeholders). + // otherwise the effective potential ("hartree/xc"). const double* vr_eff = (hellmann_feynman_type == "vl") ? this->pot->get_fixed_v() : this->pot->get_eff_v(0); From bce4a72ca3bf0312ee8ea61d0405a43f15a3c2e3 Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Tue, 2 Jun 2026 01:33:40 +0800 Subject: [PATCH 04/13] Gint_drho --- source/source_lcao/module_gint/CMakeLists.txt | 1 + source/source_lcao/module_gint/gint_drho.cpp | 77 +++++++++++++++++++ source/source_lcao/module_gint/gint_drho.h | 52 +++++++++++++ .../module_gint/gint_interface.cpp | 13 ++++ .../source_lcao/module_gint/gint_interface.h | 12 ++- 5 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 source/source_lcao/module_gint/gint_drho.cpp create mode 100644 source/source_lcao/module_gint/gint_drho.h 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_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); From e530d627ddde7eeac59a258ade2eb625bb09f23f Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Sun, 7 Jun 2026 18:25:25 +0800 Subject: [PATCH 05/13] add EXX H&dH, dH (H-F term) of Veff Hartree, and refactor --- .../source_io/module_ctrl/ctrl_scf_lcao.cpp | 58 ++++- source/source_io/module_dhs/write_dH.cpp | 24 +- source/source_io/module_dhs/write_dH.h | 24 +- .../source_io/module_dhs/write_dH_terms.cpp | 118 +++++++-- source/source_io/module_hs/write_H_terms.cpp | 239 ++++++++++++------ source/source_io/module_hs/write_H_terms.h | 103 +++----- source/source_io/module_output/filename.cpp | 2 +- .../module_parameter/input_parameter.h | 2 + .../read_input_item_output.cpp | 50 ++++ .../module_operator_lcao/ekinetic.h | 5 +- .../module_operator_lcao/ekinetic_dh.hpp | 60 ++--- .../module_operator_lcao/nonlocal.h | 5 +- .../module_operator_lcao/nonlocal_dh.hpp | 85 +++---- .../module_operator_lcao/op_exx_lcao.h | 5 + .../module_operator_lcao/op_exx_lcao.hpp | 29 +++ .../module_operator_lcao/veff_dh.hpp | 171 ++++++++++--- .../module_operator_lcao/veff_lcao.h | 8 +- source/source_lcao/module_ri/Exx_LRI.h | 10 +- source/source_lcao/module_ri/Exx_LRI.hpp | 75 +++++- .../source_lcao/module_ri/Exx_LRI_interface.h | 12 + .../module_ri/Exx_LRI_interface.hpp | 29 +++ 21 files changed, 793 insertions(+), 321 deletions(-) diff --git a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp index c485b54b2fe..cbab5c0c185 100644 --- a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp +++ b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp @@ -308,6 +308,18 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, { dh_params.dmR = dm->get_DMR_pointer(1); } +#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; @@ -319,31 +331,57 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, //! 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(ucell, gd, pv, two_center_bundle, orb, kv, nspin, istep, out_app_flag, - ucell.get_iat2iwt(), ucell.nat); + ModuleIO::write_h_t(h_params); } if (inp.out_mat_h_vnl[0]) { - ModuleIO::write_h_vnl(ucell, gd, pv, two_center_bundle, orb, kv, nspin, istep, out_app_flag, - ucell.get_iat2iwt(), ucell.nat); + ModuleIO::write_h_vnl(h_params); } if (inp.out_mat_h_vl[0]) { - ModuleIO::write_h_vl(ucell, gd, pv, orb, pelec->pot, nspin, istep, out_app_flag, - ucell.get_iat2iwt(), ucell.nat, kv); + ModuleIO::write_h_vl(h_params); } if (inp.out_mat_h_vh[0]) { - ModuleIO::write_h_vh(ucell, gd, pv, orb, pelec->charge, pw_rho, nspin, istep, out_app_flag, - ucell.get_iat2iwt(), ucell.nat, kv); + ModuleIO::write_h_vh(h_params); } if (inp.out_mat_h_vxc[0]) { - ModuleIO::write_h_vxc(ucell, gd, pv, orb, pelec->charge, pw_rho->nrxx, nspin, istep, - out_app_flag, ucell.get_iat2iwt(), ucell.nat, kv); + ModuleIO::write_h_vxc(h_params); } +#ifdef __EXX + if (inp.out_mat_h_exx[0]) + { + // 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 diff --git a/source/source_io/module_dhs/write_dH.cpp b/source/source_io/module_dhs/write_dH.cpp index a90c1f6b414..2b629c1a542 100644 --- a/source/source_io/module_dhs/write_dH.cpp +++ b/source/source_io/module_dhs/write_dH.cpp @@ -21,18 +21,15 @@ void write_dh_perI(WriteDHParams& params, const std::string& rprefix, const std::string& kprefix, const std::string& label, - std::vector*>& gx, - std::vector*>& gy, - std::vector*>& gz) + std::array*>, 3>& g) { const UnitCell& ucell = *params.ucell; const Parallel_Orbitals& pv = *params.pv; const int nat = params.nat; const int nspin = params.nspin; - const int nbasis = gx[0]->get_nbasis(); + const int nbasis = g[0][0]->get_nbasis(); - const char dirc[3] = {'x', 'y', 'z'}; - std::vector*>* g[3] = {&gx, &gy, &gz}; + const char dirc[3] = { 'x', 'y', 'z' }; // k-space (dense, folded like H(k)) parameters const int nspin_k = (nspin == 2 ? 2 : 1); @@ -54,10 +51,12 @@ void write_dh_perI(WriteDHParams& params, { for (int d = 0; d < 3; ++d) { - hamilt::HContainer* hR = (*g[d])[iat]; + 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 ---- + // ---- 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); @@ -71,6 +70,7 @@ void write_dh_perI(WriteDHParams& params, 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) @@ -140,6 +140,7 @@ void write_dH_components(WriteDHParams& 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]) @@ -152,6 +153,13 @@ void write_dH_components(WriteDHParams& params) write_dH_sum(params); } +#ifdef __EXX + if (PARAM.inp.out_mat_dh_exx[0]) + { + write_dH_exx(params); + } +#endif + ModuleBase::timer::end("ModuleIO", "write_dH_components"); } diff --git a/source/source_io/module_dhs/write_dH.h b/source/source_io/module_dhs/write_dH.h index 7f5b124b83a..4203de7bf6f 100644 --- a/source/source_io/module_dhs/write_dH.h +++ b/source/source_io/module_dhs/write_dH.h @@ -8,8 +8,13 @@ #include "source_lcao/LCAO_domain.h" #include "source_lcao/module_hcontainer/hcontainer.h" +#include +#include #include +template +class Exx_LRI_Interface; + namespace ModuleIO { @@ -36,7 +41,14 @@ struct WriteDHParams 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) const hamilt::HContainer* dmR = nullptr; +#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 }; bool any_dh_term_enabled(); @@ -45,15 +57,13 @@ bool any_dh_term_enabled(); // - 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). -// gx/gy/gz are nat per-I HContainers (already filled by an operator's cal_dH). +// g[d] are nat per-I HContainers for direction d=0..2 (already filled by an operator's cal_dH). void write_dh_perI(WriteDHParams& params, int ispin, const std::string& rprefix, const std::string& kprefix, const std::string& label, - std::vector*>& gx, - std::vector*>& gy, - std::vector*>& gz); + std::array*>, 3>& g); void write_dH_components(WriteDHParams& params); @@ -65,10 +75,16 @@ 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_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 index eedd38aa398..a5db91b10c5 100644 --- a/source/source_io/module_dhs/write_dH_terms.cpp +++ b/source/source_io/module_dhs/write_dH_terms.cpp @@ -9,6 +9,10 @@ #include "source_lcao/module_operator_lcao/operator_force_stress_utils.h" #include "source_lcao/module_operator_lcao/veff_lcao.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 @@ -19,30 +23,25 @@ namespace ModuleIO namespace { -// RAII holder for the per-atom-I dH containers: one (dx, dy, dz) HContainer per atom I. -// gx/gy/gz are raw-pointer views into the owned containers, ready to hand to an + // 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::vector>> ox, oy, oz; - std::vector*> gx, gy, gz; + std::array>>, 3> owned; + std::array*>, 3> g; PerIContainers(const Parallel_Orbitals& pv, int nat) { - ox.reserve(nat); - oy.reserve(nat); - oz.reserve(nat); - gx.reserve(nat); - gy.reserve(nat); - gz.reserve(nat); - for (int iat = 0; iat < nat; ++iat) + for (int d = 0; d < 3; ++d) { - ox.push_back(std::make_unique>(&pv)); - oy.push_back(std::make_unique>(&pv)); - oz.push_back(std::make_unique>(&pv)); - gx.push_back(ox.back().get()); - gy.push_back(oy.back().get()); - gz.push_back(oz.back().get()); + owned[d].reserve(nat); + g[d].reserve(nat); + for (int iat = 0; iat < nat; ++iat) + { + owned[d].push_back(std::make_unique>(&pv)); + g[d].push_back(owned[d].back().get()); + } } } }; @@ -78,13 +77,45 @@ bool write_dH_veff_term(WriteDHParams& params, PerIContainers c(pv, nat); - veff.cal_dH(c.gx, c.gy, c.gz, hf_type); + veff.cal_dH(c.g, hf_type, params.dmR); - ModuleIO::write_dh_perI(params, ispin, rprefix, kprefix, label, c.gx, c.gy, c.gz); + ModuleIO::write_dh_perI(params, ispin, rprefix, kprefix, label, c.g); } return true; } +#ifdef __EXX +// Shared driver for the EXX dH term, templated on the Hexx tensor data type (double for the +// real interface exd, std::complex for the complex interface exc). 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); + + // 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); + + // 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()); + + ModuleIO::write_dh_perI(params, ispin, "dvexxr", "dvexxk", "dV^EXX", c.g); + } +} +#endif + } // namespace bool write_dH_t(WriteDHParams& params) @@ -115,9 +146,9 @@ bool write_dH_t(WriteDHParams& params) &gd, two_center_bundle.kinetic_orb.get()); - tmp_ekinetic.cal_dH(c.gx, c.gy, c.gz); + tmp_ekinetic.cal_dH(c.g); - ModuleIO::write_dh_perI(params, ispin, "dtr", "dtk", "dT", c.gx, c.gy, c.gz); + ModuleIO::write_dh_perI(params, ispin, "dtr", "dtk", "dT", c.g); } ModuleBase::timer::end("ModuleIO", "write_dH_t"); @@ -149,9 +180,9 @@ bool write_dH_vnl(WriteDHParams& params) &gd, two_center_bundle.overlap_orb_beta.get()); - tmp_nonlocal.cal_dH(c.gx, c.gy, c.gz); + tmp_nonlocal.cal_dH(c.g); - ModuleIO::write_dh_perI(params, ispin, "dvnlr", "dvnlk", "dV^NL", c.gx, c.gy, c.gz); + ModuleIO::write_dh_perI(params, ispin, "dvnlr", "dvnlk", "dV^NL", c.g); } ModuleBase::timer::end("ModuleIO", "write_dH_vnl"); @@ -180,6 +211,17 @@ bool write_dH_vh(WriteDHParams& params) 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 bool ok = write_dH_veff_term(params, params.pot_vh, "none", "dvhr_pulay_", "dvhk_pulay_", "dV^H (Pulay)"); + + ModuleBase::timer::end("ModuleIO", "write_dH_vh_pulay"); + return ok; +} + bool write_dH_vxc(WriteDHParams& params) { ModuleBase::TITLE("ModuleIO", "write_dH_vxc"); @@ -191,4 +233,34 @@ bool write_dH_vxc(WriteDHParams& params) 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 + } // namespace ModuleIO diff --git a/source/source_io/module_hs/write_H_terms.cpp b/source/source_io/module_hs/write_H_terms.cpp index 7bce4039543..8b7919523c9 100644 --- a/source/source_io/module_hs/write_H_terms.cpp +++ b/source/source_io/module_hs/write_H_terms.cpp @@ -15,6 +15,11 @@ #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 @@ -149,22 +154,24 @@ static void write_hk_common(hamilt::HContainer& hR, } } -void write_h_t(const UnitCell& ucell, - const Grid_Driver& gd, - const Parallel_Orbitals& pv, - const TwoCenterBundle& two_center_bundle, - const LCAO_Orbitals& orb, - const K_Vectors& kv, - const int nspin, - const int istep, - const bool append, - const int* iat2iwt, - const int nat, - const bool also_hk) +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); @@ -176,33 +183,35 @@ void write_h_t(const UnitCell& ucell, tmp_ekinetic(nullptr, kv.kvec_d, &hR_tmp, &ucell, orb_cutoff, &gd, two_center_bundle.kinetic_orb.get()); tmp_ekinetic.contributeHR(); - gather_and_write("t", "T", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + write_hk_common(hR_tmp, "tk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); - if (also_hk) + if (also_hR) { - write_hk_common(hR_tmp, "tk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + 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(const UnitCell& ucell, - const Grid_Driver& gd, - const Parallel_Orbitals& pv, - const TwoCenterBundle& two_center_bundle, - const LCAO_Orbitals& orb, - const K_Vectors& kv, - const int nspin, - const int istep, - const bool append, - const int* iat2iwt, - const int nat, - const bool also_hk) +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); @@ -219,33 +228,35 @@ void write_h_vnl(const UnitCell& ucell, two_center_bundle.overlap_orb_beta.get()); tmp_nonlocal.contributeHR(); - gather_and_write("vnl", "V^NL", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + write_hk_common(hR_tmp, "vnlk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); - if (also_hk) + if (also_hR) { - write_hk_common(hR_tmp, "vnlk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + 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(const UnitCell& ucell, - const Grid_Driver& gd, - const Parallel_Orbitals& pv, - const LCAO_Orbitals& orb, - const elecstate::Potential* pot, - const int nspin, - const int istep, - const bool append, - const int* iat2iwt, - const int nat, - const K_Vectors& kv, - const bool also_hk) +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); @@ -257,34 +268,36 @@ void write_h_vl(const UnitCell& ucell, const double* v_local = pot->get_fixed_v(); // local pp, no Hxc ModuleGint::cal_gint_vl(v_local, &hR_tmp); - gather_and_write("vl", "V^L", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + write_hk_common(hR_tmp, "vlk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); - if (also_hk) + if (also_hR) { - write_hk_common(hR_tmp, "vlk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + 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(const UnitCell& ucell, - const Grid_Driver& gd, - const Parallel_Orbitals& pv, - const LCAO_Orbitals& orb, - const Charge* chg, - const ModulePW::PW_Basis* rho_basis, - const int nspin, - const int istep, - const bool append, - const int* iat2iwt, - const int nat, - const K_Vectors& kv, - const bool also_hk) +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); @@ -298,34 +311,36 @@ void write_h_vh(const UnitCell& ucell, ModuleGint::cal_gint_vl(&v_h(ispin, 0), &hR_tmp); - gather_and_write("vh", "V^H", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + write_hk_common(hR_tmp, "vhk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); - if (also_hk) + if (also_hR) { - write_hk_common(hR_tmp, "vhk", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + 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(const UnitCell& ucell, - const Grid_Driver& gd, - const Parallel_Orbitals& pv, - const LCAO_Orbitals& orb, - const Charge* chg, - const int nrxx, - const int nspin, - const int istep, - const bool append, - const int* iat2iwt, - const int nat, - const K_Vectors& kv, - const bool also_hk) +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); @@ -340,15 +355,85 @@ void write_h_vxc(const UnitCell& ucell, ModuleGint::cal_gint_vl(&v_xc(ispin, 0), &hR_tmp); - gather_and_write("vxc", "V^XC", hR_tmp, ucell, pv, nspin, ispin, istep, append, iat2iwt, nat); + write_hk_common(hR_tmp, "vxck", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); - if (also_hk) + if (also_hR) { - write_hk_common(hR_tmp, "vxck", ucell, pv, kv, nspin, istep, append, iat2iwt, nat); + 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 index f1434486d54..c77eeda536e 100644 --- a/source/source_io/module_hs/write_H_terms.h +++ b/source/source_io/module_hs/write_H_terms.h @@ -10,77 +10,56 @@ #include "source_lcao/LCAO_domain.h" #include "source_lcao/module_hcontainer/hcontainer.h" +#include #include +template +class Exx_LRI_Interface; + namespace ModuleIO { -void write_h_t(const UnitCell& ucell, - const Grid_Driver& gd, - const Parallel_Orbitals& pv, - const TwoCenterBundle& two_center_bundle, - const LCAO_Orbitals& orb, - const K_Vectors& kv, - const int nspin, - const int istep, - const bool append, - const int* iat2iwt, - const int nat, - const bool also_hk = true); +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_vnl(const UnitCell& ucell, - const Grid_Driver& gd, - const Parallel_Orbitals& pv, - const TwoCenterBundle& two_center_bundle, - const LCAO_Orbitals& orb, - const K_Vectors& kv, - const int nspin, - const int istep, - const bool append, - const int* iat2iwt, - const int nat, - const bool also_hk = true); +void write_h_vl(WriteHParams& params); -void write_h_vl(const UnitCell& ucell, - const Grid_Driver& gd, - const Parallel_Orbitals& pv, - const LCAO_Orbitals& orb, - const elecstate::Potential* pot, - const int nspin, - const int istep, - const bool append, - const int* iat2iwt, - const int nat, - const K_Vectors& kv, - const bool also_hk = true); +void write_h_vh(WriteHParams& params); -void write_h_vh(const UnitCell& ucell, - const Grid_Driver& gd, - const Parallel_Orbitals& pv, - const LCAO_Orbitals& orb, - const Charge* chg, - const ModulePW::PW_Basis* rho_basis, - const int nspin, - const int istep, - const bool append, - const int* iat2iwt, - const int nat, - const K_Vectors& kv, - const bool also_hk = true); +void write_h_vxc(WriteHParams& params); -void write_h_vxc(const UnitCell& ucell, - const Grid_Driver& gd, - const Parallel_Orbitals& pv, - const LCAO_Orbitals& orb, - const Charge* chg, - const int nrxx, - const int nspin, - const int istep, - const bool append, - const int* iat2iwt, - const int nat, - const K_Vectors& kv, - const bool also_hk = true); +#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 diff --git a/source/source_io/module_output/filename.cpp b/source/source_io/module_output/filename.cpp index b9c06b93898..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", "vxck", "vlk", "vnlk", "vhk" }; + 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 426b4a7e5d0..5a02a730075 100644 --- a/source/source_io/module_parameter/input_parameter.h +++ b/source/source_io/module_parameter/input_parameter.h @@ -399,12 +399,14 @@ struct Input_para 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 a64cb4931da..fd9529ae4ab 100644 --- a/source/source_io/module_parameter/read_input_item_output.cpp +++ b/source/source_io/module_parameter/read_input_item_output.cpp @@ -792,6 +792,31 @@ Also controled by out_freq_ion and out_app_flag. sync_intvec(input.out_mat_dh_vxc, 2, 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]); + } + 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, 2, 0); + this->add_item(item); + } { Input_Item item("out_mat_h_t"); item.annotation = "output kinetic energy T(R) matrix"; @@ -917,6 +942,31 @@ Also controled by out_freq_ion and out_app_flag. 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); + } { Input_Item item("out_mat_ds"); item.annotation = "output of derivative of S(R) matrix"; diff --git a/source/source_lcao/module_operator_lcao/ekinetic.h b/source/source_lcao/module_operator_lcao/ekinetic.h index afe4af35c8d..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 @@ -76,9 +77,7 @@ class EKinetic> : public OperatorLCAO ModuleBase::matrix& stress); // per-atom-I derivative d/dtau_I; one HContainer per atom I (size nat each) - void cal_dH(std::vector*>& dhR_x, - std::vector*>& dhR_y, - std::vector*>& dhR_z); + void cal_dH(std::array*>, 3>& dhR); private: const UnitCell* ucell = nullptr; diff --git a/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp b/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp index c97cd84cbdf..18dc546b7dc 100644 --- a/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp +++ b/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp @@ -7,16 +7,14 @@ namespace hamilt { template -void EKinetic>::cal_dH(std::vector*>& dhR_x, - std::vector*>& dhR_y, - std::vector*>& dhR_z) +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_x.size()) == nat); - const Parallel_Orbitals* paraV = dhR_x[0]->get_paraV(); + 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 @@ -50,18 +48,16 @@ void EKinetic>::cal_dH(std::vector ap(iat1, iat2, R_index.x, R_index.y, R_index.z, paraV); for (int iat = 0; iat < nat; ++iat) { - dhR_x[iat]->insert_pair(ap); - dhR_y[iat]->insert_pair(ap); - dhR_z[iat]->insert_pair(ap); + for (int d = 0; d < 3; ++d) + dhR[d][iat]->insert_pair(ap); } } } for (int iat = 0; iat < nat; ++iat) { - dhR_x[iat]->allocate(nullptr, true); - dhR_y[iat]->allocate(nullptr, true); - dhR_z[iat]->allocate(nullptr, true); + for (int d = 0; d < 3; ++d) + dhR[d][iat]->allocate(nullptr, true); } #pragma omp parallel @@ -93,25 +89,22 @@ void EKinetic>::cal_dH(std::vector/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_x = dhR_x[iat1]->find_matrix(iat1, iat2, R_index); - hamilt::BaseMatrix* mtxU_y = dhR_y[iat1]->find_matrix(iat1, iat2, R_index); - hamilt::BaseMatrix* mtxU_z = dhR_z[iat1]->find_matrix(iat1, iat2, R_index); - hamilt::BaseMatrix* mtxV_x = dhR_x[iat2]->find_matrix(iat1, iat2, R_index); - hamilt::BaseMatrix* mtxV_y = dhR_y[iat2]->find_matrix(iat1, iat2, R_index); - hamilt::BaseMatrix* mtxV_z = dhR_z[iat2]->find_matrix(iat1, iat2, R_index); - - if (!mtxU_x || !mtxU_y || !mtxU_z || !mtxV_x || !mtxV_y || !mtxV_z) + 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_x = mtxU_x->get_pointer(); - double* ptrU_y = mtxU_y->get_pointer(); - double* ptrU_z = mtxU_z->get_pointer(); - double* ptrV_x = mtxV_x->get_pointer(); - double* ptrV_y = mtxV_y->get_pointer(); - double* ptrV_z = mtxV_z->get_pointer(); - const int col_size = mtxU_x->get_col_size(); + 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]; @@ -155,14 +148,13 @@ void EKinetic>::cal_dH(std::vector/dtau_I = - (dtau = -grad); sign // confirmed against the finite-difference reference. - // d/dtau_V (I = iat2) - ptrV_x[idx] -= olm[0]; - ptrV_y[idx] -= olm[1]; - ptrV_z[idx] -= olm[2]; - // d/dtau_U (I = iat1) - ptrU_x[idx] -= olm_rev[0]; - ptrU_y[idx] -= olm_rev[1]; - ptrU_z[idx] -= olm_rev[2]; + for (int d = 0; d < 3; ++d) + { + // d/dtau_V (I = iat2) + ptrV[d][idx] -= olm[d]; + // d/dtau_U (I = iat1) + ptrU[d][idx] -= olm_rev[d]; + } } } } diff --git a/source/source_lcao/module_operator_lcao/nonlocal.h b/source/source_lcao/module_operator_lcao/nonlocal.h index 1a1e9f510f2..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 @@ -61,9 +62,7 @@ class Nonlocal> : public OperatorLCAO ModuleBase::matrix& stress); // per-atom-I derivative d/dtau_I; one HContainer per atom I (size nat each) - void cal_dH(std::vector*>& dhR_x, - std::vector*>& dhR_y, - std::vector*>& dhR_z); + void cal_dH(std::array*>, 3>& dhR); virtual void set_HR_fixed(void*) override; diff --git a/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp b/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp index 2b2a9a9da8f..d247840af0b 100644 --- a/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp +++ b/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp @@ -7,16 +7,14 @@ namespace hamilt { template -void Nonlocal>::cal_dH(std::vector*>& dhR_x, - std::vector*>& dhR_y, - std::vector*>& dhR_z) +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_x.size()) == nat); - const Parallel_Orbitals* paraV = dhR_x[0]->get_paraV(); + 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++) @@ -70,9 +68,8 @@ void Nonlocal>::cal_dH(std::vector ap(iat1, iat2, dR.x, dR.y, dR.z, paraV); for (int iat = 0; iat < nat; ++iat) { - dhR_x[iat]->insert_pair(ap); - dhR_y[iat]->insert_pair(ap); - dhR_z[iat]->insert_pair(ap); + for (int d = 0; d < 3; ++d) + dhR[d][iat]->insert_pair(ap); } } } @@ -80,9 +77,8 @@ void Nonlocal>::cal_dH(std::vectorallocate(nullptr, true); - dhR_y[iat]->allocate(nullptr, true); - dhR_z[iat]->allocate(nullptr, true); + for (int d = 0; d < 3; ++d) + dhR[d][iat]->allocate(nullptr, true); } #pragma omp parallel @@ -175,29 +171,23 @@ void Nonlocal>::cal_dH(std::vector* m1_x = dhR_x[iat1]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); - hamilt::BaseMatrix* m1_y = dhR_y[iat1]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); - hamilt::BaseMatrix* m1_z = dhR_z[iat1]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); - hamilt::BaseMatrix* m2_x = dhR_x[iat2]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); - hamilt::BaseMatrix* m2_y = dhR_y[iat2]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); - hamilt::BaseMatrix* m2_z = dhR_z[iat2]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); - hamilt::BaseMatrix* m0_x = dhR_x[iat0]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); - hamilt::BaseMatrix* m0_y = dhR_y[iat0]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); - hamilt::BaseMatrix* m0_z = dhR_z[iat0]->find_matrix(iat1, iat2, dR.x, dR.y, dR.z); - - if (!m1_x || !m1_y || !m1_z || !m2_x || !m2_y || !m2_z || !m0_x || !m0_y || !m0_z) + 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_x = m1_x->get_pointer(); - double* p1_y = m1_y->get_pointer(); - double* p1_z = m1_z->get_pointer(); - double* p2_x = m2_x->get_pointer(); - double* p2_y = m2_y->get_pointer(); - double* p2_z = m2_z->get_pointer(); - double* p0_x = m0_x->get_pointer(); - double* p0_y = m0_y->get_pointer(); - double* p0_z = m0_z->get_pointer(); - const int col_sz = m1_x->get_col_size(); + 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]; @@ -229,14 +219,14 @@ void Nonlocal>::cal_dH(std::vectorucell->atoms[T0].ncpp.non_zero_count_soc[0]; no++) { - const int p1 = this->ucell->atoms[T0].ncpp.index1_soc[0][no]; - const int p2 = this->ucell->atoms[T0].ncpp.index2_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, p2, tmp_d); + 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 + length * (d + 1)] * nlm2[p2] * (*tmp_d); - tV[d] += nlm1[p1] * nlm2[p2 + length * (d + 1)] * (*tmp_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); } } @@ -244,24 +234,15 @@ void Nonlocal>::cal_dH(std::vector=-- // =- for Hellmann-Feynman terms + for (int d = 0; d < 3; ++d) + { #pragma omp atomic - p1_x[idx] -= tU[0]; -#pragma omp atomic - p1_y[idx] -= tU[1]; -#pragma omp atomic - p1_z[idx] -= tU[2]; -#pragma omp atomic - p2_x[idx] -= tV[0]; -#pragma omp atomic - p2_y[idx] -= tV[1]; -#pragma omp atomic - p2_z[idx] -= tV[2]; -#pragma omp atomic - p0_x[idx] += tU[0] + tV[0]; + p1[d][idx] -= tU[d]; #pragma omp atomic - p0_y[idx] += tU[1] + tV[1]; + p2[d][idx] -= tV[d]; #pragma omp atomic - p0_z[idx] += tU[2] + tV[2]; + p0[d][idx] += tU[d] + tV[d]; + } } } } 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..e6423cc3df8 100644 --- a/source/source_lcao/module_operator_lcao/op_exx_lcao.h +++ b/source/source_lcao/module_operator_lcao/op_exx_lcao.h @@ -48,6 +48,11 @@ class OperatorEXX> : public OperatorLCAO 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; 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..5b9e10d32d0 100644 --- a/source/source_lcao/module_operator_lcao/op_exx_lcao.hpp +++ b/source/source_lcao/module_operator_lcao/op_exx_lcao.hpp @@ -506,6 +506,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 index 774e7015d04..04ee5ef0166 100644 --- a/source/source_lcao/module_operator_lcao/veff_dh.hpp +++ b/source/source_lcao/module_operator_lcao/veff_dh.hpp @@ -4,23 +4,23 @@ #include "source_lcao/module_gint/gint_dvlocal.h" #include "source_lcao/module_gint/gint_interface.h" #include "source_estate/module_charge/charge.h" +#include "source_estate/module_pot/H_Hartree_pw.h" #include "source_pw/module_pwdft/forces.h" namespace hamilt { template -void Veff>::cal_dH(std::vector*>& dhR_perI_x, - std::vector*>& dhR_perI_y, - std::vector*>& dhR_perI_z, - const std::string& hellmann_feynman_type) +void Veff>::cal_dH(std::array*>, 3>& dhR, + const std::string& hellmann_feynman_type, + const hamilt::HContainer* dmR) { ModuleBase::TITLE("Veff", "cal_dH"); ModuleBase::timer::start("Veff", "cal_dH"); const int nat = this->ucell->nat; - assert(static_cast(dhR_perI_x.size()) == nat); - const Parallel_Orbitals* paraV = dhR_perI_x[0]->get_paraV(); + 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++) @@ -48,9 +48,8 @@ void Veff>::cal_dH(std::vector*> hamilt::AtomPair tmp(iat1, iat2, R_index, paraV); for (int iat = 0; iat < nat; ++iat) { - dhR_perI_x[iat]->insert_pair(tmp); - dhR_perI_y[iat]->insert_pair(tmp); - dhR_perI_z[iat]->insert_pair(tmp); + for (int d = 0; d < 3; ++d) + dhR[d][iat]->insert_pair(tmp); } } } @@ -58,9 +57,8 @@ void Veff>::cal_dH(std::vector*> for (int iat = 0; iat < nat; ++iat) { - dhR_perI_x[iat]->allocate(nullptr, true); - dhR_perI_y[iat]->allocate(nullptr, true); - dhR_perI_z[iat]->allocate(nullptr, true); + for (int d = 0; d < 3; ++d) + dhR[d][iat]->allocate(nullptr, true); } // Pass 2: Pulay term -[ delta_UI + delta_VI ] @@ -80,7 +78,6 @@ void Veff>::cal_dH(std::vector*> hamilt::HContainer* pvdpR[3] = {gint_dv.get_pvdpRx(), gint_dv.get_pvdpRy(), gint_dv.get_pvdpRz()}; - std::vector*>* perI[3] = {&dhR_perI_x, &dhR_perI_y, &dhR_perI_z}; for (int iap = 0; iap < pvdpR[0]->size_atom_pairs(); iap++) { @@ -97,9 +94,9 @@ void Veff>::cal_dH(std::vector*> { hamilt::BaseMatrix* src = pvdpR[d]->find_matrix(iat1, iat2, R); // delta_VI (I=B): -pvdpR into block (A,B) of container B - hamilt::BaseMatrix* dV = (*perI[d])[iat2]->find_matrix(iat1, iat2, R); + hamilt::BaseMatrix* dV = dhR[d][iat2]->find_matrix(iat1, iat2, R); // delta_UI (I=B): -pvdpR^T into block (B,A) of container B - hamilt::BaseMatrix* dU = (*perI[d])[iat2]->find_matrix(iat2, iat1, negR); + hamilt::BaseMatrix* dU = dhR[d][iat2]->find_matrix(iat2, iat1, negR); if (!src || !dV || !dU) continue; @@ -155,9 +152,9 @@ void Veff>::cal_dH(std::vector*> // 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_perI_x[0]->size_atom_pairs(); ++iap) + for (int iap = 0; iap < dhR[0][0]->size_atom_pairs(); ++iap) { - dm.insert_pair(dhR_perI_x[0]->get_atom_pair(iap)); + dm.insert_pair(dhR[0][0]->get_atom_pair(iap)); } dm.allocate(nullptr, true); std::vector*> dm_vec = {&dm}; @@ -190,25 +187,24 @@ void Veff>::cal_dH(std::vector*> continue; // cache the destination pointers of this (iat1, iat2, R) block for every atom I - std::vector dst_x(nat, nullptr); - std::vector dst_y(nat, nullptr); - std::vector dst_z(nat, nullptr); + std::vector dst[3]; + for (int d = 0; d < 3; ++d) + dst[d].assign(nat, nullptr); int col_size = 0; bool ok = true; for (int iat = 0; iat < nat; ++iat) { - hamilt::BaseMatrix* mx = dhR_perI_x[iat]->find_matrix(iat1, iat2, R_index); - hamilt::BaseMatrix* my = dhR_perI_y[iat]->find_matrix(iat1, iat2, R_index); - hamilt::BaseMatrix* mz = dhR_perI_z[iat]->find_matrix(iat1, iat2, R_index); - if (!mx || !my || !mz) + hamilt::BaseMatrix* m[3]; + for (int d = 0; d < 3; ++d) + m[d] = dhR[d][iat]->find_matrix(iat1, iat2, R_index); + if (!m[0] || !m[1] || !m[2]) { ok = false; break; } - dst_x[iat] = mx->get_pointer(); - dst_y[iat] = my->get_pointer(); - dst_z[iat] = mz->get_pointer(); - col_size = mx->get_col_size(); + for (int d = 0; d < 3; ++d) + dst[d][iat] = m[d]->get_pointer(); + col_size = m[0]->get_col_size(); } if (!ok) continue; @@ -237,9 +233,8 @@ void Veff>::cal_dH(std::vector*> // (sign confirmed against central finite-difference of the V^L matrix for iat2) for (int iat = 0; iat < nat; ++iat) { - dst_x[iat][idx] -= forcelc(iat, 0); - dst_y[iat][idx] -= forcelc(iat, 1); - dst_z[iat][idx] -= forcelc(iat, 2); + for (int d = 0; d < 3; ++d) + dst[d][iat][idx] -= forcelc(iat, d); } // reset the delta element back to zero for the next orbital pair @@ -253,7 +248,119 @@ void Veff>::cal_dH(std::vector*> else if (hellmann_feynman_type == "hartree") { ModuleBase::timer::start("Veff", "cal_dH_hf_vh"); - // HF hartree term: 4-center ERIs with gradient — deferred + + // 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 != 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) + { + // 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 (D^T uses the reverse pair). + hamilt::HContainer mI(paraV); + for (int iap = 0; iap < dmR->size_atom_pairs(); ++iap) + { + mI.insert_pair(dmR->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); + hamilt::BaseMatrix* dst = mI.find_matrix(I, L, R); + const hamilt::BaseMatrix* d_il = dmR->find_matrix(I, L, R); + const hamilt::BaseMatrix* d_li = dmR->find_matrix(L, I, negR); + 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) + { + double v = 0.0; + if (d_il) + v += d_il->get_pointer()[a * ncol + b]; + if (d_li) + v += d_li->get_pointer()[b * nrow + a]; + pdst[a * ncol + b] = v; + } + } + } + } + + // [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 = - + for (int iap = 0; iap < dpI->size_atom_pairs(); ++iap) + { + auto& ap = dpI->get_atom_pair(iap); + const int i = ap.get_atom_i(); + const int j = 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 = dpI->find_matrix(i, j, R); + hamilt::BaseMatrix* src = hR_hf.find_matrix(i, j, R); + if (!dst || !src) + continue; + const int n = dst->get_row_size() * dst->get_col_size(); + double* pdst = dst->get_pointer(); + const double* psrc = src->get_pointer(); + for (int k = 0; k < n; ++k) + pdst[k] -= psrc[k]; + } + } + } + } ModuleBase::timer::end("Veff", "cal_dH_hf_vh"); } else diff --git a/source/source_lcao/module_operator_lcao/veff_lcao.h b/source/source_lcao/module_operator_lcao/veff_lcao.h index cf630a9729b..6b2746cc62e 100644 --- a/source/source_lcao/module_operator_lcao/veff_lcao.h +++ b/source/source_lcao/module_operator_lcao/veff_lcao.h @@ -5,6 +5,7 @@ #include "operator_lcao.h" #include "source_cell/module_neighbor/sltk_grid_driver.h" #include "source_cell/unitcell.h" +#include #include #include @@ -62,10 +63,9 @@ class Veff> : public OperatorLCAO // 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::vector*>& dhR_perI_x, - std::vector*>& dhR_perI_y, - std::vector*>& dhR_perI_z, - const std::string& hellmann_feynman_type = "none"); + void cal_dH(std::array*>, 3>& dhR, + const std::string& hellmann_feynman_type = "none", + const hamilt::HContainer* dmR = nullptr); 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..54f5c164f90 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,70 @@ 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_dHs"); + ModuleBase::timer::start("Exx_LRI", "cal_dHs"); + + 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. 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 + dHs_ipos_ispin[iat_col][iat_row].insert(col_item); + } + } + // 2. convert to 2D-distribution for abacus + for (int iat = 0; iat < ucell.nat; ++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]; + } + } + } + ModuleBase::timer::end("Exx_LRI", "cal_dHs"); +} + + /* 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..da68c500ae8 100644 --- a/source/source_lcao/module_ri/Exx_LRI_interface.h +++ b/source/source_lcao/module_ri/Exx_LRI_interface.h @@ -53,6 +53,7 @@ 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; } // Processes in ESolver_KS_LCAO /// @brief in init: Exx_LRI::init() @@ -76,6 +77,16 @@ 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. @@ -136,6 +147,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..54385ce37d7 100644 --- a/source/source_lcao/module_ri/Exx_LRI_interface.hpp +++ b/source/source_lcao/module_ri/Exx_LRI_interface.hpp @@ -98,6 +98,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, From c81e300803cb7bb3934cf01bb81ac64992552699 Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Mon, 8 Jun 2026 00:59:53 +0800 Subject: [PATCH 06/13] add dm_container_to_Ds and exx nscf-from-dm workflow; minor refactor OperatorEXX --- .../source_io/module_ctrl/ctrl_scf_lcao.cpp | 2 +- source/source_lcao/hamilt_lcao.cpp | 29 +-- .../module_operator_lcao/op_exx_lcao.h | 34 +++- .../module_operator_lcao/op_exx_lcao.hpp | 182 +++++++++++++----- source/source_lcao/module_ri/Exx_LRI.hpp | 14 +- .../source_lcao/module_ri/Exx_LRI_interface.h | 12 +- .../module_ri/Exx_LRI_interface.hpp | 17 +- source/source_lcao/module_ri/RI_2D_Comm.h | 12 ++ source/source_lcao/module_ri/RI_2D_Comm.hpp | 80 ++++++++ source/source_lcao/setup_exx.cpp | 16 ++ 10 files changed, 298 insertions(+), 100 deletions(-) diff --git a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp index cbab5c0c185..c80cfa509e0 100644 --- a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp +++ b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp @@ -368,7 +368,7 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, ModuleIO::write_h_vxc(h_params); } #ifdef __EXX - if (inp.out_mat_h_exx[0]) + 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) 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_operator_lcao/op_exx_lcao.h b/source/source_lcao/module_operator_lcao/op_exx_lcao.h index e6423cc3df8..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,10 +58,7 @@ 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; @@ -59,14 +74,15 @@ class OperatorEXX> : public OperatorLCAO 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 5b9e10d32d0..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) + { + ModuleIO::read_Hexxs_csr(file_name_exx_csr, ucell, PARAM.inp.nspin, PARAM.globalv.nlocal, *Hexxd); + } + else { - reallocate_hcontainer(*Hexxd, this->hR); + 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; diff --git a/source/source_lcao/module_ri/Exx_LRI.hpp b/source/source_lcao/module_ri/Exx_LRI.hpp index 54f5c164f90..cbc27778809 100644 --- a/source/source_lcao/module_ri/Exx_LRI.hpp +++ b/source/source_lcao/module_ri/Exx_LRI.hpp @@ -940,7 +940,7 @@ void Exx_LRI::cal_exx_dHs(const 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]) @@ -956,15 +956,23 @@ void Exx_LRI::cal_exx_dHs(const std::vectorsecond = ins.first->second + col_item.second; } } - // 2. convert to 2D-distribution for abacus + // 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]); } } } diff --git a/source/source_lcao/module_ri/Exx_LRI_interface.h b/source/source_lcao/module_ri/Exx_LRI_interface.h index da68c500ae8..8aa22f1a461 100644 --- a/source/source_lcao/module_ri/Exx_LRI_interface.h +++ b/source/source_lcao/module_ri/Exx_LRI_interface.h @@ -54,6 +54,10 @@ class Exx_LRI_Interface 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() @@ -83,9 +87,7 @@ class Exx_LRI_Interface 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); + 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 @@ -128,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; diff --git a/source/source_lcao/module_ri/Exx_LRI_interface.hpp b/source/source_lcao/module_ri/Exx_LRI_interface.hpp index 54385ce37d7..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, 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 } From c9ab0c23890a595a747cb38b6497ced8e7b66733 Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Tue, 9 Jun 2026 00:14:09 +0800 Subject: [PATCH 07/13] fix parallel segfaults and kinetic sign --- source/source_io/module_dhs/write_dH.cpp | 16 +- .../module_operator_lcao/ekinetic_dh.hpp | 16 +- .../module_operator_lcao/nonlocal_dh.hpp | 5 +- .../module_operator_lcao/nonlocal_dh.hpp.bak | 256 ++++++++++++++++++ .../module_operator_lcao/veff_dh.hpp | 215 +++++++++------ 5 files changed, 415 insertions(+), 93 deletions(-) create mode 100644 source/source_lcao/module_operator_lcao/nonlocal_dh.hpp.bak diff --git a/source/source_io/module_dhs/write_dH.cpp b/source/source_io/module_dhs/write_dH.cpp index 2b629c1a542..0a2bcb2572c 100644 --- a/source/source_io/module_dhs/write_dH.cpp +++ b/source/source_io/module_dhs/write_dH.cpp @@ -1,5 +1,6 @@ #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" @@ -74,10 +75,23 @@ void write_dh_perI(WriteDHParams& params, // ---- 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(static_cast(nlocal) * nlocal, 0); + 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) { diff --git a/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp b/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp index 18dc546b7dc..0dee60187a4 100644 --- a/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp +++ b/source/source_lcao/module_operator_lcao/ekinetic_dh.hpp @@ -137,23 +137,21 @@ void EKinetic>::cal_dH(std::array dtau_scaled = dtau * this->ucell->lat0; - this->intor_->calculate(T1, L1, N1, M1, T2, L2, N2, M2, dtau_scaled, nullptr, olm); + 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); + 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); - // calculate() writes the spatial gradient (d/dx,d/dy,d/dz) into - // grad_out[0..2] (here olm[0..2]); olm[3] is unused. - // d/dtau_I = - (dtau = -grad); sign + // 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) { - // d/dtau_V (I = iat2) - ptrV[d][idx] -= olm[d]; - // d/dtau_U (I = iat1) - ptrU[d][idx] -= olm_rev[d]; + ptrV[d][idx] += olm[d]; + ptrU[d][idx] += olm_rev[d]; } } } diff --git a/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp b/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp index d247840af0b..23afb15feb5 100644 --- a/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp +++ b/source/source_lcao/module_operator_lcao/nonlocal_dh.hpp @@ -133,6 +133,7 @@ void Nonlocal>::cal_dH(std::array = - = ModuleBase::Vector3 dtau_at = tau0 - tau1; this->intor_->snap(T1, qn1.L, qn1.N, qn1.M, T0, dtau_at * this->ucell->lat0, true, nlm); @@ -202,7 +203,7 @@ void Nonlocal>::cal_dH(std::array& nlm1 = it1->second; const size_t length = nlm1.size() / 4; - const int iw1_row = paraV->global2local_row(row_indexes[iw1l]); + const int iw1_row = static_cast(iw1l); for (size_t iw2l = 0; iw2l < col_indexes.size(); iw2l++) { @@ -210,7 +211,7 @@ void Nonlocal>::cal_dH(std::array& nlm2 = it2->second; - const int iw2_col = paraV->global2local_col(col_indexes[iw2l]); + const int iw2_col = static_cast(iw2l); // tU = D (orbital 1 moves) // tV = D (orbital 2 moves) 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/veff_dh.hpp b/source/source_lcao/module_operator_lcao/veff_dh.hpp index 04ee5ef0166..b0ca26edc59 100644 --- a/source/source_lcao/module_operator_lcao/veff_dh.hpp +++ b/source/source_lcao/module_operator_lcao/veff_dh.hpp @@ -1,11 +1,15 @@ #pragma once -#include "veff_lcao.h" #include "source_base/timer.h" -#include "source_lcao/module_gint/gint_dvlocal.h" -#include "source_lcao/module_gint/gint_interface.h" #include "source_estate/module_charge/charge.h" #include "source_estate/module_pot/H_Hartree_pw.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 { @@ -76,49 +80,77 @@ void Veff>::cal_dH(std::arraynspin, PARAM.globalv.npol, true); gint_dv.cal_dvlocal(); - hamilt::HContainer* pvdpR[3] + hamilt::HContainer* pvdpR[3] // grid parallel = {gint_dv.get_pvdpRx(), gint_dv.get_pvdpRy(), gint_dv.get_pvdpRz()}; - for (int iap = 0; iap < pvdpR[0]->size_atom_pairs(); iap++) +#ifdef __MPI + int mpi_size = 1; + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); +#endif + for (int I = 0; I < nat; ++I) { - const auto& ap = pvdpR[0]->get_atom_pair(iap); - const int iat1 = ap.get_atom_i(); // A - const int iat2 = ap.get_atom_j(); // B - - for (int ir = 0; ir < ap.get_R_size(); ir++) + for (int d = 0; d < 3; ++d) { - const ModuleBase::Vector3 R = ap.get_R_index(ir); - const ModuleBase::Vector3 negR(-R.x, -R.y, -R.z); + // grid-layout source (same structure as pvdpR), only atom-I blocks filled + hamilt::HContainer gI(*pvdpR[d]); + gI.set_zero(); - for (int d = 0; d < 3; ++d) + for (int iap = 0; iap < pvdpR[d]->size_atom_pairs(); iap++) { - hamilt::BaseMatrix* src = pvdpR[d]->find_matrix(iat1, iat2, R); - // delta_VI (I=B): -pvdpR into block (A,B) of container B - hamilt::BaseMatrix* dV = dhR[d][iat2]->find_matrix(iat1, iat2, R); - // delta_UI (I=B): -pvdpR^T into block (B,A) of container B - hamilt::BaseMatrix* dU = dhR[d][iat2]->find_matrix(iat2, iat1, negR); - if (!src || !dV || !dU) - continue; - - const int rowA = src->get_row_size(); - const int colB = src->get_col_size(); - double* psrc = src->get_pointer(); - double* pV = dV->get_pointer(); - double* pU = dU->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) + 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++) { - for (int b = 0; b < colB; ++b) + 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) { - const double val = psrc[a * colB + b]; - pV[a * colB + b] -= val; // block (A,B)[a,b] (delta_VI) - pU[b * rowA + a] -= val; // block (B,A)[b,a] (delta_UI, transpose) + 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 } } @@ -159,6 +191,7 @@ void Veff>::cal_dH(std::array*> dm_vec = {&dm}; + const int* iat2iwt = this->ucell->get_iat2iwt(); for (int iat1 = 0; iat1 < nat; iat1++) { auto tau1 = this->ucell->get_tau(iat1); @@ -180,45 +213,60 @@ void Veff>::cal_dH(std::array= this->orb_cutoff_[T1] + this->orb_cutoff_[T2]) continue; - 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; - - // cache the destination pointers of this (iat1, iat2, R) block for every atom I - std::vector dst[3]; - for (int d = 0; d < 3; ++d) - dst[d].assign(nat, nullptr); + // 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; - bool ok = true; - for (int iat = 0; iat < nat; ++iat) + // 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* m[3]; + 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) - m[d] = dhR[d][iat]->find_matrix(iat1, iat2, R_index); - if (!m[0] || !m[1] || !m[2]) - { - ok = false; - break; - } - for (int d = 0; d < 3; ++d) - dst[d][iat] = m[d]->get_pointer(); - col_size = m[0]->get_col_size(); + 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; + } } - if (!ok) - continue; - - double* dm_ptr = dm.find_matrix(iat1, iat2, R_index)->get_pointer(); - for (int iw1l = 0; iw1l < static_cast(row_indexes.size()); ++iw1l) + for (int iw1 = 0; iw1 < nw1; ++iw1) { - for (int iw2l = 0; iw2l < static_cast(col_indexes.size()); ++iw2l) + const int lr = paraV->global2local_row(gr0 + iw1); + for (int iw2 = 0; iw2 < nw2; ++iw2) { - const int idx = iw1l * col_size + iw2l; + 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; - // delta-density-matrix D_{Ii,Jj} = delta_{Ii,Umu} delta_{Jj,Vnu} - dm_ptr[idx] = 1.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) @@ -228,17 +276,20 @@ void Veff>::cal_dH(std::arrayucell, 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) - for (int iat = 0; iat < nat; ++iat) + if (owned) { - for (int d = 0; d < 3; ++d) - dst[d][iat][idx] -= forcelc(iat, d); - } + 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; + // reset the delta element back to zero for the next orbital pair + dm_ptr[idx] = 0.0; + } } } } @@ -268,11 +319,16 @@ void Veff>::cal_dH(std::array mI(paraV); for (int iap = 0; iap < dmR->size_atom_pairs(); ++iap) { @@ -292,9 +348,10 @@ void Veff>::cal_dH(std::array 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); + // D(I,L,R) is the same (locally-owned) 2D block as mI(I,L,R) const hamilt::BaseMatrix* d_il = dmR->find_matrix(I, L, R); - const hamilt::BaseMatrix* d_li = dmR->find_matrix(L, I, negR); const int nrow = dst->get_row_size(); const int ncol = dst->get_col_size(); double* pdst = dst->get_pointer(); @@ -302,12 +359,8 @@ void Veff>::cal_dH(std::arrayget_pointer()[a * ncol + b]; - if (d_li) - v += d_li->get_pointer()[b * nrow + a]; - pdst[a * ncol + b] = v; + // M^I(I,L,R) = D + D^T = 2*D(I,L,R) (DMR symmetry, see above) + pdst[a * ncol + b] = (d_il ? 2.0 * d_il->get_pointer()[a * ncol + b] : 0.0); } } } From c9671c8c6e64dc0f1b641ea9bf2792adbaac726d Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Mon, 15 Jun 2026 15:36:56 +0800 Subject: [PATCH 08/13] XC H-F term (FD) --- source/source_estate/init_scf.cpp | 5 +- source/source_estate/module_charge/charge.cpp | 2 +- source/source_estate/module_charge/charge.h | 2 +- .../source_io/module_ctrl/ctrl_scf_lcao.cpp | 1 + source/source_io/module_dhs/write_dH.cpp | 1 + source/source_io/module_dhs/write_dH.h | 3 + .../source_io/module_dhs/write_dH_terms.cpp | 83 +++++++++++- .../module_operator_lcao/veff_dh.hpp | 125 +++++++++++++++++- .../module_operator_lcao/veff_lcao.h | 3 +- 9 files changed, 217 insertions(+), 8 deletions(-) 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_io/module_ctrl/ctrl_scf_lcao.cpp b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp index c80cfa509e0..d494f23a133 100644 --- a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp +++ b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp @@ -266,6 +266,7 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, 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). diff --git a/source/source_io/module_dhs/write_dH.cpp b/source/source_io/module_dhs/write_dH.cpp index 0a2bcb2572c..833c17234d2 100644 --- a/source/source_io/module_dhs/write_dH.cpp +++ b/source/source_io/module_dhs/write_dH.cpp @@ -160,6 +160,7 @@ void write_dH_components(WriteDHParams& params) if (PARAM.inp.out_mat_dh_vxc[0]) { write_dH_vxc(params); + write_dH_vxc_pulay(params); } if (PARAM.inp.out_mat_dh[0] && any_dh_term_enabled()) diff --git a/source/source_io/module_dhs/write_dH.h b/source/source_io/module_dhs/write_dH.h index 4203de7bf6f..4d7b45d8bc3 100644 --- a/source/source_io/module_dhs/write_dH.h +++ b/source/source_io/module_dhs/write_dH.h @@ -43,6 +43,7 @@ struct WriteDHParams bool append = false; bool also_dhR = false; // whether to write the real-space dH(R) in addition to the k-space dH(k) const hamilt::HContainer* dmR = nullptr; + 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). @@ -79,6 +80,8 @@ 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 diff --git a/source/source_io/module_dhs/write_dH_terms.cpp b/source/source_io/module_dhs/write_dH_terms.cpp index a5db91b10c5..54d8bf47944 100644 --- a/source/source_io/module_dhs/write_dH_terms.cpp +++ b/source/source_io/module_dhs/write_dH_terms.cpp @@ -8,14 +8,21 @@ #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 { @@ -46,6 +53,59 @@ struct PerIContainers } }; +#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 + // 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, @@ -62,6 +122,12 @@ bool write_dH_veff_term(WriteDHParams& params, 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); +#endif + for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) { hamilt::HContainer hR_dummy(const_cast(&pv)); @@ -77,7 +143,7 @@ bool write_dH_veff_term(WriteDHParams& params, PerIContainers c(pv, nat); - veff.cal_dH(c.g, hf_type, params.dmR); + veff.cal_dH(c.g, hf_type, params.dmR, params.chg); ModuleIO::write_dh_perI(params, ispin, rprefix, kprefix, label, c.g); } @@ -227,12 +293,25 @@ bool write_dH_vxc(WriteDHParams& params) ModuleBase::TITLE("ModuleIO", "write_dH_vxc"); ModuleBase::timer::start("ModuleIO", "write_dH_vxc"); - const bool ok = write_dH_veff_term(params, params.pot_vxc, "none", "dvxcr", "dvxck", "dV^XC"); + const bool ok = write_dH_veff_term(params, params.pot_vxc, + params.chg ? "xc" : "none", + "dvxcr", "dvxck", "dV^XC"); 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 bool ok = write_dH_veff_term(params, params.pot_vxc, "none", "dvxcr_pulay_", "dvxck_pulay_", "dV^XC (Pulay)"); + + ModuleBase::timer::end("ModuleIO", "write_dH_vxc_pulay"); + return ok; +} + #ifdef __EXX bool write_dH_exx(WriteDHParams& params) { diff --git a/source/source_lcao/module_operator_lcao/veff_dh.hpp b/source/source_lcao/module_operator_lcao/veff_dh.hpp index b0ca26edc59..0bdeda73120 100644 --- a/source/source_lcao/module_operator_lcao/veff_dh.hpp +++ b/source/source_lcao/module_operator_lcao/veff_dh.hpp @@ -2,6 +2,7 @@ #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" @@ -17,7 +18,8 @@ namespace hamilt template void Veff>::cal_dH(std::array*>, 3>& dhR, const std::string& hellmann_feynman_type, - const hamilt::HContainer* dmR) + const hamilt::HContainer* dmR, + const Charge* chg) { ModuleBase::TITLE("Veff", "cal_dH"); ModuleBase::timer::start("Veff", "cal_dH"); @@ -160,7 +162,7 @@ void Veff>::cal_dH(std::array>::cal_dH(std::arraypot->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) + { + // M^I = 2*delta_{KI}*D(I,L,R): only atom-I rows, same pattern as Hartree branch + hamilt::HContainer mI(paraV); + for (int iap = 0; iap < dmR->size_atom_pairs(); ++iap) + { + mI.insert_pair(dmR->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); + const ModuleBase::Vector3 negR(-R.x, -R.y, -R.z); + (void)negR; + hamilt::BaseMatrix* dst = mI.find_matrix(I, L, R); + const hamilt::BaseMatrix* d_il = dmR->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); + } + } + } + } + + // [grad rho]^{S,delta}_{I,d} on the real-space grid + std::vector*> dm_vec = {&mI}; + // chg_drho is allocated once and reused across I; cal_gint_drho ACCUMULATES + // (see Gint_drho), so it must be zeroed 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); + ModuleGint::cal_gint_drho(dm_vec, 1, chg_drho[0].rho, chg_drho[1].rho, chg_drho[2].rho); + + 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); + ModuleGint::cal_gint_vl(&dvxcr(0, 0), &hR_hf); + + // d_{tau_I,d} V^XC|HF = - + for (int iap = 0; iap < dpI->size_atom_pairs(); ++iap) + { + auto& ap = dpI->get_atom_pair(iap); + const int i = ap.get_atom_i(); + const int j = 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 = dpI->find_matrix(i, j, R); + hamilt::BaseMatrix* src = hR_hf.find_matrix(i, j, R); + if (!dst || !src) + continue; + const int n = dst->get_row_size() * dst->get_col_size(); + double* pdst = dst->get_pointer(); + const double* psrc = src->get_pointer(); + for (int k = 0; k < n; ++k) + pdst[k] -= psrc[k]; + } + } + } + } + ModuleBase::timer::end("Veff", "cal_dH_hf_xc"); + } else { // Unsupported Hellmann-Feynman type diff --git a/source/source_lcao/module_operator_lcao/veff_lcao.h b/source/source_lcao/module_operator_lcao/veff_lcao.h index 6b2746cc62e..04a402bed16 100644 --- a/source/source_lcao/module_operator_lcao/veff_lcao.h +++ b/source/source_lcao/module_operator_lcao/veff_lcao.h @@ -65,7 +65,8 @@ class Veff> : public OperatorLCAO // 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 hamilt::HContainer* dmR = nullptr); + const hamilt::HContainer* dmR = nullptr, + const Charge* chg = nullptr); const UnitCell* ucell = nullptr; const Grid_Driver* gd = nullptr; From 5d0ef75c498bd0623b4ac5074460fb40c656e1f1 Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Mon, 15 Jun 2026 20:22:09 +0800 Subject: [PATCH 09/13] enable value-adding HContainers, total dH and atom-specified output; enable nspin=2 --- docs/advanced/input_files/input-main.md | 128 ++++++- .../source_io/module_ctrl/ctrl_scf_lcao.cpp | 18 +- source/source_io/module_dhs/write_dH.cpp | 121 ++----- source/source_io/module_dhs/write_dH.h | 26 +- .../source_io/module_dhs/write_dH_terms.cpp | 260 ++++++++++---- .../source_io/module_hs/output_mat_sparse.cpp | 2 +- source/source_io/module_hs/write_H_terms.cpp | 1 - .../read_input_item_output.cpp | 84 ++++- .../module_hcontainer/hcontainer.cpp | 76 ++++ .../module_hcontainer/hcontainer.h | 18 + .../module_hcontainer/test/CMakeLists.txt | 6 + .../module_hcontainer/test/test_add_value.cpp | 339 ++++++++++++++++++ .../module_operator_lcao/veff_dh.hpp | 157 ++++---- .../module_operator_lcao/veff_lcao.h | 5 +- 14 files changed, 967 insertions(+), 274 deletions(-) create mode 100644 source/source_lcao/module_hcontainer/test/test_add_value.cpp diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index a91c6dd7530..9e21458c556 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) @@ -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) @@ -1983,10 +2043,72 @@ ### 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 controled 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)* +- **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 diff --git a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp index d494f23a133..9a818123db4 100644 --- a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp +++ b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp @@ -234,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], @@ -275,21 +276,23 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, elecstate::Potential* pot_vl = nullptr; elecstate::Potential* pot_vh = nullptr; elecstate::Potential* pot_vxc = nullptr; - if (inp.out_mat_dh_vl[0]) + // 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]) + 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]) + 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); @@ -307,7 +310,12 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, dh_params.append = out_app_flag; if (PARAM.inp.nspin == 1 || PARAM.inp.nspin == 2) { - dh_params.dmR = dm->get_DMR_pointer(1); + // 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 diff --git a/source/source_io/module_dhs/write_dH.cpp b/source/source_io/module_dhs/write_dH.cpp index 833c17234d2..37a13058552 100644 --- a/source/source_io/module_dhs/write_dH.cpp +++ b/source/source_io/module_dhs/write_dH.cpp @@ -9,6 +9,7 @@ #include "source_lcao/module_hcontainer/hcontainer_funcs.h" #include "source_lcao/module_hcontainer/output_hcontainer.h" +#include #include #include #include @@ -18,11 +19,12 @@ 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) + 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; @@ -48,8 +50,17 @@ void write_dh_perI(WriteDHParams& params, 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]; @@ -113,21 +124,18 @@ void write_dh_perI(WriteDHParams& params, } } -bool any_dh_term_enabled() -{ - return PARAM.inp.out_mat_dh_t[0] || PARAM.inp.out_mat_dh_vl[0] || PARAM.inp.out_mat_dh_vnl[0] - || PARAM.inp.out_mat_dh_vh[0] || PARAM.inp.out_mat_dh_vxc[0]; -} - void write_dH_components(WriteDHParams& params) { ModuleBase::TITLE("ModuleIO", "write_dH_components"); ModuleBase::timer::start("ModuleIO", "write_dH_components"); - if (!any_dh_term_enabled()) + // 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::timer::end("ModuleIO", "write_dH_components"); - return; + 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; @@ -136,6 +144,11 @@ void write_dH_components(WriteDHParams& params) 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); @@ -163,11 +176,6 @@ void write_dH_components(WriteDHParams& params) write_dH_vxc_pulay(params); } - if (PARAM.inp.out_mat_dh[0] && any_dh_term_enabled()) - { - write_dH_sum(params); - } - #ifdef __EXX if (PARAM.inp.out_mat_dh_exx[0]) { @@ -178,79 +186,4 @@ void write_dH_components(WriteDHParams& params) ModuleBase::timer::end("ModuleIO", "write_dH_components"); } -bool write_dH_sum(WriteDHParams& params) -{ - ModuleBase::TITLE("ModuleIO", "write_dH_sum"); - ModuleBase::timer::start("ModuleIO", "write_dH_sum"); - - const UnitCell& ucell = *params.ucell; - const Parallel_Orbitals& pv = *params.pv; - const int nat = ucell.nat; - const int nspin = params.nspin; - - for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) - { - hamilt::HContainer dH_sum_x(&pv); - hamilt::HContainer dH_sum_y(&pv); - hamilt::HContainer dH_sum_z(&pv); - dH_sum_x.set_zero(); - dH_sum_y.set_zero(); - dH_sum_z.set_zero(); - - if (dH_sum_x.size_atom_pairs() == 0) - { - continue; - } - - const int nbasis = dH_sum_x.get_nbasis(); - -#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); - - hamilt::HContainer dH_x_s(&serialV); - hamilt::HContainer dH_y_s(&serialV); - hamilt::HContainer dH_z_s(&serialV); - hamilt::gatherParallels(dH_sum_x, &dH_x_s, 0); - hamilt::gatherParallels(dH_sum_y, &dH_y_s, 0); - hamilt::gatherParallels(dH_sum_z, &dH_z_s, 0); - - if (GlobalV::MY_RANK == 0) -#endif - { - std::string fname_x = ModuleIO::dhr_gen_fname("dhrx", ispin, params.append, params.istep); - std::string fname_y = ModuleIO::dhr_gen_fname("dhry", ispin, params.append, params.istep); - std::string fname_z = ModuleIO::dhr_gen_fname("dhrz", ispin, params.append, params.istep); - - if (PARAM.inp.calculation == "md" && !PARAM.inp.out_app_flag) - { - fname_x = PARAM.globalv.global_matrix_dir + fname_x; - fname_y = PARAM.globalv.global_matrix_dir + fname_y; - fname_z = PARAM.globalv.global_matrix_dir + fname_z; - } - else - { - fname_x = PARAM.globalv.global_out_dir + fname_x; - fname_y = PARAM.globalv.global_out_dir + fname_y; - fname_z = PARAM.globalv.global_out_dir + fname_z; - } - -#ifdef __MPI - ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dH_x_s, params.istep, ispin, nspin, "dH_sum"); - ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dH_y_s, params.istep, ispin, nspin, "dH_sum"); - ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dH_z_s, params.istep, ispin, nspin, "dH_sum"); -#else - ModuleIO::write_hcontainer_csr(fname_x, &ucell, 8, &dH_sum_x, params.istep, ispin, nspin, "dH_sum"); - ModuleIO::write_hcontainer_csr(fname_y, &ucell, 8, &dH_sum_y, params.istep, ispin, nspin, "dH_sum"); - ModuleIO::write_hcontainer_csr(fname_z, &ucell, 8, &dH_sum_z, params.istep, ispin, nspin, "dH_sum"); -#endif - } - } - - ModuleBase::timer::end("ModuleIO", "write_dH_sum"); - return true; -} - } // namespace ModuleIO diff --git a/source/source_io/module_dhs/write_dH.h b/source/source_io/module_dhs/write_dH.h index 4d7b45d8bc3..ef277112aab 100644 --- a/source/source_io/module_dhs/write_dH.h +++ b/source/source_io/module_dhs/write_dH.h @@ -42,7 +42,9 @@ struct WriteDHParams 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) - const hamilt::HContainer* dmR = nullptr; + // 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 @@ -52,19 +54,29 @@ struct WriteDHParams #endif }; -bool any_dh_term_enabled(); +// 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) + 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); + 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); diff --git a/source/source_io/module_dhs/write_dH_terms.cpp b/source/source_io/module_dhs/write_dH_terms.cpp index 54d8bf47944..01e2c0ebfe7 100644 --- a/source/source_io/module_dhs/write_dH_terms.cpp +++ b/source/source_io/module_dhs/write_dH_terms.cpp @@ -106,6 +106,71 @@ void validate_gint_drho(const UnitCell& ucell, } #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, @@ -113,47 +178,51 @@ bool write_dH_veff_term(WriteDHParams& params, const std::string& hf_type, const std::string& rprefix, const std::string& kprefix, - const std::string& label) + const std::string& label, + const std::vector& atom_filter = {}) { 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 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); + validate_gint_drho(ucell, pot, params.dmR.empty() ? nullptr : params.dmR[0]); #endif for (int ispin = 0; ispin < (nspin == 2 ? 2 : 1); ispin++) { - hamilt::HContainer hR_dummy(const_cast(&pv)); - - hamilt::Veff> veff(nullptr, - params.kv->kvec_d, - pot, - &hR_dummy, - &ucell, - orb_cutoff, - &gd, - nspin); - PerIContainers c(pv, nat); - veff.cal_dH(c.g, hf_type, params.dmR, params.chg); + fill_dH_veff(params, pot, hf_type, ispin, c); - ModuleIO::write_dh_perI(params, ispin, rprefix, kprefix, label, c.g); + ModuleIO::write_dh_perI(params, ispin, rprefix, kprefix, label, c.g, atom_filter); } return true; } #ifdef __EXX -// Shared driver for the EXX dH term, templated on the Hexx tensor data type (double for the -// real interface exd, std::complex for the complex interface exc). The per-atom-I dH -// is always written into real HContainer (add_HexxR converts Tdata -> double). +// 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) { @@ -165,19 +234,15 @@ void write_dH_exx_impl(WriteDHParams& params, Exx_LRI_Interface* // 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); - // 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); + fill_dH_exx(params, ex, ispin, c); - op_exx.cal_dH(ispin, c.g, ex->get_dHexxs()); - - ModuleIO::write_dh_perI(params, ispin, "dvexxr", "dvexxk", "dV^EXX", c.g); + ModuleIO::write_dh_perI(params, ispin, "dvexxr", "dvexxk", "dV^EXX", c.g, af); } } #endif @@ -189,32 +254,19 @@ bool write_dH_t(WriteDHParams& params) ModuleBase::TITLE("ModuleIO", "write_dH_t"); ModuleBase::timer::start("ModuleIO", "write_dH_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 int nat = ucell.nat; + const int nat = params.ucell->nat; const int nspin = params.nspin; - const std::vector& orb_cutoff = orb.cutoffs(); + 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); - 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); + fill_dH_t(params, c); - ModuleIO::write_dh_perI(params, ispin, "dtr", "dtk", "dT", c.g); + ModuleIO::write_dh_perI(params, ispin, "dtr", "dtk", "dT", c.g, af_t); } ModuleBase::timer::end("ModuleIO", "write_dH_t"); @@ -226,29 +278,18 @@ bool write_dH_vnl(WriteDHParams& params) ModuleBase::TITLE("ModuleIO", "write_dH_vnl"); ModuleBase::timer::start("ModuleIO", "write_dH_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 int nat = ucell.nat; + const int nat = params.ucell->nat; const int nspin = params.nspin; - const std::vector& orb_cutoff = params.orb->cutoffs(); + 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); - 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); + fill_dH_vnl(params, c); - ModuleIO::write_dh_perI(params, ispin, "dvnlr", "dvnlk", "dV^NL", c.g); + ModuleIO::write_dh_perI(params, ispin, "dvnlr", "dvnlk", "dV^NL", c.g, af_vnl); } ModuleBase::timer::end("ModuleIO", "write_dH_vnl"); @@ -260,7 +301,8 @@ bool write_dH_vl(WriteDHParams& params) ModuleBase::TITLE("ModuleIO", "write_dH_vl"); ModuleBase::timer::start("ModuleIO", "write_dH_vl"); - const bool ok = write_dH_veff_term(params, params.pot_vl, "vl", "dvlr", "dvlk", "dV^L"); + 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; @@ -271,7 +313,8 @@ bool write_dH_vh(WriteDHParams& params) ModuleBase::TITLE("ModuleIO", "write_dH_vh"); ModuleBase::timer::start("ModuleIO", "write_dH_vh"); - const bool ok = write_dH_veff_term(params, params.pot_vh, "hartree", "dvhr", "dvhk", "dV^H"); + 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; @@ -282,7 +325,8 @@ bool write_dH_vh_pulay(WriteDHParams& params) ModuleBase::TITLE("ModuleIO", "write_dH_vh_pulay"); ModuleBase::timer::start("ModuleIO", "write_dH_vh_pulay"); - const bool ok = write_dH_veff_term(params, params.pot_vh, "none", "dvhr_pulay_", "dvhk_pulay_", "dV^H (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; @@ -293,9 +337,10 @@ 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"); + "dvxcr", "dvxck", "dV^XC", af_vxc); ModuleBase::timer::end("ModuleIO", "write_dH_vxc"); return ok; @@ -306,7 +351,8 @@ bool write_dH_vxc_pulay(WriteDHParams& params) ModuleBase::TITLE("ModuleIO", "write_dH_vxc_pulay"); ModuleBase::timer::start("ModuleIO", "write_dH_vxc_pulay"); - const bool ok = write_dH_veff_term(params, params.pot_vxc, "none", "dvxcr_pulay_", "dvxck_pulay_", "dV^XC (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; @@ -342,4 +388,90 @@ bool write_dH_exx(WriteDHParams& params) } #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 index 8b7919523c9..89071785213 100644 --- a/source/source_io/module_hs/write_H_terms.cpp +++ b/source/source_io/module_hs/write_H_terms.cpp @@ -140,7 +140,6 @@ static void write_hk_common(hamilt::HContainer& hR, out_app_flag, gamma_only, istep); - std::cout << "hk term fname = " << fname << std::endl; ModuleIO::save_mat(istep, hk_global.data(), nlocal, 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 fd9529ae4ab..217fb9c22cb 100644 --- a/source/source_io/module_parameter/read_input_item_output.cpp +++ b/source/source_io/module_parameter/read_input_item_output.cpp @@ -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,7 @@ 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); } { @@ -672,14 +678,24 @@ Also controled by out_freq_ion and out_app_flag. 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. The first value controls output (0/1), and optional subsequent values specify which atoms to compute derivatives for." - "\n\nSee out_mat_dh for format details."; + 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"); @@ -689,7 +705,7 @@ Also controled by out_freq_ion and out_app_flag. 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, 2, 0); + sync_intvec(input.out_mat_dh_t, para.input.out_mat_dh_t.size(), 0); this->add_item(item); } { @@ -705,6 +721,16 @@ Also controled by out_freq_ion and out_app_flag. 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"); @@ -714,7 +740,7 @@ Also controled by out_freq_ion and out_app_flag. 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, 2, 0); + sync_intvec(input.out_mat_dh_vl, para.input.out_mat_dh_vl.size(), 0); this->add_item(item); } { @@ -730,6 +756,16 @@ Also controled by out_freq_ion and out_app_flag. 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"); @@ -739,7 +775,7 @@ Also controled by out_freq_ion and out_app_flag. 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, 2, 0); + sync_intvec(input.out_mat_dh_vnl, para.input.out_mat_dh_vnl.size(), 0); this->add_item(item); } { @@ -755,6 +791,16 @@ Also controled by out_freq_ion and out_app_flag. 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"); @@ -764,7 +810,7 @@ Also controled by out_freq_ion and out_app_flag. 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, 2, 0); + sync_intvec(input.out_mat_dh_vh, para.input.out_mat_dh_vh.size(), 0); this->add_item(item); } { @@ -780,6 +826,16 @@ Also controled by out_freq_ion and out_app_flag. 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"); @@ -789,7 +845,7 @@ Also controled by out_freq_ion and out_app_flag. 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, 2, 0); + sync_intvec(input.out_mat_dh_vxc, para.input.out_mat_dh_vxc.size(), 0); this->add_item(item); } { @@ -805,6 +861,16 @@ Also controled by out_freq_ion and out_app_flag. 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"); @@ -814,7 +880,7 @@ Also controled by out_freq_ion and out_app_flag. 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, 2, 0); + sync_intvec(input.out_mat_dh_exx, para.input.out_mat_dh_exx.size(), 0); this->add_item(item); } { diff --git a/source/source_lcao/module_hcontainer/hcontainer.cpp b/source/source_lcao/module_hcontainer/hcontainer.cpp index e1d1b909912..ff1f33a7dd3 100644 --- a/source/source_lcao/module_hcontainer/hcontainer.cpp +++ b/source/source_lcao/module_hcontainer/hcontainer.cpp @@ -438,6 +438,82 @@ 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); + tmp.allocate(nullptr, true); + 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/veff_dh.hpp b/source/source_lcao/module_operator_lcao/veff_dh.hpp index 0bdeda73120..c5266816e6e 100644 --- a/source/source_lcao/module_operator_lcao/veff_dh.hpp +++ b/source/source_lcao/module_operator_lcao/veff_dh.hpp @@ -18,8 +18,9 @@ namespace hamilt template void Veff>::cal_dH(std::array*>, 3>& dhR, const std::string& hellmann_feynman_type, - const hamilt::HContainer* dmR, - const Charge* chg) + const std::vector*>& dmR, + const Charge* chg, + const int ispin) { ModuleBase::TITLE("Veff", "cal_dH"); ModuleBase::timer::start("Veff", "cal_dH"); @@ -73,13 +74,14 @@ void Veff>::cal_dH(std::arraypot->get_fixed_v() : this->pot->get_eff_v(0); + = (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, this->nspin, PARAM.globalv.npol, true); + ModuleGint::Gint_dvlocal gint_dv(vr_eff, 1, PARAM.globalv.npol, true); gint_dv.cal_dvlocal(); hamilt::HContainer* pvdpR[3] // grid parallel @@ -309,7 +311,7 @@ void Veff>::cal_dH(std::array. - assert(dmR != nullptr); + assert(!dmR.empty() && dmR[0] != nullptr); const ModulePW::PW_Basis* rho_basis = this->pot->get_rho_basis(); const int nrxx = rho_basis->nrxx; @@ -332,9 +334,9 @@ void Veff>::cal_dH(std::array mI(paraV); - for (int iap = 0; iap < dmR->size_atom_pairs(); ++iap) + for (int iap = 0; iap < dmR[0]->size_atom_pairs(); ++iap) { - mI.insert_pair(dmR->get_atom_pair(iap)); + mI.insert_pair(dmR[0]->get_atom_pair(iap)); } mI.allocate(nullptr, true); @@ -352,18 +354,23 @@ void Veff>::cal_dH(std::array negR(-R.x, -R.y, -R.z); (void)negR; hamilt::BaseMatrix* dst = mI.find_matrix(I, L, R); - // D(I,L,R) is the same (locally-owned) 2D block as mI(I,L,R) - const hamilt::BaseMatrix* d_il = dmR->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) - { - // M^I(I,L,R) = D + D^T = 2*D(I,L,R) (DMR symmetry, see above) - pdst[a * ncol + b] = (d_il ? 2.0 * d_il->get_pointer()[a * ncol + b] : 0.0); - } + 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]; } } } @@ -395,25 +402,7 @@ void Veff>::cal_dH(std::array - for (int iap = 0; iap < dpI->size_atom_pairs(); ++iap) - { - auto& ap = dpI->get_atom_pair(iap); - const int i = ap.get_atom_i(); - const int j = 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 = dpI->find_matrix(i, j, R); - hamilt::BaseMatrix* src = hR_hf.find_matrix(i, j, R); - if (!dst || !src) - continue; - const int n = dst->get_row_size() * dst->get_col_size(); - double* pdst = dst->get_pointer(); - const double* psrc = src->get_pointer(); - for (int k = 0; k < n; ++k) - pdst[k] -= psrc[k]; - } - } + dpI->add_value_intersection(hR_hf, -1.0); } } ModuleBase::timer::end("Veff", "cal_dH_hf_vh"); @@ -422,7 +411,7 @@ void Veff>::cal_dH(std::arraypot->get_rho_basis(); const int nrxx = rho_basis->nrxx; @@ -440,50 +429,59 @@ void Veff>::cal_dH(std::array mI(paraV); - for (int iap = 0; iap < dmR->size_atom_pairs(); ++iap) - { - mI.insert_pair(dmR->get_atom_pair(iap)); - } - mI.allocate(nullptr, true); + // [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); - for (int iap = 0; iap < mI.size_atom_pairs(); ++iap) + // 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) { - auto& ap = mI.get_atom_pair(iap); - if (ap.get_atom_i() != I) + const hamilt::HContainer* dms = dmR[s]; + + hamilt::HContainer mI(paraV); + for (int iap = 0; iap < dms->size_atom_pairs(); ++iap) { - continue; + mI.insert_pair(dms->get_atom_pair(iap)); } - const int L = ap.get_atom_j(); - for (int ir = 0; ir < ap.get_R_size(); ++ir) + mI.allocate(nullptr, true); + + for (int iap = 0; iap < mI.size_atom_pairs(); ++iap) { - 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 hamilt::BaseMatrix* d_il = dmR->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) + auto& ap = mI.get_atom_pair(iap); + if (ap.get_atom_i() != I) { - for (int b = 0; b < ncol; ++b) + 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) { - pdst[a * ncol + b] = (d_il ? 2.0 * d_il->get_pointer()[a * ncol + b] : 0.0); + for (int b = 0; b < ncol; ++b) + { + pdst[a * ncol + b] = (d_il ? 2.0 * d_il->get_pointer()[a * ncol + b] : 0.0); + } } } } - } - // [grad rho]^{S,delta}_{I,d} on the real-space grid - std::vector*> dm_vec = {&mI}; - // chg_drho is allocated once and reused across I; cal_gint_drho ACCUMULATES - // (see Gint_drho), so it must be zeroed 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); - ModuleGint::cal_gint_drho(dm_vec, 1, chg_drho[0].rho, chg_drho[1].rho, chg_drho[2].rho); + 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) { @@ -511,28 +509,11 @@ void Veff>::cal_dH(std::arrayget_atom_pair(iap)); } hR_hf.allocate(nullptr, true); - ModuleGint::cal_gint_vl(&dvxcr(0, 0), &hR_hf); + // 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 = - - for (int iap = 0; iap < dpI->size_atom_pairs(); ++iap) - { - auto& ap = dpI->get_atom_pair(iap); - const int i = ap.get_atom_i(); - const int j = 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 = dpI->find_matrix(i, j, R); - hamilt::BaseMatrix* src = hR_hf.find_matrix(i, j, R); - if (!dst || !src) - continue; - const int n = dst->get_row_size() * dst->get_col_size(); - double* pdst = dst->get_pointer(); - const double* psrc = src->get_pointer(); - for (int k = 0; k < n; ++k) - pdst[k] -= psrc[k]; - } - } + dpI->add_value_intersection(hR_hf, -1.0); } } ModuleBase::timer::end("Veff", "cal_dH_hf_xc"); diff --git a/source/source_lcao/module_operator_lcao/veff_lcao.h b/source/source_lcao/module_operator_lcao/veff_lcao.h index 04a402bed16..bccc503da3c 100644 --- a/source/source_lcao/module_operator_lcao/veff_lcao.h +++ b/source/source_lcao/module_operator_lcao/veff_lcao.h @@ -65,8 +65,9 @@ class Veff> : public OperatorLCAO // 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 hamilt::HContainer* dmR = nullptr, - const Charge* chg = nullptr); + const std::vector*>& dmR = {}, + const Charge* chg = nullptr, + const int ispin = 0); const UnitCell* ucell = nullptr; const Grid_Driver* gd = nullptr; From 058bb2982b8a8b018f2b71c4d9ee8b98e6dec01d Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Tue, 16 Jun 2026 15:45:09 +0800 Subject: [PATCH 10/13] dH test cases --- tests/02_NAO_Gamma/CASES_CPU.txt | 1 + .../scf_out_dh/{genref_diff => }/INPUT | 28 ++++------- .../scf_out_dh/{genref_diff => }/STRU | 0 .../scf_out_dh/dhk_ref/dhkz_iat2_nao.txt | 37 +++++++++++++++ .../scf_out_dh/dhk_ref/dtkz_iat2_nao.txt | 37 +++++++++++++++ .../scf_out_dh/dhk_ref/dvhkz_iat2_nao.txt | 37 +++++++++++++++ .../scf_out_dh/dhk_ref/dvlkz_iat2_nao.txt | 37 +++++++++++++++ .../scf_out_dh/dhk_ref/dvnlkz_iat2_nao.txt | 37 +++++++++++++++ .../scf_out_dh/dhk_ref/dvxckz_iat2_nao.txt | 37 +++++++++++++++ tests/02_NAO_Gamma/scf_out_dh/result.ref | 8 ++++ .../dhk_ref/dhkx_iat1_ik0_nao.txt | 46 +++++++++++++++++++ .../dhk_ref/dhkx_iat1_ik1_nao.txt | 46 +++++++++++++++++++ .../dhk_ref/dhky_iat1_ik0_nao.txt | 46 +++++++++++++++++++ .../dhk_ref/dhky_iat1_ik1_nao.txt | 46 +++++++++++++++++++ .../dhk_ref/dhkz_iat1_ik0_nao.txt | 46 +++++++++++++++++++ .../dhk_ref/dhkz_iat1_ik1_nao.txt | 46 +++++++++++++++++++ tests/03_NAO_multik/scf_out_dh_t/result.ref | 6 +++ tests/integrate/tools/catch_properties.sh | 18 +++++++- 18 files changed, 538 insertions(+), 21 deletions(-) rename tests/02_NAO_Gamma/scf_out_dh/{genref_diff => }/INPUT (59%) rename tests/02_NAO_Gamma/scf_out_dh/{genref_diff => }/STRU (100%) create mode 100644 tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dhkz_iat2_nao.txt create mode 100644 tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dtkz_iat2_nao.txt create mode 100644 tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvhkz_iat2_nao.txt create mode 100644 tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvlkz_iat2_nao.txt create mode 100644 tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvnlkz_iat2_nao.txt create mode 100644 tests/02_NAO_Gamma/scf_out_dh/dhk_ref/dvxckz_iat2_nao.txt create mode 100644 tests/02_NAO_Gamma/scf_out_dh/result.ref create mode 100644 tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkx_iat1_ik0_nao.txt create mode 100644 tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkx_iat1_ik1_nao.txt create mode 100644 tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhky_iat1_ik0_nao.txt create mode 100644 tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhky_iat1_ik1_nao.txt create mode 100644 tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkz_iat1_ik0_nao.txt create mode 100644 tests/03_NAO_multik/scf_out_dh_t/dhk_ref/dhkz_iat1_ik1_nao.txt 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/genref_diff/INPUT b/tests/02_NAO_Gamma/scf_out_dh/INPUT similarity index 59% rename from tests/02_NAO_Gamma/scf_out_dh/genref_diff/INPUT rename to tests/02_NAO_Gamma/scf_out_dh/INPUT index fdb9d0fd57b..b496a977b2e 100644 --- a/tests/02_NAO_Gamma/scf_out_dh/genref_diff/INPUT +++ b/tests/02_NAO_Gamma/scf_out_dh/INPUT @@ -1,44 +1,34 @@ INPUT_PARAMETERS -#Parameters (1.General) suffix autotest calculation scf nbands 4 -symmetry 1 +symmetry 0 pseudo_dir ../../PP_ORB orbital_dir ../../PP_ORB - gamma_only 1 -#Parameters (2.Iteration) ecutwfc 20 -scf_thr 1e-8 +scf_thr 1e-5 scf_nmax 100 - -#Parameters (3.Basis) basis_type lcao - -#Parameters (4.Smearing) smearing_method gauss smearing_sigma 0.002 -out_mat_xc 1 -out_mat_xc2 1 -out_eband_terms 1 - -#Parameters (5.Mixing) mixing_type broyden mixing_beta 0.7 -mixing_gg0 1.5 +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 -out_mat_dh 1 -out_mat_dh_t 1 -out_mat_dh_vnl 1 \ No newline at end of file diff --git a/tests/02_NAO_Gamma/scf_out_dh/genref_diff/STRU b/tests/02_NAO_Gamma/scf_out_dh/STRU similarity index 100% rename from tests/02_NAO_Gamma/scf_out_dh/genref_diff/STRU rename to tests/02_NAO_Gamma/scf_out_dh/STRU 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_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 #--------------------------------------- From 6b9a7d39d763fbb24703cea22e93b64c57bdbcee Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Tue, 16 Jun 2026 16:25:32 +0800 Subject: [PATCH 11/13] exclude cal_exx_dHs with __EXX_DEV flag, waiting for LibRI PR merged --- CMakeLists.txt | 4 ++++ docs/advanced/input_files/input-main.md | 1 + source/source_lcao/module_ri/Exx_LRI.hpp | 10 +++++++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f85893c47e..fec05fe33a6 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(DEFINED 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 9e21458c556..d1067a5ebdc 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -2107,6 +2107,7 @@ - **Type**: Integer - **Availability**: *Numerical atomic orbital basis, hybrid functional only (nspin ≠ 4)* + - Currently only avaliable when 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 diff --git a/source/source_lcao/module_ri/Exx_LRI.hpp b/source/source_lcao/module_ri/Exx_LRI.hpp index cbc27778809..e4f8a6dbd02 100644 --- a/source/source_lcao/module_ri/Exx_LRI.hpp +++ b/source/source_lcao/module_ri/Exx_LRI.hpp @@ -913,8 +913,9 @@ void Exx_LRI::cal_exx_dHs(const std::vector, std::set>> judge = RI_2D_Comm::get_2D_judge(ucell, pv); @@ -976,7 +977,10 @@ void Exx_LRI::cal_exx_dHs(const std::vector Date: Tue, 16 Jun 2026 18:16:01 +0800 Subject: [PATCH 12/13] small fixes --- CMakeLists.txt | 2 +- docs/advanced/input_files/input-main.md | 12 ++++++------ source/source_io/module_ctrl/ctrl_scf_lcao.cpp | 3 ++- source/source_io/module_dhs/write_dH.h | 13 ++++++++++--- source/source_io/module_dhs/write_dH_terms.cpp | 2 +- source/source_io/module_hs/write_H_terms.h | 4 ++-- source/source_lcao/module_hcontainer/hcontainer.cpp | 1 - 7 files changed, 22 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fec05fe33a6..015b190affa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -760,7 +760,7 @@ 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(DEFINED EXX_DEV) + if(EXX_DEV) add_compile_definitions(__EXX_DEV) endif() endif() diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index d1067a5ebdc..79a0c2a1e60 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -1877,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 @@ -1938,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; @@ -2034,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 @@ -2046,7 +2046,7 @@ - **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 controled by out_freq_ion and out_app_flag. + - 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. @@ -2107,7 +2107,7 @@ - **Type**: Integer - **Availability**: *Numerical atomic orbital basis, hybrid functional only (nspin ≠ 4)* - - Currently only avaliable when compiled with the personal developing branch of LibRI and -DEXX_DEV flag, waiting for the new release of LibRI to remove the flag. + - 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 @@ -2117,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_io/module_ctrl/ctrl_scf_lcao.cpp b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp index 9a818123db4..385d1134c01 100644 --- a/source/source_io/module_ctrl/ctrl_scf_lcao.cpp +++ b/source/source_io/module_ctrl/ctrl_scf_lcao.cpp @@ -255,8 +255,9 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell, &dftu); //------------------------------------------------------------------ - //! 7c) Output dH components (dT/dR, dV^NL/dR, dV^L/dR, dV^H/dR, dV^XC/dR) + //! 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; diff --git a/source/source_io/module_dhs/write_dH.h b/source/source_io/module_dhs/write_dH.h index ef277112aab..870a19f7e30 100644 --- a/source/source_io/module_dhs/write_dH.h +++ b/source/source_io/module_dhs/write_dH.h @@ -12,6 +12,13 @@ #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; @@ -54,12 +61,12 @@ struct WriteDHParams #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 +// 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) + if (param.size() <= 2) // param elements: [on/off][precition][iat1][iat2][...] return {}; return std::vector(param.begin() + 2, param.end()); } diff --git a/source/source_io/module_dhs/write_dH_terms.cpp b/source/source_io/module_dhs/write_dH_terms.cpp index 01e2c0ebfe7..32d3ba3e316 100644 --- a/source/source_io/module_dhs/write_dH_terms.cpp +++ b/source/source_io/module_dhs/write_dH_terms.cpp @@ -46,7 +46,7 @@ struct PerIContainers g[d].reserve(nat); for (int iat = 0; iat < nat; ++iat) { - owned[d].push_back(std::make_unique>(&pv)); + owned[d].push_back(make_unique>(&pv)); g[d].push_back(owned[d].back().get()); } } diff --git a/source/source_io/module_hs/write_H_terms.h b/source/source_io/module_hs/write_H_terms.h index c77eeda536e..05a88c70a63 100644 --- a/source/source_io/module_hs/write_H_terms.h +++ b/source/source_io/module_hs/write_H_terms.h @@ -1,5 +1,5 @@ -#ifndef WRITE_HS_R_TERMS_H -#define WRITE_HS_R_TERMS_H +#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" diff --git a/source/source_lcao/module_hcontainer/hcontainer.cpp b/source/source_lcao/module_hcontainer/hcontainer.cpp index ff1f33a7dd3..e1d408e599e 100644 --- a/source/source_lcao/module_hcontainer/hcontainer.cpp +++ b/source/source_lcao/module_hcontainer/hcontainer.cpp @@ -488,7 +488,6 @@ void HContainer::add_value_union(const HContainer& other, T factor) for (int iap = 0; iap < other.size_atom_pairs(); ++iap) { AtomPair tmp = other.get_atom_pair(iap); - tmp.allocate(nullptr, true); result.insert_pair(tmp); } // 3) Rebuild result's contiguous buffer to cover the full union sparsity (zeroed). From 6086351e3598e48923617cbeb41f3010f0b72b5b Mon Sep 17 00:00:00 2001 From: maki49 <1579492865@qq.com> Date: Tue, 16 Jun 2026 20:26:18 +0800 Subject: [PATCH 13/13] change scf_in_dmr ref due to not renormalizing charge at init_chg==dm --- tests/03_NAO_multik/scf_in_dmr_GaAs/result.ref | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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