Skip to content

Commit 7a87079

Browse files
authored
add unit test for math_lebedev_laikov (#5513)
1 parent 4a69545 commit 7a87079

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed

source/module_base/test/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,11 @@ AddTest(
230230
SOURCES formatter_test.cpp
231231
)
232232

233+
AddTest(
234+
TARGET lebedev_laikov
235+
SOURCES test_lebedev_laikov.cpp ../ylm.cpp ../math_lebedev_laikov.cpp
236+
)
237+
233238
if(ENABLE_GOOGLEBENCH)
234239
AddTest(
235240
TARGET perf_sphbes
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#include "module_base/math_lebedev_laikov.h"
2+
#include "module_base/ylm.h"
3+
4+
#include "gtest/gtest.h"
5+
#include <random>
6+
#ifdef __MPI
7+
#include <mpi.h>
8+
#endif
9+
10+
using ModuleBase::Lebedev_laikov_grid;
11+
12+
// mock the function to prevent unnecessary dependency
13+
namespace ModuleBase {
14+
void WARNING_QUIT(const std::string&, const std::string&) {}
15+
}
16+
17+
class LebedevLaikovTest: public ::testing::Test {
18+
protected:
19+
void randgen(int lmax, std::vector<double>& coef);
20+
const double tol = 1e-12;
21+
};
22+
23+
24+
void LebedevLaikovTest::randgen(int lmax, std::vector<double>& coef) {
25+
coef.resize((lmax + 1) * (lmax + 1));
26+
27+
// fill coef with uniformly distributed random numbers
28+
std::random_device rd;
29+
std::mt19937 gen(rd());
30+
std::uniform_real_distribution<double> dis(0.0, 1.0);
31+
for (size_t i = 0; i < coef.size(); ++i) {
32+
coef[i] = dis(gen);
33+
}
34+
35+
// normalize the coefficients
36+
double fac = 0.0;
37+
for (size_t i = 0; i < coef.size(); ++i) {
38+
fac += coef[i] * coef[i];
39+
}
40+
41+
fac = 1.0 / std::sqrt(fac);
42+
for (size_t i = 0; i < coef.size(); ++i) {
43+
coef[i] *= fac;
44+
}
45+
}
46+
47+
48+
TEST_F(LebedevLaikovTest, Accuracy) {
49+
/*
50+
* Given
51+
*
52+
* f = c[0]*Y00 + c[1]*Y10 + c[2]*Y11 + ...,
53+
*
54+
* where c[0], c[1], c[2], ... are some random numbers, the integration
55+
* of |f|^2 on the unit sphere
56+
*
57+
* \int |f|^2 d\Omega = c[0]^2 + c[1]^2 + c[2]^2 + ... .
58+
*
59+
* This test verifies with the above integral that quadrature with
60+
* Lebedev grid is exact up to floating point errors.
61+
*
62+
*/
63+
64+
// (ngrid, lmax)
65+
std::set<std::pair<int, int>> supported = {
66+
{6, 3},
67+
{14, 5},
68+
{26, 7},
69+
{38, 9},
70+
{50, 11},
71+
{74, 13},
72+
{86, 15},
73+
{110, 17},
74+
{146, 19},
75+
{170, 21},
76+
{194, 23},
77+
{230, 25},
78+
{266, 27},
79+
{302, 29},
80+
{350, 31},
81+
{434, 35},
82+
{590, 41},
83+
{770, 47},
84+
{974, 53},
85+
{1202, 59},
86+
{1454, 65},
87+
{1730, 71},
88+
{2030, 77},
89+
{2354, 83},
90+
{2702, 89},
91+
{3074, 95},
92+
{3470, 101},
93+
{3890, 107},
94+
{4334, 113},
95+
{4802, 119},
96+
{5294, 125},
97+
{5810, 131},
98+
};
99+
100+
std::vector<double> coef;
101+
102+
for (auto& grid_info: supported) {
103+
int ngrid = grid_info.first;
104+
int grid_lmax = grid_info.second;
105+
106+
Lebedev_laikov_grid lebgrid(ngrid);
107+
lebgrid.generate_grid_points();
108+
109+
const double* weight = lebgrid.get_weight();
110+
const ModuleBase::Vector3<double>* grid = lebgrid.get_grid_coor();
111+
112+
int func_lmax = grid_lmax / 2;
113+
randgen(func_lmax, coef);
114+
115+
double val = 0.0;
116+
std::vector<double> ylm_real;
117+
for (int i = 0; i < ngrid; i++) {
118+
ModuleBase::Ylm::sph_harm(func_lmax,
119+
grid[i].x, grid[i].y, grid[i].z, ylm_real);
120+
double tmp = 0.0;
121+
for (size_t j = 0; j < coef.size(); ++j) {
122+
tmp += coef[j] * ylm_real[j];
123+
}
124+
val += weight[i] * tmp * tmp;
125+
}
126+
127+
double val_ref = 0.0;
128+
for (size_t i = 0; i < coef.size(); ++i) {
129+
val_ref += coef[i] * coef[i];
130+
}
131+
132+
double abs_diff = std::abs(val - val_ref);
133+
EXPECT_LT(abs_diff, tol);
134+
}
135+
}
136+
137+
138+
int main(int argc, char** argv)
139+
{
140+
#ifdef __MPI
141+
MPI_Init(&argc, &argv);
142+
#endif
143+
144+
testing::InitGoogleTest(&argc, argv);
145+
int result = RUN_ALL_TESTS();
146+
147+
#ifdef __MPI
148+
MPI_Finalize();
149+
#endif
150+
151+
return result;
152+
}

0 commit comments

Comments
 (0)