1 /* ----------------------------------------------------------------------
2    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
3    https://www.lammps.org/, Sandia National Laboratories
4    Steve Plimpton, sjplimp@sandia.gov
5 
6    Copyright (2003) Sandia Corporation.  Under the terms of Contract
7    DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
8    certain rights in this software.  This software is distributed under
9    the GNU General Public License.
10 
11    See the README file in the top-level LAMMPS directory.
12 ------------------------------------------------------------------------- */
13 
14 #include "MANYBODY/pair_comb.h"
15 #include "MANYBODY/pair_comb3.h"
16 #include "MANYBODY/pair_gw.h"
17 #include "MANYBODY/pair_gw_zbl.h"
18 #include "MANYBODY/pair_nb3b_harmonic.h"
19 #include "MANYBODY/pair_sw.h"
20 #include "MANYBODY/pair_tersoff.h"
21 #include "MANYBODY/pair_tersoff_mod.h"
22 #include "MANYBODY/pair_tersoff_mod_c.h"
23 #include "MANYBODY/pair_tersoff_table.h"
24 #include "MANYBODY/pair_tersoff_zbl.h"
25 #include "MANYBODY/pair_vashishta.h"
26 #include "info.h"
27 #include "input.h"
28 #include "potential_file_reader.h"
29 #include "gmock/gmock.h"
30 #include "gtest/gtest.h"
31 
32 #include "../testing/core.h"
33 
34 #include <cstring>
35 #include <iostream>
36 #include <mpi.h>
37 #include <vector>
38 
39 using namespace LAMMPS_NS;
40 using ::testing::MatchesRegex;
41 using utils::split_words;
42 
43 // whether to print verbose output (i.e. not capturing LAMMPS screen output).
44 bool verbose = false;
45 
46 #if __cplusplus < 201703L
47 constexpr int LAMMPS_NS::PairSW::NPARAMS_PER_LINE;
48 constexpr int LAMMPS_NS::PairComb::NPARAMS_PER_LINE;
49 constexpr int LAMMPS_NS::PairComb3::NPARAMS_PER_LINE;
50 constexpr int LAMMPS_NS::PairTersoff::NPARAMS_PER_LINE;
51 constexpr int LAMMPS_NS::PairTersoffMOD::NPARAMS_PER_LINE;
52 constexpr int LAMMPS_NS::PairTersoffMODC::NPARAMS_PER_LINE;
53 constexpr int LAMMPS_NS::PairTersoffZBL::NPARAMS_PER_LINE;
54 constexpr int LAMMPS_NS::PairGW::NPARAMS_PER_LINE;
55 constexpr int LAMMPS_NS::PairGWZBL::NPARAMS_PER_LINE;
56 constexpr int LAMMPS_NS::PairNb3bHarmonic::NPARAMS_PER_LINE;
57 constexpr int LAMMPS_NS::PairVashishta::NPARAMS_PER_LINE;
58 constexpr int LAMMPS_NS::PairTersoffTable::NPARAMS_PER_LINE;
59 #endif
60 
61 class PotentialFileReaderTest : public LAMMPSTest {
62 };
63 
64 // open for native units
TEST_F(PotentialFileReaderTest,Sw_native)65 TEST_F(PotentialFileReaderTest, Sw_native)
66 {
67     BEGIN_HIDE_OUTPUT();
68     command("units metal");
69     PotentialFileReader reader(lmp, "Si.sw", "Stillinger-Weber");
70     END_HIDE_OUTPUT();
71 
72     auto line = reader.next_line(PairSW::NPARAMS_PER_LINE);
73     ASSERT_EQ(utils::count_words(line), PairSW::NPARAMS_PER_LINE);
74 }
75 
76 // open with supported conversion enabled
TEST_F(PotentialFileReaderTest,Sw_conv)77 TEST_F(PotentialFileReaderTest, Sw_conv)
78 {
79     BEGIN_HIDE_OUTPUT();
80     command("units real");
81     PotentialFileReader reader(lmp, "Si.sw", "Stillinger-Weber", utils::METAL2REAL);
82     END_HIDE_OUTPUT();
83 
84     auto line = reader.next_line(PairSW::NPARAMS_PER_LINE);
85     ASSERT_EQ(utils::count_words(line), PairSW::NPARAMS_PER_LINE);
86 }
87 
88 // open without conversion enabled
TEST_F(PotentialFileReaderTest,Sw_noconv)89 TEST_F(PotentialFileReaderTest, Sw_noconv)
90 {
91     BEGIN_HIDE_OUTPUT();
92     command("units real");
93     END_HIDE_OUTPUT();
94 
95     TEST_FAILURE(".*ERROR on proc.*potential.*requires metal units but real.*",
96                  PotentialFileReader reader(lmp, "Si.sw", "Stillinger-Weber", utils::REAL2METAL););
97 }
98 
TEST_F(PotentialFileReaderTest,Comb)99 TEST_F(PotentialFileReaderTest, Comb)
100 {
101     BEGIN_HIDE_OUTPUT();
102     command("units metal");
103     PotentialFileReader reader(lmp, "ffield.comb", "COMB");
104     END_HIDE_OUTPUT();
105 
106     auto line = reader.next_line(PairComb::NPARAMS_PER_LINE);
107     ASSERT_EQ(utils::count_words(line), PairComb::NPARAMS_PER_LINE);
108 }
109 
TEST_F(PotentialFileReaderTest,Comb3)110 TEST_F(PotentialFileReaderTest, Comb3)
111 {
112     BEGIN_HIDE_OUTPUT();
113     command("units metal");
114     PotentialFileReader reader(lmp, "ffield.comb3", "COMB3");
115     END_HIDE_OUTPUT();
116 
117     auto line = reader.next_line(PairComb3::NPARAMS_PER_LINE);
118     ASSERT_EQ(utils::count_words(line), PairComb3::NPARAMS_PER_LINE);
119 }
120 
TEST_F(PotentialFileReaderTest,Tersoff)121 TEST_F(PotentialFileReaderTest, Tersoff)
122 {
123     BEGIN_HIDE_OUTPUT();
124     command("units metal");
125     PotentialFileReader reader(lmp, "Si.tersoff", "Tersoff");
126     END_HIDE_OUTPUT();
127 
128     auto line = reader.next_line(PairTersoff::NPARAMS_PER_LINE);
129     ASSERT_EQ(utils::count_words(line), PairTersoff::NPARAMS_PER_LINE);
130 }
131 
TEST_F(PotentialFileReaderTest,TersoffMod)132 TEST_F(PotentialFileReaderTest, TersoffMod)
133 {
134     BEGIN_HIDE_OUTPUT();
135     command("units metal");
136     PotentialFileReader reader(lmp, "Si.tersoff.mod", "Tersoff/Mod");
137     END_HIDE_OUTPUT();
138 
139     auto line = reader.next_line(PairTersoffMOD::NPARAMS_PER_LINE);
140     ASSERT_EQ(utils::count_words(line), PairTersoffMOD::NPARAMS_PER_LINE);
141 }
142 
TEST_F(PotentialFileReaderTest,TersoffModC)143 TEST_F(PotentialFileReaderTest, TersoffModC)
144 {
145     BEGIN_HIDE_OUTPUT();
146     command("units metal");
147     PotentialFileReader reader(lmp, "Si.tersoff.modc", "Tersoff/ModC");
148     END_HIDE_OUTPUT();
149 
150     auto line = reader.next_line(PairTersoffMODC::NPARAMS_PER_LINE);
151     ASSERT_EQ(utils::count_words(line), PairTersoffMODC::NPARAMS_PER_LINE);
152 }
153 
TEST_F(PotentialFileReaderTest,TersoffTable)154 TEST_F(PotentialFileReaderTest, TersoffTable)
155 {
156     BEGIN_HIDE_OUTPUT();
157     command("units metal");
158     PotentialFileReader reader(lmp, "Si.tersoff", "TersoffTable");
159     END_HIDE_OUTPUT();
160 
161     auto line = reader.next_line(PairTersoffTable::NPARAMS_PER_LINE);
162     ASSERT_EQ(utils::count_words(line), PairTersoffTable::NPARAMS_PER_LINE);
163 }
164 
TEST_F(PotentialFileReaderTest,TersoffZBL)165 TEST_F(PotentialFileReaderTest, TersoffZBL)
166 {
167     BEGIN_HIDE_OUTPUT();
168     command("units metal");
169     PotentialFileReader reader(lmp, "SiC.tersoff.zbl", "Tersoff/ZBL");
170     END_HIDE_OUTPUT();
171 
172     auto line = reader.next_line(PairTersoffZBL::NPARAMS_PER_LINE);
173     ASSERT_EQ(utils::count_words(line), PairTersoffZBL::NPARAMS_PER_LINE);
174 }
175 
TEST_F(PotentialFileReaderTest,GW)176 TEST_F(PotentialFileReaderTest, GW)
177 {
178     BEGIN_HIDE_OUTPUT();
179     command("units metal");
180     PotentialFileReader reader(lmp, "SiC.gw", "GW");
181     END_HIDE_OUTPUT();
182 
183     auto line = reader.next_line(PairGW::NPARAMS_PER_LINE);
184     ASSERT_EQ(utils::count_words(line), PairGW::NPARAMS_PER_LINE);
185 }
186 
TEST_F(PotentialFileReaderTest,GWZBL)187 TEST_F(PotentialFileReaderTest, GWZBL)
188 {
189     BEGIN_HIDE_OUTPUT();
190     command("units metal");
191     PotentialFileReader reader(lmp, "SiC.gw.zbl", "GW/ZBL");
192     END_HIDE_OUTPUT();
193 
194     auto line = reader.next_line(PairGWZBL::NPARAMS_PER_LINE);
195     ASSERT_EQ(utils::count_words(line), PairGWZBL::NPARAMS_PER_LINE);
196 }
197 
TEST_F(PotentialFileReaderTest,Nb3bHarmonic)198 TEST_F(PotentialFileReaderTest, Nb3bHarmonic)
199 {
200     BEGIN_HIDE_OUTPUT();
201     command("units real");
202     PotentialFileReader reader(lmp, "MOH.nb3b.harmonic", "NB3B Harmonic");
203     END_HIDE_OUTPUT();
204 
205     auto line = reader.next_line(PairNb3bHarmonic::NPARAMS_PER_LINE);
206     ASSERT_EQ(utils::count_words(line), PairNb3bHarmonic::NPARAMS_PER_LINE);
207 }
208 
TEST_F(PotentialFileReaderTest,Vashishta)209 TEST_F(PotentialFileReaderTest, Vashishta)
210 {
211     BEGIN_HIDE_OUTPUT();
212     command("units metal");
213     PotentialFileReader reader(lmp, "SiC.vashishta", "Vashishta");
214     END_HIDE_OUTPUT();
215 
216     auto line = reader.next_line(PairVashishta::NPARAMS_PER_LINE);
217     ASSERT_EQ(utils::count_words(line), PairVashishta::NPARAMS_PER_LINE);
218 }
219 
TEST_F(PotentialFileReaderTest,UnitConvert)220 TEST_F(PotentialFileReaderTest, UnitConvert)
221 {
222     PotentialFileReader *reader;
223     int unit_convert, flag;
224 
225     BEGIN_HIDE_OUTPUT();
226     command("units metal");
227     reader = new PotentialFileReader(lmp, "Si.sw", "Stillinger-Weber");
228     END_HIDE_OUTPUT();
229 
230     unit_convert = reader->get_unit_convert();
231     ASSERT_EQ(unit_convert, 0);
232     delete reader;
233 
234     BEGIN_HIDE_OUTPUT();
235     flag   = utils::get_supported_conversions(utils::UNKNOWN);
236     reader = new PotentialFileReader(lmp, "Si.sw", "Stillinger-Weber", flag);
237     END_HIDE_OUTPUT();
238 
239     unit_convert = reader->get_unit_convert();
240     ASSERT_EQ(unit_convert, 0);
241     delete reader;
242 
243     BEGIN_HIDE_OUTPUT();
244     flag   = utils::get_supported_conversions(utils::ENERGY);
245     reader = new PotentialFileReader(lmp, "Si.sw", "Stillinger-Weber", flag);
246     END_HIDE_OUTPUT();
247 
248     unit_convert = reader->get_unit_convert();
249     ASSERT_EQ(unit_convert, 0);
250     delete reader;
251 
252     BEGIN_HIDE_OUTPUT();
253     flag = utils::get_supported_conversions(utils::ENERGY);
254     command("units real");
255     reader = new PotentialFileReader(lmp, "Si.sw", "Stillinger-Weber", flag);
256     END_HIDE_OUTPUT();
257 
258     unit_convert = reader->get_unit_convert();
259     ASSERT_EQ(unit_convert, utils::METAL2REAL);
260     delete reader;
261 }
262 
263 class OpenPotentialTest : public LAMMPSTest {
264 };
265 
266 // open for native units
TEST_F(OpenPotentialTest,Sw_native)267 TEST_F(OpenPotentialTest, Sw_native)
268 {
269     int convert_flag = utils::get_supported_conversions(utils::ENERGY);
270     BEGIN_CAPTURE_OUTPUT();
271     command("units metal");
272     FILE *fp    = utils::open_potential("Si.sw", lmp, &convert_flag);
273     auto text   = END_CAPTURE_OUTPUT();
274     double conv = utils::get_conversion_factor(utils::ENERGY, convert_flag);
275 
276     ASSERT_NE(fp, nullptr);
277     ASSERT_DOUBLE_EQ(conv, 1.0);
278     fclose(fp);
279 }
280 
281 // open with supported conversion enabled
TEST_F(OpenPotentialTest,Sw_conv)282 TEST_F(OpenPotentialTest, Sw_conv)
283 {
284     int convert_flag = utils::get_supported_conversions(utils::ENERGY);
285     ASSERT_EQ(convert_flag, utils::METAL2REAL | utils::REAL2METAL);
286     BEGIN_HIDE_OUTPUT();
287     command("units real");
288     FILE *fp    = utils::open_potential("Si.sw", lmp, &convert_flag);
289     auto text   = END_CAPTURE_OUTPUT();
290     double conv = utils::get_conversion_factor(utils::ENERGY, convert_flag);
291 
292     ASSERT_NE(fp, nullptr);
293     ASSERT_EQ(convert_flag, utils::METAL2REAL);
294     ASSERT_DOUBLE_EQ(conv, 23.060549);
295     fclose(fp);
296 }
297 
298 // open with conversion disabled
TEST_F(OpenPotentialTest,Sw_noconv)299 TEST_F(OpenPotentialTest, Sw_noconv)
300 {
301     BEGIN_HIDE_OUTPUT();
302     command("units real");
303     END_HIDE_OUTPUT();
304     TEST_FAILURE(".*potential.*requires metal units but real.*",
305                  utils::open_potential("Si.sw", lmp, nullptr););
306     BEGIN_HIDE_OUTPUT();
307     command("units lj");
308     END_HIDE_OUTPUT();
309     int convert_flag = utils::get_supported_conversions(utils::UNKNOWN);
310     ASSERT_EQ(convert_flag, utils::NOCONVERT);
311 }
312 
313 // open non-existing potential
TEST_F(OpenPotentialTest,No_file)314 TEST_F(OpenPotentialTest, No_file)
315 {
316     int convert_flag = utils::get_supported_conversions(utils::ENERGY);
317     BEGIN_HIDE_OUTPUT();
318     command("units metal");
319     FILE *fp = utils::open_potential("Unknown.sw", lmp, &convert_flag);
320     END_HIDE_OUTPUT();
321     ASSERT_EQ(fp, nullptr);
322 }
323 
main(int argc,char ** argv)324 int main(int argc, char **argv)
325 {
326     MPI_Init(&argc, &argv);
327     ::testing::InitGoogleMock(&argc, argv);
328 
329     if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions())
330         std::cout << "Warning: using OpenMPI without exceptions. "
331                      "Death tests will be skipped\n";
332 
333     // handle arguments passed via environment variable
334     if (const char *var = getenv("TEST_ARGS")) {
335         std::vector<std::string> env = split_words(var);
336         for (auto arg : env) {
337             if (arg == "-v") {
338                 verbose = true;
339             }
340         }
341     }
342     if ((argc > 1) && (strcmp(argv[1], "-v") == 0)) verbose = true;
343 
344     int rv = RUN_ALL_TESTS();
345     MPI_Finalize();
346     return rv;
347 }
348