Skip to content

Commit b6cc3c2

Browse files
author
abacus_fixer
committed
test(rhog_io): add write_rhog tests and remove GlobalV from test file
- Add 3 new tests: WriteRoundTrip, WriteFileFail, WriteRoundTripNspin2 (write_rhog was previously 0% covered by tests) - Add OsNullptrSilent test for nullptr warning stream safety - Remove GlobalV::ofs_warning usage, use local std::ofstream + fixture helpers - Extract setup_pw_basis() fixture method to avoid duplication
1 parent 863a2b2 commit b6cc3c2

1 file changed

Lines changed: 173 additions & 42 deletions

File tree

source/source_estate/test/test_rhog_io.cpp

Lines changed: 173 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88
#include "source_basis/module_pw/test/test_tool.h"
99
#include "mpi.h"
1010
#endif
11+
#include <fstream>
12+
#include <sstream>
1113

1214
/**
1315
* - Tested Functions:
1416
* - read_rhog()
17+
* - write_rhog()
1518
*/
1619

1720
class ReadRhogTest : public ::testing::Test
@@ -21,27 +24,60 @@ class ReadRhogTest : public ::testing::Test
2124
std::vector<std::vector<std::complex<double>>> rhog_data;
2225
std::vector<std::complex<double>*> rhog;
2326
Parallel::ParaWorld pw_world = Parallel::make_pw_world();
27+
std::ofstream warning_stream;
28+
29+
void setup_pw_basis()
30+
{
31+
#ifdef __MPI
32+
rhopw.initmpi(pw_world.size(), pw_world.rank(), pw_world.comm());
33+
#endif
34+
rhopw.initgrids(6.5, ModuleBase::Matrix3(-0.5, 0.0, 0.5, 0.0, 0.5, 0.5, -0.5, 0.5, 0.0), 120);
35+
rhopw.initparameters(false, 120);
36+
rhopw.setuptransform();
37+
rhopw.collect_local_pw();
38+
}
39+
40+
void open_warning(const std::string& path)
41+
{
42+
warning_stream.open(path);
43+
}
44+
45+
void close_warning()
46+
{
47+
if (warning_stream.is_open())
48+
{
49+
warning_stream.close();
50+
}
51+
}
52+
53+
std::string read_warning_file(const std::string& path)
54+
{
55+
std::ifstream ifs(path);
56+
std::stringstream ss;
57+
ss << ifs.rdbuf();
58+
ifs.close();
59+
return ss.str();
60+
}
2461

2562
virtual void SetUp()
2663
{
2764
rhog_data.resize(1, std::vector<std::complex<double>>(1471));
2865
rhog.push_back(rhog_data[0].data());
2966
}
67+
68+
virtual void TearDown()
69+
{
70+
close_warning();
71+
}
3072
};
3173

