Merge branch 'master' into collected-small-changes

This commit is contained in:
Axel Kohlmeyer 2021-04-01 10:11:59 -04:00
commit 0b60650c1b
No known key found for this signature in database
GPG Key ID: D9B44E93BF0C375A
24 changed files with 665 additions and 134 deletions

View File

@ -101,6 +101,9 @@ and parsing files or arguments.
.. doxygenfunction:: split_words .. doxygenfunction:: split_words
:project: progguide :project: progguide
.. doxygenfunction:: split_lines
:project: progguide
.. doxygenfunction:: strmatch .. doxygenfunction:: strmatch
:project: progguide :project: progguide

View File

@ -740,6 +740,7 @@ void Neighbor::build_nbor_list(double **x, const int inum, const int host_inum,
// If binning on GPU, do this now // If binning on GPU, do this now
if (_gpu_nbor==1) { if (_gpu_nbor==1) {
mn = _max_nbors;
const numtyp i_cell_size=static_cast<numtyp>(1.0/_cell_size); const numtyp i_cell_size=static_cast<numtyp>(1.0/_cell_size);
const int neigh_block=_block_cell_id; const int neigh_block=_block_cell_id;
const int GX=(int)ceil((float)nall/neigh_block); const int GX=(int)ceil((float)nall/neigh_block);

View File

@ -15,7 +15,7 @@ from .pylammps import *
# convert module string version to numeric version # convert module string version to numeric version
def get_version_number(): def get_version_number():
from datetime import datetime import time
from sys import version_info from sys import version_info
vstring = None vstring = None
if version_info.major == 3 and version_info.minor >= 8: if version_info.major == 3 and version_info.minor >= 8:
@ -32,7 +32,7 @@ def get_version_number():
if not vstring: if not vstring:
return 0 return 0
d = datetime.strptime(vstring, "%d%b%Y") t = time.strptime(vstring, "%d%b%Y")
return d.year*10000 + d.month*100 + d.day return t.tm_year*10000 + t.tm_mon*100 + t.tm_mday
__version__ = get_version_number() __version__ = get_version_number()

View File

@ -729,12 +729,11 @@ class lammps(object):
def extract_global(self, name, dtype=LAMMPS_AUTODETECT): def extract_global(self, name, dtype=LAMMPS_AUTODETECT):
"""Query LAMMPS about global settings of different types. """Query LAMMPS about global settings of different types.
This is a wrapper around the :cpp:func:`lammps_extract_global` This is a wrapper around the :cpp:func:`lammps_extract_global` function
function of the C-library interface. Unlike the C function of the C-library interface. Since there are no pointers in Python, this
this method returns the value and not a pointer and thus can method will - unlike the C function - return the value or a list of
only return the first value for keywords representing a list values. The :cpp:func:`lammps_extract_global` documentation includes a
of values. The :cpp:func:`lammps_extract_global` documentation list of the supported keywords and their data types.
includes a list of the supported keywords and their data types.
Since Python needs to know the data type to be able to interpret Since Python needs to know the data type to be able to interpret
the result, by default, this function will try to auto-detect the data type the result, by default, this function will try to auto-detect the data type
by asking the library. You can also force a specific data type. For that by asking the library. You can also force a specific data type. For that
@ -746,12 +745,23 @@ class lammps(object):
:type name: string :type name: string
:param dtype: data type of the returned data (see :ref:`py_datatype_constants`) :param dtype: data type of the returned data (see :ref:`py_datatype_constants`)
:type dtype: int, optional :type dtype: int, optional
:return: value of the property or None :return: value of the property or list of values or None
:rtype: int, float, or NoneType :rtype: int, float, list, or NoneType
""" """
if dtype == LAMMPS_AUTODETECT: if dtype == LAMMPS_AUTODETECT:
dtype = self.extract_global_datatype(name) dtype = self.extract_global_datatype(name)
# set length of vector for items that are not a scalar
vec_dict = { 'boxlo':3, 'boxhi':3, 'sublo':3, 'subhi':3,
'sublo_lambda':3, 'subhi_lambda':3, 'periodicity':3 }
if name in vec_dict:
veclen = vec_dict[name]
elif name == 'respa_dt':
veclen = self.extract_global('respa_levels',LAMMPS_INT)
else:
veclen = 1
if name: name = name.encode() if name: name = name.encode()
else: return None else: return None
@ -766,14 +776,19 @@ class lammps(object):
target_type = float target_type = float
elif dtype == LAMMPS_STRING: elif dtype == LAMMPS_STRING:
self.lib.lammps_extract_global.restype = c_char_p self.lib.lammps_extract_global.restype = c_char_p
target_type = lambda x: str(x, 'ascii')
ptr = self.lib.lammps_extract_global(self.lmp, name) ptr = self.lib.lammps_extract_global(self.lmp, name)
if ptr: if ptr:
return target_type(ptr[0]) if dtype == LAMMPS_STRING:
return ptr.decode('utf-8')
if veclen > 1:
result = []
for i in range(0,veclen):
result.append(target_type(ptr[i]))
return result
else: return target_type(ptr[0])
return None return None
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# extract per-atom info datatype # extract per-atom info datatype

View File

@ -12,11 +12,11 @@
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
Contributing authors: Axel Kohlmeyer (Temple U), Contributing authors: Axel Kohlmeyer (Temple U),
Ryan S. Elliott (UMN) Ryan S. Elliott (UMN),
Ellad B. Tadmor (UMN) Ellad B. Tadmor (UMN),
Ronald Miller (Carleton U) Ronald Miller (Carleton U),
Yaser Afshar (UMN) Yaser Afshar (UMN)
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -65,6 +65,7 @@
#include "error.h" #include "error.h"
#include "fix_store_kim.h" #include "fix_store_kim.h"
#include "input.h" #include "input.h"
#include "variable.h"
#include "modify.h" #include "modify.h"
#include "update.h" #include "update.h"
@ -129,6 +130,7 @@ void KimInteractions::do_setup(int narg, char **arg)
"=======\n"); "=======\n");
if (simulatorModel) { if (simulatorModel) {
auto first_visit = input->variable->find("kim_update");
if (!fixed_types) { if (!fixed_types) {
std::string atom_type_sym_list = std::string atom_type_sym_list =
fmt::format("{}", fmt::join(arg, arg + narg, " ")); fmt::format("{}", fmt::join(arg, arg + narg, " "));
@ -198,15 +200,17 @@ void KimInteractions::do_setup(int narg, char **arg)
const std::string sim_field_str(sim_field); const std::string sim_field_str(sim_field);
if (sim_field_str == "model-defn") { if (sim_field_str == "model-defn") {
if (first_visit < 0) input->one("variable kim_update equal 0");
else input->one("variable kim_update equal 1");
if (domain->periodicity[0] && if (domain->periodicity[0] &&
domain->periodicity[1] && domain->periodicity[1] &&
domain->periodicity[2]) domain->periodicity[2])
input->one("variable kim_periodic equal 1"); input->one("variable kim_periodic equal 1");
else if (domain->periodicity[0] && else if (!domain->periodicity[0] &&
domain->periodicity[1] && !domain->periodicity[1] &&
!domain->periodicity[2]) !domain->periodicity[2])
input->one("variable kim_periodic equal 2"); input->one("variable kim_periodic equal 0");
else input->one("variable kim_periodic equal 0"); else input->one("variable kim_periodic equal 2");
// KIM Simulator Model has a Model definition // KIM Simulator Model has a Model definition
no_model_definition = false; no_model_definition = false;
@ -241,6 +245,7 @@ void KimInteractions::do_setup(int narg, char **arg)
} else { } else {
// not a simulator model. issue pair_style and pair_coeff commands. // not a simulator model. issue pair_style and pair_coeff commands.
if (fixed_types) if (fixed_types)

View File

@ -55,6 +55,16 @@ PythonImpl::PythonImpl(LAMMPS *lmp) : Pointers(lmp)
nfunc = 0; nfunc = 0;
pfuncs = nullptr; pfuncs = nullptr;
// check for PYTHONUNBUFFERED environment variable
const char * PYTHONUNBUFFERED = getenv("PYTHONUNBUFFERED");
if (PYTHONUNBUFFERED != nullptr && strcmp(PYTHONUNBUFFERED, "1") == 0) {
// Python Global configuration variable
// Force the stdout and stderr streams to be unbuffered.
Py_UnbufferedStdioFlag = 1;
}
// one-time initialization of Python interpreter // one-time initialization of Python interpreter
// pyMain stores pointer to main module // pyMain stores pointer to main module
external_interpreter = Py_IsInitialized(); external_interpreter = Py_IsInitialized();
@ -496,6 +506,7 @@ int PythonImpl::create_entry(char *name)
"cannot be used unless output is a string"); "cannot be used unless output is a string");
pfuncs[ifunc].length_longstr = length_longstr; pfuncs[ifunc].length_longstr = length_longstr;
pfuncs[ifunc].longstr = new char[length_longstr+1]; pfuncs[ifunc].longstr = new char[length_longstr+1];
pfuncs[ifunc].longstr[length_longstr] = '\0';
} }
if (strstr(ostr,"v_") != ostr) error->all(FLERR,"Invalid python command"); if (strstr(ostr,"v_") != ostr) error->all(FLERR,"Invalid python command");

View File

@ -551,7 +551,7 @@ void PairOxdna2Coaxstk::coeff(int narg, char **arg)
{ {
int count; int count;
if (narg != 21) error->all(FLERR,"Incorrect args for pair coefficients in oxdna/coaxstk"); if (narg != 21) error->all(FLERR,"Incorrect args for pair coefficients in oxdna2/coaxstk");
if (!allocated) allocate(); if (!allocated) allocate();
int ilo,ihi,jlo,jhi; int ilo,ihi,jlo,jhi;
@ -673,7 +673,7 @@ void PairOxdna2Coaxstk::coeff(int narg, char **arg)
} }
} }
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients in oxdna/coaxstk"); if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients in oxdna2/coaxstk");
} }

