Skip to content

Commit c27c60d

Browse files
author
abacus_fixer
committed
test(dftu_pw): rewire 7 dftu_pw_test cases to call real free functions
Step 4d of the dftu_pw decoupling plan. The 7 tests in dftu_pw_test.cpp previously used arithmetic re-implementations of the VU/energy/occ formulas, meaning they could not catch bugs in the real dftu_pw implementations (test and production code were two independent copies). Now that the free functions live in dftu_tools_pw.{h,cpp} with minimal dependencies (only <complex> and matrix.h), the tests can link against the real implementations directly. Tests rewired: - VUPotNspin1_DiagonalLocale -> compute_vu_scalar - VUPotNspin2_TwoSpinChannels -> compute_vu_scalar (twice, up/down) - VUPotNspin4_PauliTransform -> pauli_to_spin_basis (in-place) - EnergyNspin12_DiagonalLocale -> compute_vu_scalar (check return value) - EnergyNspin4_WithOffDiagonal -> compute_vu_spinor (check return value) - LocaleAccumNspin12 -> accumulate_occ_scalar - LocaleAccumNspin4_PauliComponents -> accumulate_occ_spinor Tests kept as arithmetic (out of dftu_tools_pw scope): - EnergyWeightsAllNspin, BecpIndexNspin12vs4 (pure constants/arithmetic) - MultiAtomSplitLayout_Nspin2 (Plus_U_Base member layout) - OnsitePsOpKernel_Nspin2_Npol1 (onsite_op.cpp kernel) Files changed: - source/source_lcao/module_dftu/test/dftu_pw_test.cpp - add includes: <vector>, source_base/matrix.h, source_pw/module_pwdft/dftu_tools_pw.h - replace inlined arithmetic loops with calls to the real free functions; expected values unchanged - VUPotNspin4_PauliTransform: m_size 3 -> 1 (the test only fills a single (m1,m2) pair; m_size=1 matches the data layout) - EnergyNspin4_WithOffDiagonal: pass diag_coeff=1.0 (the nspin==4 value used in cal_occ_pw) - source/source_lcao/module_dftu/test/CMakeLists.txt - add ../../../source_pw/module_pwdft/dftu_tools_pw.cpp to dftu_pw_test SOURCES so the real implementations are linked Effects: - tests now exercise the same code path as cal_occ_pw - arithmetic re-implementations removed (~80 lines of duplicated logic) - any future change to the free functions is automatically covered Verification: - make dftu_pw_test build passed (verified by user) - ctest -R dftu_pw_test passed (verified by user)
1 parent 45189f6 commit c27c60d

2 files changed

Lines changed: 57 additions & 81 deletions

File tree

source/source_lcao/module_dftu/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ AddTest(
44
TARGET dftu_pw_test
55
LIBS base device parameter
66
SOURCES dftu_pw_test.cpp
7+
../../../source_pw/module_pwdft/dftu_tools_pw.cpp
78
)
89