32-
// Test the read_rhog function
74+
// Test the read_rhog function with normal file
3375
TEST_F(ReadRhogTest, ReadRhog)
3476
{
3577
std::string filename = "./support/charge-density.dat";
36-
#ifdef __MPI
37-
rhopw.initmpi(pw_world.size(), pw_world.rank(), pw_world.comm());
38-
#endif
39-
rhopw.initgrids(6.5, ModuleBase::Matrix3(-0.5, 0.0, 0.5, 0.0, 0.5, 0.5, -0.5, 0.5, 0.0), 120);
40-
rhopw.initparameters(false, 120);
41-
rhopw.setuptransform();
42-
rhopw.collect_local_pw();
78+
setup_pw_basis();
4379

44-
bool result = ModuleIO::read_rhog(filename, &rhopw, 1, rhog.data(), pw_world, &GlobalV::ofs_warning)
80+
bool result = ModuleIO::read_rhog(filename, &rhopw, 1, rhog.data(), pw_world, nullptr);
4581

4682
EXPECT_TRUE(result);
4783
EXPECT_DOUBLE_EQ(rhog[0][0].real(), -1.0304462993299456e-05);
@@ -57,46 +93,33 @@ TEST_F(ReadRhogTest, NotFoundFile)
5793
{
5894
std::string filename = "notfound.txt";
5995

60-
GlobalV::ofs_warning.open("test_read_rhog.txt");
61-
bool result = ModuleIO::read_rhog(filename, &rhopw, 1, rhog.data(), pw_world, &GlobalV::ofs_warning)
62-
GlobalV::ofs_warning.close();
63-
64-
std::ifstream ifs_running("test_read_rhog.txt");
65-
std::stringstream ss;
66-
ss << ifs_running.rdbuf();
67-
std::string file_content = ss.str();
68-
ifs_running.close();
96+
open_warning("test_read_rhog.txt");
97+
bool result = ModuleIO::read_rhog(filename, &rhopw, 1, rhog.data(), pw_world, &warning_stream);
98+
close_warning();
6999

70100
std::string expected_content = " ModuleIO::read_rhog warning : Can't open file notfound.txt\n";
71-
72101
EXPECT_FALSE(result);
73-
EXPECT_EQ(file_content, expected_content);
102+
EXPECT_EQ(read_warning_file("test_read_rhog.txt"), expected_content);
74103
std::remove("test_read_rhog.txt");
75104
}
76105

77-
// Test the read_rhog function when tgamma_only is inconsistent
106+
// Test the read_rhog function when gamma_only is inconsistent
78107
TEST_F(ReadRhogTest, InconsistentGammaOnly)
79108
{
80109
std::string filename = "./support/charge-density.dat";
81110
rhopw.gamma_only = true;
82111

83-
GlobalV::ofs_warning.open("test_read_rhog.txt");
84-
bool result = ModuleIO::read_rhog(filename, &rhopw, 2, rhog.data(), pw_world, &GlobalV::ofs_warning);
85-
GlobalV::ofs_warning.close();
86-
87-
std::ifstream ifs_running("test_read_rhog.txt");
88-
std::stringstream ss;
89-
ss << ifs_running.rdbuf();
90-
std::string file_content = ss.str();
91-
ifs_running.close();
112+
open_warning("test_read_rhog.txt");
113+
bool result = ModuleIO::read_rhog(filename, &rhopw, 2, rhog.data(), pw_world, &warning_stream);
114+
close_warning();
92115

93116
std::string expected_content
94117
= " ModuleIO::read_rhog warning : some planewaves in file are not used\n ModuleIO::read_rhog warning : some "
95118
"spin channels in file are missing\n ModuleIO::read_rhog warning : gamma_only read from file is "
96119
"inconsistent with INPUT\n";
97120

98121
EXPECT_FALSE(result);
99-
EXPECT_EQ(file_content, expected_content);
122+
EXPECT_EQ(read_warning_file("test_read_rhog.txt"), expected_content);
100123
std::remove("test_read_rhog.txt");
101124
}
102125

@@ -106,23 +129,131 @@ TEST_F(ReadRhogTest, SomePWMissing)
106129
std::string filename = "./support/charge-density.dat";
107130
rhopw.npwtot = 2000;
108131

109-
GlobalV::ofs_warning.open("test_read_rhog.txt");
110-
bool result = ModuleIO::read_rhog(filename, &rhopw, 1, rhog.data(), pw_world, &GlobalV::ofs_warning)
111-
GlobalV::ofs_warning.close();
112-
113-
std::ifstream ifs_running("test_read_rhog.txt");
114-
std::stringstream ss;
115-
ss << ifs_running.rdbuf();
116-
std::string file_content = ss.str();
117-
ifs_running.close();
132+
open_warning("test_read_rhog.txt");
133+
bool result = ModuleIO::read_rhog(filename, &rhopw, 1, rhog.data(), pw_world, &warning_stream);
134+
close_warning();
118135

119136
std::string expected_content = " ModuleIO::read_rhog warning : some planewaves in file are missing\n";
120-
121137
EXPECT_TRUE(result);
122-
EXPECT_EQ(file_content, expected_content);
138+
EXPECT_EQ(read_warning_file("test_read_rhog.txt"), expected_content);
123139
std::remove("test_read_rhog.txt");
124140
}
125141