View File

@ -273,7 +273,7 @@ void PairOxdna2Dh::coeff(int narg, char **arg)
{ {
int count; int count;
if (narg != 5) error->all(FLERR,"Incorrect args for pair coefficients in oxdna/dh"); if (narg != 5) error->all(FLERR,"Incorrect args for pair coefficients in oxdna2/dh");
if (!allocated) allocate(); if (!allocated) allocate();
int ilo,ihi,jlo,jhi; int ilo,ihi,jlo,jhi;
@ -356,7 +356,7 @@ void PairOxdna2Dh::coeff(int narg, char **arg)
} }
} }
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients in oxdna/dh"); if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients in oxdna2/dh");
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------

View File

@ -1022,7 +1022,7 @@ void PairOxrna2Stk::coeff(int narg, char **arg)
} }
} }
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients in oxdna/stk"); if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients in oxrna2/stk");
} }

View File

@ -576,7 +576,7 @@ void PairOxrna2Xstk::coeff(int narg, char **arg)
{ {
int count; int count;
if (narg != 22) error->all(FLERR,"Incorrect args for pair coefficients in oxdna/xstk"); if (narg != 22) error->all(FLERR,"Incorrect args for pair coefficients in oxrna2/xstk");
if (!allocated) allocate(); if (!allocated) allocate();
int ilo,ihi,jlo,jhi; int ilo,ihi,jlo,jhi;
@ -707,7 +707,7 @@ void PairOxrna2Xstk::coeff(int narg, char **arg)
} }
} }
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients in oxdna/xstk"); if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients in oxrna2/xstk");
} }

