Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions source/source_hamilt/module_xc/libxc_abacus.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ namespace XC_Functional_Libxc
const std::vector<int> &func_id,
const double &rho,
const double &grho,
const double &lapl_rho,
const double &atau,
double &sxc,
double &v1xc,
Expand All @@ -211,6 +212,8 @@ namespace XC_Functional_Libxc
double rhodw,
ModuleBase::Vector3<double> gdr1,
ModuleBase::Vector3<double> gdr2,
double laplup,
double lapldw,
double tauup,
double taudw,
double &sxc,
Expand Down
6 changes: 4 additions & 2 deletions source/source_hamilt/module_xc/libxc_mgga_wrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ void XC_Functional_Libxc::tau_xc(
const std::vector<int>& func_id,
const double& rho,
const double& grho,
const double& lapl_rho,
const double& atau,
double& sxc,
double& v1xc,
Expand All @@ -28,7 +29,6 @@ void XC_Functional_Libxc::tau_xc(
double v1 = 0.0;
double v2 = 0.0;
double v3 = 0.0;
double lapl_rho = grho;
double vlapl_rho = 0.0;
std::vector<xc_func_type> funcs = XC_Functional_Libxc::init_func(
/* func_id = */ func_id,
Expand Down Expand Up @@ -68,6 +68,8 @@ void XC_Functional_Libxc::tau_xc_spin(
double rhodw,
ModuleBase::Vector3<double> gdr1,
ModuleBase::Vector3<double> gdr2,
double laplup,
double lapldw,
double tauup,
double taudw,
double& sxc,
Expand Down Expand Up @@ -119,7 +121,7 @@ void XC_Functional_Libxc::tau_xc_spin(
double s = 0.0;
std::array<double, 2> v1xc = {0.0, 0.0};
std::array<double, 2> v3xc = {0.0, 0.0};
std::array<double, 2> lapl = {0.0, 0.0};
std::array<double, 2> lapl = {laplup, lapldw};
std::array<double, 2> vlapl = {0.0, 0.0};
std::array<double, 3> v2xc = {0.0, 0.0, 0.0};
// call Libxc function: xc_mgga_exc_vxc
Expand Down
24 changes: 23 additions & 1 deletion source/source_hamilt/module_xc/libxc_pot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <xc.h>

#include <vector>
#include <complex>

std::tuple<double,double,ModuleBase::matrix> XC_Functional_Libxc::v_xc_libxc( // Peize Lin update for nspin==4 at 2023.01.14
const std::vector<int> &func_id,
Expand Down Expand Up @@ -237,6 +238,27 @@ std::tuple<double,double,ModuleBase::matrix,ModuleBase::matrix> XC_Functional_Li
= XC_Functional_Libxc::cal_gdr(nspin, nrxx, rho, tpiba, chr);
const std::vector<double> sigma = XC_Functional_Libxc::convert_sigma(gdr);

// compute laplacian for mGGA functionals
std::vector<double> lapl(nrxx * nspin, 0.0);
{
std::vector<std::complex<double>> rhog_tmp(chr->rhopw->npw);
std::vector<double> rhor(nrxx);
for( int is=0; is<nspin; ++is )
{
for( int ir=0; ir<nrxx; ++ir )
{
rhor[ir] = rho[ir*nspin+is];
}
chr->rhopw->real2recip(rhor.data(), rhog_tmp.data());
std::vector<double> lapl_spin(nrxx);
XC_Functional::laplacian_rho(rhog_tmp.data(), lapl_spin.data(), chr->rhopw, tpiba);
for( int ir=0; ir<nrxx; ++ir )
{
lapl[ir*nspin+is] = lapl_spin[ir];
}
}
}

//converting kin_r
std::vector<double> kin_r;
kin_r.resize(nrxx*nspin);
Expand Down Expand Up @@ -315,7 +337,7 @@ std::tuple<double,double,ModuleBase::matrix,ModuleBase::matrix> XC_Functional_Li
nrxx_thread,
rho.data() + ir_start * nspin,
sigma.data() + ir_start * ((1==nspin)?1:3),
sigma.data() + ir_start * ((1==nspin)?1:3),
lapl.data() + ir_start * nspin,
kin_r.data() + ir_start * nspin,
exc.data() + ir_start,
vrho.data() + ir_start * nspin,
Expand Down
13 changes: 13 additions & 0 deletions source/source_hamilt/module_xc/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,17 @@ AddTest(
../../../source_base/module_fft/fft_bundle.cpp
../../../source_base/module_fft/fft_cpu.cpp
${FFT_SRC}
)

AddTest(
TARGET MODULE_HAMILT_XCTest_SCANL_LAPL
LIBS parameter MPI::MPI_CXX Libxc::xc
SOURCES test_xc6.cpp ../xc_functional.cpp ../xc_lda_wrap.cpp
../xc_gga_wrap.cpp
../libxc_setup.cpp
../libxc_lda_wrap.cpp
../libxc_gga_wrap.cpp
../libxc_mgga_wrap.cpp
../xc_gga_corr.cpp ../xc_lda_corr.cpp
../xc_gga_exch.cpp ../xc_lda_exch.cpp ../xc_hcth.cpp
)
3 changes: 2 additions & 1 deletion source/source_hamilt/module_xc/test/test_xc4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ class XCTest_SCAN : public XCTest
{
double e,v,v1,v2,v3;
double hybrid_alpha = 0.0;
XC_Functional_Libxc::tau_xc(XC_Functional::get_func_id(), rho[i],grho[i],tau[i],e,v1,v2,v3,hybrid_alpha);
double lapl_rho = grho[i];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine as-is: test_xc4 uses SCAN, a τ-mGGA that ignores the Laplacian, so passing grho here doesn't affect the reference values. A one-line comment noting that would avoid confusion.

XC_Functional_Libxc::tau_xc(XC_Functional::get_func_id(), rho[i],grho[i],lapl_rho,tau[i],e,v1,v2,v3,hybrid_alpha);
e_.push_back(e);
v1_.push_back(v1);
v2_.push_back(v2);
Expand Down
84 changes: 84 additions & 0 deletions source/source_hamilt/module_xc/test/test_xc6.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#include "../xc_functional.h"
#include "../libxc_abacus.h"
#include "gtest/gtest.h"
#include "xctest.h"
#include "../exx_info.h"
#include <cmath>
#include <iostream>
#include <iomanip>

namespace ModuleBase
{
void WARNING_QUIT(const std::string &file,const std::string &description) {exit(1);}
void TITLE(const std::string &class_function_name,bool disable){};
void TITLE(const std::string &class_name,const std::string &function_name,bool disable){};
}

namespace GlobalV
{
std::string BASIS_TYPE = "";
bool CAL_STRESS = false;
int CAL_FORCE = 0;
int NSPIN = 1;
}

namespace GlobalC
{
Exx_Info exx_info;
}

class XCTest_SCANL_Laplacian : public XCTest
{
protected:
double e_base, v1_base, v2_base, v3_base;
double e_modified, v1_modified, v2_modified, v3_modified;
double e_scaled, v1_scaled, v2_scaled, v3_scaled;

void SetUp()
{
XC_Functional::set_xc_type("MGGA_X_SCANL+MGGA_C_SCANL");

const double rho = 0.17E+01;
const double grho = 0.81E-11;
const double tau = 0.02403590412;
const double lapl_base = 0.15E+01;
double hybrid_alpha = 0.0;

XC_Functional_Libxc::tau_xc(
XC_Functional::get_func_id(),
rho, grho, lapl_base, tau,
e_base, v1_base, v2_base, v3_base, hybrid_alpha
);

XC_Functional_Libxc::tau_xc(
XC_Functional::get_func_id(),
rho, grho, lapl_base + 1.0, tau,
e_modified, v1_modified, v2_modified, v3_modified, hybrid_alpha
);

XC_Functional_Libxc::tau_xc(
XC_Functional::get_func_id(),
rho, grho, 2.0 * lapl_base, tau,
e_scaled, v1_scaled, v2_scaled, v3_scaled, hybrid_alpha
);
}
};

TEST_F(XCTest_SCANL_Laplacian, laplacian_affects_energy)
{
EXPECT_NE(e_base, e_modified);
EXPECT_NE(e_base, e_scaled);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only asserts the Laplacian changes the energy (EXPECT_NE). Please add a quantitative check of laplacian_rho against an analytical case, the test_xc7.cpp (Gaussian density) referenced in the PR description isn't included.


std::cout << std::scientific << std::setprecision(15);
std::cout << "\n=== SCAN Laplacian Sensitivity Test ===" << std::endl;
std::cout << "Base Laplacian: " << 0.15E+01 << std::endl;
std::cout << " E_xc = " << e_base << std::endl;
std::cout << " dE/dlapl ≈ " << (e_modified - e_base) / 1.0 << std::endl;
std::cout << "Modified Laplacian:" << 0.15E+01 + 1.0 << std::endl;
std::cout << " E_xc = " << e_modified << std::endl;
std::cout << " Delta E = " << e_modified - e_base << std::endl;
std::cout << "Scaled Laplacian: " << 2.0 * 0.15E+01 << std::endl;
std::cout << " E_xc = " << e_scaled << std::endl;
std::cout << " Delta E = " << e_scaled - e_base << std::endl;
std::cout << "========================================" << std::endl;
}
6 changes: 6 additions & 0 deletions source/source_hamilt/module_xc/xc_functional.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,12 @@ class XC_Functional
const ModulePW::PW_Basis* rho_basis,
const double tpiba);

static void laplacian_rho(
const std::complex<double>* rhog,
double* lapl,
const ModulePW::PW_Basis* rho_basis,
const double tpiba);

static void noncolin_rho(
double* rhoout1,
double* rhoout2,
Expand Down
78 changes: 74 additions & 4 deletions source/source_hamilt/module_xc/xc_grad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ void XC_Functional::gradcorr(
double* neg = nullptr;
double** vsave = nullptr;
double** vgg = nullptr;
double* lapl1 = nullptr;
double* lapl2 = nullptr;

// for spin unpolarized case,
// calculate the gradient of (rho_core+rho) in reciprocal space.
Expand Down Expand Up @@ -118,6 +120,12 @@ void XC_Functional::gradcorr(

XC_Functional::grad_rho( rhogsum1 , gdr1, rhopw, ucell->tpiba);

if(func_type == 3 || func_type == 5)
{
lapl1 = new double[rhopw->nrxx];
XC_Functional::laplacian_rho(rhogsum1, lapl1, rhopw, ucell->tpiba);
}

// for spin polarized case;
// calculate the gradient of (rho_core+rho) in reciprocal space.
if(PARAM.inp.nspin==2)
Expand Down Expand Up @@ -146,6 +154,12 @@ void XC_Functional::gradcorr(
}

XC_Functional::grad_rho( rhogsum2 , gdr2, rhopw, ucell->tpiba);

if(func_type == 3 || func_type == 5)
{
lapl2 = new double[rhopw->nrxx];
XC_Functional::laplacian_rho(rhogsum2, lapl2, rhopw, ucell->tpiba);
}
}

if(PARAM.inp.nspin == 4&&(PARAM.globalv.domag||PARAM.globalv.domag_z))
Expand Down Expand Up @@ -222,6 +236,20 @@ void XC_Functional::gradcorr(

XC_Functional::grad_rho( rhogsum1 , gdr1, rhopw, ucell->tpiba);
XC_Functional::grad_rho( rhogsum2 , gdr2, rhopw, ucell->tpiba);

if(func_type == 3 || func_type == 5)
{
if(lapl1 == nullptr)
{
lapl1 = new double[rhopw->nrxx];
}
XC_Functional::laplacian_rho(rhogsum1, lapl1, rhopw, ucell->tpiba);
if(lapl2 == nullptr)
{
lapl2 = new double[rhopw->nrxx];
}
XC_Functional::laplacian_rho(rhogsum2, lapl2, rhopw, ucell->tpiba);
}
}

const double epsr = 1.0e-6;
Expand Down Expand Up @@ -297,7 +325,8 @@ void XC_Functional::gradcorr(
#ifdef __EXX
hybrid_alpha = GlobalC::exx_info.info_global.hybrid_alpha;
#endif
XC_Functional_Libxc::tau_xc( func_id, arho, grho2a, atau, sxc, v1xc, v2xc, v3xc, hybrid_alpha);
double lapl_val = (lapl1 != nullptr) ? lapl1[ir] : 0.0;
XC_Functional_Libxc::tau_xc( func_id, arho, grho2a, lapl_val, atau, sxc, v1xc, v2xc, v3xc, hybrid_alpha);
}
else
{
Expand Down Expand Up @@ -366,10 +395,12 @@ void XC_Functional::gradcorr(
#ifdef __EXX
hybrid_alpha = GlobalC::exx_info.info_global.hybrid_alpha;
#endif
double laplup_val = (lapl1 != nullptr) ? lapl1[ir] : 0.0;
double lapldw_val = (lapl2 != nullptr) ? lapl2[ir] : 0.0;
XC_Functional_Libxc::tau_xc_spin(
func_id,
rhotmp1[ir], rhotmp2[ir], gdr1[ir], gdr2[ir],
atau1, atau2, sxc, v1xcup, v1xcdw, v2xcup, v2xcdw, v2xcud, v3xcup, v3xcdw, hybrid_alpha);
laplup_val, lapldw_val, atau1, atau2, sxc, v1xcup, v1xcdw, v2xcup, v2xcdw, v2xcud, v3xcup, v3xcdw, hybrid_alpha);
}
else
{
Expand Down Expand Up @@ -653,14 +684,18 @@ void XC_Functional::gradcorr(
delete[] rhotmp2;
delete[] rhogsum2;
delete[] gdr2;
delete[] lapl2;
if(!is_stress)
{
delete[] h2;
}
delete[] lapl1;
}
if(PARAM.inp.nspin == 4 && (PARAM.globalv.domag||PARAM.globalv.domag_z))
else if(PARAM.inp.nspin == 4 && (PARAM.globalv.domag||PARAM.globalv.domag_z))
{
delete[] neg;
delete[] lapl1;
delete[] lapl2;
if(!is_stress)
{
for(int i=0; i<nspin0; i++)
Expand All @@ -679,6 +714,10 @@ void XC_Functional::gradcorr(
delete[] rhogsum2;
delete[] gdr2;
}
else
{
delete[] lapl1;
}

return;
}
Expand Down Expand Up @@ -816,11 +855,42 @@ void XC_Functional::grad_dot(
dh[ir] = aux[ir].real() * tpiba;
}

delete[] aux;
delete[] aux;
delete[] gaux;
return;
}


void XC_Functional::laplacian_rho(
const std::complex<double>* rhog,
double* lapl,
const ModulePW::PW_Basis* rho_basis,
const double tpiba)
{
std::complex<double>* lapl_tmp = new std::complex<double>[rho_basis->nmaxgr];

for(int ir=0; ir<rho_basis->nrxx; ir++)
{
lapl[ir] = 0.0;
}

for(int i=0; i<3; i++)
{
for(int ig=0; ig<rho_basis->npw; ig++)
{
lapl_tmp[ig] = -rhog[ig] * rho_basis->gcar[ig][i] * rho_basis->gcar[ig][i];
}
rho_basis->recip2real(lapl_tmp, lapl_tmp);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One small cleanup: this does 3 inverse FFTs; you can build −|G|² = −(Gx²+Gy²+Gz²) in one pass and call recip2real once.

for(int ir=0; ir<rho_basis->nrxx; ir++)
{
lapl[ir] += lapl_tmp[ir].real() * tpiba * tpiba;
}
}

delete[] lapl_tmp;
}


void XC_Functional::noncolin_rho(
double *rhoout1,
double *rhoout2,
Expand Down
Loading