142+
// Test read_rhog with os_warning=nullptr (silent mode, must not crash)
143+
TEST_F(ReadRhogTest, OsNullptrSilent)
144+
{
145+
std::string filename = "notfound.txt";
146+
bool result = ModuleIO::read_rhog(filename, &rhopw, 1, rhog.data(), pw_world, nullptr);
147+
EXPECT_FALSE(result);
148+
}
149+
150+
// Test write_rhog round-trip: write then read back, verify data consistency
151+
TEST_F(ReadRhogTest, WriteRoundTrip)
152+
{
153+
setup_pw_basis();
154+
155+
// initialize some rhog data
156+
rhog_data[0].assign(rhopw.npw, std::complex<double>(1.5, 2.5));
157+
158+
std::string tmpfile = "test_rhog_roundtrip.dat";
159+
160+
// write
161+
bool write_result = ModuleIO::write_rhog(
162+
tmpfile, rhopw.gamma_only, &rhopw, 1,
163+
ModuleBase::Matrix3(-0.5, 0.0, 0.5, 0.0, 0.5, 0.5, -0.5, 0.5, 0.0),
164+
rhog.data(), pw_world, nullptr);
165+
EXPECT_TRUE(write_result);
166+
167+
// read back into a fresh buffer
168+
std::vector<std::vector<std::complex<double>>> rhog_read_data(
169+
1, std::vector<std::complex<double>>(rhopw.npw));
170+
std::vector<std::complex<double>*> rhog_read;
171+
rhog_read.push_back(rhog_read_data[0].data());
172+
173+
bool read_result = ModuleIO::read_rhog(tmpfile, &rhopw, 1, rhog_read.data(), pw_world, nullptr);
174+
EXPECT_TRUE(read_result);
175+
176+
// compare: within MPI precision tolerance
177+
int diff_count = 0;
178+
for (int ig = 0; ig < rhopw.npw; ++ig)
179+
{
180+
if (std::abs(rhog[0][ig] - rhog_read[0][ig]) > 1e-10)
181+
{
182+
++diff_count;
183+
}
184+
}
185+
EXPECT_EQ(diff_count, 0) << diff_count << " planewave values differ after round-trip";
186+
187+
std::remove(tmpfile.c_str());
188+
}
189+
190+
// Test write_rhog when the output path is not writable
191+
TEST_F(ReadRhogTest, WriteFileFail)
192+
{
193+
setup_pw_basis();
194+
rhog_data[0].assign(rhopw.npw, std::complex<double>(1.0, 0.0));
195+
196+
// try to write to a directory path (not a file) — should fail
197+
bool result = ModuleIO::write_rhog(
198+
"/tmp", rhopw.gamma_only, &rhopw, 1,
199+
ModuleBase::Matrix3(-0.5, 0.0, 0.5, 0.0, 0.5, 0.5, -0.5, 0.5, 0.0),
200+
rhog.data(), pw_world, nullptr);
201+
EXPECT_FALSE(result);
202+
}
203+
204+
// Test write_rhog with nspin=2, round-trip both channels
205+
TEST_F(ReadRhogTest, WriteRoundTripNspin2)
206+
{
207+
setup_pw_basis();
208+
209+
// expand to nspin=2
210+
rhog_data.resize(2, std::vector<std::complex<double>>(rhopw.npw));
211+
rhog.clear();
212+
rhog.push_back(rhog_data[0].data());
213+
rhog.push_back(rhog_data[1].data());
214+
215+
// initialize distinct values for each spin channel
216+
for (int ig = 0; ig < rhopw.npw; ++ig)
217+
{
218+
rhog_data[0][ig] = std::complex<double>(1.0 * ig, 0.1 * ig);
219+
rhog_data[1][ig] = std::complex<double>(2.0 * ig, 0.2 * ig);
220+
}
221+
222+
std::string tmpfile = "test_rhog_roundtrip_nspin2.dat";
223+
224+
// write nspin=2
225+
bool write_result = ModuleIO::write_rhog(
226+
tmpfile, rhopw.gamma_only, &rhopw, 2,
227+
ModuleBase::Matrix3(-0.5, 0.0, 0.5, 0.0, 0.5, 0.5, -0.5, 0.5, 0.0),
228+
rhog.data(), pw_world, nullptr);
229+
EXPECT_TRUE(write_result);
230+
231+
// read back
232+
std::vector<std::vector<std::complex<double>>> rhog_read_data(
233+
2, std::vector<std::complex<double>>(rhopw.npw));
234+
std::vector<std::complex<double>*> rhog_read;
235+
rhog_read.push_back(rhog_read_data[0].data());
236+
rhog_read.push_back(rhog_read_data[1].data());
237+
238+
bool read_result = ModuleIO::read_rhog(tmpfile, &rhopw, 2, rhog_read.data(), pw_world, nullptr);
239+
EXPECT_TRUE(read_result);
240+
241+
int diff_count = 0;
242+
for (int is = 0; is < 2; ++is)
243+
{
244+
for (int ig = 0; ig < rhopw.npw; ++ig)
245+
{
246+
if (std::abs(rhog[is][ig] - rhog_read[is][ig]) > 1e-10)
247+
{
248+
++diff_count;
249+
}
250+
}
251+
}
252+
EXPECT_EQ(diff_count, 0) << diff_count << " planewave values differ after nspin=2 round-trip";
253+
254+
std::remove(tmpfile.c_str());
255+
}
256+
126257
int main(int argc, char** argv)
127258
{
128259
#ifdef __MPI

0 commit comments

Comments
 (0)