Skip to content

Commit eed4d64

Browse files
authored
Merge pull request #806 from hongriTianqi/develop
test: unittest of diago_cg
2 parents e6b9cf9 + f8dee70 commit eed4d64

File tree

4 files changed

+369
-135
lines changed

4 files changed

+369
-135
lines changed

source/src_pw/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ add_library(
7878
OBJECT
7979
${objects}
8080
)
81+
8182
IF (BUILD_TESTING)
8283
add_subdirectory(test)
83-
endif()
84+
endif()

source/src_pw/test/CMakeLists.txt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
remove_definitions(-D__MPI)
22
AddTest(
33
TARGET hsolver_david
4-
LIBS ${math_libs} base
5-
SOURCES diago_david_test.cpp ../diago_david.cpp ../../src_parallel/parallel_reduce.cpp
4+
LIBS ${math_libs} base
5+
SOURCES diago_david_test.cpp ../diago_david.cpp ../../src_parallel/parallel_reduce.cpp
66
)
77

8-
install(FILES data-H DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
8+
AddTest(
9+
TARGET hsolver_cg
10+
LIBS ${math_libs} base
11+
SOURCES diago_cg_test.cpp ../diago_cg.cpp ../../src_parallel/parallel_reduce.cpp
12+
)
13+
14+
install(FILES data-H DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
#include "../../module_base/inverse_matrix.h"
2+
#include "../../module_base/lapack_connector.h"
3+
#include "../diago_cg.h"
4+
#include "diago_mock.h"
5+
#include "mpi.h"
6+
7+
#include "gtest/gtest.h"
8+
#include <random>
9+
10+
/************************************************
11+
* unit test of functions in Diago_CG
12+
***********************************************/
13+
14+
/**
15+
* Class Diago_CG is an approach for eigenvalue problems
16+
* This unittest test the function Diago_CG::diag()
17+
* with different examples.
18+
* - the Hermite matrices (npw=500,1000) produced using random numbers and with sparsity of 0%, 60%, 80%
19+
* - the Hamiltonian matrix read from "data-H", produced by using out_hs in INPUT of a LCAO calculation
20+
* - a 2x2 Hermite matrix for learning and checking
21+
*
22+
* Note:
23+
* The test is passed when the eignvalues are closed to these calculated by LAPACK.
24+
* It is used together with a header file diago_mock.h.
25+
* The default Hermite matrix generated here is real symmetric, one can add an imaginary part
26+
* by changing two commented out lines in diago_mock.h.
27+
*
28+
*/
29+
30+
// call lapack in order to compare to cg
31+
void lapackEigen(int &npw, ModuleBase::ComplexMatrix &hm, double *e, bool outtime = false)
32+
{
33+
clock_t start, end;
34+
start = clock();
35+
int lwork = 2 * npw;
36+
std::complex<double> *work2 = new std::complex<double>[lwork];
37+
double *rwork = new double[3 * npw - 2];
38+
int info = 0;
39+
LapackConnector::zheev('V', 'U', npw, hm, npw, e, work2, lwork, rwork, &info);
40+
end = clock();
41+
if (outtime)
42+
std::cout << "Lapack Run time: " << (double)(end - start) / CLOCKS_PER_SEC << " S" << std::endl;
43+
delete[] rwork;
44+
delete[] work2;
45+
}
46+
47+
class DiagoCGPrepare
48+
{
49+
public:
50+
DiagoCGPrepare(int nband, int npw, bool sub, int sparsity, bool reorder, double eps, int maxiter, double threshold)
51+
: nband(nband), npw(npw), sub(sub), sparsity(sparsity), reorder(reorder), eps(eps), maxiter(maxiter),
52+
threshold(threshold)
53+
{
54+
}
55+
56+
int nband, npw, sparsity, maxiter, notconv;
57+
// eps is the convergence threshold within cg_diago
58+
double eps, avg_iter;
59+
bool sub; // do subspace diagonalization if true
60+
bool reorder;
61+
double threshold;
62+
// threshold is the comparison standard between cg and lapack
63+
64+
void CompareEigen(double *precondition)
65+
{
66+
// calculate eigenvalues by LAPACK;
67+
double *e_lapack = new double[npw];
68+
ModuleBase::ComplexMatrix ev = DIAGOTEST::hmatrix;
69+
lapackEigen(npw, ev, e_lapack, false);
70+
// initial guess of psi by perturbing lapack psi
71+
ModuleBase::ComplexMatrix psiguess(nband, npw);
72+
std::default_random_engine p(1);
73+
std::uniform_int_distribution<unsigned> u(1, 10);
74+
for (int i = 0; i < nband; i++)
75+
{
76+
for (int j = 0; j < npw; j++)
77+
{
78+
double rand = static_cast<double>(u(p))/10.;
79+
// psiguess(i,j) = ev(j,i)*(1+rand);
80+
psiguess(i, j) = ev(j, i) * rand;
81+
}
82+
}
83+
// run cg
84+
clock_t start, end;
85+
start = clock();
86+
avg_iter = 0.0;
87+
notconv = 0;
88+
double *en = new double[npw];
89+
int ik = 1;
90+
int ntry = 0;
91+
Hamilt_PW hpw;
92+
Diago_CG cg(&hpw);
93+
do
94+
{
95+
if (sub && ntry > 0)
96+
{
97+
hpw.diagH_subspace(ik, nband, nband, psiguess, psiguess, en);
98+
}
99+
cg.diag(psiguess, en, npw, npw, nband, precondition, eps, maxiter, reorder, notconv, avg_iter);
100+
++ntry;
101+
} while ((ntry <= 5) && (notconv > 0));
102+
end = clock();
103+
// std::cout<<"diag Run time: "<<(double)(end - start) / CLOCKS_PER_SEC<<" S, notconv="
104+
// << notconv <<", avg_iter=" << avg_iter << std::endl;
105+
// std::cout << " ntry " << ntry << std::endl;
106+
for (int i = 0; i < nband; i++)
107+
{
108+
// std::cout << " en " << en[i] << " e_lapack " << e_lapack[i] << std::endl;
109+
EXPECT_NEAR(en[i], e_lapack[i], threshold);
110+
}
111+
112+
delete[] en;
113+
delete[] e_lapack;
114+
}
115+
};
116+
117+
class DiagoCGTest : public ::testing::TestWithParam<DiagoCGPrepare>
118+
{
119+
};
120+
121+
TEST_P(DiagoCGTest, RandomHamilt)
122+
{
123+
DiagoCGPrepare dcp = GetParam();
124+
// std::cout << "npw=" << dcp.npw << ", nband=" << dcp.nband << ", sparsity="
125+
// << dcp.sparsity << ", eps=" << dcp.eps << std::endl;
126+
127+
HPsi hpsi(dcp.nband, dcp.npw, dcp.sparsity);
128+
DIAGOTEST::hmatrix = hpsi.hamilt();
129+
DIAGOTEST::npw = dcp.npw;
130+
// ModuleBase::ComplexMatrix psi = hpsi.psi();
131+
dcp.CompareEigen(hpsi.precond());
132+
}
133+
134+
INSTANTIATE_TEST_SUITE_P(VerifyCG,
135+
DiagoCGTest,
136+
::testing::Values(
137+
// nband, npw, sub, sparsity, reorder, eps, maxiter, threshold
138+
DiagoCGPrepare(10, 500, true, 0, true, 1e-5, 50, 1e-3),
139+
DiagoCGPrepare(20, 500, true, 6, true, 1e-5, 50, 1e-3),
140+
DiagoCGPrepare(20, 1000, true, 8, true, 1e-5, 50, 1e-3),
141+
DiagoCGPrepare(40, 1000, true, 8, true, 1e-5, 50, 1e-3)));
142+
143+
// check that the mock class HPsi work well
144+
// in generating a Hermite matrix
145+
TEST(DiagoCGTest, Hamilt)
146+
{
147+
int dim = 2;
148+
int nbnd = 2;
149+
HPsi hpsi(nbnd, dim);
150+
ModuleBase::ComplexMatrix hm = hpsi.hamilt();
151+
EXPECT_EQ(hm.nr, 2);
152+
EXPECT_EQ(hm.nc, 2);
153+
EXPECT_EQ(hm(0, 0).imag(), 0.0);
154+
EXPECT_EQ(hm(1, 1).imag(), 0.0);
155+
EXPECT_EQ(conj(hm(1, 0)).real(), hm(0, 1).real());
156+
EXPECT_EQ(conj(hm(1, 0)).imag(), hm(0, 1).imag());
157+
}
158+
159+
// check that lapack work well
160+
// for an eigenvalue problem
161+
TEST(DiagoCGTest, ZHEEV)
162+
{
163+
int dim = 100;
164+
int nbnd = 2;
165+
HPsi hpsi(nbnd, dim);
166+
ModuleBase::ComplexMatrix hm = hpsi.hamilt();
167+
ModuleBase::ComplexMatrix hm_backup = hm;
168+
ModuleBase::ComplexMatrix eig(dim, dim);
169+
double e[dim];
170+
// using zheev to do a direct test
171+
lapackEigen(dim, hm, e);
172+
eig = transpose(hm, true) * hm_backup * hm;
173+
// for (int i=0;i<dim;i++) std::cout<< " e[i] "<<e[i]<<std::endl;
174+
for (int i = 0; i < dim; i++)
175+
{
176+
EXPECT_NEAR(e[i], eig(i, i).real(), 1e-10);
177+
}
178+
}
179+
180+
// cg for a 2x2 matrix
181+
TEST(DiagoCGTest, TwoByTwo)
182+
{
183+
int dim = 2;
184+
int nband = 2;
185+
ModuleBase::ComplexMatrix hm(2, 2);
186+
hm(0, 0) = std::complex<double>{4.0, 0.0};
187+
hm(0, 1) = std::complex<double>{1.0, 0.0};
188+
hm(1, 0) = std::complex<double>{1.0, 0.0};
189+
hm(1, 1) = std::complex<double>{3.0, 0.0};
190+
// nband, npw, sub, sparsity, reorder, eps, maxiter, threshold
191+
DiagoCGPrepare dcp(nband, dim, false, 0, true, 1e-4, 50, 1e-10);
192+
HPsi hpsi;
193+
hpsi.create(nband, dim);
194+
DIAGOTEST::hmatrix = hm;
195+
DIAGOTEST::npw = dim;
196+
dcp.CompareEigen(hpsi.precond());
197+
}
198+
199+
TEST(DiagoCGTest, readH)
200+
{
201+
// read Hamilt matrix from file data-H
202+
ModuleBase::ComplexMatrix hm;
203+
std::ifstream ifs;
204+
ifs.open("data-H");
205+
DIAGOTEST::readh(ifs, hm);
206+
ifs.close();
207+
int dim = hm.nr;
208+
int nband = 10; // not nband < dim, here dim = 26 in data-H
209+
// nband, npw, sub, sparsity, reorder, eps, maxiter, threshold
210+
DiagoCGPrepare dcp(nband, dim, true, 0, true, 1e-4, 50, 1e-3);
211+
HPsi hpsi;
212+
hpsi.create(nband, dim);
213+
DIAGOTEST::hmatrix = hpsi.hamilt();
214+
DIAGOTEST::npw = dim;
215+
dcp.CompareEigen(hpsi.precond());
216+
}
217+
218+
int main(int argc, char **argv)
219+
{
220+
221+
MPI_Init(&argc, &argv);
222+
223+
testing::InitGoogleTest(&argc, argv);
224+
int result = RUN_ALL_TESTS();
225+
226+
MPI_Finalize();
227+
228+
return result;
229+
}

0 commit comments

Comments
 (0)