View File

@ -31,12 +31,14 @@
#include "group.h" #include "group.h"
#include "info.h" #include "info.h"
#include "input.h" #include "input.h"
#include "integrate.h"
#include "memory.h" #include "memory.h"
#include "modify.h" #include "modify.h"
#include "molecule.h" #include "molecule.h"
#include "neigh_list.h" #include "neigh_list.h"
#include "neighbor.h" #include "neighbor.h"
#include "region.h" #include "region.h"
#include "respa.h"
#include "output.h" #include "output.h"
#include "thermo.h" #include "thermo.h"
#include "timer.h" #include "timer.h"
@ -984,12 +986,14 @@ to then decide how to cast the (void*) pointer and access the data.
* \return integer constant encoding the data type of the property * \return integer constant encoding the data type of the property
* or -1 if not found. */ * or -1 if not found. */
int lammps_extract_global_datatype(void *handle, const char *name) int lammps_extract_global_datatype(void * /*handle*/, const char *name)
{ {
if (strcmp(name,"dt") == 0) return LAMMPS_DOUBLE; if (strcmp(name,"dt") == 0) return LAMMPS_DOUBLE;
if (strcmp(name,"ntimestep") == 0) return LAMMPS_BIGINT; if (strcmp(name,"ntimestep") == 0) return LAMMPS_BIGINT;
if (strcmp(name,"atime") == 0) return LAMMPS_DOUBLE; if (strcmp(name,"atime") == 0) return LAMMPS_DOUBLE;
if (strcmp(name,"atimestep") == 0) return LAMMPS_BIGINT; if (strcmp(name,"atimestep") == 0) return LAMMPS_BIGINT;
if (strcmp(name,"respa_levels") == 0) return LAMMPS_INT;
if (strcmp(name,"respa_dt") == 0) return LAMMPS_DOUBLE;
if (strcmp(name,"boxlo") == 0) return LAMMPS_DOUBLE; if (strcmp(name,"boxlo") == 0) return LAMMPS_DOUBLE;
if (strcmp(name,"boxhi") == 0) return LAMMPS_DOUBLE; if (strcmp(name,"boxhi") == 0) return LAMMPS_DOUBLE;
@ -1116,6 +1120,14 @@ report the "native" data type. The following tables are provided:
- bigint - bigint
- 1 - 1
- the number of the timestep when "atime" was last updated. - the number of the timestep when "atime" was last updated.
* - respa_levels
- int
- 1
- number of r-RESPA levels. See :doc:`run_style`.
* - respa_dt
- double
- number of r-RESPA levels
- length of the time steps with r-RESPA. See :doc:`run_style`.
.. _extract_box_settings: .. _extract_box_settings:
@ -1366,12 +1378,22 @@ void *lammps_extract_global(void *handle, const char *name)
if (strcmp(name,"atime") == 0) return (void *) &lmp->update->atime; if (strcmp(name,"atime") == 0) return (void *) &lmp->update->atime;
if (strcmp(name,"atimestep") == 0) return (void *) &lmp->update->atimestep; if (strcmp(name,"atimestep") == 0) return (void *) &lmp->update->atimestep;
if (utils::strmatch(lmp->update->integrate_style,"^respa")) {
Respa *respa = (Respa *)lmp->update->integrate;
if (strcmp(name,"respa_levels") == 0) return (void *) &respa->nlevels;
if (strcmp(name,"respa_dt") == 0) return (void *) respa->step;
}
if (strcmp(name,"boxlo") == 0) return (void *) lmp->domain->boxlo; if (strcmp(name,"boxlo") == 0) return (void *) lmp->domain->boxlo;
if (strcmp(name,"boxhi") == 0) return (void *) lmp->domain->boxhi; if (strcmp(name,"boxhi") == 0) return (void *) lmp->domain->boxhi;
if (strcmp(name,"sublo") == 0) return (void *) lmp->domain->sublo; if (strcmp(name,"sublo") == 0) return (void *) lmp->domain->sublo;
if (strcmp(name,"subhi") == 0) return (void *) lmp->domain->subhi; if (strcmp(name,"subhi") == 0) return (void *) lmp->domain->subhi;
if (strcmp(name,"sublo_lambda") == 0) return (void *) lmp->domain->sublo_lamda; // these are only valid for a triclinic cell
if (strcmp(name,"subhi_lambda") == 0) return (void *) lmp->domain->subhi_lamda; if (lmp->domain->triclinic) {
if (strcmp(name,"sublo_lambda") == 0)
return (void *) lmp->domain->sublo_lamda;
if (strcmp(name,"subhi_lambda") == 0)
return (void *) lmp->domain->subhi_lamda;
}
if (strcmp(name,"boxxlo") == 0) return (void *) &lmp->domain->boxlo[0]; if (strcmp(name,"boxxlo") == 0) return (void *) &lmp->domain->boxlo[0];
if (strcmp(name,"boxxhi") == 0) return (void *) &lmp->domain->boxhi[0]; if (strcmp(name,"boxxhi") == 0) return (void *) &lmp->domain->boxhi[0];
if (strcmp(name,"boxylo") == 0) return (void *) &lmp->domain->boxlo[1]; if (strcmp(name,"boxylo") == 0) return (void *) &lmp->domain->boxlo[1];

View File

@ -851,6 +851,14 @@ std::vector<std::string> utils::split_words(const std::string &text)
return list; return list;
} }
/* ----------------------------------------------------------------------
Convert multi-line string into lines
------------------------------------------------------------------------- */
std::vector<std::string> utils::split_lines(const std::string &text)
{
return Tokenizer(text, "\n").as_vector();
}
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
Return whether string is a valid integer number Return whether string is a valid integer number
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */

View File

@ -321,6 +321,12 @@ namespace LAMMPS_NS {
std::vector<std::string> split_words(const std::string &text); std::vector<std::string> split_words(const std::string &text);
/** Take multi-line text and split into lines
*
* \param text string that should be split
* \return STL vector with the lines */
std::vector<std::string> split_lines(const std::string &text);
/** Check if string can be converted to valid integer /** Check if string can be converted to valid integer
* *
* \param str string that should be checked * \param str string that should be checked

View File

@ -124,7 +124,7 @@ file(GLOB FIX_TIMESTEP_TESTS LIST_DIRECTORIES false ${TEST_INPUT_FOLDER}/fix-tim
foreach(TEST ${FIX_TIMESTEP_TESTS}) foreach(TEST ${FIX_TIMESTEP_TESTS})
string(REGEX REPLACE "^.*fix-timestep-(.*)\.yaml" "FixTimestep:\\1" TNAME ${TEST}) 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}) 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() endforeach()
# dihedral style tester # 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_link_libraries(test_python_package PRIVATE lammps GTest::GMock GTest::GTest)
target_compile_definitions(test_python_package PRIVATE -DTEST_INPUT_FOLDER=${TEST_INPUT_FOLDER}) 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}) 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 # we must have shared libraries enabled for testing the python module
if(NOT BUILD_SHARED_LIBS) if(NOT BUILD_SHARED_LIBS)

View File

@ -4,6 +4,16 @@ from __future__ import print_function
def square(val): def square(val):
return val*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(): def printnum():
print("2.25") print("2.25")
@ -11,8 +21,10 @@ def printtxt():
print("sometext") print("sometext")
def getidxvar(lmpptr): def getidxvar(lmpptr):
from lammps import lammps, LMP_VAR_EQUAL from lammps import lammps
lmp = lammps(ptr=lmpptr) lmp = lammps(ptr=lmpptr)
val = lmp.extract_variable("idx")
val = lmp.extract_variable("idx",None,LMP_VAR_EQUAL)
print(val) 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) result = self.lmp.get_thermo(key)
self.assertEqual(value, result, 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("region box block -1 1 -2 2 -3 3")
self.lmp.command("create_box 1 box") 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("boxxlo"), -1.0)
self.assertEqual(self.lmp.extract_global("boxxhi"), 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("boxylo"), -2.0)
self.assertEqual(self.lmp.extract_global("boxyhi"), 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("boxzlo"), -3.0)
self.assertEqual(self.lmp.extract_global("boxzhi"), 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__": 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 "atom.h"
#include "info.h" #include "info.h"
#include "input.h" #include "input.h"
#include "variable.h"
#include "library.h"
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <vector> #include <vector>
#include <functional>
#include "../testing/core.h"
#include "../testing/systems/melt.h"
// location of '*.py' files required by tests // location of '*.py' files required by tests
#define STRINGIFY(val) XSTR(val) #define STRINGIFY(val) XSTR(val)
#define XSTR(val) #val #define XSTR(val) #val
std::string INPUT_FOLDER = STRINGIFY(TEST_INPUT_FOLDER); 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; bool verbose = false;
using LAMMPS_NS::utils::split_words; using LAMMPS_NS::utils::split_words;
@ -34,95 +40,287 @@ using LAMMPS_NS::utils::split_words;
namespace LAMMPS_NS { namespace LAMMPS_NS {
using ::testing::MatchesRegex; using ::testing::MatchesRegex;
using ::testing::StrEq; using ::testing::StrEq;
using ::testing::Eq;
using ::testing::HasSubstr;
class PythonPackageTest : public ::testing::Test { class PythonPackageTest : public LAMMPSTest {
protected: protected:
LAMMPS *lmp; void InitSystem() override
Info *info;
void SetUp() override
{ {
const char *args[] = {"PythonPackageTest", "-log", "none", "-echo", "screen", "-nocite"}; if (!info->has_package("PYTHON")) GTEST_SKIP();
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();
}
void TearDown() override HIDE_OUTPUT([&] {
{ command("units real");
if (!verbose) ::testing::internal::CaptureStdout(); command("dimension 3");
delete info; command("region box block -4 4 -4 4 -4 4");
delete lmp; command("create_box 1 box");
if (!verbose) ::testing::internal::GetCapturedStdout(); 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 // execute python function from file
if (!verbose) ::testing::internal::CaptureStdout(); HIDE_OUTPUT([&] {
lmp->input->one("python printnum file ${input_dir}/func.py"); command("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.*"));
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 // execute another python function from same file
if (!verbose) ::testing::internal::CaptureStdout(); HIDE_OUTPUT([&] {
lmp->input->one("python printtxt exists"); command("python printnum file ${input_dir}/func.py");
if (!verbose) ::testing::internal::GetCapturedStdout(); command("python printtxt exists");
::testing::internal::CaptureStdout(); });
lmp->input->one("python printtxt invoke");
output = ::testing::internal::GetCapturedStdout();
if (verbose) std::cout << output;
ASSERT_THAT(output, MatchesRegex("python.*sometext.*"));
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 // execute python function that uses the LAMMPS python module
if (!verbose) ::testing::internal::CaptureStdout(); HIDE_OUTPUT([&] {
lmp->input->one("variable idx equal 2.25"); command("python printnum file ${input_dir}/func.py");
lmp->input->one("python getidxvar input 1 SELF format p exists"); command("variable idx equal 2.25");
if (!verbose) ::testing::internal::GetCapturedStdout(); command("python getidxvar input 1 SELF format p exists");
::testing::internal::CaptureStdout(); });
lmp->input->one("python getidxvar invoke"); auto output = CAPTURE_OUTPUT([&] {
output = ::testing::internal::GetCapturedStdout(); command("python getidxvar invoke");
if (verbose) std::cout << output; });
ASSERT_THAT(output, MatchesRegex("python.*2.25.*")); ASSERT_THAT(output, HasSubstr("2.25\n"));
} }
TEST_F(PythonPackageTest, python_variable) TEST_F(PythonPackageTest, python_variable)
{ {
if (!info->has_style("command", "python")) GTEST_SKIP(); // define variable that evaluates a python function
if (!verbose) ::testing::internal::CaptureStdout(); HIDE_OUTPUT([&] {
lmp->input->one("variable sq python square"); command("variable sq python square");
lmp->input->one("variable val index 1.5"); command("variable val index 1.5");
lmp->input->one("python square input 1 v_val return v_sq format ff file ${input_dir}/func.py"); command("python square input 1 v_val return v_sq format ff file ${input_dir}/func.py");
if (!verbose) ::testing::internal::GetCapturedStdout(); });
::testing::internal::CaptureStdout(); std::string output = CAPTURE_OUTPUT([&] {
lmp->input->one("print \"${sq}\""); command("print \"${sq}\"");
std::string output = ::testing::internal::GetCapturedStdout(); });
if (verbose) std::cout << output;
ASSERT_THAT(output, MatchesRegex("print.*2.25.*")); 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 } // namespace LAMMPS_NS
int main(int argc, char **argv) int main(int argc, char **argv)
@ -132,7 +330,7 @@ int main(int argc, char **argv)
// handle arguments passed via environment variable // handle arguments passed via environment variable
if (const char *var = getenv("TEST_ARGS")) { if (const char *var = getenv("TEST_ARGS")) {
std::vector<std::string> env = split_words(var); auto env = split_words(var);
for (auto arg : env) { for (auto arg : env) {
if (arg == "-v") { if (arg == "-v") {
verbose = true; verbose = true;

View File

@ -16,9 +16,12 @@
#include "info.h" #include "info.h"
#include "input.h" #include "input.h"
#include "lammps.h" #include "lammps.h"
#include "variable.h"
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include <functional>
using namespace LAMMPS_NS; using namespace LAMMPS_NS;
using ::testing::MatchesRegex; using ::testing::MatchesRegex;
@ -45,29 +48,58 @@ class LAMMPSTest : public ::testing::Test {
public: public:
void command(const std::string &line) { lmp->input->one(line.c_str()); } 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: protected:
const char *testbinary = "LAMMPSTest"; const char *testbinary = "LAMMPSTest";
LAMMPS *lmp; LAMMPS *lmp;
Info *info;
void SetUp() override void SetUp() override
{ {
const char *args[] = {testbinary, "-log", "none", "-echo", "screen", "-nocite"}; const char *args[] = {testbinary, "-log", "none", "-echo", "screen", "-nocite"};
char **argv = (char **)args; char **argv = (char **)args;
int argc = sizeof(args) / sizeof(char *); int argc = sizeof(args) / sizeof(char *);
if (!verbose) ::testing::internal::CaptureStdout(); HIDE_OUTPUT([&] {
lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD);
info = new Info(lmp);
});
InitSystem(); InitSystem();
if (!verbose) ::testing::internal::GetCapturedStdout();
} }
virtual void InitSystem() {} virtual void InitSystem() {}
void TearDown() override void TearDown() override
{ {
if (!verbose) ::testing::internal::CaptureStdout(); HIDE_OUTPUT([&] {
delete lmp; delete info;
lmp = nullptr; delete lmp;
if (!verbose) ::testing::internal::GetCapturedStdout(); info = nullptr;
lmp = nullptr;
});
} }
}; };

View File

@ -19,23 +19,25 @@ class MeltTest : public LAMMPSTest {
protected: protected:
virtual void InitSystem() override virtual void InitSystem() override
{ {
command("units lj"); HIDE_OUTPUT([&] {
command("atom_style atomic"); command("units lj");
command("atom_modify map yes"); command("atom_style atomic");
command("atom_modify map yes");
command("lattice fcc 0.8442"); command("lattice fcc 0.8442");
command("region box block 0 2 0 2 0 2"); command("region box block 0 2 0 2 0 2");
command("create_box 1 box"); command("create_box 1 box");
command("create_atoms 1 box"); command("create_atoms 1 box");
command("mass 1 1.0"); 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_style lj/cut 2.5");
command("pair_coeff 1 1 1.0 1.0 2.5"); command("pair_coeff 1 1 1.0 1.0 2.5");
command("neighbor 0.3 bin"); command("neighbor 0.3 bin");
command("neigh_modify every 20 delay 0 check no"); 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) 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_EQ(list.size(), 3);
ASSERT_THAT(list[0], StrEq("one")); ASSERT_THAT(list[0], StrEq("one"));
ASSERT_THAT(list[1], StrEq("two")); ASSERT_THAT(list[1], StrEq("two"));
@ -122,7 +122,7 @@ TEST(Utils, split_words_simple)
TEST(Utils, split_words_quoted) 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_EQ(list.size(), 3);
ASSERT_THAT(list[0], StrEq("one")); ASSERT_THAT(list[0], StrEq("one"));
ASSERT_THAT(list[1], StrEq("two")); ASSERT_THAT(list[1], StrEq("two"));
@ -131,7 +131,7 @@ TEST(Utils, split_words_quoted)
TEST(Utils, split_words_escaped) 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_EQ(list.size(), 3);
ASSERT_THAT(list[0], StrEq("1\\'")); ASSERT_THAT(list[0], StrEq("1\\'"));
ASSERT_THAT(list[1], StrEq("\"two\"")); ASSERT_THAT(list[1], StrEq("\"two\""));
@ -140,13 +140,22 @@ TEST(Utils, split_words_escaped)
TEST(Utils, split_words_quote_in_quoted) 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_EQ(list.size(), 3);
ASSERT_THAT(list[0], StrEq("one")); ASSERT_THAT(list[0], StrEq("one"));
ASSERT_THAT(list[1], StrEq("t\\'wo")); ASSERT_THAT(list[1], StrEq("t\\'wo"));
ASSERT_THAT(list[2], StrEq("th\\\"ree")); 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) TEST(Utils, valid_integer1)
{ {
ASSERT_TRUE(utils::is_integer("10")); ASSERT_TRUE(utils::is_integer("10"));