diff --git a/doc/src/pg_lib_config.rst b/doc/src/pg_lib_config.rst index 9576e31dcd..d33afe3b5b 100644 --- a/doc/src/pg_lib_config.rst +++ b/doc/src/pg_lib_config.rst @@ -1,9 +1,51 @@ Retrieving LAMMPS configuration information =========================================== -The following library functions can be used to query the -LAMMPS library about compile time settings and included -packages and styles. +The following library functions can be used to query the LAMMPS library +about compile time settings and included packages and styles. This +enables programs that use the library interface to run LAMMPS +simulations to determine, whether the linked LAMMPS library is compatible +with the requirements of the application without crashing during the +LAMMPS functions (e.g. due to missing pair styles from packages) or to +choose between different options (e.g. whether to use ``lj/cut``, +``lj/cut/opt``, ``lj/cut/omp`` or ``lj/cut/intel``). Most of the +functions can be called directly without first creating a LAMMPS +instance. While crashes within LAMMPS may be recovered from through +enabling :ref:`exceptions `, avoiding them proactively is +a safer approach. + +.. code-block:: C + :caption: Example for using configuration settings functions + + #include "library.h" + #include + + int main(int argc, char **argv) + { + void *handle; + + handle = lammps_open_no_mpi(0, NULL, NULL); + lammps_file(handle, "in.missing"); + if (lammps_has_error(handle)) { + char errmsg[256]; + int errtype; + errtype = lammps_get_last_error_message(handle, errmsg, 256); + fprintf(stderr, "LAMMPS failed with error: %s\n", errmsg); + return 1; + } + /* write compressed dump file depending on available of options */ + if (lammps_has_style(handle, "dump", "atom/zstd")) { + lammps_command(handle, "dump d1 all atom/zstd 100 dump.zst"); + } else if (lammps_has_style(handle, "dump", "atom/gz")) { + lammps_command(handle, "dump d1 all atom/gz 100 dump.gz"); + } else if (lammps_config_has_gzip_support()) { + lammps_command(handle, "dump d1 all atom 100 dump.gz"); + } else { + lammps_command(handle, "dump d1 all atom 100 dump"); + } + lammps_close(handle); + return 0; + } ----------------------- diff --git a/doc/src/pg_lib_properties.rst b/doc/src/pg_lib_properties.rst index cdc7617d91..65ce9cf940 100644 --- a/doc/src/pg_lib_properties.rst +++ b/doc/src/pg_lib_properties.rst @@ -2,8 +2,8 @@ Retrieving or setting LAMMPS system properties ============================================== The library interface allows to extract different kinds of information -about the active simulation instance and also to modify some of them. -This allows to combine MD simulation steps with other processing and +about the active simulation instance and also to modify some of it. +This enables combining MD simulation steps with other processing and simulation methods computed in the calling code or another code that is coupled to LAMMPS via the library interface. In some cases the data returned is direct reference to the original data inside LAMMPS cast @@ -14,6 +14,34 @@ is the per-processor **local** data and indexed accordingly. These arrays can change sizes and order at every neighbor list rebuild and atom sort event as atoms are migrating between sub-domains. +.. code-block:: C + + #include "library.h" + #include + + int main(int argc, char **argv) + { + void *handle; + int i; + + handle = lammps_open_no_mpi(0, NULL, NULL); + lammps_file(handle,"in.sysinit"); + printf("running simulation with %g atoms\n", + lammps_get_natoms(handle)); + + lammps_command(handle,"run 1000 post no"); + + for (i=0; i < 10; ++i) { + lammps_command(handle,"run 100 pre no post no"); + printf("PE = %g\nKE = %g\n", + lammps_get_thermo(handle,"pe"), + lammps_get_thermo(handle,"ke")); + } + lammps_close(handle); + return 0; + } + + ----------------------- .. doxygenfunction:: lammps_version diff --git a/src/atom.cpp b/src/atom.cpp index 49ff262764..f28237cf74 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -2508,7 +2508,7 @@ length of the data area, and a short description. Typically the name of the pointer variable returned * \return pointer to the requested data cast to ``void *`` or NULL */ -void *Atom::extract(char *name) +void *Atom::extract(const char *name) { // -------------------------------------------------------------------- // 4th customization section: customize by adding new variable name diff --git a/src/atom.h b/src/atom.h index 21b9c06f8c..728d420596 100644 --- a/src/atom.h +++ b/src/atom.h @@ -331,7 +331,7 @@ class Atom : protected Pointers { virtual void sync_modify(ExecutionSpace, unsigned int, unsigned int) {} - void *extract(char *); + void *extract(const char *); inline int* get_map_array() {return map_array;}; inline int get_map_size() {return map_tag_max+1;}; diff --git a/src/library.cpp b/src/library.cpp index 0e0c4070ea..7abc0df38a 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -69,7 +69,7 @@ using namespace LAMMPS_NS; #ifdef LAMMPS_EXCEPTIONS #define BEGIN_CAPTURE \ - Error * error = lmp->error; \ + Error *error = lmp->error; \ try #define END_CAPTURE \ @@ -594,7 +594,7 @@ double lammps_get_natoms(void *handle) { LAMMPS *lmp = (LAMMPS *) handle; - double natoms = static_cast (lmp->atom->natoms); + double natoms = static_cast(lmp->atom->natoms); if (natoms > 9.0e15) return 0; // TODO:XXX why not -1? return natoms; } @@ -616,7 +616,7 @@ a double, so it can also return information that is computed on-the-fly. * \param keyword string with the name of the thermo keyword * \return value of the requested thermo property or 0.0 */ -double lammps_get_thermo(void *handle, char *keyword) +double lammps_get_thermo(void *handle, const char *keyword) { LAMMPS *lmp = (LAMMPS *) handle; double dval = 0.0; @@ -807,7 +807,7 @@ recognized, the function returns -1. Please also see :cpp:func:`lammps_extract_ * \param keyword string with the name of the thermo keyword * \return value of the queried setting or -1 if unknown */ -int lammps_extract_setting(void * handle, char *keyword) +int lammps_extract_setting(void *handle, const char *keyword) { LAMMPS *lmp = (LAMMPS *) handle; @@ -865,7 +865,8 @@ Please also see :cpp:func:`lammps_extract_setting`, This table lists the supported names, their data types, length of the data area, and a short description. The ``bigint`` type may be defined to be either an ``int`` or an ``int64_t``. This is selected at -:ref:`compile time `. +:ref:`compile time ` and can be queried through calling +:cpp:func:`lammps_extract_setting`. .. list-table:: :header-rows: 1 @@ -1073,7 +1074,7 @@ to be either an ``int`` or an ``int64_t``. This is selected at * \return pointer (cast to ``void *``) to the location of the requested property. NULL if name is not known. */ -void *lammps_extract_global(void *handle, char *name) +void *lammps_extract_global(void *handle, const char *name) { LAMMPS *lmp = (LAMMPS *) handle; @@ -1165,7 +1166,7 @@ of the :cpp:func:`Atom::extract() ` function. * \return pointer (cast to ``void *``) to the location of the * requested data or ``NULL`` if not found. */ -void *lammps_extract_atom(void *handle, char *name) +void *lammps_extract_atom(void *handle, const char *name) { LAMMPS *lmp = (LAMMPS *) handle; return lmp->atom->extract(name); @@ -3724,7 +3725,7 @@ specific :doc:`LAMMPS package ` provided as argument. * \param name string with the name of the package * \return 1 if included, 0 if not. */ -int lammps_config_has_package(char * name) { +int lammps_config_has_package(const char *name) { return Info::has_package(name) ? 1 : 0; } @@ -3764,7 +3765,7 @@ the function returns 0 and *buffer* is set to an empty string, otherwise 1; * \param buf_size size of the provided string buffer * \return 1 if successful, otherwise 0 */ -int lammps_config_package_name(int idx, char * buffer, int buf_size) { +int lammps_config_package_name(int idx, char *buffer, int buf_size) { int maxidx = lammps_config_package_count(); if ((idx < 0) || (idx >= maxidx)) { buffer[0] = '\0'; @@ -3788,14 +3789,14 @@ Valid categories are: *atom*\ , *integrate*\ , *minimize*\ , \endverbatim * * \param handle pointer to a previously created LAMMPS instance cast to ``void *``. - * \param category category of the style - * \param name name of the style - * \return 1 if included, 0 if not. + * \param category category of the style + * \param name name of the style + * \return 1 if included, 0 if not. */ -int lammps_has_style(void * handle, char * category, char * name) { +int lammps_has_style(void *handle, const char *category, const char *name) { LAMMPS *lmp = (LAMMPS *) handle; Info info(lmp); - return info.has_style(category, name) ? 0 : 1; + return info.has_style(category, name) ? 1 : 0; } /* ---------------------------------------------------------------------- */ @@ -3813,7 +3814,7 @@ categories. * \param category category of styles * \return number of styles in category */ -int lammps_style_count(void * handle, char * category) { +int lammps_style_count(void *handle, const char *category) { LAMMPS *lmp = (LAMMPS *) handle; Info info(lmp); return info.get_available_styles(category).size(); @@ -3839,7 +3840,8 @@ Please see :cpp:func:`lammps_has_style` for a list of valid categories. * \param buf_size size of the provided string buffer * \return 1 if successful, otherwise 0 */ -int lammps_style_name(void* handle, char * category, int idx, char * buffer, int buf_size) { +int lammps_style_name(void *handle, const char *category, int idx, + char *buffer, int buf_size) { LAMMPS *lmp = (LAMMPS *) handle; Info info(lmp); auto styles = info.get_available_styles(category); @@ -4265,10 +4267,10 @@ the failing MPI ranks to send messages. * \param buf_size size of the provided string buffer * \return 1 when all ranks had the error, 1 on a single rank error. */ -int lammps_get_last_error_message(void *handle, char * buffer, int buf_size) { +int lammps_get_last_error_message(void *handle, char *buffer, int buf_size) { #ifdef LAMMPS_EXCEPTIONS - LAMMPS * lmp = (LAMMPS *) handle; - Error * error = lmp->error; + LAMMPS *lmp = (LAMMPS *) handle; + Error *error = lmp->error; if(!error->get_last_error().empty()) { int error_type = error->get_last_error_type(); diff --git a/src/library.h b/src/library.h index f5a02502e7..0c6ca184e5 100644 --- a/src/library.h +++ b/src/library.h @@ -100,7 +100,7 @@ void lammps_commands_string(void *handle, const char *str); int lammps_version(void *handle); int lammps_get_mpi_comm(void* handle); double lammps_get_natoms(void *handle); -double lammps_get_thermo(void *handle, char *keyword); +double lammps_get_thermo(void *handle, const char *keyword); void lammps_extract_box(void *handle, double *boxlo, double *boxhi, double *xy, double *yz, double *xz, @@ -108,9 +108,9 @@ void lammps_extract_box(void *handle, double *boxlo, double *boxhi, void lammps_reset_box(void *handle, double *boxlo, double *boxhi, double xy, double yz, double xz); -int lammps_extract_setting(void *handle, char *keyword); -void *lammps_extract_global(void *handle, char *name); -void *lammps_extract_atom(void *handle, char *name); +int lammps_extract_setting(void *handle, const char *keyword); +void *lammps_extract_global(void *handle, const char *name); +void *lammps_extract_atom(void *handle, const char *name); #if !defined(LAMMPS_BIGBIG) int lammps_create_atoms(void *handle, int n, int *id, int *type, @@ -152,7 +152,7 @@ void lammps_scatter_atoms_subset(void *, char *, int, int, int, int *, void *); * ---------------------------------------------------------------------- */ int lammps_config_has_mpi_support(); -int lammps_config_has_package(char *); +int lammps_config_has_package(const char *); int lammps_config_package_count(); int lammps_config_package_name(int, char *, int); int lammps_config_has_gzip_support(); @@ -161,9 +161,9 @@ int lammps_config_has_jpeg_support(); int lammps_config_has_ffmpeg_support(); int lammps_config_has_exceptions(); -int lammps_has_style(void *, char *, char *); -int lammps_style_count(void *, char *); -int lammps_style_name(void *, char *, int, char *, int); +int lammps_has_style(void *, const char *, const char *); +int lammps_style_count(void *, const char *); +int lammps_style_name(void *, const char *, int, char *, int); /* ---------------------------------------------------------------------- * Library functions for accessing neighbor lists diff --git a/unittest/c-library/CMakeLists.txt b/unittest/c-library/CMakeLists.txt index 90c57f1fa7..fe70cb1584 100644 --- a/unittest/c-library/CMakeLists.txt +++ b/unittest/c-library/CMakeLists.txt @@ -1,13 +1,57 @@ -add_executable(test_library_open test_library_open.cpp) -target_link_libraries(test_library_open PRIVATE lammps GTest::GTest GTest::GTestMain) +add_executable(test_library_open test_library_open.cpp test_main.cpp) +target_link_libraries(test_library_open PRIVATE lammps GTest::GTest GTest::GMock) add_test(LibraryOpen test_library_open) -add_executable(test_library_commands test_library_commands.cpp) -target_link_libraries(test_library_commands PRIVATE lammps GTest::GTest GTest::GTestMain) +add_executable(test_library_commands test_library_commands.cpp test_main.cpp) +target_link_libraries(test_library_commands PRIVATE lammps GTest::GTest GTest::GMock) add_test(LibraryCommands test_library_commands) -add_executable(test_library_properties test_library_properties.cpp) -target_link_libraries(test_library_properties PRIVATE lammps GTest::GTest GTest::GTestMain) +add_executable(test_library_properties test_library_properties.cpp test_main.cpp) +target_link_libraries(test_library_properties PRIVATE lammps GTest::GTest GTest::GMock) +target_compile_definitions(test_library_properties PRIVATE -DTEST_INPUT_FOLDER=${CMAKE_CURRENT_SOURCE_DIR}) add_test(LibraryProperties test_library_properties) +set(TEST_CONFIG_DEFS "-DTEST_INPUT_FOLDER=${CMAKE_CURRENT_SOURCE_DIR};-DLAMMPS_${LAMMPS_SIZES}") +set(PKG_COUNT 0) +foreach(PKG ${STANDARD_PACKAGES} ${SUFFIX_PACKAGES}) + if(PKG_${PKG}) + MATH(EXPR PKG_COUNT "${PKG_COUNT}+1") + endif() +endforeach() +list(APPEND TEST_CONFIG_DEFS -DNUM_LAMMPS_PACKAGES=${PKG_COUNT}) + +if(PKG_MANYBODY) + set(HAS_MANYBODY 1) +else() + set(HAS_MANYBODY 0) +endif() +list(APPEND TEST_CONFIG_DEFS -DLAMMPS_HAS_MANYBODY=${HAS_MANYBODY}) + +if(BUILD_MPI) + set(HAS_MPI 1) +else() + set(HAS_MPI 0) +endif() +list(APPEND TEST_CONFIG_DEFS -DLAMMPS_HAS_MPI=${HAS_MPI}) + +if(LAMMPS_EXCEPTIONS) + set(HAS_EXCEPTIONS 1) +else() + set(HAS_EXCEPTIONS 0) +endif() +list(APPEND TEST_CONFIG_DEFS -DLAMMPS_HAS_EXCEPTIONS=${HAS_EXCEPTIONS}) + +foreach(WITH "JPEG" "PNG" "GZIP" "FFMPEG") + if(WITH_${WITH}) + set(HAS_${WITH} 1) + else() + set(HAS_${WITH} 0) + endif() + list(APPEND TEST_CONFIG_DEFS -DLAMMPS_HAS_${WITH}=${HAS_${WITH}}) +endforeach() + +add_executable(test_library_config test_library_config.cpp test_main.cpp) +target_link_libraries(test_library_config PRIVATE lammps GTest::GTest GTest::GMock) +target_compile_definitions(test_library_config PRIVATE ${TEST_CONFIG_DEFS}) +add_test(LibraryConfig test_library_config) diff --git a/unittest/c-library/data.fourmol b/unittest/c-library/data.fourmol new file mode 100644 index 0000000000..386ad81c49 --- /dev/null +++ b/unittest/c-library/data.fourmol @@ -0,0 +1,210 @@ +LAMMPS data file via write_data, version 5 May 2020, timestep = 0 + +29 atoms +5 atom types +24 bonds +5 bond types +30 angles +4 angle types +31 dihedrals +5 dihedral types +2 impropers +2 improper types + + -6.024572 8.975428 xlo xhi + -7.692866 7.307134 ylo yhi + -8.086924 6.913076 zlo zhi + +Masses + +1 12.0107 +2 4.00794 +3 14.0067 +4 15.9994 +5 15.9994 + +Pair Coeffs # zero + +1 +2 +3 +4 +5 + +Bond Coeffs # zero + +1 1.5 +2 1.1 +3 1.3 +4 1.2 +5 1 + +Angle Coeffs # zero + +1 110.1 +2 111 +3 120 +4 108.5 + +Atoms # full + +10 2 1 7.0000000000000007e-02 2.0185283555536988e+00 -1.4283966846517357e+00 -9.6733527271133024e-01 0 0 0 +11 2 2 8.9999999999999997e-02 1.7929780509347666e+00 -1.9871047540768743e+00 -1.8840626643185674e+00 0 0 0 +12 2 1 -2.7000000000000002e-01 3.0030247876861225e+00 -4.8923319967572748e-01 -1.6188658531537248e+00 0 0 0 +13 2 2 8.9999999999999997e-02 4.0447273787895934e+00 -9.0131998547446246e-01 -1.6384447268320836e+00 0 0 0 +14 2 2 8.9999999999999997e-02 2.6033152817257075e+00 -4.0789761505963579e-01 -2.6554413538823063e+00 0 0 0 +2 1 2 3.1000000000000000e-01 3.0197083955402204e-01 2.9515239068888608e+00 -8.5689735572907566e-01 0 0 0 +3 1 1 -2.0000000000000000e-02 -6.9435377880558602e-01 1.2440473127136711e+00 -6.2233801468892025e-01 0 0 0 +4 1 2 8.9999999999999997e-02 -1.5771614164685133e+00 1.4915333140468066e+00 -1.2487126845040522e+00 0 0 0 +6 1 1 5.1000000000000001e-01 2.9412607937706009e-01 2.2719282656652909e-01 -1.2843094067857870e+00 0 0 0 +7 1 4 -5.1000000000000001e-01 3.4019871062879609e-01 -9.1277350075786561e-03 -2.4633113224304561e+00 0 0 0 +19 3 2 4.2359999999999998e-01 1.5349125211132961e+00 2.6315969880333707e+00 -4.2472859440220647e+00 0 0 0 +15 2 2 8.9999999999999997e-02 2.9756315249791303e+00 5.6334269722969288e-01 -1.2437650754599008e+00 0 0 0 +18 3 4 -8.4719999999999995e-01 2.1384791188033843e+00 3.0177261773770208e+00 -3.5160827596876225e+00 0 0 0 +20 3 2 4.2359999999999998e-01 2.7641167828863153e+00 3.6833419064000221e+00 -3.9380850623312638e+00 0 0 0 +8 2 3 -4.6999999999999997e-01 1.1641187171852805e+00 -4.8375305955385234e-01 -6.7659823767368688e-01 0 0 0 +9 2 2 3.1000000000000000e-01 1.3777459838125838e+00 -2.5366338669522998e-01 2.6877644730326306e-01 0 0 0 +16 2 1 5.1000000000000001e-01 2.6517554244980306e+00 -2.3957110424978438e+00 3.2908335999178327e-02 0 0 0 +17 2 4 -5.1000000000000001e-01 2.2309964792710639e+00 -2.1022918943319384e+00 1.1491948328949437e+00 0 0 0 +1 1 3 -4.6999999999999997e-01 -2.7993683669226832e-01 2.4726588069312840e+00 -1.7200860244148433e-01 0 0 0 +5 1 2 8.9999999999999997e-02 -8.9501761359359255e-01 9.3568128743071344e-01 4.0227731871484346e-01 0 0 0 +21 4 5 -8.4719999999999995e-01 4.9064454390208301e+00 -4.0751205255383196e+00 -3.6215576073601046e+00 0 0 0 +22 4 2 4.2359999999999998e-01 4.3687453488627543e+00 -4.2054270536772504e+00 -4.4651491269372565e+00 0 0 0 +23 4 2 4.2359999999999998e-01 5.7374928154769504e+00 -3.5763355905184966e+00 -3.8820297194230728e+00 0 0 0 +24 5 5 -8.4719999999999995e-01 2.0684115301174013e+00 3.1518221747664397e+00 3.1554242678474576e+00 0 0 0 +25 5 2 4.2359999999999998e-01 1.2998381073113014e+00 3.2755513587518097e+00 2.5092990173114837e+00 0 0 0 +26 5 2 4.2359999999999998e-01 2.5807438597688113e+00 4.0120175892854135e+00 3.2133398379059099e+00 0 0 0 +27 6 5 -8.4719999999999995e-01 -1.9613581876744359e+00 -4.3556300596085160e+00 2.1101467673534788e+00 0 0 0 +28 6 2 4.2359999999999998e-01 -2.7406520384725965e+00 -4.0207251278130975e+00 1.5828689861678511e+00 0 0 0 +29 6 2 4.2359999999999998e-01 -1.3108232656499081e+00 -3.5992986322410760e+00 2.2680459788743503e+00 0 0 0 + +Velocities + +1 7.7867804888392077e-04 5.8970331623292821e-04 -2.2179517633030531e-04 +2 2.7129529964126462e-03 4.6286427111164284e-03 3.5805549693846352e-03 +3 -1.2736791029204805e-03 1.6108674226414498e-03 -3.3618185901550799e-04 +4 -9.2828595122009308e-04 -1.2537885319521818e-03 -4.1204974953432108e-03 +5 -1.1800848061603740e-03 7.5424401975844038e-04 6.9023177964912290e-05 +6 -3.0914004879905335e-04 1.2755385764678133e-03 7.9574303350202582e-04 +7 -1.1037894966874103e-04 -7.6764845099077425e-04 -7.7217630460203659e-04 +8 3.9060281273221989e-04 -8.1444231918053418e-04 1.5134641148324972e-04 +9 1.2475530960659720e-03 -2.6608454451432528e-03 1.1117602907112732e-03 +10 4.5008983776042893e-04 4.9530197647538077e-04 -2.3336234361093645e-04 +11 -3.6977669078869707e-04 -1.5289071951960539e-03 -2.9176389881837113e-03 +12 1.0850834530183159e-03 -6.4965897903201833e-04 -1.2971152622619948e-03 +13 4.0754559196230639e-03 3.5043502394946119e-03 -7.8324487687854666e-04 +14 -1.3837220448746613e-04 -4.0656048637594394e-03 -3.9333461173944500e-03 +15 -4.3301707382721859e-03 -3.1802661664634938e-03 3.2037919043360571e-03 +16 -9.6715751018414326e-05 -5.0016572678960377e-04 1.4945658875149626e-03 +17 6.5692180538157174e-04 3.6635779995305095e-04 8.3495414466050911e-04 +18 -6.0936815808025862e-04 -9.3774557532468582e-04 -3.3558072507805731e-04 +19 -6.9919768291957119e-04 -3.6060777270430031e-03 4.2833405289822791e-03 +20 4.7777805013736515e-03 5.1003745845520452e-03 1.8002873923729241e-03 +21 -9.5568188553430398e-04 1.6594630943762931e-04 -1.8199788009966615e-04 +22 -3.3137518957653462e-03 -2.8683968287936054e-03 3.6384389958326871e-03 +23 2.4209481134686401e-04 -4.5457709985051130e-03 2.7663581642115042e-03 +24 2.5447450568861086e-04 4.8412447786110117e-04 -4.8021914527341357e-04 +25 4.3722771097312743e-03 -4.5184411669545515e-03 2.5200952006556795e-03 +26 -1.9250110555001179e-03 -3.0342169883610837e-03 3.5062814567984532e-03 +27 -2.6510179146429716e-04 3.6306203629019116e-04 -5.6235585400647747e-04 +28 -2.3068708109787484e-04 -8.5663070212203200e-04 2.1302563179109169e-03 +29 -2.5054744388303732e-03 -1.6773997805290820e-04 2.8436699761004796e-03 + +Bonds + +1 5 1 2 +2 3 1 3 +3 2 3 4 +4 2 3 5 +5 1 3 6 +6 3 6 8 +7 4 6 7 +8 5 8 9 +9 3 8 10 +10 2 10 11 +11 1 10 12 +12 1 10 16 +13 2 12 13 +14 2 12 14 +15 2 12 15 +16 4 16 17 +17 5 18 19 +18 5 18 20 +19 5 21 22 +20 5 21 23 +21 5 24 25 +22 5 24 26 +23 5 27 28 +24 5 27 29 + +Angles + +1 4 2 1 3 +2 4 1 3 5 +3 4 1 3 4 +4 4 1 3 6 +5 4 4 3 5 +6 2 5 3 6 +7 2 4 3 6 +8 3 3 6 7 +9 3 3 6 8 +10 3 7 6 8 +11 2 6 8 9 +12 2 9 8 10 +13 3 6 8 10 +14 2 8 10 11 +15 3 8 10 16 +16 2 11 10 12 +17 1 12 10 16 +18 1 8 10 12 +19 2 11 10 16 +20 2 10 12 15 +21 2 10 12 14 +22 2 10 12 13 +23 4 13 12 15 +24 4 13 12 14 +25 4 14 12 15 +26 4 10 16 17 +27 1 19 18 20 +28 1 22 21 23 +29 1 25 24 26 +30 1 28 27 29 + +Dihedrals + +1 2 2 1 3 6 +2 2 2 1 3 4 +3 3 2 1 3 5 +4 1 1 3 6 8 +5 1 1 3 6 7 +6 5 4 3 6 8 +7 5 4 3 6 7 +8 5 5 3 6 8 +9 5 5 3 6 7 +10 4 3 6 8 9 +11 3 3 6 8 10 +12 3 7 6 8 9 +13 4 7 6 8 10 +14 2 6 8 10 12 +15 2 6 8 10 16 +16 2 6 8 10 11 +17 2 9 8 10 12 +18 4 9 8 10 16 +19 5 9 8 10 11 +20 5 8 10 12 13 +21 1 8 10 12 14 +22 5 8 10 12 15 +23 4 8 10 16 17 +24 5 11 10 12 13 +25 5 11 10 12 14 +26 5 11 10 12 15 +27 2 11 10 16 17 +28 2 12 10 16 17 +29 5 16 10 12 13 +30 5 16 10 12 14 +31 5 16 10 12 15 + +Impropers + +1 1 6 3 8 7 +2 2 8 6 10 9 diff --git a/unittest/c-library/in.fourmol b/unittest/c-library/in.fourmol new file mode 100644 index 0000000000..6ef2a19167 --- /dev/null +++ b/unittest/c-library/in.fourmol @@ -0,0 +1,25 @@ +variable units index real +variable input_dir index . +variable data_file index ${input_dir}/data.fourmol +variable pair_style index 'zero 8.0' +variable bond_style index zero +variable angle_style index zero +variable dihedral_style index zero +variable improper_style index zero + +atom_style full +atom_modify map array +neigh_modify delay 2 every 2 check no +timestep 0.1 +units ${units} + +pair_style ${pair_style} +bond_style ${bond_style} +angle_style ${angle_style} +dihedral_style ${dihedral_style} +improper_style ${improper_style} + +read_data ${data_file} +dihedral_coeff * +improper_coeff * + diff --git a/unittest/c-library/test_library_commands.cpp b/unittest/c-library/test_library_commands.cpp index 8cd2200f8a..d9c750975d 100644 --- a/unittest/c-library/test_library_commands.cpp +++ b/unittest/c-library/test_library_commands.cpp @@ -1,103 +1,121 @@ // unit tests for issuing command to a LAMMPS instance through the library interface -#include "library.h" #include "lammps.h" +#include "library.h" #include +#include "gmock/gmock.h" #include "gtest/gtest.h" -const char *demo_input[] = { - "region box block 0 $x 0 2 0 2", - "create_box 1 box", - "create_atoms 1 single 1.0 1.0 ${zpos}" }; -const char *cont_input[] = { - "create_atoms 1 single &", - "0.2 0.1 0.1" }; +#include "test_main.h" -class LAMMPS_commands : public ::testing::Test -{ +using ::testing::HasSubstr; +using ::testing::StartsWith; + +const char *demo_input[] = {"region box block 0 $x 0 2 0 2", "create_box 1 box", + "create_atoms 1 single 1.0 1.0 ${zpos}"}; +const char *cont_input[] = {"create_atoms 1 single &", "0.2 0.1 0.1"}; + +class LibraryCommands : public ::testing::Test { protected: void *lmp; - LAMMPS_commands() {}; - ~LAMMPS_commands() override {}; + LibraryCommands(){}; + ~LibraryCommands() override{}; + + void SetUp() override + { + const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite", + "-var", "x", "2", "-var", "zpos", "1.5"}; - void SetUp() override { - const char *args[] = {"LAMMPS_test", - "-log", "none", - "-echo", "screen", - "-nocite", "-var","x","2", - "-var", "zpos", "1.5"}; char **argv = (char **)args; - int argc = sizeof(args)/sizeof(char *); + int argc = sizeof(args) / sizeof(char *); ::testing::internal::CaptureStdout(); - lmp = lammps_open_no_mpi(argc, argv, NULL); + lmp = lammps_open_no_mpi(argc, argv, NULL); std::string output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.substr(0,8).c_str(), "LAMMPS ("); + if (verbose) std::cout << output; + EXPECT_THAT(output, StartsWith("LAMMPS (")); } - void TearDown() override { + void TearDown() override + { ::testing::internal::CaptureStdout(); lammps_close(lmp); std::string output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.substr(0,16).c_str(), "Total wall time:"); + EXPECT_THAT(output, HasSubstr("Total wall time:")); + if (verbose) std::cout << output; lmp = nullptr; } }; -TEST_F(LAMMPS_commands, from_file) { +TEST_F(LibraryCommands, from_file) +{ FILE *fp; const char demo_file[] = "in.test"; const char cont_file[] = "in.cont"; - fp = fopen(demo_file,"w"); - for (unsigned int i=0; i < sizeof(demo_input)/sizeof(char *); ++i) { - fputs(demo_input[i],fp); - fputc('\n',fp); + fp = fopen(demo_file, "w"); + for (unsigned int i = 0; i < sizeof(demo_input) / sizeof(char *); ++i) { + fputs(demo_input[i], fp); + fputc('\n', fp); } fclose(fp); - fp = fopen(cont_file,"w"); - for (unsigned int i=0; i < sizeof(cont_input)/sizeof(char *); ++i) { - fputs(cont_input[i],fp); - fputc('\n',fp); + fp = fopen(cont_file, "w"); + for (unsigned int i = 0; i < sizeof(cont_input) / sizeof(char *); ++i) { + fputs(cont_input[i], fp); + fputc('\n', fp); } fclose(fp); - EXPECT_EQ(lammps_get_natoms(lmp),0); - lammps_file(lmp,demo_file); - lammps_file(lmp,cont_file); - EXPECT_EQ(lammps_get_natoms(lmp),2); + EXPECT_EQ(lammps_get_natoms(lmp), 0); + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_file(lmp, demo_file); + if (!verbose) ::testing::internal::GetCapturedStdout(); + EXPECT_EQ(lammps_get_natoms(lmp), 1); + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_file(lmp, cont_file); + if (!verbose) ::testing::internal::GetCapturedStdout(); + EXPECT_EQ(lammps_get_natoms(lmp), 2); unlink(demo_file); unlink(cont_file); }; -TEST_F(LAMMPS_commands, from_line) { - EXPECT_EQ(lammps_get_natoms(lmp),0); - for (unsigned int i=0; i < sizeof(demo_input)/sizeof(char *); ++i) { - lammps_command(lmp,demo_input[i]); +TEST_F(LibraryCommands, from_line) +{ + EXPECT_EQ(lammps_get_natoms(lmp), 0); + if (!verbose) ::testing::internal::CaptureStdout(); + for (unsigned int i = 0; i < sizeof(demo_input) / sizeof(char *); ++i) { + lammps_command(lmp, demo_input[i]); } - EXPECT_EQ(lammps_get_natoms(lmp),1); + if (!verbose) ::testing::internal::GetCapturedStdout(); + EXPECT_EQ(lammps_get_natoms(lmp), 1); }; -TEST_F(LAMMPS_commands, from_list) { - EXPECT_EQ(lammps_get_natoms(lmp),0); - lammps_commands_list(lmp,sizeof(demo_input)/sizeof(char *),demo_input); - lammps_commands_list(lmp,sizeof(cont_input)/sizeof(char *),cont_input); - EXPECT_EQ(lammps_get_natoms(lmp),2); +TEST_F(LibraryCommands, from_list) +{ + EXPECT_EQ(lammps_get_natoms(lmp), 0); + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_commands_list(lmp, sizeof(demo_input) / sizeof(char *), demo_input); + lammps_commands_list(lmp, sizeof(cont_input) / sizeof(char *), cont_input); + if (!verbose) ::testing::internal::GetCapturedStdout(); + EXPECT_EQ(lammps_get_natoms(lmp), 2); }; -TEST_F(LAMMPS_commands, from_string) { +TEST_F(LibraryCommands, from_string) +{ std::string cmds(""); - for (unsigned int i=0; i < sizeof(demo_input)/sizeof(char *); ++i) { + for (unsigned int i = 0; i < sizeof(demo_input) / sizeof(char *); ++i) { cmds += demo_input[i]; cmds += "\n"; } - for (unsigned int i=0; i < sizeof(cont_input)/sizeof(char *); ++i) { + for (unsigned int i = 0; i < sizeof(cont_input) / sizeof(char *); ++i) { cmds += cont_input[i]; cmds += "\n"; } - EXPECT_EQ(lammps_get_natoms(lmp),0); - lammps_commands_string(lmp,cmds.c_str()); - EXPECT_EQ(lammps_get_natoms(lmp),2); + EXPECT_EQ(lammps_get_natoms(lmp), 0); + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_commands_string(lmp, cmds.c_str()); + if (!verbose) ::testing::internal::GetCapturedStdout(); + EXPECT_EQ(lammps_get_natoms(lmp), 2); }; diff --git a/unittest/c-library/test_library_config.cpp b/unittest/c-library/test_library_config.cpp new file mode 100644 index 0000000000..0e81683159 --- /dev/null +++ b/unittest/c-library/test_library_config.cpp @@ -0,0 +1,149 @@ +// unit tests for checking LAMMPS configuration settings through the library interface + +#include "lammps.h" +#include "library.h" +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include "test_main.h" + +#define STRINGIFY(val) XSTR(val) +#define XSTR(val) #val + +using ::testing::HasSubstr; +using ::testing::StartsWith; +using ::testing::StrEq; + +class LibraryConfig : public ::testing::Test { +protected: + void *lmp; + std::string INPUT_DIR = STRINGIFY(TEST_INPUT_FOLDER); + + LibraryConfig(){}; + ~LibraryConfig() override{}; + + void SetUp() override + { + const char *args[] = {"LAMMPS_test", "-log", "none", + "-echo", "screen", "-nocite", + "-var", "input_dir", STRINGIFY(TEST_INPUT_FOLDER)}; + + char **argv = (char **)args; + int argc = sizeof(args) / sizeof(char *); + + ::testing::internal::CaptureStdout(); + lmp = lammps_open_no_mpi(argc, argv, NULL); + std::string output = ::testing::internal::GetCapturedStdout(); + if (verbose) std::cout << output; + EXPECT_THAT(output, StartsWith("LAMMPS (")); + } + void TearDown() override + { + ::testing::internal::CaptureStdout(); + lammps_close(lmp); + std::string output = ::testing::internal::GetCapturedStdout(); + EXPECT_THAT(output, HasSubstr("Total wall time:")); + if (verbose) std::cout << output; + lmp = nullptr; + } +}; + +TEST(LAMMPSConfig, package_count) +{ + EXPECT_EQ(lammps_config_package_count(), NUM_LAMMPS_PACKAGES); +}; + +TEST(LAMMPSConfig, has_package) +{ + EXPECT_EQ(lammps_config_has_package("MANYBODY"), LAMMPS_HAS_MANYBODY); +}; + +TEST(LAMMPSConfig, package_name) +{ + char buf[128]; + int numpkgs = lammps_config_package_count(); + if (numpkgs > 0) { + EXPECT_EQ(lammps_config_package_name(0, buf, 128), 1); + EXPECT_EQ(lammps_config_package_name(numpkgs + 10, buf, 128), 0); + EXPECT_THAT(buf, StrEq("")); + } else { + EXPECT_EQ(lammps_config_package_name(0, buf, 128), 1); + EXPECT_THAT(buf, StrEq("")); + } +}; + +TEST_F(LibraryConfig, has_style) +{ + EXPECT_EQ(lammps_has_style(lmp, "atom", "atomic"), 1); + EXPECT_EQ(lammps_has_style(lmp, "compute", "temp"), 1); + EXPECT_EQ(lammps_has_style(lmp, "fix", "nve"), 1); + EXPECT_EQ(lammps_has_style(lmp, "pair", "lj/cut"), 1); + EXPECT_EQ(lammps_has_style(lmp, "bond", "zero"), 1); + EXPECT_EQ(lammps_has_style(lmp, "dump", "custom"), 1); + EXPECT_EQ(lammps_has_style(lmp, "region", "sphere"), 1); + EXPECT_EQ(lammps_has_style(lmp, "xxxxx", "lj/cut"), 0); + EXPECT_EQ(lammps_has_style(lmp, "pair", "xxxxxx"), 0); +#if LAMMPS_HAS_MANYBODY + EXPECT_EQ(lammps_has_style(lmp, "pair", "sw"), 1); +#else + EXPECT_EQ(lammps_has_style(lmp, "pair", "sw"), 0); +#endif +}; + +TEST_F(LibraryConfig, style_count) +{ + EXPECT_GT(lammps_style_count(lmp, "atom"), 1); + EXPECT_GT(lammps_style_count(lmp, "bond"), 1); + EXPECT_GT(lammps_style_count(lmp, "angle"), 1); + EXPECT_GT(lammps_style_count(lmp, "dihedral"), 1); + EXPECT_GT(lammps_style_count(lmp, "improper"), 1); + EXPECT_GT(lammps_style_count(lmp, "pair"), 1); + EXPECT_GT(lammps_style_count(lmp, "kspace"), 1); + EXPECT_GT(lammps_style_count(lmp, "compute"), 1); + EXPECT_GT(lammps_style_count(lmp, "fix"), 1); + EXPECT_GT(lammps_style_count(lmp, "region"), 1); + EXPECT_GT(lammps_style_count(lmp, "dump"), 1); + EXPECT_GT(lammps_style_count(lmp, "integrate"), 1); + EXPECT_GT(lammps_style_count(lmp, "minimize"), 1); +}; + +TEST_F(LibraryConfig, style_name) +{ + char buf[128]; + int numstyles = lammps_style_count(lmp, "atom"); + EXPECT_EQ(lammps_style_name(lmp, "atom", 0, buf, 128), 1); + EXPECT_EQ(lammps_style_name(lmp, "atom", numstyles + 10, buf, 128), 0); + EXPECT_THAT(buf, StrEq("")); +}; + +TEST(LAMMPSConfig, exceptions) +{ + EXPECT_EQ(lammps_config_has_exceptions(), LAMMPS_HAS_EXCEPTIONS); +}; + +TEST(LAMMPSConfig, mpi_support) +{ + EXPECT_EQ(lammps_config_has_mpi_support(), LAMMPS_HAS_MPI); +}; + +TEST(LAMMPSConfig, png_support) +{ + EXPECT_EQ(lammps_config_has_png_support(), LAMMPS_HAS_PNG); +}; + +TEST(LAMMPSConfig, jpeg_support) +{ + EXPECT_EQ(lammps_config_has_jpeg_support(), LAMMPS_HAS_JPEG); +}; + +TEST(LAMMPSConfig, gzip_support) +{ + EXPECT_EQ(lammps_config_has_gzip_support(), LAMMPS_HAS_GZIP); +}; + +TEST(LAMMPSConfig, ffmpeg_support) +{ + EXPECT_EQ(lammps_config_has_ffmpeg_support(), LAMMPS_HAS_FFMPEG); +}; diff --git a/unittest/c-library/test_library_open.cpp b/unittest/c-library/test_library_open.cpp index 16d25eca13..a948295017 100644 --- a/unittest/c-library/test_library_open.cpp +++ b/unittest/c-library/test_library_open.cpp @@ -1,21 +1,29 @@ -// unit tests for the LAMMPS base class +// unit tests creating LAMMPS instances via the library interface -#include "library.h" #include "lammps.h" +#include "library.h" +#include // for stdin, stdout #include -#include // for stdin, stdout #include +#include "gmock/gmock.h" #include "gtest/gtest.h" -TEST(lammps_open, null_args) { +#include "test_main.h" + +using ::testing::HasSubstr; +using ::testing::StartsWith; + +TEST(lammps_open, null_args) +{ ::testing::internal::CaptureStdout(); - void *handle = lammps_open(0,NULL, MPI_COMM_WORLD, NULL); + void *handle = lammps_open(0, NULL, MPI_COMM_WORLD, NULL); std::string output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.substr(0,6).c_str(),"LAMMPS"); - int mpi_init=0; + EXPECT_THAT(output, StartsWith("LAMMPS (")); + if (verbose) std::cout << output; + int mpi_init = 0; MPI_Initialized(&mpi_init); - EXPECT_GT(mpi_init,0); + EXPECT_GT(mpi_init, 0); LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; EXPECT_EQ(lmp->world, MPI_COMM_WORLD); EXPECT_EQ(lmp->infile, stdin); @@ -24,25 +32,26 @@ TEST(lammps_open, null_args) { ::testing::internal::CaptureStdout(); lammps_close(handle); output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.substr(0,16).c_str(), "Total wall time:"); + EXPECT_THAT(output, HasSubstr("Total wall time:")); + if (verbose) std::cout << output; } -TEST(lammps_open, with_args) { - const char *args[] = {"liblammps", - "-log", "none", - "-nocite"}; - char **argv = (char **)args; - int argc = sizeof(args)/sizeof(char *); +TEST(lammps_open, with_args) +{ + const char *args[] = {"liblammps", "-log", "none", "-nocite"}; + char **argv = (char **)args; + int argc = sizeof(args) / sizeof(char *); // MPI is already initialized MPI_Comm mycomm; MPI_Comm_split(MPI_COMM_WORLD, 0, 1, &mycomm); ::testing::internal::CaptureStdout(); void *alt_ptr; - void *handle = lammps_open(argc, argv, mycomm, &alt_ptr); + void *handle = lammps_open(argc, argv, mycomm, &alt_ptr); std::string output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.substr(0,6).c_str(),"LAMMPS"); - EXPECT_EQ(handle,alt_ptr); + EXPECT_THAT(output, StartsWith("LAMMPS (")); + if (verbose) std::cout << output; + EXPECT_EQ(handle, alt_ptr); LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; // MPI STUBS uses no real communicators @@ -60,24 +69,24 @@ TEST(lammps_open, with_args) { ::testing::internal::CaptureStdout(); lammps_close(handle); output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.substr(0,16).c_str(), "Total wall time:"); + EXPECT_THAT(output, HasSubstr("Total wall time:")); + if (verbose) std::cout << output; } -TEST(lammps_open, with_kokkos) { +TEST(lammps_open, with_kokkos) +{ if (!LAMMPS_NS::LAMMPS::is_installed_pkg("KOKKOS")) GTEST_SKIP(); - const char *args[] = {"liblammps", - "-k", "on", "t", "2", - "-sf", "kk", - "-log", "none" }; - char **argv = (char **)args; - int argc = sizeof(args)/sizeof(char *); + const char *args[] = {"liblammps", "-k", "on", "t", "2", "-sf", "kk", "-log", "none"}; + char **argv = (char **)args; + int argc = sizeof(args) / sizeof(char *); ::testing::internal::CaptureStdout(); void *alt_ptr; - void *handle = lammps_open(argc, argv, MPI_COMM_WORLD, &alt_ptr); + void *handle = lammps_open(argc, argv, MPI_COMM_WORLD, &alt_ptr); std::string output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.substr(0,6).c_str(),"LAMMPS"); - EXPECT_EQ(handle,alt_ptr); + EXPECT_THAT(output, StartsWith("LAMMPS (")); + if (verbose) std::cout << output; + EXPECT_EQ(handle, alt_ptr); LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; EXPECT_EQ(lmp->world, MPI_COMM_WORLD); @@ -91,23 +100,22 @@ TEST(lammps_open, with_kokkos) { ::testing::internal::CaptureStdout(); lammps_close(handle); output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.substr(0,16).c_str(), "Total wall time:"); + EXPECT_THAT(output, HasSubstr("Total wall time:")); + if (verbose) std::cout << output; } -TEST(lammps_open_no_mpi, no_screen) { - const char *args[] = {"liblammps", - "-log", "none", - "-screen", "none", - "-nocite"}; - char **argv = (char **)args; - int argc = sizeof(args)/sizeof(char *); +TEST(lammps_open_no_mpi, no_screen) +{ + const char *args[] = {"liblammps", "-log", "none", "-screen", "none", "-nocite"}; + char **argv = (char **)args; + int argc = sizeof(args) / sizeof(char *); ::testing::internal::CaptureStdout(); void *alt_ptr; - void *handle = lammps_open_no_mpi(argc, argv, &alt_ptr); + void *handle = lammps_open_no_mpi(argc, argv, &alt_ptr); std::string output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.c_str(),""); - EXPECT_EQ(handle,alt_ptr); + EXPECT_STREQ(output.c_str(), ""); + EXPECT_EQ(handle, alt_ptr); LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; EXPECT_EQ(lmp->world, MPI_COMM_WORLD); @@ -125,22 +133,21 @@ TEST(lammps_open_no_mpi, no_screen) { EXPECT_STREQ(output.c_str(), ""); } -TEST(lammps_open_no_mpi, with_omp) { +TEST(lammps_open_no_mpi, with_omp) +{ if (!LAMMPS_NS::LAMMPS::is_installed_pkg("USER-OMP")) GTEST_SKIP(); - const char *args[] = {"liblammps", - "-pk", "omp", "2", "neigh", "no", - "-sf", "omp", - "-log", "none", - "-nocite"}; - char **argv = (char **)args; - int argc = sizeof(args)/sizeof(char *); + const char *args[] = {"liblammps", "-pk", "omp", "2", "neigh", "no", + "-sf", "omp", "-log", "none", "-nocite"}; + char **argv = (char **)args; + int argc = sizeof(args) / sizeof(char *); ::testing::internal::CaptureStdout(); void *alt_ptr; - void *handle = lammps_open_no_mpi(argc, argv, &alt_ptr); + void *handle = lammps_open_no_mpi(argc, argv, &alt_ptr); std::string output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.substr(0,6).c_str(),"LAMMPS"); - EXPECT_EQ(handle,alt_ptr); + EXPECT_THAT(output, StartsWith("LAMMPS (")); + if (verbose) std::cout << output; + EXPECT_EQ(handle, alt_ptr); LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; EXPECT_EQ(lmp->world, MPI_COMM_WORLD); @@ -155,18 +162,21 @@ TEST(lammps_open_no_mpi, with_omp) { ::testing::internal::CaptureStdout(); lammps_close(handle); output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.substr(0,16).c_str(), "Total wall time:"); + EXPECT_THAT(output, HasSubstr("Total wall time:")); + if (verbose) std::cout << output; } -TEST(lammps_open_fortran, no_args) { +TEST(lammps_open_fortran, no_args) +{ // MPI is already initialized MPI_Comm mycomm; MPI_Comm_split(MPI_COMM_WORLD, 0, 1, &mycomm); int fcomm = MPI_Comm_c2f(mycomm); ::testing::internal::CaptureStdout(); - void *handle = lammps_open_fortran(0, NULL, fcomm); + void *handle = lammps_open_fortran(0, NULL, fcomm); std::string output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.substr(0,6).c_str(),"LAMMPS"); + EXPECT_THAT(output, StartsWith("LAMMPS (")); + if (verbose) std::cout << output; LAMMPS_NS::LAMMPS *lmp = (LAMMPS_NS::LAMMPS *)handle; // MPI STUBS uses no real communicators @@ -182,5 +192,6 @@ TEST(lammps_open_fortran, no_args) { ::testing::internal::CaptureStdout(); lammps_close(handle); output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.substr(0,16).c_str(), "Total wall time:"); + EXPECT_THAT(output, HasSubstr("Total wall time:")); + if (verbose) std::cout << output; } diff --git a/unittest/c-library/test_library_properties.cpp b/unittest/c-library/test_library_properties.cpp index 5e8c410cce..3b1393e5c6 100644 --- a/unittest/c-library/test_library_properties.cpp +++ b/unittest/c-library/test_library_properties.cpp @@ -1,53 +1,216 @@ // unit tests for checking and changing simulation properties through the library interface -#include "library.h" #include "lammps.h" +#include "library.h" #include +#include "gmock/gmock.h" #include "gtest/gtest.h" -const char *demo_input[] = { - "region box block 0 $x 0 2 0 2", - "create_box 1 box", - "create_atoms 1 single 1.0 1.0 ${zpos}" }; -const char *cont_input[] = { - "create_atoms 1 single &", - "0.2 0.1 0.1" }; +#include "test_main.h" -class LAMMPS_properties : public ::testing::Test -{ +#define STRINGIFY(val) XSTR(val) +#define XSTR(val) #val + +using ::testing::HasSubstr; +using ::testing::StartsWith; + +class LibraryProperties : public ::testing::Test { protected: void *lmp; - LAMMPS_properties() {}; - ~LAMMPS_properties() override {}; + std::string INPUT_DIR = STRINGIFY(TEST_INPUT_FOLDER); + + LibraryProperties(){}; + ~LibraryProperties() override{}; + + void SetUp() override + { + const char *args[] = {"LAMMPS_test", "-log", "none", + "-echo", "screen", "-nocite", + "-var", "input_dir", STRINGIFY(TEST_INPUT_FOLDER)}; - void SetUp() override { - const char *args[] = {"LAMMPS_test", "-log", "none", - "-echo", "screen", "-nocite" }; char **argv = (char **)args; - int argc = sizeof(args)/sizeof(char *); + int argc = sizeof(args) / sizeof(char *); ::testing::internal::CaptureStdout(); - lmp = lammps_open_no_mpi(argc, argv, NULL); + lmp = lammps_open_no_mpi(argc, argv, NULL); std::string output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.substr(0,8).c_str(), "LAMMPS ("); + if (verbose) std::cout << output; + EXPECT_THAT(output, StartsWith("LAMMPS (")); } - void TearDown() override { + void TearDown() override + { ::testing::internal::CaptureStdout(); lammps_close(lmp); std::string output = ::testing::internal::GetCapturedStdout(); - EXPECT_STREQ(output.substr(0,16).c_str(), "Total wall time:"); + EXPECT_THAT(output, HasSubstr("Total wall time:")); + if (verbose) std::cout << output; lmp = nullptr; } }; -TEST_F(LAMMPS_properties, get_mpi_comm) { - int f_comm = lammps_get_mpi_comm(lmp); - if (lammps_config_has_mpi_support()) - EXPECT_GE(f_comm,0); - else - EXPECT_EQ(f_comm,-1); +TEST_F(LibraryProperties, version) +{ + EXPECT_GE(20200824, lammps_version(lmp)); }; -TEST_F(LAMMPS_properties, box) { +TEST_F(LibraryProperties, get_mpi_comm) +{ + int f_comm = lammps_get_mpi_comm(lmp); + if (lammps_config_has_mpi_support()) + EXPECT_GE(f_comm, 0); + else + EXPECT_EQ(f_comm, -1); +}; + +TEST_F(LibraryProperties, natoms) +{ + if (!lammps_has_style(lmp, "atom", "full")) GTEST_SKIP(); + std::string input = INPUT_DIR + PATH_SEP + "in.fourmol"; + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_file(lmp, input.c_str()); + if (!verbose) ::testing::internal::GetCapturedStdout(); + EXPECT_EQ(lammps_get_natoms(lmp), 29); +}; + +TEST_F(LibraryProperties, thermo) +{ + if (!lammps_has_style(lmp, "atom", "full")) GTEST_SKIP(); + std::string input = INPUT_DIR + PATH_SEP + "in.fourmol"; + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_file(lmp, input.c_str()); + lammps_command(lmp, "run 2 post no"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + EXPECT_EQ(lammps_get_thermo(lmp, "step"), 2); + EXPECT_EQ(lammps_get_thermo(lmp, "atoms"), 29); + EXPECT_DOUBLE_EQ(lammps_get_thermo(lmp, "vol"), 3375.0); + EXPECT_DOUBLE_EQ(lammps_get_thermo(lmp, "density"), 0.12211250945013695); + EXPECT_DOUBLE_EQ(lammps_get_thermo(lmp, "cellalpha"), 90.0); +}; + +TEST_F(LibraryProperties, box) +{ + if (!lammps_has_style(lmp, "atom", "full")) GTEST_SKIP(); + std::string input = INPUT_DIR + PATH_SEP + "in.fourmol"; + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_file(lmp, input.c_str()); + lammps_command(lmp, "run 2 post no"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + double boxlo[3], boxhi[3], xy, yz, xz; + int pflags[3], boxflag; + lammps_extract_box(lmp, boxlo, boxhi, &xy, &yz, &xz, pflags, &boxflag); + EXPECT_DOUBLE_EQ(boxlo[0], -6.024572); + EXPECT_DOUBLE_EQ(boxlo[1], -7.692866); + EXPECT_DOUBLE_EQ(boxlo[2], -8.086924); + EXPECT_DOUBLE_EQ(boxhi[0], 8.975428); + EXPECT_DOUBLE_EQ(boxhi[1], 7.307134); + EXPECT_DOUBLE_EQ(boxhi[2], 6.913076); + EXPECT_DOUBLE_EQ(xy, 0.0); + EXPECT_DOUBLE_EQ(yz, 0.0); + EXPECT_DOUBLE_EQ(xz, 0.0); + EXPECT_EQ(pflags[0], 1); + EXPECT_EQ(pflags[1], 1); + EXPECT_EQ(pflags[2], 1); + EXPECT_EQ(boxflag, 0); + EXPECT_DOUBLE_EQ(lammps_get_thermo(lmp, "vol"), 3375.0); + EXPECT_DOUBLE_EQ(lammps_get_thermo(lmp, "density"), 0.12211250945013695); + EXPECT_DOUBLE_EQ(lammps_get_thermo(lmp, "cellalpha"), 90.0); + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_command(lmp, "change_box all boundary p p f triclinic xy final 0.5"); + lammps_command(lmp, "fix box all box/relax x 0.0 y 0.0"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + lammps_extract_box(lmp, boxlo, boxhi, &xy, &yz, &xz, pflags, &boxflag); + EXPECT_DOUBLE_EQ(boxlo[0], -6.024572); + EXPECT_DOUBLE_EQ(boxlo[1], -7.692866); + EXPECT_DOUBLE_EQ(boxlo[2], -8.086924); + EXPECT_DOUBLE_EQ(boxhi[0], 8.975428); + EXPECT_DOUBLE_EQ(boxhi[1], 7.307134); + EXPECT_DOUBLE_EQ(boxhi[2], 6.913076); + EXPECT_DOUBLE_EQ(xy, 0.5); + EXPECT_DOUBLE_EQ(yz, 0.0); + EXPECT_DOUBLE_EQ(xz, 0.0); + EXPECT_EQ(pflags[0], 1); + EXPECT_EQ(pflags[1], 1); + EXPECT_EQ(pflags[2], 0); + EXPECT_EQ(boxflag, 1); + EXPECT_DOUBLE_EQ(lammps_get_thermo(lmp, "vol"), 3375.0); + EXPECT_DOUBLE_EQ(lammps_get_thermo(lmp, "density"), 0.12211250945013695); + EXPECT_DOUBLE_EQ(lammps_get_thermo(lmp, "cellalpha"), 90.0); + EXPECT_DOUBLE_EQ(lammps_get_thermo(lmp, "cellbeta"), 90.0); + EXPECT_DOUBLE_EQ(lammps_get_thermo(lmp, "cellgamma"), 88.090847567003621); + + boxlo[0] = -6.1; + boxhi[1] = 7.3; + xy = 0.1; + lammps_reset_box(lmp, boxlo, boxhi, xy, yz, xz); + lammps_extract_box(lmp, boxlo, boxhi, &xy, &yz, &xz, pflags, &boxflag); + EXPECT_DOUBLE_EQ(boxlo[0], -6.1); + EXPECT_DOUBLE_EQ(boxlo[1], -7.692866); + EXPECT_DOUBLE_EQ(boxlo[2], -8.086924); + EXPECT_DOUBLE_EQ(boxhi[0], 8.975428); + EXPECT_DOUBLE_EQ(boxhi[1], 7.3); + EXPECT_DOUBLE_EQ(boxhi[2], 6.913076); + EXPECT_DOUBLE_EQ(xy, 0.1); + EXPECT_DOUBLE_EQ(yz, 0.0); + EXPECT_DOUBLE_EQ(xz, 0.0); + EXPECT_EQ(pflags[0], 1); + EXPECT_EQ(pflags[1], 1); + EXPECT_EQ(pflags[2], 0); + EXPECT_EQ(boxflag, 1); + EXPECT_DOUBLE_EQ(lammps_get_thermo(lmp, "vol"), 3390.3580784497199); + EXPECT_DOUBLE_EQ(lammps_get_thermo(lmp, "cellgamma"), 89.61785205109274); +}; +TEST_F(LibraryProperties, setting) +{ +#if defined(LAMMPS_SMALLSMALL) + EXPECT_EQ(lammps_extract_setting(lmp, "bigint"), 4); +#else + EXPECT_EQ(lammps_extract_setting(lmp, "bigint"), 8); +#endif +#if defined(LAMMPS_BIGBIG) + EXPECT_EQ(lammps_extract_setting(lmp, "tagint"), 8); + EXPECT_EQ(lammps_extract_setting(lmp, "imageint"), 8); +#else + EXPECT_EQ(lammps_extract_setting(lmp, "tagint"), 4); + EXPECT_EQ(lammps_extract_setting(lmp, "imageint"), 4); +#endif + + EXPECT_EQ(lammps_extract_setting(lmp, "box_exist"), 0); + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_command(lmp, "dimension 2"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + EXPECT_EQ(lammps_extract_setting(lmp, "dimension"), 2); + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_command(lmp, "dimension 3"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + EXPECT_EQ(lammps_extract_setting(lmp, "molecule_flag"), 0); + EXPECT_EQ(lammps_extract_setting(lmp, "q_flag"), 0); + EXPECT_EQ(lammps_extract_setting(lmp, "mu_flag"), 0); + EXPECT_EQ(lammps_extract_setting(lmp, "rmass_flag"), 0); + EXPECT_EQ(lammps_extract_setting(lmp, "UNKNOWN"), -1); + + if (lammps_has_style(lmp, "atom", "full")) { + std::string input = INPUT_DIR + PATH_SEP + "in.fourmol"; + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_file(lmp, input.c_str()); + lammps_command(lmp, "run 2 post no"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + EXPECT_EQ(lammps_extract_setting(lmp, "triclinic"), 0); + EXPECT_EQ(lammps_extract_setting(lmp, "box_exist"), 1); + EXPECT_EQ(lammps_extract_setting(lmp, "dimension"), 3); + EXPECT_EQ(lammps_extract_setting(lmp, "nlocal"), 29); + EXPECT_EQ(lammps_extract_setting(lmp, "nghost"), 518); + EXPECT_EQ(lammps_extract_setting(lmp, "nall"), 547); + EXPECT_EQ(lammps_extract_setting(lmp, "nmax"), 16384); + EXPECT_EQ(lammps_extract_setting(lmp, "molecule_flag"), 1); + EXPECT_EQ(lammps_extract_setting(lmp, "q_flag"), 1); + EXPECT_EQ(lammps_extract_setting(lmp, "mu_flag"), 0); + EXPECT_EQ(lammps_extract_setting(lmp, "rmass_flag"), 0); + if (!verbose) ::testing::internal::CaptureStdout(); + lammps_command(lmp, "change_box all triclinic"); + lammps_command(lmp, "fix rmass all property/atom rmass ghost yes"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + EXPECT_EQ(lammps_extract_setting(lmp, "triclinic"), 1); + EXPECT_EQ(lammps_extract_setting(lmp, "rmass_flag"), 1); + } }; diff --git a/unittest/c-library/test_main.cpp b/unittest/c-library/test_main.cpp new file mode 100644 index 0000000000..f32e222e1e --- /dev/null +++ b/unittest/c-library/test_main.cpp @@ -0,0 +1,59 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#include "test_main.h" +#include "utils.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include +#include + +// whether to print verbose output (i.e. not capturing LAMMPS screen output). +bool verbose = false; + +int main(int argc, char **argv) +{ + MPI_Init(&argc, &argv); + ::testing::InitGoogleMock(&argc, argv); + + if (argc < 1) { + return 1; + } + + // handle arguments passed via environment variable + if (const char *var = getenv("TEST_ARGS")) { + std::vector env = LAMMPS_NS::utils::split_words(var); + for (auto arg : env) { + if (arg == "-v") { + verbose = true; + } + } + } + + int iarg = 1; + while (iarg < argc) { + if (strcmp(argv[iarg], "-v") == 0) { + verbose = true; + ++iarg; + } else { + std::cerr << "unknown option: " << argv[iarg] << "\n\n"; + MPI_Finalize(); + return 1; + } + } + + int rv = RUN_ALL_TESTS(); + MPI_Finalize(); + return rv; +} diff --git a/unittest/c-library/test_main.h b/unittest/c-library/test_main.h new file mode 100644 index 0000000000..ac9bc0d26a --- /dev/null +++ b/unittest/c-library/test_main.h @@ -0,0 +1,33 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifndef TEST_MAIN_H +#define TEST_MAIN_H + +extern bool verbose; + +#define EXPECT_FP_LE_WITH_EPS(val1, val2, eps) \ + do { \ + const double diff = fabs(val1 - val2); \ + const double div = std::min(fabs(val1), fabs(val2)); \ + const double err = (div == 0.0) ? diff : diff / div; \ + EXPECT_PRED_FORMAT2(::testing::DoubleLE, err, eps); \ + } while (0); + +#endif + +#if defined _WIN32 +static const char PATH_SEP = '\\'; +#else +static const char PATH_SEP = '/'; +#endif