910
AddTest(

source/source_lcao/module_dftu/test/dftu_pw_test.cpp

Lines changed: 56 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
#include "gtest/gtest.h"
22
#include <complex>
3+
#include <vector>
34
#define private public
45
#include "source_io/module_parameter/parameter.h"
56
#undef private
7+
#include "source_base/matrix.h"
8+
#include "source_pw/module_pwdft/dftu_tools_pw.h"
69

710
/***********************************************************************
811
* Unit tests for DFT+U PW nspin=1/2/4 support (PR-2)
@@ -80,9 +83,7 @@ TEST_F(DftuPwTest, VUPotNspin1_DiagonalLocale)
8083
locale_c[m * m_size + m] = 0.3; // diagonal
8184

8285
std::vector<std::complex<double>> vu(size, {0.0, 0.0});
83-
for (int m1 = 0; m1 < m_size; m1++)
84-
for (int m2 = 0; m2 < m_size; m2++)
85-
vu[m1 * m_size + m2] = U_val * (0.5 * (m1 == m2) - locale_c[m2 * m_size + m1]);
86+
dftu_pw::compute_vu_scalar(vu.data(), locale_c.data(), U_val, 0.5, 1.0, m_size);
8687

8788
// diagonal: U*(0.5 - 0.3) = 4.0*0.2 = 0.8
8889
for (int m = 0; m < m_size; m++)
@@ -104,13 +105,15 @@ TEST_F(DftuPwTest, VUPotNspin2_TwoSpinChannels)
104105
locale_up[0] = 0.4; // locale_up(0,0) = 0.4
105106
locale_dn[0] = 0.1; // locale_dn(0,0) = 0.1
106107

107-
// VU_up[0,0] = U*(0.5 - 0.4) = 0.5
108-
double vu_up_00 = U_val * (0.5 - locale_up[0 * m_size + 0]);
109-
EXPECT_DOUBLE_EQ(vu_up_00, 0.5);
108+
std::vector<std::complex<double>> vu_up(size, {0.0, 0.0});
109+
std::vector<std::complex<double>> vu_dn(size, {0.0, 0.0});
110+
dftu_pw::compute_vu_scalar(vu_up.data(), locale_up.data(), U_val, 0.5, 0.5, m_size);
111+
dftu_pw::compute_vu_scalar(vu_dn.data(), locale_dn.data(), U_val, 0.5, 0.5, m_size);
110112

113+
// VU_up[0,0] = U*(0.5 - 0.4) = 0.5
114+
EXPECT_DOUBLE_EQ(vu_up[0].real(), 0.5);
111115
// VU_dn[0,0] = U*(0.5 - 0.1) = 2.0
112-
double vu_dn_00 = U_val * (0.5 - locale_dn[0 * m_size + 0]);
113-
EXPECT_DOUBLE_EQ(vu_dn_00, 2.0);
116+
EXPECT_DOUBLE_EQ(vu_dn[0].real(), 2.0);
114117
}
115118

116119
TEST_F(DftuPwTest, VUPotNspin4_PauliTransform)
@@ -120,30 +123,26 @@ TEST_F(DftuPwTest, VUPotNspin4_PauliTransform)
120123
// vu_spin[3] = 0.5*(vu_pauli[0] - vu_pauli[3])
121124
// vu_spin[1] = 0.5*(vu_pauli[1] + i*vu_pauli[2])
122125
// vu_spin[2] = 0.5*(vu_pauli[1] - i*vu_pauli[2])
123-
const int m_size = 3;
126+
const int m_size = 1;
124127
const int size = m_size * m_size;
125128

126-
// For a single (m1,m2) pair, test the Pauli->spin transform
127-
std::complex<double> vu_pauli[4];
128-
vu_pauli[0] = {1.0, 0.0}; // charge channel
129-
vu_pauli[1] = {0.5, 0.0}; // sigma_x
130-
vu_pauli[2] = {0.3, 0.0}; // sigma_y
131-
vu_pauli[3] = {0.2, 0.0}; // sigma_z
132-
133-
std::complex<double> vu_spin[4];
134-
vu_spin[0] = 0.5 * (vu_pauli[0] + vu_pauli[3]);
135-
vu_spin[3] = 0.5 * (vu_pauli[0] - vu_pauli[3]);
136-
vu_spin[1] = 0.5 * (vu_pauli[1] + std::complex<double>(0.0, 1.0) * vu_pauli[2]);
137-
vu_spin[2] = 0.5 * (vu_pauli[1] - std::complex<double>(0.0, 1.0) * vu_pauli[2]);
138-
139-
EXPECT_DOUBLE_EQ(vu_spin[0].real(), 0.6); // 0.5*(1.0+0.2)
140-
EXPECT_DOUBLE_EQ(vu_spin[0].imag(), 0.0);
141-
EXPECT_DOUBLE_EQ(vu_spin[3].real(), 0.4); // 0.5*(1.0-0.2)
142-
EXPECT_DOUBLE_EQ(vu_spin[3].imag(), 0.0);
143-
EXPECT_DOUBLE_EQ(vu_spin[1].real(), 0.25); // 0.5*0.5
144-
EXPECT_DOUBLE_EQ(vu_spin[1].imag(), 0.15); // 0.5*0.3
145-
EXPECT_DOUBLE_EQ(vu_spin[2].real(), 0.25); // 0.5*0.5
146-
EXPECT_DOUBLE_EQ(vu_spin[2].imag(), -0.15);// -0.5*0.3
129+
// For a single (m1,m2) pair, test the Pauli->spin transform (in-place)
130+
std::complex<double> vu[4];
131+
vu[0] = {1.0, 0.0}; // charge channel
132+
vu[1] = {0.5, 0.0}; // sigma_x
133+
vu[2] = {0.3, 0.0}; // sigma_y
134+
vu[3] = {0.2, 0.0}; // sigma_z
135+
136+
dftu_pw::pauli_to_spin_basis(vu, m_size);
137+
138+
EXPECT_DOUBLE_EQ(vu[0].real(), 0.6); // 0.5*(1.0+0.2)
139+
EXPECT_DOUBLE_EQ(vu[0].imag(), 0.0);
140+
EXPECT_DOUBLE_EQ(vu[3].real(), 0.4); // 0.5*(1.0-0.2)
141+
EXPECT_DOUBLE_EQ(vu[3].imag(), 0.0);
142+
EXPECT_DOUBLE_EQ(vu[1].real(), 0.25); // 0.5*0.5
143+
EXPECT_DOUBLE_EQ(vu[1].imag(), 0.15); // 0.5*0.3
144+
EXPECT_DOUBLE_EQ(vu[2].real(), 0.25); // 0.5*0.5
145+
EXPECT_DOUBLE_EQ(vu[2].imag(), -0.15);// -0.5*0.3
147146
}
148147

149148
// =====================================================================
@@ -164,19 +163,21 @@ TEST_F(DftuPwTest, EnergyNspin12_DiagonalLocale)
164163
locale_c[2 * m_size + 2] = 0.2;
165164

166165
// nspin=1: E = U * 1.0 * (0.5^2 + 0.3^2 + 0.2^2) = 4 * 0.38 = 1.52
167-
double energy_u = 0.0;
168-
for (int m1 = 0; m1 < m_size; m1++)
169-
for (int m2 = 0; m2 < m_size; m2++)
170-
energy_u += U_val * 1.0 * locale_c[m2 * m_size + m1] * locale_c[m1 * m_size + m2];
166+
std::vector<std::complex<double>> vu_nspin1(size, {0.0, 0.0});
167+
double energy_u = dftu_pw::compute_vu_scalar(
168+
vu_nspin1.data(), locale_c.data(), U_val, 0.5, 1.0, m_size);
171169
EXPECT_DOUBLE_EQ(energy_u, 1.52);
172170

173171
// nspin=2: two spin channels, weight_eu = 0.5
174-
energy_u = 0.0;
175172
std::vector<double> locale_up(size, 0.0), locale_dn(size, 0.0);
176173
locale_up[0] = 0.4; locale_dn[0] = 0.6;
177-
// Only diagonal element (0,0) is non-zero, so only m1=0, m2=0 contributes
178-
energy_u += U_val * 0.5 * locale_up[0] * locale_up[0];
179-
energy_u += U_val * 0.5 * locale_dn[0] * locale_dn[0];
174+
std::vector<std::complex<double>> vu_up(size, {0.0, 0.0});
175+
std::vector<std::complex<double>> vu_dn(size, {0.0, 0.0});
176+
energy_u = 0.0;
177+
energy_u += dftu_pw::compute_vu_scalar(
178+
vu_up.data(), locale_up.data(), U_val, 0.5, 0.5, m_size);
179+
energy_u += dftu_pw::compute_vu_scalar(
180+
vu_dn.data(), locale_dn.data(), U_val, 0.5, 0.5, m_size);
180181
// E = U*0.5*(0.4^2 + 0.6^2) = 4*0.5*(0.16+0.36) = 1.04
181182
EXPECT_DOUBLE_EQ(energy_u, 1.04);
182183
}
@@ -198,15 +199,9 @@ TEST_F(DftuPwTest, EnergyNspin4_WithOffDiagonal)
198199
locale_c[size + 0] = 0.2; locale_c[size + 1] = 0.0;
199200
locale_c[size + 2] = 0.0; locale_c[size + 3] = 0.2;
200201

201-
double energy_u = 0.0;
202-
for (int is = 0; is < 4; is++) {
203-
int start = is * size;
204-
for (int m1 = 0; m1 < m_size; m1++)
205-
for (int m2 = 0; m2 < m_size; m2++)
206-
energy_u += U_val * weight_eu
207-
* locale_c[start + m2 * m_size + m1]
208-
* locale_c[start + m1 * m_size + m2];
209-
}
202+
std::vector<std::complex<double>> vu(size * 4, {0.0, 0.0});
203+
double energy_u = dftu_pw::compute_vu_spinor(
204+
vu.data(), locale_c.data(), U_val, 1.0, weight_eu, m_size);
210205

211206
// is=0: 2*0.25*(0.5*0.5 + 0.1*0.1 + 0.1*0.1 + 0.5*0.5) = 0.26
212207
// is=1: 2*0.25*(0.2*0.2 + 0 + 0 + 0.2*0.2) = 0.04
@@ -221,25 +216,20 @@ TEST_F(DftuPwTest, EnergyNspin4_WithOffDiagonal)
221216
TEST_F(DftuPwTest, LocaleAccumNspin12)
222217
{
223218
// nspin=1/2: locale[m1*m_size+m2] += weight * real(conj(becp[m1]) * becp[m2])
224-
const int m_size = 3, nkb = 5, begin_ih = 0, m_begin = 0, nbands = 2;
225-
const double weights[2] = {1.0, 0.5};
219+
const int m_size = 3, nkb = 5, begin_ih = 0, m_begin = 0, nbands = 2, ik = 0;
226220

227221
std::vector<std::complex<double>> becp(nbands * nkb, {0.0, 0.0});
228222
becp[0 * nkb + 0] = {1.0, 0.0}; becp[0 * nkb + 1] = {0.0, 1.0}; becp[0 * nkb + 2] = {0.5, 0.5};
229223
becp[1 * nkb + 0] = {0.5, 0.0}; becp[1 * nkb + 1] = {0.5, -0.5}; becp[1 * nkb + 2] = {0.0, 1.0};
230224

225+
ModuleBase::matrix wg(1, nbands);
226+
wg(0, 0) = 1.0;
227+
wg(0, 1) = 0.5;
228+
231229
std::vector<double> locale_c(m_size * m_size, 0.0);
232-
for (int ib = 0; ib < nbands; ib++) {
233-
int ind_m1m2 = 0;
234-
for (int m1 = 0; m1 < m_size; m1++) {
235-
const int index_m1 = ib * nkb + begin_ih + m_begin + m1;
236-
for (int m2 = 0; m2 < m_size; m2++) {
237-
const int index_m2 = ib * nkb + begin_ih + m_begin + m2;
238-
locale_c[ind_m1m2] += weights[ib] * (std::conj(becp[index_m1]) * becp[index_m2]).real();
239-
ind_m1m2++;
240-
}
241-
}
242-
}
230+
dftu_pw::accumulate_occ_scalar(
231+
locale_c.data(), becp.data(), nbands, nkb,
232+
begin_ih, m_begin, m_size, wg, ik);
243233

244234
// band0, w=1.0: locale[0,0] = 1.0*|1|^2 = 1.0
245235
// band1, w=0.5: locale[0,0] = 0.5*|0.5|^2 = 0.125
@@ -260,8 +250,7 @@ TEST_F(DftuPwTest, LocaleAccumNspin4_PauliComponents)
260250
// locale[ind+size] += (occ[1]+occ[2]).real() -- sigma_x
261251
// locale[ind+2*size] += (occ[1]-occ[2]).imag() -- sigma_y
262252
// locale[ind+3*size] += (occ[0]-occ[3]).real() -- sigma_z
263-
const int m_size = 1, nkb = 2, nbands = 1;
264-
const double weight = 1.0;
253+
const int m_size = 1, nkb = 2, nbands = 1, npol = 2, ik = 0;
265254

266255
std::vector<std::complex<double>> becp(nbands * 2 * nkb, {0.0, 0.0});
267256
becp[0] = {0.8, 0.0}; // becp_up[m=0]
@@ -270,25 +259,11 @@ TEST_F(DftuPwTest, LocaleAccumNspin4_PauliComponents)
270259
const int size = m_size * m_size;
271260
std::vector<double> locale_c(size * 4, 0.0);
272261

273-
for (int ib = 0; ib < nbands; ib++) {
274-
int ind_m1m2 = 0;
275-
for (int m1 = 0; m1 < m_size; m1++) {
276-
const int index_m1 = ib * 2 * nkb + 0 + m1;
277-
for (int m2 = 0; m2 < m_size; m2++) {
278-
const int index_m2 = ib * 2 * nkb + 0 + m2;
279-
std::complex<double> occ[4];
280-
occ[0] = weight * std::conj(becp[index_m1]) * becp[index_m2];
281-
occ[1] = weight * std::conj(becp[index_m1]) * becp[index_m2 + nkb];
282-
occ[2] = weight * std::conj(becp[index_m1 + nkb]) * becp[index_m2];
283-
occ[3] = weight * std::conj(becp[index_m1 + nkb]) * becp[index_m2 + nkb];
284-
locale_c[ind_m1m2] += (occ[0] + occ[3]).real();
285-
locale_c[ind_m1m2 + size] += (occ[1] + occ[2]).real();
286-
locale_c[ind_m1m2 + 2 * size] += (occ[1] - occ[2]).imag();
287-
locale_c[ind_m1m2 + 3 * size] += (occ[0] - occ[3]).real();
288-
ind_m1m2++;
289-
}
290-
}
291-
}
262+
ModuleBase::matrix wg(1, nbands);
263+
wg(0, 0) = 1.0;
264+
dftu_pw::accumulate_occ_spinor(
265+
locale_c.data(), becp.data(), nbands, npol, nkb,
266+
0, 0, m_size, wg, ik);
292267

293268
// becp_up = (0.8, 0), becp_dn = (0, 0.6)
294269
// occ[0] = 0.64, occ[1] = (0, 0.48), occ[2] = (0, -0.48), occ[3] = 0.36

0 commit comments

Comments
 (0)