diff --git a/.github/ISSUE_TEMPLATE/help_request.md b/.github/ISSUE_TEMPLATE/help_request.md index 5e5b3ebffd..bde37650b2 100644 --- a/.github/ISSUE_TEMPLATE/help_request.md +++ b/.github/ISSUE_TEMPLATE/help_request.md @@ -1,6 +1,6 @@ --- name: Request for Help -about: "Don't post help requests here, email the lammps-users mailing list" +about: "Don't post help requests here, post in the LAMMPS forum" title: "" labels: invalid assignees: '' @@ -8,8 +8,9 @@ assignees: '' --- Please **do not** post requests for help (e.g. with installing or using LAMMPS) here. -Instead send an e-mail to the lammps-users mailing list. +Instead, you can post to the LAMMPS category in the Materials Science Community +Discourse forum at: https://matsci.org/lammps/ This issue tracker is for tracking LAMMPS development related issues only. -Thanks for your cooperation. +Thank you in advance for your cooperation. diff --git a/doc/src/Library.rst b/doc/src/Library.rst index 05b652f7a7..3533c347c8 100644 --- a/doc/src/Library.rst +++ b/doc/src/Library.rst @@ -2,12 +2,13 @@ LAMMPS Library Interfaces ************************* As described on the :doc:`library interface to LAMMPS ` -page, LAMMPS can be built as a library (static or shared), so that -it can be called by another code, used in a :doc:`coupled manner +page, LAMMPS can be built as a library (static or shared), so that it +can be called by another code, used in a :doc:`coupled manner ` with other codes, or driven through a :doc:`Python -script `. Even the LAMMPS standalone executable is -essentially a thin wrapper on top of the LAMMPS library, creating a -LAMMPS instance, processing input and then existing. +script `. The LAMMPS standalone executable itself is +essentially a thin wrapper on top of the LAMMPS library, which creates a +LAMMPS instance, passes the input for processing to that instance, and +then exits. Most of the APIs described below are based on C language wrapper functions in the files ``src/library.h`` and ``src/library.cpp``, but @@ -87,6 +88,18 @@ run LAMMPS in serial mode. message retrieved `. We thus recommend enabling C++ exceptions when using the library interface, +.. admonition:: Using the C library interface as a plugin + :class: note + + Rather than including the C library directly and link to the LAMMPS + library at compile time, you can use the ``liblammpsplugin.h`` header + file and the ``liblammpsplugin.c`` C code in the + ``examples/COUPLE/plugin`` folder for an interface to LAMMPS that is + largely identical to the regular library interface, only that it will + load a LAMMPS shared library file at runtime. This can be useful for + applications where the interface to LAMMPS would be an optional + feature. + .. warning:: No checks are made on the arguments of the function calls of the C @@ -163,5 +176,3 @@ The following links provide some examples and references to the C++ API. :maxdepth: 1 Cplusplus - - diff --git a/doc/src/pair_pace.rst b/doc/src/pair_pace.rst index 3119efcc25..697a9965b6 100644 --- a/doc/src/pair_pace.rst +++ b/doc/src/pair_pace.rst @@ -112,7 +112,7 @@ requests to compute `gamma`, as shown in example below: compute max_pace_gamma all reduce max f_pace_gamma variable dump_skip equal "c_max_pace_gamma < 5" - dump pace_dump all custom 20 extrapolative_structures.dump id x y z f_pace_gamma + dump pace_dump all custom 20 extrapolative_structures.dump id type x y z f_pace_gamma dump_modify pace_dump skip v_dump_skip variable max_pace_gamma equal c_max_pace_gamma diff --git a/examples/COUPLE/plugin/.gitignore b/examples/COUPLE/plugin/.gitignore new file mode 100644 index 0000000000..796b96d1c4 --- /dev/null +++ b/examples/COUPLE/plugin/.gitignore @@ -0,0 +1 @@ +/build diff --git a/examples/COUPLE/plugin/CMakeLists.txt b/examples/COUPLE/plugin/CMakeLists.txt new file mode 100644 index 0000000000..f4064d3f65 --- /dev/null +++ b/examples/COUPLE/plugin/CMakeLists.txt @@ -0,0 +1,47 @@ +########################################## +# CMake build system for coupling to the LAMMPS library +# where the library is loaded dynamically at runtime. +########################################## + +cmake_minimum_required(VERSION 3.10) + +# enforce out-of-source build +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) + message(FATAL_ERROR "In-source builds are not allowed. You must create and use a build directory. " + "Please remove CMakeCache.txt and CMakeFiles first.") +endif() + +project(liblammpsplugin VERSION 1.0 LANGUAGES C) + +# by default, install into $HOME/.local (not /usr/local), +# so that no root access (and sudo) is needed +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/.local" CACHE PATH "Default install path" FORCE) +endif() + +# ugly hacks for MSVC which by default always reports an old C++ standard in the __cplusplus macro +# and prints lots of pointless warnings about "unsafe" functions +if(MSVC) + if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + if(LAMMPS_EXCEPTIONS) + add_compile_options(/EHsc) + endif() + endif() + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) +endif() + +find_package(MPI REQUIRED) +# do not include the (obsolete) MPI C++ bindings which makes +# for leaner object files and avoids namespace conflicts +set(MPI_CXX_SKIP_MPICXX TRUE) + +########################## + +add_executable(simple-plugin simple.c liblammpsplugin.c) +target_link_libraries(simple-plugin PRIVATE MPI::MPI_C) +target_compile_definitions(simple-plugin PRIVATE LAMMPS_LIB_MPI) + +# link with -ldl or equivalent for plugin loading; except on Windows +if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + target_link_libraries(simple-plugin PRIVATE ${CMAKE_DL_LIBS}) +endif() diff --git a/examples/COUPLE/plugin/README b/examples/COUPLE/plugin/README index bced08b6d7..beed549d3f 100644 --- a/examples/COUPLE/plugin/README +++ b/examples/COUPLE/plugin/README @@ -11,32 +11,39 @@ liblammpsplugin.c is the LAMMPS library plugin loader You can then build the driver executable codes with a compile line like below. -mpicc -c -O -Wall -g -I$HOME/lammps/src liblammpsplugin.c -mpicc -c -O -Wall -g simple.c -mpicc simple.o liblammpsplugin.o -ldl -o simpleC +mpicc -c -O -DLAMMPS_LIB_MPI -Wall -g liblammpsplugin.c +mpicc -c -O -DLAMMPS_LIB_MPI -Wall -g simple.c +mpicc simple.o liblammpsplugin.o -ldl -o simple-plugin + +or using the provided CMake file with: + +mkdir build +cd build +cmake ../ +cmake --build . You also need to build LAMMPS as a shared library -(see examples/COUPLE/README), e.g. +(see examples/COUPLE/README), e.g. cd $HOME/lammps/src make mode=shlib mpi -or +or cd $HOME/lammps mkdir build-shared cd build-shared -cmake -D BUILD_LIB=on -D BUILD_SHARED_LIBS=on ../cmake +cmake -D BUILD_MPI=on -D BUILD_SHARED_LIBS=on ../cmake make -You then run simpleC on a parallel machine +You then run simple-plugin on a parallel machine on some number of processors Q with 3 arguments: -% mpirun -np Q simpleC P in.lj $HOME/lammps/src/liblammps.so +% mpirun -np Q simple-plugin P in.lj $HOME/lammps/src/liblammps.so or -% mpirun -np Q simpleC P in.lj $HOME/lammps/build-shared/liblammps.so +% mpirun -np Q simple-plugin P in.lj $HOME/lammps/build-shared/liblammps.so P is the number of procs you want LAMMPS to run on (must be <= Q) and in.lj is a LAMMPS input script and the last argument is the path to diff --git a/examples/COUPLE/plugin/liblammpsplugin.c b/examples/COUPLE/plugin/liblammpsplugin.c index a56c8ca2fd..996a27524f 100644 --- a/examples/COUPLE/plugin/liblammpsplugin.c +++ b/examples/COUPLE/plugin/liblammpsplugin.c @@ -18,10 +18,29 @@ a LAMMPS plugin to some other software. */ -#include "library.h" #include "liblammpsplugin.h" -#include + +#if defined(_WIN32) + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#if defined(_WIN32_WINNT) +#undef _WIN32_WINNT +#endif + +// target Windows version is windows 7 and later +#define _WIN32_WINNT _WIN32_WINNT_WIN7 +#define PSAPI_VERSION 2 + +#include +#else #include +#endif + +#include + liblammpsplugin_t *liblammpsplugin_load(const char *lib) { @@ -29,14 +48,29 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib) void *handle; if (lib == NULL) return NULL; + +#ifdef _WIN32 + handle = (void *) LoadLibrary(lib); +#else handle = dlopen(lib,RTLD_NOW|RTLD_GLOBAL); +#endif if (handle == NULL) return NULL; lmp = (liblammpsplugin_t *) malloc(sizeof(liblammpsplugin_t)); lmp->handle = handle; -#define ADDSYM(symbol) lmp->symbol = dlsym(handle,"lammps_" #symbol) +#ifdef _WIN32 +#define ADDSYM(symbol) *(void **) (&lmp->symbol) = (void *) GetProcAddress((HINSTANCE) handle, "lammps_" #symbol) +#else +#define ADDSYM(symbol) *(void **) (&lmp->symbol) = dlsym(handle,"lammps_" #symbol) +#endif + +#if defined(LAMMPS_LIB_MPI) ADDSYM(open); +#else + lmp->open = NULL; +#endif + ADDSYM(open_no_mpi); ADDSYM(open_fortran); ADDSYM(close); @@ -46,6 +80,8 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib) ADDSYM(kokkos_finalize); ADDSYM(python_finalize); + ADDSYM(error); + ADDSYM(file); ADDSYM(command); ADDSYM(commands_list); @@ -70,6 +106,7 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib) ADDSYM(extract_compute); ADDSYM(extract_fix); ADDSYM(extract_variable); + ADDSYM(extract_variable_datatype); ADDSYM(set_variable); ADDSYM(gather_atoms); @@ -77,8 +114,15 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib) ADDSYM(gather_atoms_subset); ADDSYM(scatter_atoms); ADDSYM(scatter_atoms_subset); + ADDSYM(gather_bonds); + ADDSYM(gather); + ADDSYM(gather_concat); + ADDSYM(gather_subset); + ADDSYM(scatter); + ADDSYM(scatter_subset); + ADDSYM(create_atoms); ADDSYM(find_pair_neighlist); @@ -116,6 +160,9 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib) ADDSYM(plugin_count); ADDSYM(plugin_name); + ADDSYM(encode_image_flags); + ADDSYM(decode_image_flags); + ADDSYM(set_fix_external_callback); ADDSYM(fix_external_get_force); ADDSYM(fix_external_set_energy_global); @@ -125,6 +172,8 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib) ADDSYM(fix_external_set_vector_length); ADDSYM(fix_external_set_vector); + ADDSYM(flush_buffers); + ADDSYM(free); ADDSYM(is_running); @@ -139,6 +188,8 @@ liblammpsplugin_t *liblammpsplugin_load(const char *lib) lmp->has_error = NULL; lmp->get_last_error_message = NULL; #endif + + ADDSYM(python_api_version); return lmp; } @@ -147,7 +198,11 @@ int liblammpsplugin_release(liblammpsplugin_t *lmp) if (lmp == NULL) return 1; if (lmp->handle == NULL) return 2; +#ifdef _WIN32 + FreeLibrary((HINSTANCE) handle); +#else dlclose(lmp->handle); +#endif free((void *)lmp); return 0; } diff --git a/examples/COUPLE/plugin/liblammpsplugin.h b/examples/COUPLE/plugin/liblammpsplugin.h index 45cb468846..26abf74d02 100644 --- a/examples/COUPLE/plugin/liblammpsplugin.h +++ b/examples/COUPLE/plugin/liblammpsplugin.h @@ -28,11 +28,71 @@ #define LAMMPS_SMALLBIG #endif +#if defined(LAMMPS_LIB_MPI) #include -#if defined(LAMMPS_BIGBIG) || defined(LAMMPS_SMALLBIG) -#include /* for int64_t */ #endif +#if defined(LAMMPS_BIGBIG) || defined(LAMMPS_SMALLBIG) +#include /* for int64_t */ +#endif + +/* The following must be kept in sync with the equivalent constants in + * python/lammps/constants.py, fortran/lammps.f90, tools/swig/lammps.i, + * and examples/COUPLE/plugin/liblammpsplugin.h */ + +/* Data type constants for extracting data from atoms, computes and fixes */ + +enum _LMP_DATATYPE_CONST { + LAMMPS_INT = 0, /*!< 32-bit integer (array) */ + LAMMPS_INT_2D = 1, /*!< two-dimensional 32-bit integer array */ + LAMMPS_DOUBLE = 2, /*!< 64-bit double (array) */ + LAMMPS_DOUBLE_2D = 3, /*!< two-dimensional 64-bit double array */ + LAMMPS_INT64 = 4, /*!< 64-bit integer (array) */ + LAMMPS_INT64_2D = 5, /*!< two-dimensional 64-bit integer array */ + LAMMPS_STRING = 6 /*!< C-String */ +}; + +/* Style constants for extracting data from computes and fixes. */ + +enum _LMP_STYLE_CONST { + LMP_STYLE_GLOBAL = 0, /*!< return global data */ + LMP_STYLE_ATOM = 1, /*!< return per-atom data */ + LMP_STYLE_LOCAL = 2 /*!< return local data */ +}; + +/* Type and size constants for extracting data from computes and fixes. */ + +enum _LMP_TYPE_CONST { + LMP_TYPE_SCALAR = 0, /*!< return scalar */ + LMP_TYPE_VECTOR = 1, /*!< return vector */ + LMP_TYPE_ARRAY = 2, /*!< return array */ + LMP_SIZE_VECTOR = 3, /*!< return length of vector */ + LMP_SIZE_ROWS = 4, /*!< return number of rows */ + LMP_SIZE_COLS = 5 /*!< return number of columns */ +}; + +/* Error codes to select the suitable function in the Error class */ + +enum _LMP_ERROR_CONST { + LMP_ERROR_WARNING = 0, /*!< call Error::warning() */ + LMP_ERROR_ONE = 1, /*!< called from one MPI rank */ + LMP_ERROR_ALL = 2, /*!< called from all MPI ranks */ + LMP_ERROR_WORLD = 4, /*!< error on Comm::world */ + LMP_ERROR_UNIVERSE = 8 /*!< error on Comm::universe */ +}; + +/** Variable style constants for extracting data from variables. + * + * Must be kept in sync with the equivalent constants in python/lammps/constants.py, + * fortran/lammps.f90, and tools/swig/lammps.i */ + +enum _LMP_VAR_CONST { + LMP_VAR_EQUAL = 0, /*!< compatible with equal-style variables */ + LMP_VAR_ATOM = 1, /*!< compatible with atom-style variables */ + LMP_VAR_VECTOR = 2, /*!< compatible with vector-style variables */ + LMP_VAR_STRING = 3 /*!< return value will be a string (catch-all) */ +}; + #ifdef __cplusplus extern "C" { #endif @@ -49,7 +109,11 @@ struct _liblammpsplugin { int abiversion; int has_exceptions; void *handle; +#if defined(LAMMPS_LIB_MPI) void *(*open)(int, char **, MPI_Comm, void **); +#else + void *open; +#endif void *(*open_no_mpi)(int, char **, void **); void *(*open_fortran)(int, char **, void **, int); void (*close)(void *); @@ -59,13 +123,15 @@ struct _liblammpsplugin { void (*kokkos_finalize)(); void (*python_finalize)(); + void (*error)(void *, int, const char *); + void (*file)(void *, char *); char *(*command)(void *, const char *); void (*commands_list)(void *, int, const char **); void (*commands_string)(void *, const char *); double (*get_natoms)(void *); - double (*get_thermo)(void *, char *); + double (*get_thermo)(void *, const char *); void (*extract_box)(void *, double *, double *, double *, double *, double *, int *, int *); @@ -78,12 +144,13 @@ struct _liblammpsplugin { int *(*extract_global_datatype)(void *, const char *); void *(*extract_global)(void *, const char *); - void *(*extract_atom_datatype)(void *, const char *); + int *(*extract_atom_datatype)(void *, const char *); void *(*extract_atom)(void *, const char *); void *(*extract_compute)(void *, const char *, int, int); void *(*extract_fix)(void *, const char *, int, int, int, int); void *(*extract_variable)(void *, const char *, char *); + int (*extract_variable_datatype)(void *, const char *); int (*set_variable)(void *, char *, char *); void (*gather_atoms)(void *, char *, int, int, void *); @@ -93,22 +160,26 @@ struct _liblammpsplugin { void (*scatter_atoms_subset)(void *, char *, int, int, int, int *, void *); void (*gather_bonds)(void *, void *); - -// lammps_create_atoms() takes tagint and imageint as args -// ifdef insures they are compatible with rest of LAMMPS -// caller must match to how LAMMPS library is built + + void (*gather)(void *, char *, int, int, void *); + void (*gather_concat)(void *, char *, int, int, void *); + void (*gather_subset)(void *, char *, int, int, int, int *,void *); + void (*scatter)(void *, char *, int, int, void *); + void (*scatter_subset)(void *, char *, int, int, int, int *, void *); + +/* lammps_create_atoms() takes tagint and imageint as args + * the ifdef insures they are compatible with rest of LAMMPS + * caller must match to how LAMMPS library is built */ #ifndef LAMMPS_BIGBIG - void (*create_atoms)(void *, int, int *, int *, double *, - double *, int *, int); + void (*create_atoms)(void *, int, int *, int *, double *, double *, int *, int); #else - void (*create_atoms)(void *, int, int64_t *, int *, double *, - double *, int64_t *, int); + void (*create_atoms)(void *, int, int64_t *, int *, double *, double *, int64_t *, int); #endif int (*find_pair_neighlist)(void *, const char *, int, int, int); int (*find_fix_neighlist)(void *, const char *, int); - int (*find_compute_neighlist)(void *, char *, int); + int (*find_compute_neighlist)(void *, const char *, int); int (*neighlist_num_elements)(void *, int); void (*neighlist_element_neighbors)(void *, int, int, int *, int *, int **); @@ -141,8 +212,16 @@ struct _liblammpsplugin { int (*plugin_count)(); int (*plugin_name)(int, char *, char *, int); - void (*set_fix_external_callback)(void *, const char *, FixExternalFnPtr, void*); - void (*fix_external_get_force)(void *, const char *); +#if !defined(LAMMPS_BIGBIG) + int (*encode_image_flags)(int, int, int); + void (*decode_image_flags)(int, int *); +#else + int64_t (*encode_image_flags)(int, int, int); + void (*decode_image_flags)(int64_t, int *); +#endif + + void (*set_fix_external_callback)(void *, const char *, FixExternalFnPtr, void *); + double **(*fix_external_get_force)(void *, const char *); void (*fix_external_set_energy_global)(void *, const char *, double); void (*fix_external_set_energy_peratom)(void *, const char *, double *); void (*fix_external_set_virial_global)(void *, const char *, double *); @@ -150,6 +229,8 @@ struct _liblammpsplugin { void (*fix_external_set_vector_length)(void *, const char *, int); void (*fix_external_set_vector)(void *, const char *, int, double); + void (*flush_buffers)(void *); + void (*free)(void *); void (*is_running)(void *); @@ -157,6 +238,8 @@ struct _liblammpsplugin { int (*has_error)(void *); int (*get_last_error_message)(void *, char *, int); + + int (*python_api_version)(); }; typedef struct _liblammpsplugin liblammpsplugin_t; diff --git a/examples/COUPLE/plugin/simple.c b/examples/COUPLE/plugin/simple.c index 609aeb1dfc..8383584a38 100644 --- a/examples/COUPLE/plugin/simple.c +++ b/examples/COUPLE/plugin/simple.c @@ -19,10 +19,16 @@ in.lammps = LAMMPS input script See README for compilation instructions */ +#include + #include #include #include -#include + +/* define so interface to lammps_open() is available, + since we will run on split communicator */ +#define LAMMPS_LIB_MPI 1 + #include "liblammpsplugin.h" /* this is the include for the plugin loader */ int main(int narg, char **arg) @@ -87,7 +93,13 @@ int main(int narg, char **arg) MPI_Abort(MPI_COMM_WORLD,1); } } - if (lammps == 1) lmp = plugin->open(0,NULL,comm_lammps,NULL); + if (lammps == 1) { + if (plugin->open == NULL) { + printf("ERROR: liblammpsmpi.c must be compiled with -DLAMMPS_LIB_MPI=1 for this program\n"); + MPI_Abort(MPI_COMM_WORLD,2); + } + lmp = plugin->open(0,NULL,comm_lammps,NULL); + } while (1) { if (me == 0) { @@ -112,23 +124,23 @@ int main(int narg, char **arg) int natoms = plugin->get_natoms(lmp); x = (double *) malloc(3*natoms*sizeof(double)); - plugin->gather_atoms(lmp,"x",1,3,x); + plugin->gather_atoms(lmp,(char *)"x",1,3,x); v = (double *) malloc(3*natoms*sizeof(double)); - plugin->gather_atoms(lmp,"v",1,3,v); + plugin->gather_atoms(lmp,(char *)"v",1,3,v); double epsilon = 0.1; x[0] += epsilon; - plugin->scatter_atoms(lmp,"x",1,3,x); + plugin->scatter_atoms(lmp,(char *)"x",1,3,x); plugin->command(lmp,"run 1"); } - // extract force on single atom two different ways + /* extract force on single atom two different ways */ if (lammps == 1) { double **f = (double **) plugin->extract_atom(lmp,"f"); printf("Force on 1 atom via extract_atom: %g\n",f[0][0]); - double *fx = (double *) plugin->extract_variable(lmp,"fx","all"); + double *fx = (double *) plugin->extract_variable(lmp,"fx",(char *)"all"); printf("Force on 1 atom via extract_variable: %g\n",fx[0]); } @@ -160,7 +172,7 @@ int main(int narg, char **arg) if (v) free(v); if (type) free(type); - // close down LAMMPS + /* close down LAMMPS */ if (lammps == 1) { plugin->close(lmp); diff --git a/examples/COUPLE/simple/CMakeLists.txt b/examples/COUPLE/simple/CMakeLists.txt index 4112eaa4e7..d9b877ec76 100644 --- a/examples/COUPLE/simple/CMakeLists.txt +++ b/examples/COUPLE/simple/CMakeLists.txt @@ -1,17 +1,44 @@ cmake_minimum_required(VERSION 3.10) -project(simple CXX) -set(LAMMPS_SRC_DIRECTORY "" CACHE PATH "Path for lammps source") -if(NOT LAMMPS_SRC_DIRECTORY STREQUAL "" AND EXISTS ${LAMMPS_SRC_DIRECTORY}/cmake/CMakeLists.txt) - option(BUILD_LIB "Build LAMMPS library" ON) - add_subdirectory(${LAMMPS_SRC_DIRECTORY}/cmake lammps) -else() +# enforce out-of-source build +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) + message(FATAL_ERROR "In-source builds are not allowed. You must create and use a build directory. " + "Please remove CMakeCache.txt and CMakeFiles first.") +endif() + +project(couple-simple VERSION 1.0 LANGUAGES C CXX) + +# by default, install into $HOME/.local (not /usr/local), +# so that no root access (and sudo) is needed +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/.local" CACHE PATH "Default install path" FORCE) +endif() + +# ugly hacks for MSVC which by default always reports an old C++ standard in the __cplusplus macro +# and prints lots of pointless warnings about "unsafe" functions +if(MSVC) + if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + if(LAMMPS_EXCEPTIONS) + add_compile_options(/EHsc) + endif() + endif() + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) +endif() + +find_package(MPI QUIET) +# do not include the (obsolete) MPI C++ bindings which makes +# for leaner object files and avoids namespace conflicts +set(MPI_CXX_SKIP_MPICXX TRUE) + +########################## + +# build within LAMMPS build system +if(NOT LAMMPS_SOURCE_DIR) find_package(LAMMPS REQUIRED) endif() add_executable(simpleCC simple.cpp) target_link_libraries(simpleCC LAMMPS::lammps) -enable_language(C) add_executable(simpleC simple.c) target_link_libraries(simpleC LAMMPS::lammps) diff --git a/fortran/lammps.f90 b/fortran/lammps.f90 index 8eae2eb1a4..3ab7a26d25 100644 --- a/fortran/lammps.f90 +++ b/fortran/lammps.f90 @@ -44,7 +44,8 @@ MODULE LIBLAMMPS ! Data type constants for extracting data from global, atom, compute, and fix ! ! Must be kept in sync with the equivalent declarations in - ! src/library.h, python/lammps/constants.py, and tools/swig/lammps.i + ! src/library.h, python/lammps/constants.py, tools/swig/lammps.i, + ! and examples/COUPLE/plugin/liblammpsplugin.h ! ! These are NOT part of the API (the part the user sees) INTEGER(c_int), PARAMETER :: & diff --git a/python/lammps/constants.py b/python/lammps/constants.py index a006d0b17a..8fd6a9eaf5 100644 --- a/python/lammps/constants.py +++ b/python/lammps/constants.py @@ -22,8 +22,8 @@ LAMMPS_INT64 = 4 LAMMPS_INT64_2D = 5 LAMMPS_STRING = 6 -# these must be kept in sync with the enums in src/library.h, tools/swig/lammps.i -# and the constants in fortran/lammps.f90 +# these must be kept in sync with the enums in src/library.h, tools/swig/lammps.i, +# examples/COUPLE/plugin/liblammpsplugin.h, and the constants in fortran/lammps.f90 LMP_STYLE_GLOBAL = 0 LMP_STYLE_ATOM = 1 LMP_STYLE_LOCAL = 2 diff --git a/src/fix_pair.cpp b/src/fix_pair.cpp index 0b54c24418..360cee2d5a 100644 --- a/src/fix_pair.cpp +++ b/src/fix_pair.cpp @@ -240,15 +240,19 @@ void FixPair::post_force(int /*vflag*/) // extract pair style fields one by one // store their values in this fix - int nlocal = atom->nlocal; + const int nlocal = atom->nlocal; int icol = 0; int columns; for (int ifield = 0; ifield < nfield; ifield++) { void *pvoid = pstyle->extract_peratom(fieldname[ifield],columns); - if (pvoid == nullptr) - error->all(FLERR,"Fix pair pair style cannot extract {}",fieldname[ifield]); + + // Pair::extract_peratom() may return a null pointer if there are no atoms the sub-domain + // so returning null is only an error if there are local atoms. + + if ((pvoid == nullptr) && (nlocal > 0)) + error->one(FLERR, "Fix pair cannot extract property {} from pair style", fieldname[ifield]); if (columns == 0) { double *pvector = (double *) pvoid; diff --git a/src/library.h b/src/library.h index 4ec6b21655..26006a3e9e 100644 --- a/src/library.h +++ b/src/library.h @@ -41,7 +41,7 @@ /** Data type constants for extracting data from atoms, computes and fixes * * Must be kept in sync with the equivalent constants in python/lammps/constants.py, - * fortran/lammps.f90, and tools/swig/lammps.i */ + * fortran/lammps.f90, tools/swig/lammps.i, examples/COUPLE/plugin/liblammpsplugin.h */ enum _LMP_DATATYPE_CONST { LAMMPS_INT = 0, /*!< 32-bit integer (array) */ @@ -56,7 +56,7 @@ enum _LMP_DATATYPE_CONST { /** Style constants for extracting data from computes and fixes. * * Must be kept in sync with the equivalent constants in python/lammps/constants.py, - * fortran/lammps.f90, and tools/swig/lammps.i */ + * fortran/lammps.f90, tools/swig/lammps.i, and examples/COUPLE/plugin/liblammpsplugin.h */ enum _LMP_STYLE_CONST { LMP_STYLE_GLOBAL = 0, /*!< return global data */ @@ -67,7 +67,7 @@ enum _LMP_STYLE_CONST { /** Type and size constants for extracting data from computes and fixes. * * Must be kept in sync with the equivalent constants in python/lammps/constants.py, - * fortran/lammps.f90, and tools/swig/lammps.i */ + * fortran/lammps.f90, tools/swig/lammps.i, and examples/COUPLE/plugin/liblammpsplugin.h */ enum _LMP_TYPE_CONST { LMP_TYPE_SCALAR = 0, /*!< return scalar */ @@ -81,7 +81,7 @@ enum _LMP_TYPE_CONST { /** Error codes to select the suitable function in the Error class * * Must be kept in sync with the equivalent constants in python/lammps/constants.py, - * fortran/lammps.f90, and tools/swig/lammps.i */ + * fortran/lammps.f90, tools/swig/lammps.i, and examples/COUPLE/plugin/liblammpsplugin.h */ enum _LMP_ERROR_CONST { LMP_ERROR_WARNING = 0, /*!< call Error::warning() */ @@ -94,7 +94,7 @@ enum _LMP_ERROR_CONST { /** Variable style constants for extracting data from variables. * * Must be kept in sync with the equivalent constants in python/lammps/constants.py, - * fortran/lammps.f90, and tools/swig/lammps.i */ + * fortran/lammps.f90, tools/swig/lammps.i, and examples/COUPLE/plugin/liblammpsplugin.h */ enum _LMP_VAR_CONST { LMP_VAR_EQUAL = 0, /*!< compatible with equal-style variables */ @@ -260,15 +260,14 @@ void lammps_decode_image_flags(int64_t image, int *flags); #if defined(LAMMPS_BIGBIG) typedef void (*FixExternalFnPtr)(void *, int64_t, int, int64_t *, double **, double **); -void lammps_set_fix_external_callback(void *handle, const char *id, FixExternalFnPtr funcptr, - void *ptr); #elif defined(LAMMPS_SMALLBIG) typedef void (*FixExternalFnPtr)(void *, int64_t, int, int *, double **, double **); -void lammps_set_fix_external_callback(void *, const char *, FixExternalFnPtr, void *); #else typedef void (*FixExternalFnPtr)(void *, int, int, int *, double **, double **); -void lammps_set_fix_external_callback(void *, const char *, FixExternalFnPtr, void *); #endif + +void lammps_set_fix_external_callback(void *handle, const char *id, FixExternalFnPtr funcptr, + void *ptr); double **lammps_fix_external_get_force(void *handle, const char *id); void lammps_fix_external_set_energy_global(void *handle, const char *id, double eng); void lammps_fix_external_set_energy_peratom(void *handle, const char *id, double *eng); diff --git a/unittest/c-library/CMakeLists.txt b/unittest/c-library/CMakeLists.txt index e9409be0cc..966fac177f 100644 --- a/unittest/c-library/CMakeLists.txt +++ b/unittest/c-library/CMakeLists.txt @@ -71,3 +71,23 @@ add_executable(test_library_mpi test_library_mpi.cpp) target_link_libraries(test_library_mpi PRIVATE lammps GTest::GMock) target_compile_definitions(test_library_mpi PRIVATE ${TEST_CONFIG_DEFS}) add_mpi_test(NAME LibraryMPI NUM_PROCS 4 COMMAND $) + +# simple run tests for coupling to the LAMMPS library +if(BUILD_MPI) + if(BUILD_SHARED_LIBS) + add_subdirectory(${LAMMPS_DIR}/examples/COUPLE/plugin ${CMAKE_BINARY_DIR}/build-couple) + add_test(NAME RunCoupleSimplePlugin + COMMAND $ 1 ${LAMMPS_DIR}/examples/COUPLE/plugin/in.lj $) + set_tests_properties(RunCoupleSimplePlugin PROPERTIES + ENVIRONMENT "TSAN_OPTIONS=ignore_noninstrumented_modules=1;HWLOC_HIDE_ERRORS=2" + PASS_REGULAR_EXPRESSION "LAMMPS \\([0-9]+ [A-Za-z]+ 2[0-9][0-9][0-9]( - Update [0-9]+)?\\)") + endif() + add_subdirectory(${LAMMPS_DIR}/examples/COUPLE/simple ${CMAKE_BINARY_DIR}/build-simple) + add_test(NAME RunCoupleSimpleC + COMMAND $ 1 ${LAMMPS_DIR}/examples/COUPLE/simple/in.lj) + add_test(NAME RunCoupleSimpleCC + COMMAND $ 1 ${LAMMPS_DIR}/examples/COUPLE/simple/in.lj) + set_tests_properties(RunCoupleSimpleC RunCoupleSimpleCC PROPERTIES + ENVIRONMENT "TSAN_OPTIONS=ignore_noninstrumented_modules=1;HWLOC_HIDE_ERRORS=2" + PASS_REGULAR_EXPRESSION "LAMMPS \\([0-9]+ [A-Za-z]+ 2[0-9][0-9][0-9]( - Update [0-9]+)?\\)") +endif()