Merge pull request #2682 from rbberger/python_unittests

Python package unit tests
This commit is contained in:
Axel Kohlmeyer
2021-04-01 10:11:26 -04:00
committed by GitHub
18 changed files with 643 additions and 118 deletions

View File

@ -124,7 +124,7 @@ file(GLOB FIX_TIMESTEP_TESTS LIST_DIRECTORIES false ${TEST_INPUT_FOLDER}/fix-tim
foreach(TEST ${FIX_TIMESTEP_TESTS})
string(REGEX REPLACE "^.*fix-timestep-(.*)\.yaml" "FixTimestep:\\1" TNAME ${TEST})
add_test(NAME ${TNAME} COMMAND test_fix_timestep ${TEST} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set_tests_properties(${TNAME} PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR};PYTHONPATH=${TEST_INPUT_FOLDER}:$ENV{PYTHONPATH}")
set_tests_properties(${TNAME} PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR};PYTHONPATH=${TEST_INPUT_FOLDER}:${LAMMPS_PYTHON_DIR}:$ENV{PYTHONPATH}")
endforeach()
# dihedral style tester

View File

@ -0,0 +1,73 @@
---
lammps_version: 10 Mar 2021
date_generated: Wed Mar 24 18:57:26 202
epsilon: 9e-12
prerequisites: ! |
atom full
fix python/move
pre_commands: ! ""
post_commands: ! |
fix test all python/move py_nve.NVE
input_file: in.fourmol
natoms: 29
run_pos: ! |2
1 -2.7045559775384037e-01 2.4912159905679729e+00 -1.6695851791541885e-01
2 3.1004029573899528e-01 2.9612354631094391e+00 -8.5466363037021464e-01
3 -7.0398551400789477e-01 1.2305509955830618e+00 -6.2777526944456274e-01
4 -1.5818159336499285e+00 1.4837407818929933e+00 -1.2538710836062004e+00
5 -9.0719763672789266e-01 9.2652103885675297e-01 3.9954210488374786e-01
6 2.4831720524855985e-01 2.8313021497871271e-01 -1.2314233331711453e+00
7 3.4143527641386412e-01 -2.2646551041391422e-02 -2.5292291414903052e+00
8 1.1743552229100009e+00 -4.8863228565853950e-01 -6.3783432910825522e-01
9 1.3800524229500313e+00 -2.5274721030406683e-01 2.8353985887095157e-01
10 2.0510765220543883e+00 -1.4604063740302866e+00 -9.8323745081712954e-01
11 1.7878031944442556e+00 -1.9921863272948861e+00 -1.8890602447625777e+00
12 3.0063007039340053e+00 -4.9013350496963298e-01 -1.6231898107386229e+00
13 4.0515402959192999e+00 -8.9202011606653986e-01 -1.6400005529924957e+00
14 2.6066963345543819e+00 -4.1789253965514150e-01 -2.6634003608794394e+00
15 2.9695287185712913e+00 5.5422613165234036e-01 -1.2342022021790127e+00
16 2.6747029695228521e+00 -2.4124119054564295e+00 -2.3435746150616148e-02
17 2.2153577785283796e+00 -2.0897985186907717e+00 1.1963150794479436e+00
18 2.1369701704115704e+00 3.0158507413630606e+00 -3.5179348337215015e+00
19 1.5355837136087378e+00 2.6255292355375675e+00 -4.2353987779879052e+00
20 2.7727573005678776e+00 3.6923910449610169e+00 -3.9330842459133493e+00
21 4.9040128073204299e+00 -4.0752348172957946e+00 -3.6210314709891711e+00
22 4.3582355554440841e+00 -4.2126119427287048e+00 -4.4612844196314052e+00
23 5.7439382849307599e+00 -3.5821957939275029e+00 -3.8766361295935821e+00
24 2.0689243582422630e+00 3.1513346907271012e+00 3.1550389754828800e+00
25 1.3045351331492134e+00 3.2665125705842848e+00 2.5111855257433504e+00
26 2.5809237402711274e+00 4.0117602605482832e+00 3.2212060529089896e+00
27 -1.9611343130357228e+00 -4.3563411931359752e+00 2.1098293115523705e+00
28 -2.7473562684513411e+00 -4.0200819932379330e+00 1.5830052163433954e+00
29 -1.3126000191359855e+00 -3.5962518039482929e+00 2.2746342468737835e+00
run_vel: ! |2
1 8.1705744183262364e-03 1.6516406176274288e-02 4.7902264318912978e-03
2 5.4501493445687759e-03 5.1791699408496334e-03 -1.4372931530376651e-03
3 -8.2298292722385643e-03 -1.2926551614621381e-02 -4.0984181178163881e-03
4 -3.7699042590093588e-03 -6.5722892098813799e-03 -1.1184640360133230e-03
5 -1.1021961004346586e-02 -9.8906780939335987e-03 -2.8410737829284395e-03
6 -3.9676663166400034e-02 4.6817061464710256e-02 3.7148491979476124e-02
7 9.1033953013898580e-04 -1.0128524411938794e-02 -5.1568251805019748e-02
8 7.9064712058855707e-03 -3.3507254552631767e-03 3.4557098492564629e-02
9 1.5644176117320923e-03 3.7365546102722164e-03 1.5047408822037646e-02
10 2.9201446820573174e-02 -2.9249578745486147e-02 -1.5018077424322538e-02
11 -4.7835961513517560e-03 -3.7481385134185206e-03 -2.3464104142290089e-03
12 2.2696451841920521e-03 -3.4774154398129479e-04 -3.0640770327796806e-03
13 2.7531740451953168e-03 5.8171061612840667e-03 -7.9467454022160518e-04
14 3.5246182371994252e-03 -5.7939995585585468e-03 -3.9478431172751344e-03
15 -1.8547943640122894e-03 -5.8554729942777743e-03 6.2938485140538649e-03
16 1.8681499973445245e-02 -1.3262466204585335e-02 -4.5638651457003243e-02
17 -1.2896269981100382e-02 9.7527665265956451e-03 3.7296535360836762e-02
18 -8.0065794848261610e-04 -8.6270473212554395e-04 -1.4483040697508738e-03
19 1.2452390836182623e-03 -2.5061097118772701e-03 7.2998631009712975e-03
20 3.5930060229597042e-03 3.6938860309252966e-03 3.2322732687893028e-03
21 -1.4689220370766550e-03 -2.7352129761527741e-04 7.0581624215243391e-04
22 -7.0694199254630339e-03 -4.2577148924878554e-03 2.8079117614251796e-04
23 6.0446963117374913e-03 -1.4000131614795382e-03 2.5819754847014255e-03
24 3.1926367902287940e-04 -9.9445664749276438e-04 1.4999996959365452e-04
25 1.3789754514814662e-04 -4.4335894884532569e-03 -8.1808136725080281e-04
26 2.0485904035217549e-03 2.7813358633835984e-03 4.3245727149206692e-03
27 4.5604120293369857e-04 -1.0305523026921137e-03 2.1188058381358511e-04
28 -6.2544520861855116e-03 1.4127711176146942e-03 -1.8429821884794269e-03
29 6.4110631534401762e-04 3.1273432719593867e-03 3.7253671105656715e-03
...

View File

@ -0,0 +1,104 @@
from __future__ import print_function
from lammps import lammps
class LAMMPSFix(object):
def __init__(self, ptr, group_name="all"):
self.lmp = lammps(ptr=ptr)
self.group_name = group_name
class LAMMPSFixMove(LAMMPSFix):
def __init__(self, ptr, group_name="all"):
super(LAMMPSFixMove, self).__init__(ptr, group_name)
def init(self):
pass
def initial_integrate(self, vflag):
pass
def final_integrate(self):
pass
def initial_integrate_respa(self, vflag, ilevel, iloop):
pass
def final_integrate_respa(self, ilevel, iloop):
pass
def reset_dt(self):
pass
class NVE(LAMMPSFixMove):
""" Python implementation of fix/nve """
def __init__(self, ptr, group_name="all"):
super(NVE, self).__init__(ptr)
assert(self.group_name == "all")
self._step_respa = None
def init(self):
dt = self.lmp.extract_global("dt")
ftm2v = self.lmp.extract_global("ftm2v")
self.ntypes = self.lmp.extract_global("ntypes")
self.dtv = dt
self.dtf = 0.5 * dt * ftm2v
@property
def step_respa(self):
if not self._step_respa:
self._step_respa = self.lmp.extract_global("respa_dt")
return self._step_respa
def initial_integrate(self, vflag):
nlocal = self.lmp.extract_global("nlocal")
mass = self.lmp.extract_atom("mass")
atype = self.lmp.extract_atom("type")
x = self.lmp.extract_atom("x")
v = self.lmp.extract_atom("v")
f = self.lmp.extract_atom("f")
for i in range(nlocal):
dtfm = self.dtf / mass[int(atype[i])]
v[i][0] += dtfm * f[i][0]
v[i][1] += dtfm * f[i][1]
v[i][2] += dtfm * f[i][2]
x[i][0] += self.dtv * v[i][0]
x[i][1] += self.dtv * v[i][1]
x[i][2] += self.dtv * v[i][2]
def final_integrate(self):
nlocal = self.lmp.extract_global("nlocal")
mass = self.lmp.extract_atom("mass")
atype = self.lmp.extract_atom("type")
v = self.lmp.extract_atom("v")
f = self.lmp.extract_atom("f")
for i in range(nlocal):
dtfm = self.dtf / mass[int(atype[i])]
v[i][0] += dtfm * f[i][0]
v[i][1] += dtfm * f[i][1]
v[i][2] += dtfm * f[i][2]
def initial_integrate_respa(self, vflag, ilevel, iloop):
ftm2v = self.lmp.extract_global("ftm2v")
self.dtv = self.step_respa[ilevel]
self.dtf = 0.5 * self.step_respa[ilevel] * ftm2v
# innermost level - NVE update of v and x
# all other levels - NVE update of v
if ilevel == 0:
self.initial_integrate(vflag)
else:
self.final_integrate()
def final_integrate_respa(self, ilevel, iloop):
ftm2v = self.lmp.extract_global("ftm2v")
self.dtf = 0.5 * self.step_respa[ilevel] * ftm2v
self.final_integrate()
def reset_dt(self):
dt = self.lmp.extract_global("dt")
ftm2v = self.lmp.extract_global("ftm2v")
self.dtv = dt;
self.dtf = 0.5 * dt * ftm2v;

View File

@ -8,7 +8,7 @@ add_executable(test_python_package test_python_package.cpp)
target_link_libraries(test_python_package PRIVATE lammps GTest::GMock GTest::GTest)
target_compile_definitions(test_python_package PRIVATE -DTEST_INPUT_FOLDER=${TEST_INPUT_FOLDER})
add_test(NAME PythonPackage COMMAND test_python_package WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set_tests_properties(PythonPackage PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR};PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}:${LAMMPS_PYTHON_DIR}:$ENV{PYTHONPATH}")
set_tests_properties(PythonPackage PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR};PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}:${LAMMPS_PYTHON_DIR}:$ENV{PYTHONPATH};PYTHONUNBUFFERED=1")
# we must have shared libraries enabled for testing the python module
if(NOT BUILD_SHARED_LIBS)

View File

@ -4,6 +4,16 @@ from __future__ import print_function
def square(val):
return val*val
def bool_to_val(txt):
if txt.upper() in ["TRUE", "YES"]:
return 1.0
return 0.0
def val_to_bool(val):
if val != 0:
return "True"
return "False"
def printnum():
print("2.25")
@ -11,8 +21,10 @@ def printtxt():
print("sometext")
def getidxvar(lmpptr):
from lammps import lammps, LMP_VAR_EQUAL
from lammps import lammps
lmp = lammps(ptr=lmpptr)
val = lmp.extract_variable("idx",None,LMP_VAR_EQUAL)
val = lmp.extract_variable("idx")
print(val)
def longstr():
return "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent metus."

View File

@ -259,15 +259,43 @@ create_atoms 1 single &
result = self.lmp.get_thermo(key)
self.assertEqual(value, result, key)
def test_extract_global_double(self):
def test_extract_global(self):
self.lmp.command("region box block -1 1 -2 2 -3 3")
self.lmp.command("create_box 1 box")
self.assertEqual(self.lmp.extract_global("units"), "lj")
self.assertEqual(self.lmp.extract_global("ntimestep"), 0)
self.assertEqual(self.lmp.extract_global("dt"), 0.005)
self.assertEqual(self.lmp.extract_global("boxxlo"), -1.0)
self.assertEqual(self.lmp.extract_global("boxxhi"), 1.0)
self.assertEqual(self.lmp.extract_global("boxylo"), -2.0)
self.assertEqual(self.lmp.extract_global("boxyhi"), 2.0)
self.assertEqual(self.lmp.extract_global("boxzlo"), -3.0)
self.assertEqual(self.lmp.extract_global("boxzhi"), 3.0)
self.assertEqual(self.lmp.extract_global("boxlo"), [-1.0, -2.0, -3.0])
self.assertEqual(self.lmp.extract_global("boxhi"), [1.0, 2.0, 3.0])
self.assertEqual(self.lmp.extract_global("sublo"), [-1.0, -2.0, -3.0])
self.assertEqual(self.lmp.extract_global("subhi"), [1.0, 2.0, 3.0])
self.assertEqual(self.lmp.extract_global("periodicity"), [1,1,1])
self.assertEqual(self.lmp.extract_global("triclinic"), 0)
self.assertEqual(self.lmp.extract_global("sublo_lambda"), None)
self.assertEqual(self.lmp.extract_global("subhi_lambda"), None)
self.assertEqual(self.lmp.extract_global("respa_levels"), None)
self.assertEqual(self.lmp.extract_global("respa_dt"), None)
# set and initialize r-RESPA
self.lmp.command("run_style respa 3 5 2 pair 2 kspace 3")
self.lmp.command("mass * 1.0")
self.lmp.command("run 1 post no")
self.assertEqual(self.lmp.extract_global("ntimestep"), 1)
self.assertEqual(self.lmp.extract_global("respa_levels"), 3)
self.assertEqual(self.lmp.extract_global("respa_dt"), [0.0005, 0.0025, 0.005])
# checks only for triclinic boxes
self.lmp.command("change_box all triclinic")
self.assertEqual(self.lmp.extract_global("triclinic"), 1)
self.assertEqual(self.lmp.extract_global("sublo_lambda"), [0.0, 0.0, 0.0])
self.assertEqual(self.lmp.extract_global("subhi_lambda"), [1.0, 1.0, 1.0])
##############################
if __name__ == "__main__":

2
unittest/python/run.py Normal file
View File

@ -0,0 +1,2 @@
from __future__ import print_function
print("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent metus.")

View File

@ -14,19 +14,25 @@
#include "atom.h"
#include "info.h"
#include "input.h"
#include "variable.h"
#include "library.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <cmath>
#include <cstring>
#include <vector>
#include <functional>
#include "../testing/core.h"
#include "../testing/systems/melt.h"
// location of '*.py' files required by tests
#define STRINGIFY(val) XSTR(val)
#define XSTR(val) #val
std::string INPUT_FOLDER = STRINGIFY(TEST_INPUT_FOLDER);
// whether to print verbose output (i.e. not capturing LAMMPS screen output).
const char * LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent metus.";
bool verbose = false;
using LAMMPS_NS::utils::split_words;
@ -34,95 +40,287 @@ using LAMMPS_NS::utils::split_words;
namespace LAMMPS_NS {
using ::testing::MatchesRegex;
using ::testing::StrEq;
using ::testing::Eq;
using ::testing::HasSubstr;
class PythonPackageTest : public ::testing::Test {
class PythonPackageTest : public LAMMPSTest {
protected:
LAMMPS *lmp;
Info *info;
void SetUp() override
void InitSystem() override
{
const char *args[] = {"PythonPackageTest", "-log", "none", "-echo", "screen", "-nocite"};
char **argv = (char **)args;
int argc = sizeof(args) / sizeof(char *);
if (!verbose) ::testing::internal::CaptureStdout();
lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD);
if (!verbose) ::testing::internal::GetCapturedStdout();
ASSERT_NE(lmp, nullptr);
info = new Info(lmp);
if (!verbose) ::testing::internal::CaptureStdout();
lmp->input->one("units real");
lmp->input->one("dimension 3");
lmp->input->one("region box block -4 4 -4 4 -4 4");
lmp->input->one("create_box 1 box");
lmp->input->one("create_atoms 1 single 0.0 0.0 0.0 units box");
lmp->input->one("create_atoms 1 single 1.9 -1.9 1.9999 units box");
lmp->input->one("pair_style zero 2.0");
lmp->input->one("pair_coeff * *");
lmp->input->one("mass * 1.0");
lmp->input->one("variable input_dir index " + INPUT_FOLDER);
if (!verbose) ::testing::internal::GetCapturedStdout();
}
if (!info->has_package("PYTHON")) GTEST_SKIP();
void TearDown() override
{
if (!verbose) ::testing::internal::CaptureStdout();
delete info;
delete lmp;
if (!verbose) ::testing::internal::GetCapturedStdout();
HIDE_OUTPUT([&] {
command("units real");
command("dimension 3");
command("region box block -4 4 -4 4 -4 4");
command("create_box 1 box");
command("create_atoms 1 single 0.0 0.0 0.0 units box");
command("create_atoms 1 single 1.9 -1.9 1.9999 units box");
command("pair_style zero 2.0");
command("pair_coeff * *");
command("mass * 1.0");
command("variable input_dir index " + INPUT_FOLDER);
});
}
};
TEST_F(PythonPackageTest, python_invoke)
class FixPythonInvokeTest : public MeltTest {
protected:
void InitSystem() override
{
if (!info->has_package("PYTHON")) GTEST_SKIP();
MeltTest::InitSystem();
}
};
TEST_F(PythonPackageTest, InvokeFunctionFromFile)
{
if (!info->has_style("command", "python")) GTEST_SKIP();
// execute python function from file
if (!verbose) ::testing::internal::CaptureStdout();
lmp->input->one("python printnum file ${input_dir}/func.py");
if (!verbose) ::testing::internal::GetCapturedStdout();
::testing::internal::CaptureStdout();
lmp->input->one("python printnum invoke");
std::string output = ::testing::internal::GetCapturedStdout();
if (verbose) std::cout << output;
ASSERT_THAT(output, MatchesRegex("python.*2.25.*"));
HIDE_OUTPUT([&] {
command("python printnum file ${input_dir}/func.py");
});
auto output = CAPTURE_OUTPUT([&]() {
command("python printnum invoke");
});
ASSERT_THAT(output, HasSubstr("2.25\n"));
}
TEST_F(PythonPackageTest, InvokeFunctionPassInt)
{
// execute python function, passing integer as argument
HIDE_OUTPUT([&] {
command("variable sq python square");
command("python square input 1 2 format ii return v_sq file ${input_dir}/func.py");
command("python square invoke");
});
ASSERT_EQ(get_variable_value("sq"), 4.0);
}
TEST_F(PythonPackageTest, InvokeFunctionPassFloat)
{
// execute python function, passing float as argument
HIDE_OUTPUT([&] {
command("variable sq python square");
command("python square input 1 2.5 format ff return v_sq file ${input_dir}/func.py");
});
ASSERT_EQ(get_variable_value("sq"), 6.25);
}
TEST_F(PythonPackageTest, InvokeFunctionPassString)
{
// execute python function, passing string as argument
HIDE_OUTPUT([&] {
command("variable val python bool_to_val");
command("python bool_to_val input 1 \"true\" format sf return v_val file ${input_dir}/func.py");
});
ASSERT_EQ(get_variable_value("val"), 1.0);
}
TEST_F(PythonPackageTest, InvokeFunctionPassStringVariable)
{
// execute python function, passing string variable as argument
HIDE_OUTPUT([&] {
command("variable val python bool_to_val");
command("python bool_to_val input 1 v_str format sf return v_val file ${input_dir}/func.py");
});
HIDE_OUTPUT([&] {
command("variable str string \"true\"");
});
ASSERT_EQ(get_variable_value("val"), 1.0);
HIDE_OUTPUT([&] {
command("variable str string \"false\"");
});
ASSERT_EQ(get_variable_value("val"), 0.0);
}
TEST_F(PythonPackageTest, InvokeStringFunction)
{
// execute python function, passing string variable as argument
HIDE_OUTPUT([&] {
command("variable str python val_to_bool");
command("python val_to_bool input 1 v_val format is return v_str file ${input_dir}/func.py");
});
HIDE_OUTPUT([&] {
command("variable val equal 0");
});
ASSERT_THAT(get_variable_string("str"), StrEq("False"));
HIDE_OUTPUT([&] {
command("variable val equal 1");
});
ASSERT_THAT(get_variable_string("str"), StrEq("True"));
}
TEST_F(PythonPackageTest, InvokeLongStringFunction)
{
// execute python function, passing string variable as argument
HIDE_OUTPUT([&] {
command("variable str python longstr");
command("python longstr format s length 72 return v_str file ${input_dir}/func.py");
});
ASSERT_THAT(get_variable_string("str"), StrEq(LOREM_IPSUM));
}
TEST_F(PythonPackageTest, InvokeOtherFunctionFromFile)
{
// execute another python function from same file
if (!verbose) ::testing::internal::CaptureStdout();
lmp->input->one("python printtxt exists");
if (!verbose) ::testing::internal::GetCapturedStdout();
::testing::internal::CaptureStdout();
lmp->input->one("python printtxt invoke");
output = ::testing::internal::GetCapturedStdout();
if (verbose) std::cout << output;
ASSERT_THAT(output, MatchesRegex("python.*sometext.*"));
HIDE_OUTPUT([&] {
command("python printnum file ${input_dir}/func.py");
command("python printtxt exists");
});
auto output = CAPTURE_OUTPUT([&] {
command("python printtxt invoke");
});
ASSERT_THAT(output, HasSubstr("sometext\n"));
}
TEST_F(PythonPackageTest, InvokeFunctionThatUsesLAMMPSModule)
{
// execute python function that uses the LAMMPS python module
if (!verbose) ::testing::internal::CaptureStdout();
lmp->input->one("variable idx equal 2.25");
lmp->input->one("python getidxvar input 1 SELF format p exists");
if (!verbose) ::testing::internal::GetCapturedStdout();
::testing::internal::CaptureStdout();
lmp->input->one("python getidxvar invoke");
output = ::testing::internal::GetCapturedStdout();
if (verbose) std::cout << output;
ASSERT_THAT(output, MatchesRegex("python.*2.25.*"));
HIDE_OUTPUT([&] {
command("python printnum file ${input_dir}/func.py");
command("variable idx equal 2.25");
command("python getidxvar input 1 SELF format p exists");
});
auto output = CAPTURE_OUTPUT([&] {
command("python getidxvar invoke");
});
ASSERT_THAT(output, HasSubstr("2.25\n"));
}
TEST_F(PythonPackageTest, python_variable)
{
if (!info->has_style("command", "python")) GTEST_SKIP();
if (!verbose) ::testing::internal::CaptureStdout();
lmp->input->one("variable sq python square");
lmp->input->one("variable val index 1.5");
lmp->input->one("python square input 1 v_val return v_sq format ff file ${input_dir}/func.py");
if (!verbose) ::testing::internal::GetCapturedStdout();
::testing::internal::CaptureStdout();
lmp->input->one("print \"${sq}\"");
std::string output = ::testing::internal::GetCapturedStdout();
if (verbose) std::cout << output;
// define variable that evaluates a python function
HIDE_OUTPUT([&] {
command("variable sq python square");
command("variable val index 1.5");
command("python square input 1 v_val return v_sq format ff file ${input_dir}/func.py");
});
std::string output = CAPTURE_OUTPUT([&] {
command("print \"${sq}\"");
});
ASSERT_THAT(output, MatchesRegex("print.*2.25.*"));
}
TEST_F(PythonPackageTest, InlineFunction)
{
// define variable that evaluates a python function
HIDE_OUTPUT([&] {
command("variable fact python factorial");
command("python factorial input 1 v_n return v_fact format ii here \"\"\"\n"
"def factorial(n):\n"
" if n == 0 or n == 1: return 1\n"
" return n*factorial(n-1)\n"
"\"\"\"");
});
HIDE_OUTPUT([&] {
command("variable n equal 1");
});
ASSERT_EQ(get_variable_value("fact"), 1.0);
HIDE_OUTPUT([&] {
command("variable n equal 2");
});
ASSERT_EQ(get_variable_value("fact"), 2.0);
HIDE_OUTPUT([&] {
command("variable n equal 3");
});
ASSERT_EQ(get_variable_value("fact"), 6.0);
}
TEST_F(PythonPackageTest, RunSource)
{
// execute python script from file
auto output = CAPTURE_OUTPUT([&] {
command("python xyz source ${input_dir}/run.py");
});
ASSERT_THAT(output, HasSubstr(LOREM_IPSUM));
}
TEST_F(PythonPackageTest, RunSourceInline)
{
// execute inline python script
auto output = CAPTURE_OUTPUT([&] {
command("python xyz source \"\"\"\n"
"from __future__ import print_function\n"
"print(2+2)\n"
"\"\"\""
);
});
ASSERT_THAT(output, HasSubstr("4"));
}
TEST_F(FixPythonInvokeTest, end_of_step)
{
HIDE_OUTPUT([&] {
command("python end_of_step_callback here \"\"\"\n"
"from __future__ import print_function\n"
"def end_of_step_callback(ptr):\n"
" print(\"PYTHON_END_OF_STEP\")\n"
"\"\"\"");
command("fix eos all python/invoke 10 end_of_step end_of_step_callback");
});
auto output = CAPTURE_OUTPUT([&] {
command("run 50");
});
auto lines = utils::split_lines(output);
int count = 0;
for(auto & line : lines) {
if (line == "PYTHON_END_OF_STEP") ++count;
}
ASSERT_EQ(count, 5);
}
TEST_F(FixPythonInvokeTest, post_force)
{
HIDE_OUTPUT([&] {
command("python post_force_callback here \"\"\"\n"
"from __future__ import print_function\n"
"def post_force_callback(ptr, vflag):\n"
" print(\"PYTHON_POST_FORCE\")\n"
"\"\"\"");
command("fix pf all python/invoke 10 post_force post_force_callback");
});
auto output = CAPTURE_OUTPUT([&] {
command("run 50");
});
auto lines = utils::split_lines(output);
int count = 0;
for(auto & line : lines) {
if (line == "PYTHON_POST_FORCE") ++count;
}
ASSERT_EQ(count, 5);
}
} // namespace LAMMPS_NS
int main(int argc, char **argv)
@ -132,7 +330,7 @@ int main(int argc, char **argv)
// handle arguments passed via environment variable
if (const char *var = getenv("TEST_ARGS")) {
std::vector<std::string> env = split_words(var);
auto env = split_words(var);
for (auto arg : env) {
if (arg == "-v") {
verbose = true;

View File

@ -16,9 +16,12 @@
#include "info.h"
#include "input.h"
#include "lammps.h"
#include "variable.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <functional>
using namespace LAMMPS_NS;
using ::testing::MatchesRegex;
@ -45,29 +48,58 @@ class LAMMPSTest : public ::testing::Test {
public:
void command(const std::string &line) { lmp->input->one(line.c_str()); }
void HIDE_OUTPUT(std::function<void()> f) {
if (!verbose) ::testing::internal::CaptureStdout();
f();
if (!verbose) ::testing::internal::GetCapturedStdout();
}
std::string CAPTURE_OUTPUT(std::function<void()> f) {
::testing::internal::CaptureStdout();
f();
auto output = ::testing::internal::GetCapturedStdout();
if (verbose) std::cout << output;
return output;
}
double get_variable_value(const std::string & name) {
char * str = utils::strdup(fmt::format("v_{}", name));
double value = lmp->input->variable->compute_equal(str);
delete [] str;
return value;
}
std::string get_variable_string(const std::string & name) {
return lmp->input->variable->retrieve(name.c_str());
}
protected:
const char *testbinary = "LAMMPSTest";
LAMMPS *lmp;
Info *info;
void SetUp() override
{
const char *args[] = {testbinary, "-log", "none", "-echo", "screen", "-nocite"};
char **argv = (char **)args;
int argc = sizeof(args) / sizeof(char *);
if (!verbose) ::testing::internal::CaptureStdout();
lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD);
HIDE_OUTPUT([&] {
lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD);
info = new Info(lmp);
});
InitSystem();
if (!verbose) ::testing::internal::GetCapturedStdout();
}
virtual void InitSystem() {}
void TearDown() override
{
if (!verbose) ::testing::internal::CaptureStdout();
delete lmp;
lmp = nullptr;
if (!verbose) ::testing::internal::GetCapturedStdout();
HIDE_OUTPUT([&] {
delete info;
delete lmp;
info = nullptr;
lmp = nullptr;
});
}
};

View File

@ -19,23 +19,25 @@ class MeltTest : public LAMMPSTest {
protected:
virtual void InitSystem() override
{
command("units lj");
command("atom_style atomic");
command("atom_modify map yes");
HIDE_OUTPUT([&] {
command("units lj");
command("atom_style atomic");
command("atom_modify map yes");
command("lattice fcc 0.8442");
command("region box block 0 2 0 2 0 2");
command("create_box 1 box");
command("create_atoms 1 box");
command("mass 1 1.0");
command("lattice fcc 0.8442");
command("region box block 0 2 0 2 0 2");
command("create_box 1 box");
command("create_atoms 1 box");
command("mass 1 1.0");
command("velocity all create 3.0 87287");
command("velocity all create 3.0 87287");
command("pair_style lj/cut 2.5");
command("pair_coeff 1 1 1.0 1.0 2.5");
command("pair_style lj/cut 2.5");
command("pair_coeff 1 1 1.0 1.0 2.5");
command("neighbor 0.3 bin");
command("neigh_modify every 20 delay 0 check no");
command("neighbor 0.3 bin");
command("neigh_modify every 20 delay 0 check no");
});
}
};

View File

@ -113,7 +113,7 @@ TEST(Utils, count_words_with_extra_spaces)
TEST(Utils, split_words_simple)
{
std::vector<std::string> list = utils::split_words("one two three");
auto list = utils::split_words("one two three");
ASSERT_EQ(list.size(), 3);
ASSERT_THAT(list[0], StrEq("one"));
ASSERT_THAT(list[1], StrEq("two"));
@ -122,7 +122,7 @@ TEST(Utils, split_words_simple)
TEST(Utils, split_words_quoted)
{
std::vector<std::string> list = utils::split_words("one 'two' \"three\"");
auto list = utils::split_words("one 'two' \"three\"");
ASSERT_EQ(list.size(), 3);
ASSERT_THAT(list[0], StrEq("one"));
ASSERT_THAT(list[1], StrEq("two"));
@ -131,7 +131,7 @@ TEST(Utils, split_words_quoted)
TEST(Utils, split_words_escaped)
{
std::vector<std::string> list = utils::split_words("1\\' '\"two\"' 3\\\"");
auto list = utils::split_words("1\\' '\"two\"' 3\\\"");
ASSERT_EQ(list.size(), 3);
ASSERT_THAT(list[0], StrEq("1\\'"));
ASSERT_THAT(list[1], StrEq("\"two\""));
@ -140,13 +140,22 @@ TEST(Utils, split_words_escaped)
TEST(Utils, split_words_quote_in_quoted)
{
std::vector<std::string> list = utils::split_words("one 't\\'wo' \"th\\\"ree\"");
auto list = utils::split_words("one 't\\'wo' \"th\\\"ree\"");
ASSERT_EQ(list.size(), 3);
ASSERT_THAT(list[0], StrEq("one"));
ASSERT_THAT(list[1], StrEq("t\\'wo"));
ASSERT_THAT(list[2], StrEq("th\\\"ree"));
}
TEST(Utils, split_lines)
{
auto list = utils::split_lines(" line 1\nline 2 \n line 3 \n");
ASSERT_EQ(list.size(), 3);
ASSERT_THAT(list[0], StrEq(" line 1"));
ASSERT_THAT(list[1], StrEq("line 2 "));
ASSERT_THAT(list[2], StrEq(" line 3 "));
}
TEST(Utils, valid_integer1)
{
ASSERT_TRUE(utils::is_integer("10"));