diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 2d259791f2..aefa9cd597 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -156,8 +156,7 @@ if(BUILD_MPI) endif() endif() else() - enable_language(C) - file(GLOB MPI_SOURCES ${LAMMPS_SOURCE_DIR}/STUBS/mpi.c) + file(GLOB MPI_SOURCES ${LAMMPS_SOURCE_DIR}/STUBS/mpi.cpp) add_library(mpi_stubs STATIC ${MPI_SOURCES}) set_target_properties(mpi_stubs PROPERTIES OUTPUT_NAME lammps_mpi_stubs${LAMMPS_MACHINE}) target_include_directories(mpi_stubs PUBLIC $) diff --git a/cmake/Modules/Packages/MESSAGE.cmake b/cmake/Modules/Packages/MESSAGE.cmake index fb62763828..6ff4e322aa 100644 --- a/cmake/Modules/Packages/MESSAGE.cmake +++ b/cmake/Modules/Packages/MESSAGE.cmake @@ -2,9 +2,8 @@ if(LAMMPS_SIZES STREQUAL BIGBIG) message(FATAL_ERROR "The MESSAGE Package is not compatible with -DLAMMPS_BIGBIG") endif() option(MESSAGE_ZMQ "Use ZeroMQ in MESSAGE package" OFF) -file(GLOB_RECURSE cslib_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/message/cslib/[^.]*.F - ${LAMMPS_LIB_SOURCE_DIR}/message/cslib/[^.]*.c - ${LAMMPS_LIB_SOURCE_DIR}/message/cslib/[^.]*.cpp) +file(GLOB_RECURSE cslib_SOURCES + ${LAMMPS_LIB_SOURCE_DIR}/message/cslib/[^.]*.cpp) add_library(cslib STATIC ${cslib_SOURCES}) target_compile_definitions(cslib PRIVATE -DLAMMPS_${LAMMPS_SIZES}) diff --git a/doc/src/Build_basics.rst b/doc/src/Build_basics.rst index cb6bd9f6aa..c7baa21e62 100644 --- a/doc/src/Build_basics.rst +++ b/doc/src/Build_basics.rst @@ -95,7 +95,7 @@ standard. A more detailed discussion of that is below. .. note:: - The file ``src/STUBS/mpi.c`` provides a CPU timer function + The file ``src/STUBS/mpi.cpp`` provides a CPU timer function called ``MPI_Wtime()`` that calls ``gettimeofday()``. If your operating system does not support ``gettimeofday()``, you will need to insert code to call another timer. Note that the diff --git a/doc/src/Build_link.rst b/doc/src/Build_link.rst index 3d66371304..5255620231 100644 --- a/doc/src/Build_link.rst +++ b/doc/src/Build_link.rst @@ -20,16 +20,8 @@ the suffix ``.so.0`` (or some other number). .. note:: Care should be taken to use the same MPI library for the calling code - and the LAMMPS library. The ``library.h`` file includes ``mpi.h`` - and uses definitions from it so those need to be available and - consistent. When LAMMPS is compiled with the included STUBS MPI - library, then its ``mpi.h`` file needs to be included. While it is - technically possible to use a full MPI library in the calling code - and link to a serial LAMMPS library compiled with MPI STUBS, it is - recommended to use the *same* MPI library for both, and then use - ``MPI_Comm_split()`` in the calling code to pass a suitable - communicator with a subset of MPI ranks to the function creating the - LAMMPS instance. + and the LAMMPS library unless LAMMPS is to be compiled without (real) + MPI support using the include STUBS MPI library. Link with LAMMPS as a static library ------------------------------------ @@ -110,7 +102,7 @@ executable, that are also required to link the LAMMPS executable. .. code-block:: bash - gcc -c -O -I${HOME}/lammps/src/STUBS -I${HOME}/lammps/src -caller.c + gcc -c -O -I${HOME}/lammps/src -caller.c g++ -o caller caller.o -L${HOME}/lammps/lib/poems \ -L${HOME}/lammps/src/STUBS -L${HOME}/lammps/src \ -llammps_serial -lpoems -lmpi_stubs @@ -174,7 +166,7 @@ the POEMS package installed becomes: .. code-block:: bash - gcc -c -O -I${HOME}/lammps/src/STUBS -I${HOME}/lammps/src -caller.c + gcc -c -O -I${HOME}/lammps/src -caller.c g++ -o caller caller.o -L${HOME}/lammps/src -llammps_serial Locating liblammps.so at runtime diff --git a/python/lammps/core.py b/python/lammps/core.py index 1a4650c285..e13bf9585b 100644 --- a/python/lammps/core.py +++ b/python/lammps/core.py @@ -286,15 +286,16 @@ class lammps(object): self.lib.lammps_fix_external_set_energy_global = [c_void_p, c_char_p, c_double] self.lib.lammps_fix_external_set_virial_global = [c_void_p, c_char_p, POINTER(c_double)] - # detect if Python is using version of mpi4py that can pass a communicator - + # detect if Python is using a version of mpi4py that can pass communicators + # only needed if LAMMPS has been compiled with MPI support. self.has_mpi4py = False - try: - from mpi4py import __version__ as mpi4py_version - # tested to work with mpi4py versions 2 and 3 - self.has_mpi4py = mpi4py_version.split('.')[0] in ['2','3'] - except: - pass + if self.has_mpi_support: + try: + from mpi4py import __version__ as mpi4py_version + # tested to work with mpi4py versions 2 and 3 + self.has_mpi4py = mpi4py_version.split('.')[0] in ['2','3'] + except: + pass # if no ptr provided, create an instance of LAMMPS # don't know how to pass an MPI communicator from PyPar @@ -307,23 +308,27 @@ class lammps(object): if not ptr: - # with mpi4py v2, can pass MPI communicator to LAMMPS + # with mpi4py v2+, we can pass MPI communicators to LAMMPS # need to adjust for type of MPI communicator object # allow for int (like MPICH) or void* (like OpenMPI) - if self.has_mpi4py and self.has_mpi_support: + if self.has_mpi_support and self.has_mpi4py: from mpi4py import MPI self.MPI = MPI if comm: - if not self.has_mpi4py: - raise Exception('Python mpi4py version is not 2 or 3') if not self.has_mpi_support: raise Exception('LAMMPS not compiled with real MPI library') + if not self.has_mpi4py: + raise Exception('Python mpi4py version is not 2 or 3') if self.MPI._sizeof(self.MPI.Comm) == sizeof(c_int): MPI_Comm = c_int else: MPI_Comm = c_void_p + # Detect whether LAMMPS and mpi4py definitely use different MPI libs + if sizeof(MPI_Comm) != self.lib.lammps_config_has_mpi_support(): + raise Exception('Inconsistent MPI library in LAMMPS and mpi4py') + narg = 0 cargs = None if cmdargs: diff --git a/src/STUBS/Makefile b/src/STUBS/Makefile index 3c3c3b46d9..c9b6fdb65a 100644 --- a/src/STUBS/Makefile +++ b/src/STUBS/Makefile @@ -11,13 +11,13 @@ SHELL = /bin/sh # Files -SRC = mpi.c +SRC = mpi.cpp INC = mpi.h # Definitions EXE = libmpi_stubs.a -OBJ = $(SRC:.c=.o) +OBJ = $(SRC:.cpp=.o) # System-specific settings @@ -36,7 +36,7 @@ clean: # Compilation rules -.c.o: +.cpp.o: $(CC) $(CCFLAGS) -c $< # Individual dependencies diff --git a/src/STUBS/Makefile.mingw32-cross b/src/STUBS/Makefile.mingw32-cross index 4144954ec7..2934bbd468 100644 --- a/src/STUBS/Makefile.mingw32-cross +++ b/src/STUBS/Makefile.mingw32-cross @@ -5,17 +5,17 @@ SHELL = /bin/sh # Files -SRC = mpi.c +SRC = mpi.cpp INC = mpi.h # Definitions EXE = libmpi_mingw32.a -OBJ = $(SRC:%.c=%_mingw32.o) +OBJ = $(SRC:%.cpp=%_mingw32.o) # System-specific settings -CC = i686-w64-mingw32-gcc +CC = i686-w64-mingw32-g++ CCFLAGS = -O2 -Wall -march=i686 -mtune=generic -mfpmath=387 -mpc64 -I. ARCHIVE = i686-w64-mingw32-ar ARCHFLAG = rs diff --git a/src/STUBS/Makefile.mingw64-cross b/src/STUBS/Makefile.mingw64-cross index 70b971f262..e62d5dcbe1 100644 --- a/src/STUBS/Makefile.mingw64-cross +++ b/src/STUBS/Makefile.mingw64-cross @@ -5,17 +5,17 @@ SHELL = /bin/sh # Files -SRC = mpi.c +SRC = mpi.cpp INC = mpi.h # Definitions EXE = libmpi_mingw64.a -OBJ = $(SRC:%.c=%_mingw64.o) +OBJ = $(SRC:%.cpp=%_mingw64.o) # System-specific settings -CC = x86_64-w64-mingw32-gcc +CC = x86_64-w64-mingw32-g++ CCFLAGS = -O2 -Wall -march=core2 -mtune=core2 -msse2 -mpc64 -I. ARCHIVE = x86_64-w64-mingw32-ar ARCHFLAG = rs diff --git a/src/STUBS/mpi.c b/src/STUBS/mpi.cpp similarity index 100% rename from src/STUBS/mpi.c rename to src/STUBS/mpi.cpp diff --git a/src/STUBS/mpi.h b/src/STUBS/mpi.h index 063dc542be..28e897960d 100644 --- a/src/STUBS/mpi.h +++ b/src/STUBS/mpi.h @@ -16,12 +16,17 @@ #include -/* use C bindings for MPI interface */ +/* We compile STUBS with C++ so the symbols embedded + * the serial shared library will not collide with any + * corresponding symbols from a real MPI library (which + * uses C bindings). As a consequence the header *must* + * enforce compiling with C++ only. */ -#ifdef __cplusplus -extern "C" { +#ifndef __cplusplus +#error "MPI STUBS must be compiled with a C++ compiler" #endif + /* Dummy defs for MPI stubs */ #define MPI_COMM_WORLD 0 @@ -176,8 +181,4 @@ int MPI_Alltoallv(void *sendbuf, int *sendcounts, int *sdispls, MPI_Datatype recvtype, MPI_Comm comm); /* ---------------------------------------------------------------------- */ -#ifdef __cplusplus -} -#endif - #endif diff --git a/src/library.cpp b/src/library.cpp index 71bf205d90..2a7bbf07b3 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -4128,16 +4128,18 @@ void lammps_get_os_info(char *buffer, int buf_size) /* ---------------------------------------------------------------------- */ /** This function is used to query whether LAMMPS was compiled with - * a real MPI library or in serial. + * a real MPI library or in serial. For the real MPI library it + * reports the size of the MPI communicator in bytes (4 or 8), + * which allows to check for compatibility with a hosting code. * - * \return 0 when compiled with MPI STUBS, otherwise 1 */ + * \return 0 when compiled with MPI STUBS, otherwise the MPI_Comm size in bytes */ int lammps_config_has_mpi_support() { #ifdef MPI_STUBS return 0; #else - return 1; + return sizeof(MPI_Comm); #endif } diff --git a/unittest/c-library/test_library_config.cpp b/unittest/c-library/test_library_config.cpp index f196f800da..e5eb044d31 100644 --- a/unittest/c-library/test_library_config.cpp +++ b/unittest/c-library/test_library_config.cpp @@ -74,7 +74,7 @@ TEST(LAMMPSConfig, package_name) 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_EQ(lammps_config_package_name(0, buf, 128), 0); EXPECT_THAT(buf, StrEq("")); } }; @@ -200,7 +200,10 @@ TEST(LAMMPSConfig, exceptions) TEST(LAMMPSConfig, mpi_support) { - EXPECT_EQ(lammps_config_has_mpi_support(), LAMMPS_HAS_MPI); + if (LAMMPS_HAS_MPI) + EXPECT_GT(lammps_config_has_mpi_support(), 0); + else + EXPECT_EQ(lammps_config_has_mpi_support(), 0); }; TEST(LAMMPSConfig, png_support) diff --git a/unittest/python/python-open.py b/unittest/python/python-open.py index 67500ea6fa..5140ce9185 100644 --- a/unittest/python/python-open.py +++ b/unittest/python/python-open.py @@ -37,7 +37,7 @@ class PythonOpen(unittest.TestCase): lmp=lammps(name=self.machine) self.assertIsNot(lmp.lmp,None) self.assertEqual(lmp.opened,1) - self.assertEqual(has_mpi4py,lmp.has_mpi4py) + self.assertEqual(has_mpi and has_mpi4py,lmp.has_mpi4py) self.assertEqual(has_mpi,lmp.has_mpi_support) lmp.close() self.assertIsNone(lmp.lmp,None)