diff --git a/.github/workflows/compile-msvc.yml b/.github/workflows/compile-msvc.yml new file mode 100644 index 0000000000..307dc81fe6 --- /dev/null +++ b/.github/workflows/compile-msvc.yml @@ -0,0 +1,33 @@ +# GitHub action to build LAMMPS on Windows with Visual C++ +name: "Native Windows Compilation" + +on: + push: + branches: [master] + +jobs: + build: + name: Windows Compilation Test + if: ${{ github.repository == 'lammps/lammps' }} + runs-on: windows-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + fetch-depth: 2 + + - name: Building LAMMPS via CMake + shell: bash + run: | + cmake -C cmake/presets/windows.cmake \ + -S cmake -B build \ + -D BUILD_SHARED_LIBS=on \ + -D LAMMPS_EXCEPTIONS=on + cmake --build build --config Release + + - name: Run LAMMPS executable + shell: bash + run: | + ./build/Release/lmp.exe -h + ./build/Release/lmp.exe -in bench/in.lj diff --git a/.gitignore b/.gitignore index ae708ff184..3fb3af0d13 100644 --- a/.gitignore +++ b/.gitignore @@ -37,8 +37,8 @@ vgcore.* .Trashes ehthumbs.db Thumbs.db -.clang-format .lammps_history +.vs #cmake /build* @@ -49,3 +49,8 @@ Thumbs.db /Testing /cmake_install.cmake /lmp +out/Debug +out/RelWithDebInfo +out/Release +out/x86 +out/x64 diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 3af67bf8e0..fc427acdc9 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -82,11 +82,22 @@ include(CheckIncludeFileCXX) # set required compiler flags and compiler/CPU arch specific optimizations if((CMAKE_CXX_COMPILER_ID STREQUAL "Intel") OR (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -restrict") - if(CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.3 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.4) - set(CMAKE_TUNE_DEFAULT "-xCOMMON-AVX512") + if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Qrestrict") + endif() + if(CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.3 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.4) + set(CMAKE_TUNE_DEFAULT "/QxCOMMON-AVX512") + else() + set(CMAKE_TUNE_DEFAULT "/QxHost") + endif() else() - set(CMAKE_TUNE_DEFAULT "-xHost") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -restrict") + if(CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.3 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.4) + set(CMAKE_TUNE_DEFAULT "-xCOMMON-AVX512") + else() + set(CMAKE_TUNE_DEFAULT "-xHost") + endif() endif() endif() @@ -97,9 +108,13 @@ if(PKG_KOKKOS AND (CMAKE_CXX_STANDARD LESS 14)) endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "Use compiler extensions") -# ugly hack for MSVC which by default always reports an old C++ standard in the __cplusplus macro +# 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) add_compile_options(/Zc:__cplusplus) + add_compile_options(/wd4244) + add_compile_options(/wd4267) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) endif() # export all symbols when building a .dll file on windows @@ -284,6 +299,11 @@ else() target_include_directories(mpi_stubs PUBLIC $) if(BUILD_SHARED_LIBS) target_link_libraries(lammps PRIVATE mpi_stubs) + if(MSVC) + target_link_libraries(lmp PRIVATE mpi_stubs) + target_include_directories(lmp INTERFACE $) + target_compile_definitions(lmp INTERFACE $) + endif(MSVC) target_include_directories(lammps INTERFACE $) target_compile_definitions(lammps INTERFACE $) else() @@ -471,9 +491,12 @@ foreach(HEADER cmath) endif(NOT FOUND_${HEADER}) endforeach(HEADER) -set(MATH_LIBRARIES "m" CACHE STRING "math library") -mark_as_advanced( MATH_LIBRARIES ) -target_link_libraries(lammps PRIVATE ${MATH_LIBRARIES}) +# make the standard math library overrideable and autodetected (for systems that don't have it) +find_library(STANDARD_MATH_LIB m DOC "Standard Math library") +mark_as_advanced(STANDARD_MATH_LIB) +if(STANDARD_MATH_LIB) + target_link_libraries(lammps PRIVATE ${STANDARD_MATH_LIB}) +endif() ###################################### # Generate Basic Style files @@ -611,7 +634,7 @@ endif() # and after everything else that is compiled locally ###################################################################### if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - target_link_libraries(lammps PRIVATE -lwsock32 -lpsapi) + target_link_libraries(lammps PRIVATE "wsock32;psapi") endif() ###################################################### diff --git a/cmake/CMakeSettings.json b/cmake/CMakeSettings.json new file mode 100644 index 0000000000..dada2f6752 --- /dev/null +++ b/cmake/CMakeSettings.json @@ -0,0 +1,55 @@ +{ + "configurations": [ + { + "name": "x64-Debug-MSVC", + "generator": "Ninja", + "configurationType": "Debug", + "buildRoot": "${workspaceRoot}\\build\\${name}", + "installRoot": "${workspaceRoot}\\install\\${name}", + "cmakeCommandArgs": "-S ${workspaceRoot}\\cmake -C ${workspaceRoot}\\cmake\\presets\\windows.cmake", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "msvc_x64_x64" ], + "variables": [ + { + "name": "BUILD_SHARED_LIBS", + "value": "True", + "type": "BOOL" + }, + { + "name": "BUILD_TOOLS", + "value": "True", + "type": "BOOL" + }, + { + "name": "LAMMPS_EXCEPTIONS", + "value": "True", + "type": "BOOL" + } + ] + }, + { + "name": "x64-Debug-Clang", + "generator": "Ninja", + "configurationType": "Debug", + "buildRoot": "${workspaceRoot}\\build\\${name}", + "installRoot": "${workspaceRoot}\\install\\${name}", + "cmakeCommandArgs": "-S ${workspaceRoot}\\cmake -C ${workspaceRoot}\\cmake\\presets\\windows.cmake", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "clang_cl_x64" ], + "variables": [ + { + "name": "BUILD_TOOLS", + "value": "True", + "type": "BOOL" + }, + { + "name": "LAMMPS_EXCEPTIONS", + "value": "True", + "type": "BOOL" + } + ] + } + ] +} \ No newline at end of file diff --git a/cmake/Modules/Tools.cmake b/cmake/Modules/Tools.cmake index 146764dbd5..c3b0a0771d 100644 --- a/cmake/Modules/Tools.cmake +++ b/cmake/Modules/Tools.cmake @@ -25,7 +25,9 @@ if(BUILD_TOOLS) get_filename_component(MSI2LMP_SOURCE_DIR ${LAMMPS_TOOLS_DIR}/msi2lmp/src ABSOLUTE) file(GLOB MSI2LMP_SOURCES ${MSI2LMP_SOURCE_DIR}/[^.]*.c) add_executable(msi2lmp ${MSI2LMP_SOURCES}) - target_link_libraries(msi2lmp PRIVATE ${MATH_LIBRARIES}) + if(STANDARD_MATH_LIB) + target_link_libraries(msi2lmp PRIVATE ${STANDARD_MATH_LIB}) + endif() install(TARGETS msi2lmp DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${LAMMPS_DOC_DIR}/msi2lmp.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) endif() diff --git a/cmake/presets/windows.cmake b/cmake/presets/windows.cmake new file mode 100644 index 0000000000..d4e69c5fca --- /dev/null +++ b/cmake/presets/windows.cmake @@ -0,0 +1,64 @@ +set(WIN_PACKAGES + ASPHERE + BOCS + BODY + BROWNIAN + CG-DNA + CG-SDK + CLASS2 + COLLOID + COLVARS + CORESHELL + DIELECTRIC + DIFFRACTION + DIPOLE + DPD-BASIC + DPD-MESO + DPD-REACT + DPD-SMOOTH + DRUDE + EFF + EXTRA-COMPUTE + EXTRA-DUMP + EXTRA-FIX + EXTRA-MOLECULE + EXTRA-PAIR + FEP + GRANULAR + INTERLAYER + KSPACE + MANIFOLD + MANYBODY + MC + MEAM + MISC + ML-IAP + ML-SNAP + MOFFF + MOLECULE + MOLFILE + OPENMP + ORIENT + PERI + PHONON + POEMS + PTM + QEQ + QTB + REACTION + REAXFF + REPLICA + RIGID + SHOCK + SMTBQ + SPH + SPIN + SRD + TALLY + UEF + YAFF) + +foreach(PKG ${WIN_PACKAGES}) + set(PKG_${PKG} ON CACHE BOOL "" FORCE) +endforeach() + diff --git a/doc/doxygen/Doxyfile.in b/doc/doxygen/Doxyfile.in index 49a271355f..d454898f4e 100644 --- a/doc/doxygen/Doxyfile.in +++ b/doc/doxygen/Doxyfile.in @@ -435,6 +435,8 @@ INPUT = @LAMMPS_SOURCE_DIR@/utils.cpp \ @LAMMPS_SOURCE_DIR@/my_pool_chunk.cpp \ @LAMMPS_SOURCE_DIR@/my_pool_chunk.h \ @LAMMPS_SOURCE_DIR@/math_eigen.h \ + @LAMMPS_SOURCE_DIR@/platform.h \ + @LAMMPS_SOURCE_DIR@/platform.cpp \ # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded diff --git a/doc/src/Build_settings.rst b/doc/src/Build_settings.rst index c7397935d8..01bd8e2c80 100644 --- a/doc/src/Build_settings.rst +++ b/doc/src/Build_settings.rst @@ -354,8 +354,10 @@ Read or write compressed files ----------------------------------------- If this option is enabled, large files can be read or written with -gzip compression by several LAMMPS commands, including -:doc:`read_data `, :doc:`rerun `, and :doc:`dump `. +compression by ``gzip`` or similar tools by several LAMMPS commands, +including :doc:`read_data `, :doc:`rerun `, and +:doc:`dump `. Currently supported compression tools are: +``gzip``, ``bzip2``, ``zstd``, and ``lzma``. .. tabs:: @@ -364,8 +366,7 @@ gzip compression by several LAMMPS commands, including .. code-block:: bash -D WITH_GZIP=value # yes or no - # default is yes if CMake can find gzip, else no - -D GZIP_EXECUTABLE=path # path to gzip executable if CMake cannot find it + # default is yes if CMake can find the gzip program, else no .. tab:: Traditional make @@ -373,14 +374,15 @@ gzip compression by several LAMMPS commands, including LMP_INC = -DLAMMPS_GZIP -This option requires that your operating system fully supports the "popen()" -function in the standard runtime library and that a ``gzip`` executable can be -found by LAMMPS during a run. +This option requires that your operating system fully supports the +"popen()" function in the standard runtime library and that a ``gzip`` +or other executable can be found by LAMMPS in the standard search path +during a run. .. note:: - On some clusters with high-speed networks, using the "fork()" library - call (required by "popen()") can interfere with the fast communication + On clusters with high-speed networks, using the "fork()" library call + (required by "popen()") can interfere with the fast communication library and lead to simulations using compressed output or input to hang or crash. For selected operations, compressed file I/O is also available using a compression library instead, which is what the diff --git a/doc/src/Build_windows.rst b/doc/src/Build_windows.rst index 3a56f29d09..fa2296d302 100644 --- a/doc/src/Build_windows.rst +++ b/doc/src/Build_windows.rst @@ -4,6 +4,7 @@ Notes for building LAMMPS on Windows * :ref:`General remarks ` * :ref:`Running Linux on Windows ` * :ref:`Using GNU GCC ported to Windows ` +* :ref:`Using Visual Studio ` * :ref:`Using a cross-compiler ` ---------- @@ -31,13 +32,13 @@ pre-compiled Windows binary packages are sufficient for your needs. If it is necessary for you to compile LAMMPS on a Windows machine (e.g. because it is your main desktop), please also consider using a virtual machine software and compile and run LAMMPS in a Linux virtual -machine, or - if you have a sufficiently up-to-date Windows 10 -installation - consider using the Windows subsystem for Linux. This -optional Windows feature allows you to run the bash shell from Ubuntu -from within Windows and from there on, you can pretty much use that -shell like you are running on an Ubuntu Linux machine (e.g. installing -software via apt-get and more). For more details on that, please see -:doc:`this tutorial `. +machine, or - if you have a sufficiently up-to-date Windows 10 or +Windows 11 installation - consider using the Windows subsystem for +Linux. This optional Windows feature allows you to run the bash shell +from Ubuntu from within Windows and from there on, you can pretty much +use that shell like you are running on an Ubuntu Linux machine +(e.g. installing software via apt-get and more). For more details on +that, please see :doc:`this tutorial `. .. _gnu: @@ -67,6 +68,35 @@ requiring changes to the LAMMPS source code, or figure out corrections yourself, please report them on the lammps-users mailing list, or file them as an issue or pull request on the LAMMPS GitHub project. +.. _msvc: + +Using Microsoft Visual Studio +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Following the integration of the :doc:`platform namespace +` into the LAMMPS code base, portability of LAMMPS +to be compiled on Windows using Visual Studio has been significantly +improved. This has been tested with Visual Studio 2019 (aka version +16). Not all features and packages in LAMMPS are currently supported +out of the box, but a preset ``cmake/presets/windows.cmake`` is provided +that contains the packages that have been compiled successfully. You +must use the CMake based build procedure, and either use the integrated +CMake support of Visual Studio or use an external CMake installation to +create build files for the Visual Studio build system. Please note that +on launching Visual Studio it will scan the directory tree and likely +miss the correct master ``CMakeLists.txt``. Try to open the +``cmake/CMakeSettings.json`` and use those CMake configurations as a +starting point. It is also possible to configure and compile LAMMPS +from the command line with a CMake binary from `cmake.org `_. + +To support running in parallel you can compile with OpenMP enabled using +the OPENMP package or install Microsoft MPI (including the SDK) and compile +LAMMPS with MPI enabled. + +This is work in progress and you should contact the LAMMPS developers +via GitHub, the forum, or the mailing list, if you have questions or +LAMMPS specific problems. + .. _cross: Using a cross-compiler diff --git a/doc/src/Developer.rst b/doc/src/Developer.rst index f68007486d..fd4a44a8a0 100644 --- a/doc/src/Developer.rst +++ b/doc/src/Developer.rst @@ -18,4 +18,5 @@ of time and requests from the LAMMPS user community. Developer_plugins Developer_unittest Classes + Developer_platform Developer_utils diff --git a/doc/src/Developer_platform.rst b/doc/src/Developer_platform.rst new file mode 100644 index 0000000000..4cea36f94c --- /dev/null +++ b/doc/src/Developer_platform.rst @@ -0,0 +1,149 @@ +Platform abstraction functions +------------------------------ + +The ``platform`` sub-namespace inside the ``LAMMPS_NS`` namespace +provides a collection of wrapper and convenience functions and utilities +that perform common tasks for which platform specific code would be +required or for which a more high-level abstraction would be convenient +and reduce duplicated code. This reduces redundant implementations and +encourages consistent behavior and thus has some overlap with the +:doc:`"utils" sub-namespace `. + +Time functions +^^^^^^^^^^^^^^ + +.. doxygenfunction:: cputime + :project: progguide + +.. doxygenfunction:: walltime + :project: progguide + +.. doxygenfunction:: usleep + :project: progguide + +Platform information functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. doxygenfunction:: os_info + :project: progguide + +.. doxygenfunction:: compiler_info + :project: progguide + +.. doxygenfunction:: cxx_standard + :project: progguide + +.. doxygenfunction:: openmp_standard + :project: progguide + +.. doxygenfunction:: mpi_vendor + :project: progguide + +.. doxygenfunction:: mpi_info + :project: progguide + + +File and path functions and global constants +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. doxygenvariable:: filepathsep + :project: progguide + +.. doxygenvariable:: pathvarsep + :project: progguide + +.. doxygenfunction:: guesspath + :project: progguide + +.. doxygenfunction:: path_basename + :project: progguide + +.. doxygenfunction:: path_join + :project: progguide + +.. doxygenfunction:: file_is_readable + :project: progguide + +.. doxygenfunction:: is_console + :project: progguide + +.. doxygenfunction:: path_is_directory + :project: progguide + +.. doxygenfunction:: current_directory + :project: progguide + +.. doxygenfunction:: list_directory + :project: progguide + +.. doxygenfunction:: chdir + :project: progguide + +.. doxygenfunction:: mkdir + :project: progguide + +.. doxygenfunction:: rmdir + :project: progguide + +.. doxygenfunction:: unlink + :project: progguide + +Standard I/O function wrappers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. doxygenvariable:: END_OF_FILE + :project: progguide + +.. doxygenfunction:: ftell + :project: progguide + +.. doxygenfunction:: fseek + :project: progguide + +.. doxygenfunction:: ftruncate + :project: progguide + +.. doxygenfunction:: popen + :project: progguide + +.. doxygenfunction:: pclose + :project: progguide + +Environment variable functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. doxygenfunction:: putenv + :project: progguide + +.. doxygenfunction:: list_pathenv + :project: progguide + +.. doxygenfunction:: find_exe_path + :project: progguide + +Dynamically loaded object or library functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. doxygenfunction:: dlopen + :project: progguide + +.. doxygenfunction:: dlclose + :project: progguide + +.. doxygenfunction:: dlsym + :project: progguide + +.. doxygenfunction:: dlerror + :project: progguide + +Compressed file I/O functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. doxygenfunction:: has_compress_extension + :project: progguide + +.. doxygenfunction:: compressed_read + :project: progguide + +.. doxygenfunction:: compressed_write + :project: progguide diff --git a/doc/src/Developer_utils.rst b/doc/src/Developer_utils.rst index 041fce60b0..db47a9e3c3 100644 --- a/doc/src/Developer_utils.rst +++ b/doc/src/Developer_utils.rst @@ -7,7 +7,9 @@ a collection of convenience functions and utilities that perform common tasks that are required repeatedly throughout the LAMMPS code like reading or writing to files with error checking or translation of strings into specific types of numbers with checking for validity. This -reduces redundant implementations and encourages consistent behavior. +reduces redundant implementations and encourages consistent behavior and +thus has some overlap with the :doc:`"platform" sub-namespace +`. I/O with status check and similar functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -101,6 +103,12 @@ and parsing files or arguments. .. doxygenfunction:: strdup :project: progguide +.. doxygenfunction:: lowercase + :project: progguide + +.. doxygenfunction:: uppercase + :project: progguide + .. doxygenfunction:: trim :project: progguide @@ -143,21 +151,6 @@ and parsing files or arguments. .. doxygenfunction:: is_double :project: progguide -File and path functions -^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. doxygenfunction:: guesspath - :project: progguide - -.. doxygenfunction:: path_basename - :project: progguide - -.. doxygenfunction:: path_join - :project: progguide - -.. doxygenfunction:: file_is_readable - :project: progguide - Potential file functions ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/src/fix_saed_vtk.rst b/doc/src/fix_saed_vtk.rst index a9e8f154e6..dd5db32966 100644 --- a/doc/src/fix_saed_vtk.rst +++ b/doc/src/fix_saed_vtk.rst @@ -28,7 +28,6 @@ Syntax Nstart = start averaging on this timestep *file* arg = filename filename = name of file to output time averages to - *overwrite* arg = none = overwrite output file with only latest output Examples """""""" @@ -161,10 +160,6 @@ the *file* keyword and this string is appended with _N.vtk where N is an index (0,1,2...) to account for situations with multiple diffraction intensity outputs. -The *overwrite* keyword will continuously overwrite the output file -with the latest output, so that it only contains one timestep worth of -output. This option can only be used with the *ave running* setting. - Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 7126b3cfe7..1a590d47b8 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -1137,6 +1137,7 @@ Germann Germano gerolf Gerolf +getrusage Gershgorin getter gettimeofday @@ -1224,6 +1225,7 @@ Guo gw gyromagnetic gz +gzip gzipped Haak Hafskjold @@ -1812,6 +1814,7 @@ lyon Lysogorskiy Lyulin lz +lzma Maaravi MACHDYN machdyn @@ -2765,6 +2768,7 @@ REAXFF ReaxFF reaxff rebo +recurse recursing Ree refactored @@ -3445,6 +3449,7 @@ usec uSemiParallel userguide username +usleep usr util utils diff --git a/examples/plugins/CMakeLists.txt b/examples/plugins/CMakeLists.txt index 59c2802b45..c61454870a 100644 --- a/examples/plugins/CMakeLists.txt +++ b/examples/plugins/CMakeLists.txt @@ -14,6 +14,15 @@ endif() project(plugins VERSION 1.0 LANGUAGES CXX) +# 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) + add_compile_options(/Zc:__cplusplus) + add_compile_options(/wd4244) + add_compile_options(/wd4267) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) +endif() + # NOTE: the next line should be commented out when used outside of the LAMMPS package get_filename_component(LAMMPS_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../../src ABSOLUTE) set(LAMMPS_HEADER_DIR ${LAMMPS_SOURCE_DIR} CACHE PATH "Location of LAMMPS headers") @@ -36,11 +45,6 @@ if((CMAKE_CXX_COMPILER_ID STREQUAL "Intel") OR (CMAKE_CXX_COMPILER_ID STREQUAL " set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -restrict") endif() -# bail out on windows -if(CMAKE_SYSTEM_NAME STREQUAL Windows) - message(FATAL_ERROR "LAMMPS plugins are currently not supported on Windows") -endif() - set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}) include(CheckIncludeFileCXX) include(LAMMPSInterfaceCXX) @@ -62,12 +66,21 @@ add_library(zero2plugin MODULE zero2plugin.cpp pair_zero2.cpp bond_zero2.cpp angle_zero2.cpp dihedral_zero2.cpp improper_zero2.cpp) target_link_libraries(zero2plugin PRIVATE lammps) -set_target_properties(morse2plugin nve2plugin helloplugin zero2plugin PROPERTIES - PREFIX "" - LINK_FLAGS "-rdynamic") +set_target_properties(morse2plugin nve2plugin helloplugin zero2plugin PROPERTIES PREFIX "") # MacOS seems to need this if(CMAKE_SYSTEM_NAME STREQUAL Darwin) + set_target_properties(morse2plugin nve2plugin helloplugin zero2plugin + PROPERTIES LINK_FLAGS "-Wl,-undefined,dynamic_lookup") +elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") +# tell CMake to export all symbols to a .dll on Windows with special case for MinGW cross-compilers + set_target_properties(morse2plugin nve2plugin helloplugin zero2plugin + PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE) + if(CMAKE_CROSSCOMPILING) + set_target_properties(morse2plugin nve2plugin helloplugin zero2plugin + PROPERTIES LINK_FLAGS "-Wl,--export-all-symbols") + endif() +else() set_target_properties(morse2plugin nve2plugin helloplugin zero2plugin PROPERTIES - LINK_FLAGS "-Wl,-undefined,dynamic_lookup") + LINK_FLAGS "-rdynamic") endif() diff --git a/examples/plugins/LAMMPSInterfaceCXX.cmake b/examples/plugins/LAMMPSInterfaceCXX.cmake index 02f9159319..d52cf8f4e5 100644 --- a/examples/plugins/LAMMPSInterfaceCXX.cmake +++ b/examples/plugins/LAMMPSInterfaceCXX.cmake @@ -23,7 +23,9 @@ endfunction(validate_option) # LAMMPS C++ interface. We only need the header related parts. add_library(lammps INTERFACE) target_include_directories(lammps INTERFACE ${LAMMPS_HEADER_DIR}) - +if((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND CMAKE_CROSSCOMPILING) + target_link_libraries(lammps INTERFACE ${CMAKE_BINARY_DIR}/../liblammps.dll.a) +endif() ################################################################################ # MPI configuration if(NOT CMAKE_CROSSCOMPILING) diff --git a/lib/gpu/geryon/ocl_device.h b/lib/gpu/geryon/ocl_device.h index 003b4b3ba7..df53aff5b8 100644 --- a/lib/gpu/geryon/ocl_device.h +++ b/lib/gpu/geryon/ocl_device.h @@ -481,7 +481,7 @@ int UCL_Device::set_platform(int pid) { cl_device_id *subdevice_list = new cl_device_id[num_subdevices]; CL_SAFE_CALL(clCreateSubDevices(device_list[i], props, num_subdevices, subdevice_list, &num_subdevices)); - for (int j=0; j= 3.0) op.has_shuffle_support=true; } + delete[] buffer2; #endif _properties.push_back(op); @@ -836,7 +837,7 @@ int UCL_Device::auto_set_platform(const enum UCL_DEVICE_TYPE type, bool vendor_match=false; bool type_match=false; - int max_cus=0; + unsigned int max_cus=0; int best_platform=0; std::string vendor_upper=vendor; diff --git a/src/COLVARS/fix_colvars.cpp b/src/COLVARS/fix_colvars.cpp index 32211f7689..6d6799b43e 100644 --- a/src/COLVARS/fix_colvars.cpp +++ b/src/COLVARS/fix_colvars.cpp @@ -303,7 +303,7 @@ FixColvars::FixColvars(LAMMPS *lmp, int narg, char **arg) : me = comm->me; root2root = MPI_COMM_NULL; - conf_file = strdup(arg[3]); + conf_file = utils::strdup(arg[3]); rng_seed = 1966; unwrap_flag = 1; @@ -319,22 +319,22 @@ FixColvars::FixColvars(LAMMPS *lmp, int narg, char **arg) : error->all(FLERR,"Missing argument to keyword"); if (0 == strcmp(arg[iarg], "input")) { - inp_name = strdup(arg[iarg+1]); + inp_name = utils::strdup(arg[iarg+1]); } else if (0 == strcmp(arg[iarg], "output")) { - out_name = strdup(arg[iarg+1]); + out_name = utils::strdup(arg[iarg+1]); } else if (0 == strcmp(arg[iarg], "seed")) { rng_seed = utils::inumeric(FLERR,arg[iarg+1],false,lmp); } else if (0 == strcmp(arg[iarg], "unwrap")) { unwrap_flag = utils::logical(FLERR,arg[iarg+1],false,lmp); } else if (0 == strcmp(arg[iarg], "tstat")) { - tmp_name = strdup(arg[iarg+1]); + tmp_name = utils::strdup(arg[iarg+1]); } else { error->all(FLERR,"Unknown fix colvars parameter"); } ++iarg; ++iarg; } - if (!out_name) out_name = strdup("out"); + if (!out_name) out_name = utils::strdup("out"); /* initialize various state variables. */ tstat_id = -1; @@ -359,10 +359,10 @@ FixColvars::FixColvars(LAMMPS *lmp, int narg, char **arg) : FixColvars::~FixColvars() { - memory->sfree(conf_file); - memory->sfree(inp_name); - memory->sfree(out_name); - memory->sfree(tmp_name); + delete[] conf_file; + delete[] inp_name; + delete[] out_name; + delete[] tmp_name; memory->sfree(comm_buf); if (proxy) { @@ -430,17 +430,15 @@ void FixColvars::one_time_init() // create and initialize the colvars proxy if (me == 0) { - if (screen) fputs("colvars: Creating proxy instance\n",screen); - if (logfile) fputs("colvars: Creating proxy instance\n",logfile); + utils::logmesg(lmp,"colvars: Creating proxy instance\n"); #ifdef LAMMPS_BIGBIG - if (screen) fputs("colvars: cannot handle atom ids > 2147483647\n",screen); - if (logfile) fputs("colvars: cannot handle atom ids > 2147483647\n",logfile); + utils::logmesg(lmp,"colvars: cannot handle atom ids > 2147483647\n"); #endif if (inp_name) { if (strcmp(inp_name,"NULL") == 0) { - memory->sfree(inp_name); + delete[] inp_name; inp_name = nullptr; } } @@ -458,8 +456,7 @@ void FixColvars::one_time_init() } } - proxy = new colvarproxy_lammps(lmp,inp_name,out_name, - rng_seed,t_target,root2root); + proxy = new colvarproxy_lammps(lmp,inp_name,out_name,rng_seed,t_target,root2root); proxy->init(conf_file); num_coords = (proxy->modify_atom_positions()->size()); diff --git a/src/COMPRESS/dump_atom_gz.cpp b/src/COMPRESS/dump_atom_gz.cpp index 38229a71bb..5f799054bb 100644 --- a/src/COMPRESS/dump_atom_gz.cpp +++ b/src/COMPRESS/dump_atom_gz.cpp @@ -33,7 +33,7 @@ DumpAtomGZ::~DumpAtomGZ() {} /* ---------------------------------------------------------------------- generic opening of a dump file - ASCII or binary or gzipped + ASCII or binary or compressed some derived classes override this function ------------------------------------------------------------------------- */ diff --git a/src/COMPRESS/dump_cfg_gz.cpp b/src/COMPRESS/dump_cfg_gz.cpp index ea51ce87c3..8d6347d978 100644 --- a/src/COMPRESS/dump_cfg_gz.cpp +++ b/src/COMPRESS/dump_cfg_gz.cpp @@ -35,7 +35,7 @@ DumpCFGGZ::~DumpCFGGZ() {} /* ---------------------------------------------------------------------- generic opening of a dump file - ASCII or binary or gzipped + ASCII or binary or compressed some derived classes override this function ------------------------------------------------------------------------- */ diff --git a/src/COMPRESS/dump_custom_gz.cpp b/src/COMPRESS/dump_custom_gz.cpp index 7cbab10cb4..f40cf8d3d1 100644 --- a/src/COMPRESS/dump_custom_gz.cpp +++ b/src/COMPRESS/dump_custom_gz.cpp @@ -33,7 +33,7 @@ DumpCustomGZ::~DumpCustomGZ() {} /* ---------------------------------------------------------------------- generic opening of a dump file - ASCII or binary or gzipped + ASCII or binary or compressed some derived classes override this function ------------------------------------------------------------------------- */ diff --git a/src/COMPRESS/dump_custom_zstd.cpp b/src/COMPRESS/dump_custom_zstd.cpp index 8b7d153fc4..347c9c08e2 100644 --- a/src/COMPRESS/dump_custom_zstd.cpp +++ b/src/COMPRESS/dump_custom_zstd.cpp @@ -45,7 +45,7 @@ DumpCustomZstd::~DumpCustomZstd() /* ---------------------------------------------------------------------- generic opening of a dump file - ASCII or binary or gzipped + ASCII or binary or compressed some derived classes override this function ------------------------------------------------------------------------- */ diff --git a/src/COMPRESS/dump_local_gz.cpp b/src/COMPRESS/dump_local_gz.cpp index 206e2aeb09..a23fa1a1ac 100644 --- a/src/COMPRESS/dump_local_gz.cpp +++ b/src/COMPRESS/dump_local_gz.cpp @@ -33,7 +33,7 @@ DumpLocalGZ::~DumpLocalGZ() {} /* ---------------------------------------------------------------------- generic opening of a dump file - ASCII or binary or gzipped + ASCII or binary or compressed some derived classes override this function ------------------------------------------------------------------------- */ diff --git a/src/COMPRESS/dump_local_zstd.cpp b/src/COMPRESS/dump_local_zstd.cpp index 91fb36bb6e..1d3fc4756e 100644 --- a/src/COMPRESS/dump_local_zstd.cpp +++ b/src/COMPRESS/dump_local_zstd.cpp @@ -39,7 +39,7 @@ DumpLocalZstd::~DumpLocalZstd() {} /* ---------------------------------------------------------------------- generic opening of a dump file - ASCII or binary or gzipped + ASCII or binary or compressed some derived classes override this function ------------------------------------------------------------------------- */ diff --git a/src/COMPRESS/dump_xyz_gz.cpp b/src/COMPRESS/dump_xyz_gz.cpp index a1acad7fc2..2d9548bf14 100644 --- a/src/COMPRESS/dump_xyz_gz.cpp +++ b/src/COMPRESS/dump_xyz_gz.cpp @@ -32,7 +32,7 @@ DumpXYZGZ::~DumpXYZGZ() {} /* ---------------------------------------------------------------------- generic opening of a dump file - ASCII or binary or gzipped + ASCII or binary or compressed some derived classes override this function ------------------------------------------------------------------------- */ diff --git a/src/COMPRESS/dump_xyz_zstd.cpp b/src/COMPRESS/dump_xyz_zstd.cpp index 534bc0ee56..b56488ec09 100644 --- a/src/COMPRESS/dump_xyz_zstd.cpp +++ b/src/COMPRESS/dump_xyz_zstd.cpp @@ -38,7 +38,7 @@ DumpXYZZstd::~DumpXYZZstd() {} /* ---------------------------------------------------------------------- generic opening of a dump file - ASCII or binary or gzipped + ASCII or binary or compressed some derived classes override this function ------------------------------------------------------------------------- */ diff --git a/src/DIFFRACTION/compute_saed.cpp b/src/DIFFRACTION/compute_saed.cpp index e5af83ca92..e2df7fe3b8 100644 --- a/src/DIFFRACTION/compute_saed.cpp +++ b/src/DIFFRACTION/compute_saed.cpp @@ -31,7 +31,6 @@ #include #include -#include // for strcasecmp() #include "omp_compat.h" using namespace LAMMPS_NS; @@ -85,13 +84,13 @@ ComputeSAED::ComputeSAED(LAMMPS *lmp, int narg, char **arg) : ztype[i] = SAEDmaxType + 1; } for (int i=0; iall(FLERR,"Compute SAED: Invalid ASF atom type"); + } + if (ztype[i] == SAEDmaxType + 1) + error->all(FLERR,"Compute SAED: Invalid ASF atom type"); iarg++; } @@ -348,7 +347,7 @@ void ComputeSAED::compute_vector() if (me == 0 && echo) utils::logmesg(lmp,"-----\nComputing SAED intensities"); - double t0 = MPI_Wtime(); + double t0 = platform::walltime(); double *Fvec = new double[2*nRows]; // Strct factor (real & imaginary) // -- Note, vector entries correspond to different RELP @@ -491,7 +490,7 @@ void ComputeSAED::compute_vector() vector[i] = (scratch[2*i] * scratch[2*i] + scratch[2*i+1] * scratch[2*i+1]) / natoms; } - double t2 = MPI_Wtime(); + double t2 = platform::walltime(); // compute memory usage per processor double bytes = memory_usage(); diff --git a/src/DIFFRACTION/compute_xrd.cpp b/src/DIFFRACTION/compute_xrd.cpp index c6cf7be2ce..d798c2f4db 100644 --- a/src/DIFFRACTION/compute_xrd.cpp +++ b/src/DIFFRACTION/compute_xrd.cpp @@ -32,7 +32,6 @@ #include #include -#include // for strcasecmp() #include "omp_compat.h" using namespace LAMMPS_NS; @@ -87,7 +86,7 @@ ComputeXRD::ComputeXRD(LAMMPS *lmp, int narg, char **arg) : } for (int i = 0; i < ntypes; i++) { for (int j = 0; j < XRDmaxType; j++) { - if (strcasecmp(arg[iarg],XRDtypeList[j]) == 0) { + if (utils::lowercase(arg[iarg]) == utils::lowercase(XRDtypeList[j])) { ztype[i] = j; } } @@ -300,7 +299,7 @@ void ComputeXRD::compute_array() if (me == 0 && echo) utils::logmesg(lmp, "-----\nComputing XRD intensities"); - double t0 = MPI_Wtime(); + double t0 = platform::walltime(); double *Fvec = new double[2*size_array_rows]; // Strct factor (real & imaginary) // -- Note: array rows correspond to different RELP @@ -496,7 +495,7 @@ void ComputeXRD::compute_array() array[i][1] = (scratch[2*i] * scratch[2*i] + scratch[2*i+1] * scratch[2*i+1]) / natoms; } - double t2 = MPI_Wtime(); + double t2 = platform::walltime(); // compute memory usage per processor double bytes = memory_usage(); diff --git a/src/DIFFRACTION/fix_saed_vtk.cpp b/src/DIFFRACTION/fix_saed_vtk.cpp index 2e7d0897a6..89627b64ef 100644 --- a/src/DIFFRACTION/fix_saed_vtk.cpp +++ b/src/DIFFRACTION/fix_saed_vtk.cpp @@ -31,6 +31,7 @@ #include #include + using namespace LAMMPS_NS; using namespace FixConst; @@ -100,8 +101,6 @@ FixSAEDVTK::FixSAEDVTK(LAMMPS *lmp, int narg, char **arg) : error->all(FLERR,"Illegal fix saed/vtk command"); if (nfreq % nevery || nrepeat*nevery > nfreq) error->all(FLERR,"Illegal fix saed/vtk command"); - if (ave != RUNNING && overwrite) - error->all(FLERR,"Illegal fix saed/vtk command"); // allocate memory for averaging @@ -315,7 +314,7 @@ void FixSAEDVTK::invoke_vector(bigint ntimestep) if (irepeat == 0) for (int i = 0; i < nrows; i++) - vector[i] = 0.0; + vector[i] = 0.0; // accumulate results of computes,fixes,variables to local copy // compute/fix/variable may invoke computes so wrap with clear/add @@ -369,7 +368,7 @@ void FixSAEDVTK::invoke_vector(bigint ntimestep) for (int i = 0; i < nrows; i++) { vector_total[i] += vector[i]; if (window_limit) vector_total[i] -= vector_list[iwindow][i]; - vector_list[iwindow][i] = vector[i]; + vector_list[iwindow][i] = vector[i]; } iwindow++; @@ -391,8 +390,7 @@ void FixSAEDVTK::invoke_vector(bigint ntimestep) fp = fopen(nName.c_str(),"w"); if (fp == nullptr) - error->one(FLERR,"Cannot open fix saed/vtk file {}: {}", - nName,utils::getsyserror()); + error->one(FLERR,"Cannot open fix saed/vtk file {}: {}", nName,utils::getsyserror()); } fprintf(fp,"# vtk DataFile Version 3.0 c_%s\n",ids); @@ -406,71 +404,68 @@ void FixSAEDVTK::invoke_vector(bigint ntimestep) fprintf(fp,"SCALARS intensity float\n"); fprintf(fp,"LOOKUP_TABLE default\n"); - filepos = ftell(fp); - if (overwrite) fseek(fp,filepos,SEEK_SET); + // Finding the intersection of the reciprical space and Ewald sphere + int NROW1 = 0; + int NROW2 = 0; + double dinv2 = 0.0; + double r = 0.0; + double K[3]; - // Finding the intersection of the reciprical space and Ewald sphere - int NROW1 = 0; - int NROW2 = 0; - double dinv2 = 0.0; - double r = 0.0; - double K[3]; - - // Zone flag to capture entire recrocal space volume - if ((Zone[0] == 0) && (Zone[1] == 0) && (Zone[2] == 0)) { - for (int k = Knmin[2]; k <= Knmax[2]; k++) { - for (int j = Knmin[1]; j <= Knmax[1]; j++) { - for (int i = Knmin[0]; i <= Knmax[0]; i++) { - K[0] = i * dK[0]; - K[1] = j * dK[1]; - K[2] = k * dK[2]; - dinv2 = (K[0] * K[0] + K[1] * K[1] + K[2] * K[2]); - if (dinv2 < Kmax * Kmax) { - fprintf(fp,"%g\n",vector_total[NROW1]/norm); - fflush(fp); - NROW1++; - NROW2++; - } else { + // Zone flag to capture entire recrocal space volume + if ((Zone[0] == 0) && (Zone[1] == 0) && (Zone[2] == 0)) { + for (int k = Knmin[2]; k <= Knmax[2]; k++) { + for (int j = Knmin[1]; j <= Knmax[1]; j++) { + for (int i = Knmin[0]; i <= Knmax[0]; i++) { + K[0] = i * dK[0]; + K[1] = j * dK[1]; + K[2] = k * dK[2]; + dinv2 = (K[0] * K[0] + K[1] * K[1] + K[2] * K[2]); + if (dinv2 < Kmax * Kmax) { + fprintf(fp,"%g\n",vector_total[NROW1]/norm); + fflush(fp); + NROW1++; + NROW2++; + } else { fprintf(fp,"%d\n",-1); fflush(fp); NROW2++; - } } } } - } else { - for (int k = Knmin[2]; k <= Knmax[2]; k++) { - for (int j = Knmin[1]; j <= Knmax[1]; j++) { - for (int i = Knmin[0]; i <= Knmax[0]; i++) { - K[0] = i * dK[0]; - K[1] = j * dK[1]; - K[2] = k * dK[2]; - dinv2 = (K[0] * K[0] + K[1] * K[1] + K[2] * K[2]); - if (dinv2 < Kmax * Kmax) { - r=0.0; - for (int m=0; m<3; m++) r += pow(K[m] - Zone[m],2.0); - r = sqrt(r); - if ( (r > (R_Ewald - dR_Ewald) ) && (r < (R_Ewald + dR_Ewald) )) { - fprintf(fp,"%g\n",vector_total[NROW1]/norm); - fflush(fp); - NROW2++; - NROW1++; - } else { - fprintf(fp,"%d\n",-1); - fflush(fp); - NROW2++; - } + } + } else { + for (int k = Knmin[2]; k <= Knmax[2]; k++) { + for (int j = Knmin[1]; j <= Knmax[1]; j++) { + for (int i = Knmin[0]; i <= Knmax[0]; i++) { + K[0] = i * dK[0]; + K[1] = j * dK[1]; + K[2] = k * dK[2]; + dinv2 = (K[0] * K[0] + K[1] * K[1] + K[2] * K[2]); + if (dinv2 < Kmax * Kmax) { + r=0.0; + for (int m=0; m<3; m++) r += pow(K[m] - Zone[m],2.0); + r = sqrt(r); + if ( (r > (R_Ewald - dR_Ewald) ) && (r < (R_Ewald + dR_Ewald) )) { + fprintf(fp,"%g\n",vector_total[NROW1]/norm); + fflush(fp); + NROW2++; + NROW1++; } else { + fprintf(fp,"%d\n",-1); + fflush(fp); + NROW2++; + } + } else { fprintf(fp,"%d\n",-1); fflush(fp); NROW2++; - } } } } } } + } nOutput++; } @@ -497,7 +492,6 @@ void FixSAEDVTK::options(int narg, char **arg) fp = nullptr; ave = ONE; startstep = 0; - overwrite = 0; // optional args int iarg = 7; @@ -534,9 +528,6 @@ void FixSAEDVTK::options(int narg, char **arg) if (iarg+2 > narg) error->all(FLERR,"Illegal fix saed/vtk command"); startstep = utils::inumeric(FLERR,arg[iarg+1],false,lmp); iarg += 2; - } else if (strcmp(arg[iarg],"overwrite") == 0) { - overwrite = 1; - iarg += 1; } else error->all(FLERR,"Illegal fix saed/vtk command"); } } diff --git a/src/DIFFRACTION/fix_saed_vtk.h b/src/DIFFRACTION/fix_saed_vtk.h index 07aebce63d..a5691ea986 100644 --- a/src/DIFFRACTION/fix_saed_vtk.h +++ b/src/DIFFRACTION/fix_saed_vtk.h @@ -43,8 +43,6 @@ class FixSAEDVTK : public Fix { int nrows; int ave, nwindow, nsum, startstep; - int overwrite; - long filepos; int norm, iwindow, window_limit; double *vector; diff --git a/src/DPD-MESO/pair_mdpd.cpp b/src/DPD-MESO/pair_mdpd.cpp index 9e704de2a7..53994800d0 100644 --- a/src/DPD-MESO/pair_mdpd.cpp +++ b/src/DPD-MESO/pair_mdpd.cpp @@ -19,19 +19,19 @@ #include "pair_mdpd.h" +#include "atom.h" +#include "citeme.h" +#include "comm.h" +#include "error.h" +#include "force.h" +#include "memory.h" +#include "neigh_list.h" +#include "neighbor.h" +#include "random_mars.h" +#include "update.h" + #include #include -#include "atom.h" -#include "comm.h" -#include "update.h" -#include "force.h" -#include "neighbor.h" -#include "neigh_list.h" -#include "random_mars.h" -#include "citeme.h" -#include "memory.h" -#include "error.h" - using namespace LAMMPS_NS; @@ -217,12 +217,13 @@ void PairMDPD::settings(int narg, char **arg) seed = utils::inumeric(FLERR,arg[2],false,lmp); // initialize Marsaglia RNG with processor-unique seed + // create a positive seed based on the system clock, if requested. if (seed <= 0) { - struct timespec time; - clock_gettime( CLOCK_REALTIME, &time ); - seed = time.tv_nsec; // if seed is non-positive, get the current time as the seed + constexpr double LARGE_NUM = 2<<30; + seed = int(fmod(platform::walltime() * LARGE_NUM, LARGE_NUM)) + 1; } + delete random; random = new RanMars(lmp,(seed + comm->me) % 900000000); diff --git a/src/DPD-MESO/pair_tdpd.cpp b/src/DPD-MESO/pair_tdpd.cpp index e99edfa5ff..70168c0e2a 100644 --- a/src/DPD-MESO/pair_tdpd.cpp +++ b/src/DPD-MESO/pair_tdpd.cpp @@ -18,19 +18,19 @@ ------------------------------------------------------------------------- */ #include "pair_tdpd.h" -#include -#include -#include "atom.h" -#include "comm.h" -#include "update.h" -#include "force.h" -#include "neighbor.h" -#include "neigh_list.h" -#include "random_mars.h" -#include "citeme.h" -#include "memory.h" -#include "error.h" +#include "atom.h" +#include "citeme.h" +#include "comm.h" +#include "error.h" +#include "force.h" +#include "memory.h" +#include "neigh_list.h" +#include "neighbor.h" +#include "random_mars.h" +#include "update.h" + +#include using namespace LAMMPS_NS; @@ -239,12 +239,13 @@ void PairTDPD::settings(int narg, char **arg) seed = utils::inumeric(FLERR,arg[2],false,lmp); // initialize Marsaglia RNG with processor-unique seed + // create a positive seed based on the system clock, if requested. if (seed <= 0) { - struct timespec time; - clock_gettime( CLOCK_REALTIME, &time ); - seed = time.tv_nsec; // if seed is non-positive, get the current time as the seed + constexpr double LARGE_NUM = 2<<30; + seed = int(fmod(platform::walltime() * LARGE_NUM, LARGE_NUM)) + 1; } + delete random; random = new RanMars(lmp,(seed + comm->me) % 900000000); diff --git a/src/DPD-REACT/fix_rx.cpp b/src/DPD-REACT/fix_rx.cpp index 526c2d508f..b14831ee8d 100644 --- a/src/DPD-REACT/fix_rx.cpp +++ b/src/DPD-REACT/fix_rx.cpp @@ -58,7 +58,7 @@ namespace /* anonymous */ { typedef double TimerType; -TimerType getTimeStamp() { return MPI_Wtime(); } +TimerType getTimeStamp() { return platform::walltime(); } double getElapsedTime( const TimerType &t0, const TimerType &t1) { return t1-t0; } } // end namespace @@ -126,7 +126,7 @@ FixRX::FixRX(LAMMPS *lmp, int narg, char **arg) : error->all(FLERR, errmsg); } - if (comm->me == 0 and Verbosity > 1) { + if (comm->me == 0 && Verbosity > 1) { std::string msg = "FixRX: matrix format is "; if (useSparseKinetics) msg += std::string("sparse"); @@ -172,7 +172,7 @@ FixRX::FixRX(LAMMPS *lmp, int narg, char **arg) : char *word = arg[iarg++]; minSteps = atoi( word ); - if (comm->me == 0 and Verbosity > 1) { + if (comm->me == 0 && Verbosity > 1) { char msg[128]; sprintf(msg, "FixRX: RK4 numSteps= %d", minSteps); error->message(FLERR, msg); @@ -197,7 +197,7 @@ FixRX::FixRX(LAMMPS *lmp, int narg, char **arg) : // maxIters must be at least minSteps. maxIters = std::max( minSteps, maxIters ); - if (comm->me == 0 and Verbosity > 1) { + if (comm->me == 0 && Verbosity > 1) { //printf("FixRX: RKF45 minSteps= %d maxIters= %d absTol= %e relTol= %e\n", minSteps, maxIters, absTol, relTol); char msg[128]; sprintf(msg, "FixRX: RKF45 minSteps= %d maxIters= %d relTol= %.1e absTol= %.1e diagnosticFrequency= %d", minSteps, maxIters, relTol, absTol, diagnosticFrequency); @@ -371,7 +371,7 @@ void FixRX::initSparse() { const int Verbosity = 1; - if (comm->me == 0 and Verbosity > 1) { + if (comm->me == 0 && Verbosity > 1) { for (int k = 0; k < nspecies; ++k) printf("atom->dvname[%d]= %s\n", k, atom->dvname[k]); @@ -421,7 +421,7 @@ void FixRX::initSparse() std::string pstr, rstr; bool allAreIntegral = true; for (int k = 0; k < nspecies; ++k) { - if (stoichReactants[i][k] == 0 and stoichProducts[i][k] == 0) + if (stoichReactants[i][k] == 0 && stoichProducts[i][k] == 0) nzeros++; if (stoichReactants[i][k] > 0.0) { @@ -448,7 +448,7 @@ void FixRX::initSparse() pstr += atom->dvname[k]; } } - if (comm->me == 0 and Verbosity > 1) + if (comm->me == 0 && Verbosity > 1) printf("rx%3d: %d %d %d ... %s %s %s\n", i, nreac_i, nprod_i, allAreIntegral, rstr.c_str(), /*reversible[i]*/ (false) ? "<=>" : "=", pstr.c_str()); mxreac = std::max( mxreac, nreac_i ); @@ -457,7 +457,7 @@ void FixRX::initSparse() if (allAreIntegral) nIntegral++; } - if (comm->me == 0 and Verbosity > 1) { + if (comm->me == 0 && Verbosity > 1) { char msg[256]; sprintf(msg, "FixRX: Sparsity of Stoichiometric Matrix= %.1f%% non-zeros= %d nspecies= %d nreactions= %d maxReactants= %d maxProducts= %d maxSpecies= %d integralReactions= %d", 100*(double(nzeros) / (nspecies * nreactions)), nzeros, nspecies, nreactions, mxreac, mxprod, (mxreac + mxprod), SparseKinetics_enableIntegralReactions); error->message(FLERR, msg); @@ -539,7 +539,7 @@ void FixRX::initSparse() sparseKinetics_isIntegralReaction[i] = isIntegral_i; } - if (comm->me == 0 and Verbosity > 1) { + if (comm->me == 0 && Verbosity > 1) { for (int i = 1; i < nu_bin.size(); ++i) if (nu_bin[i] > 0) printf("nu_bin[%d] = %d\n", i, nu_bin[i]); @@ -554,7 +554,7 @@ void FixRX::initSparse() rstr += " + "; char digit[6]; - if (SparseKinetics_enableIntegralReactions and sparseKinetics_isIntegralReaction[i]) + if (SparseKinetics_enableIntegralReactions && sparseKinetics_isIntegralReaction[i]) sprintf(digit,"%d ", sparseKinetics_inu[i][kk]); else sprintf(digit,"%4.1f ", sparseKinetics_nu[i][kk]); @@ -570,7 +570,7 @@ void FixRX::initSparse() pstr += " + "; char digit[6]; - if (SparseKinetics_enableIntegralReactions and sparseKinetics_isIntegralReaction[i]) + if (SparseKinetics_enableIntegralReactions && sparseKinetics_isIntegralReaction[i]) sprintf(digit,"%d ", sparseKinetics_inu[i][kk]); else sprintf(digit,"%4.1f ", sparseKinetics_nu[i][kk]); @@ -578,7 +578,7 @@ void FixRX::initSparse() pstr += atom->dvname[k]; } } - if (comm->me == 0 and Verbosity > 1) + if (comm->me == 0 && Verbosity > 1) printf("rx%3d: %s %s %s\n", i, rstr.c_str(), /*reversible[i]*/ (false) ? "<=>" : "=", pstr.c_str()); } // end for nreactions diff --git a/src/DRUDE/fix_tgnh_drude.cpp b/src/DRUDE/fix_tgnh_drude.cpp index eb8922d4cc..700f9669d8 100644 --- a/src/DRUDE/fix_tgnh_drude.cpp +++ b/src/DRUDE/fix_tgnh_drude.cpp @@ -761,7 +761,7 @@ void FixTGNHDrude::setup_mol_mass_dof() { dof_mol, dof_int, dof_drude); } } - if (dof_mol <=0 or dof_int <=0 or dof_drude <=0) + if (dof_mol <=0 || dof_int <=0 || dof_drude <=0) error->all(FLERR, "TGNHC thermostat requires DOFs of molecules, atoms and dipoles larger than 0"); } diff --git a/src/EXTRA-DUMP/xdr_compat.h b/src/EXTRA-DUMP/xdr_compat.h index 30aecbcb62..6557a60a53 100644 --- a/src/EXTRA-DUMP/xdr_compat.h +++ b/src/EXTRA-DUMP/xdr_compat.h @@ -59,8 +59,8 @@ extern "C" { typedef int bool_t; -#if defined(__MINGW32__) || defined(__APPLE__) || defined(__FreeBSD__) || \ - defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__) +#if defined(_WIN32) || defined(__APPLE__) || defined(__FreeBSD__) || \ + defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__) typedef char *caddr_t; typedef unsigned int u_int; #endif diff --git a/src/EXTRA-FIX/fix_ave_correlate_long.cpp b/src/EXTRA-FIX/fix_ave_correlate_long.cpp index 6e4e26754f..1746c7f6f5 100644 --- a/src/EXTRA-FIX/fix_ave_correlate_long.cpp +++ b/src/EXTRA-FIX/fix_ave_correlate_long.cpp @@ -36,7 +36,6 @@ #include #include -#include using namespace LAMMPS_NS; using namespace FixConst; @@ -260,11 +259,11 @@ FixAveCorrelateLong::FixAveCorrelateLong(LAMMPS * lmp, int narg, char **arg): fprintf(fp," %s*%s",arg[5+i],arg[5+j]); fprintf(fp,"\n"); } - filepos = ftell(fp); + filepos = platform::ftell(fp); } - delete [] title1; - delete [] title2; + delete[] title1; + delete[] title2; // allocate and initialize memory for calculated values and correlators @@ -319,11 +318,11 @@ FixAveCorrelateLong::FixAveCorrelateLong(LAMMPS * lmp, int narg, char **arg): FixAveCorrelateLong::~FixAveCorrelateLong() { - delete [] which; - delete [] argindex; - delete [] value2index; - for (int i = 0; i < nvalues; i++) delete [] ids[i]; - delete [] ids; + delete[] which; + delete[] argindex; + delete[] value2index; + for (int i = 0; i < nvalues; i++) delete[] ids[i]; + delete[] ids; memory->destroy(values); memory->destroy(shift); @@ -467,7 +466,7 @@ void FixAveCorrelateLong::end_of_step() evaluate(); if (fp && me == 0) { - if (overwrite) fseek(fp,filepos,SEEK_SET); + if (overwrite) platform::fseek(fp,filepos); fprintf(fp,"# Timestep: " BIGINT_FORMAT "\n", ntimestep); for (unsigned int i=0;idt*nevery); @@ -478,9 +477,9 @@ void FixAveCorrelateLong::end_of_step() } fflush(fp); if (overwrite) { - long fileend = ftell(fp); - if ((fileend > 0) && (ftruncate(fileno(fp),fileend))) - perror("Error while tuncating output"); + bigint fileend = platform::ftell(fp); + if ((fileend > 0) && (platform::ftruncate(fp,fileend))) + error->warning(FLERR,"Error while tuncating output: {}", utils::getsyserror()); } } diff --git a/src/EXTRA-FIX/fix_ave_correlate_long.h b/src/EXTRA-FIX/fix_ave_correlate_long.h index b62c6aefcb..a31ae78217 100644 --- a/src/EXTRA-FIX/fix_ave_correlate_long.h +++ b/src/EXTRA-FIX/fix_ave_correlate_long.h @@ -66,7 +66,7 @@ class FixAveCorrelateLong : public Fix { FILE *fp; int type, startstep, overwrite; - long filepos; + bigint filepos; int npair; // number of correlation pairs to calculate double *values; diff --git a/src/EXTRA-FIX/fix_tmd.cpp b/src/EXTRA-FIX/fix_tmd.cpp index a46eb89713..4d85687e4d 100644 --- a/src/EXTRA-FIX/fix_tmd.cpp +++ b/src/EXTRA-FIX/fix_tmd.cpp @@ -123,7 +123,10 @@ nfileevery(0), fp(nullptr), xf(nullptr), xold(nullptr) FixTMD::~FixTMD() { - if (nfileevery && me == 0) fclose(fp); + if (nfileevery && me == 0) { + if (compressed) platform::pclose(fp); + else fclose(fp); + } // unregister callbacks to this fix from Atom class @@ -492,7 +495,7 @@ void FixTMD::readfile(char *file) delete [] buffer; if (me == 0) { - if (compressed) pclose(fp); + if (compressed) platform::pclose(fp); else fclose(fp); } @@ -514,33 +517,21 @@ void FixTMD::readfile(char *file) /* ---------------------------------------------------------------------- proc 0 opens TMD data file - test if gzipped + test if compressed ------------------------------------------------------------------------- */ -void FixTMD::open(char *file) +void FixTMD::open(const std::string &file) { - if (utils::strmatch(file,"\\.gz$")) { + if (platform::has_compress_extension(file)) { compressed = 1; - -#ifdef LAMMPS_GZIP - auto gunzip = fmt::format("gzip -c -d {}",file); - -#ifdef _WIN32 - fp = _popen(gunzip.c_str(),"rb"); -#else - fp = popen(gunzip.c_str(),"r"); -#endif - -#else - error->one(FLERR,"Cannot open gzipped file without gzip support"); -#endif + fp = platform::compressed_read(file); + if (!fp) error->one(FLERR,"Cannot open compressed file for reading"); } else { compressed = 0; - fp = fopen(file,"r"); + fp = fopen(file.c_str(),"r"); } - if (fp == nullptr) - error->one(FLERR,"Cannot open file {}: {}",file, utils::getsyserror()); + if (!fp) error->one(FLERR,"Cannot open file {}: {}", file, utils::getsyserror()); } /* ---------------------------------------------------------------------- */ diff --git a/src/EXTRA-FIX/fix_tmd.h b/src/EXTRA-FIX/fix_tmd.h index fd818eb583..b85869930a 100644 --- a/src/EXTRA-FIX/fix_tmd.h +++ b/src/EXTRA-FIX/fix_tmd.h @@ -52,7 +52,7 @@ class FixTMD : public Fix { double **xf, **xold; void readfile(char *); - void open(char *); + void open(const std::string &); }; } // namespace LAMMPS_NS diff --git a/src/EXTRA-PAIR/pair_e3b.cpp b/src/EXTRA-PAIR/pair_e3b.cpp index a904939e42..7e865ac6f8 100644 --- a/src/EXTRA-PAIR/pair_e3b.cpp +++ b/src/EXTRA-PAIR/pair_e3b.cpp @@ -643,7 +643,7 @@ void PairE3B::checkInputs(const double &bondL) if (k2 == NOT_SET) error->all(FLERR, "K2 keyword missing"); //now test that values are within acceptable ranges - if (k2 < 0.0 or k3 < 0.0) error->all(FLERR, "exponential decay is negative"); + if (k2 < 0.0 || k3 < 0.0) error->all(FLERR, "exponential decay is negative"); if (bondL < 0.0) error->all(FLERR, "OH bond length is negative"); if (rc2 < 0.0 || rc3 < 0.0 || rs < 0.0) error->all(FLERR, "potential cutoff is negative"); if (rs > rc3) error->all(FLERR, "potential switching distance is larger than cutoff"); diff --git a/src/GPU/pair_beck_gpu.cpp b/src/GPU/pair_beck_gpu.cpp index a2a3133a24..e3dfda428f 100644 --- a/src/GPU/pair_beck_gpu.cpp +++ b/src/GPU/pair_beck_gpu.cpp @@ -120,9 +120,9 @@ void PairBeckGPU::compute(int eflag, int vflag) error->one(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_start < inum) { - cpu_time = MPI_Wtime(); + cpu_time = platform::walltime(); cpu_compute(host_start, inum, eflag, vflag, ilist, numneigh, firstneigh); - cpu_time = MPI_Wtime() - cpu_time; + cpu_time = platform::walltime() - cpu_time; } } diff --git a/src/GPU/pair_lj96_cut_gpu.cpp b/src/GPU/pair_lj96_cut_gpu.cpp index f03fbc9d7f..546c31a94e 100644 --- a/src/GPU/pair_lj96_cut_gpu.cpp +++ b/src/GPU/pair_lj96_cut_gpu.cpp @@ -117,9 +117,9 @@ void PairLJ96CutGPU::compute(int eflag, int vflag) error->one(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); // if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_start(host_start, inum, ilist, numneigh, firstneigh); else cpu_compute<1,0>(host_start, inum, ilist, numneigh, firstneigh); } else cpu_compute<0,0>(host_start, inum, ilist, numneigh, firstneigh); - cpu_time = MPI_Wtime() - cpu_time; + cpu_time = platform::walltime() - cpu_time; } } diff --git a/src/GPU/pair_lj_sdk_gpu.cpp b/src/GPU/pair_lj_sdk_gpu.cpp index 9f925d0250..938ee83e4a 100644 --- a/src/GPU/pair_lj_sdk_gpu.cpp +++ b/src/GPU/pair_lj_sdk_gpu.cpp @@ -122,12 +122,12 @@ void PairLJSDKGPU::compute(int eflag, int vflag) error->one(FLERR,"Insufficient memory on accelerator"); if (host_start(host_start, inum, ilist, numneigh, firstneigh); else cpu_compute<1,0>(host_start, inum, ilist, numneigh, firstneigh); } else cpu_compute<0,0>(host_start, inum, ilist, numneigh, firstneigh); - cpu_time = MPI_Wtime() - cpu_time; + cpu_time = platform::walltime() - cpu_time; } } diff --git a/src/GPU/pair_lj_sf_dipole_sf_gpu.cpp b/src/GPU/pair_lj_sf_dipole_sf_gpu.cpp index bd40f855dc..0bb0e66d92 100644 --- a/src/GPU/pair_lj_sf_dipole_sf_gpu.cpp +++ b/src/GPU/pair_lj_sf_dipole_sf_gpu.cpp @@ -127,9 +127,9 @@ void PairLJSFDipoleSFGPU::compute(int eflag, int vflag) error->one(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR, "Insufficient memory on accelerator"); if (host_start < inum) { - cpu_time = MPI_Wtime(); + cpu_time = platform::walltime(); cpu_compute(host_start, inum, eflag, vflag, ilist, numneigh, firstneigh); - cpu_time = MPI_Wtime() - cpu_time; + cpu_time = platform::walltime() - cpu_time; } //fprintf("LJ_SMOOTH_GPU"); } diff --git a/src/GPU/pair_mie_cut_gpu.cpp b/src/GPU/pair_mie_cut_gpu.cpp index 568b4dbc18..a059607880 100644 --- a/src/GPU/pair_mie_cut_gpu.cpp +++ b/src/GPU/pair_mie_cut_gpu.cpp @@ -118,9 +118,9 @@ void PairMIECutGPU::compute(int eflag, int vflag) error->one(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_start < inum) { - cpu_time = MPI_Wtime(); + cpu_time = platform::walltime(); cpu_compute(host_start, inum, eflag, vflag, ilist, numneigh, firstneigh); - cpu_time = MPI_Wtime() - cpu_time; + cpu_time = platform::walltime() - cpu_time; } } diff --git a/src/GPU/pair_soft_gpu.cpp b/src/GPU/pair_soft_gpu.cpp index 9b6fc6a39a..654e2e603b 100644 --- a/src/GPU/pair_soft_gpu.cpp +++ b/src/GPU/pair_soft_gpu.cpp @@ -121,9 +121,9 @@ void PairSoftGPU::compute(int eflag, int vflag) error->one(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_startone(FLERR,"Insufficient memory on accelerator"); if (host_start void FixIntel::add_off_results(const ft * _noalias const f_in, const acc_t * _noalias const ev_global) { if (_offload_balance < 0.0) - _balance_other_time = MPI_Wtime() - _balance_other_time; + _balance_other_time = platform::walltime() - _balance_other_time; start_watch(TIME_OFFLOAD_WAIT); #ifdef _LMP_INTEL_OFFLOAD diff --git a/src/KIM/kim_query.cpp b/src/KIM/kim_query.cpp index c1669650cc..3e891468a6 100644 --- a/src/KIM/kim_query.cpp +++ b/src/KIM/kim_query.cpp @@ -377,7 +377,7 @@ char *do_query(const std::string &qfunction, const std::string &mname, } auto user_agent = fmt::format("kim query--LAMMPS/{} ({})", - LAMMPS_VERSION, Info::get_os_info()); + LAMMPS_VERSION, platform::os_info()); curl_easy_setopt(handle, CURLOPT_USERAGENT, user_agent.c_str()); curl_easy_setopt(handle, CURLOPT_URL, url.c_str()); diff --git a/src/KOKKOS/bond_class2_kokkos.cpp b/src/KOKKOS/bond_class2_kokkos.cpp index e538c8e045..b4e87b4119 100644 --- a/src/KOKKOS/bond_class2_kokkos.cpp +++ b/src/KOKKOS/bond_class2_kokkos.cpp @@ -68,14 +68,14 @@ void BondClass2Kokkos::compute(int eflag_in, int vflag_in) //if(k_eatom.extent(0)destroy_kokkos(k_eatom,eatom); memoryKK->create_kokkos(k_eatom,eatom,maxeatom,"improper:eatom"); - d_eatom = k_eatom.template view(); + d_eatom = k_eatom.template view(); //} } if (vflag_atom) { //if(k_vatom.extent(0)destroy_kokkos(k_vatom,vatom); memoryKK->create_kokkos(k_vatom,vatom,maxvatom,"improper:vatom"); - d_vatom = k_vatom.template view(); + d_vatom = k_vatom.template view(); //} } @@ -210,10 +210,10 @@ void BondClass2Kokkos::coeff(int narg, char **arg) BondClass2::coeff(narg, arg); int n = atom->nbondtypes; - Kokkos::DualView k_k2("BondClass2::k2",n+1); - Kokkos::DualView k_k3("BondClass2::k3",n+1); - Kokkos::DualView k_k4("BondClass2::k4",n+1); - Kokkos::DualView k_r0("BondClass2::r0",n+1); + typename AT::tdual_ffloat_1d k_k2("BondClass2::k2",n+1); + typename AT::tdual_ffloat_1d k_k3("BondClass2::k3",n+1); + typename AT::tdual_ffloat_1d k_k4("BondClass2::k4",n+1); + typename AT::tdual_ffloat_1d k_r0("BondClass2::r0",n+1); d_k2 = k_k2.template view(); d_k3 = k_k3.template view(); @@ -247,10 +247,10 @@ void BondClass2Kokkos::read_restart(FILE *fp) BondClass2::read_restart(fp); int n = atom->nbondtypes; - Kokkos::DualView k_k2("BondClass2::k2",n+1); - Kokkos::DualView k_k3("BondClass2::k3",n+1); - Kokkos::DualView k_k4("BondClass2::k4",n+1); - Kokkos::DualView k_r0("BondClass2::r0",n+1); + typename AT::tdual_ffloat_1d k_k2("BondClass2::k2",n+1); + typename AT::tdual_ffloat_1d k_k3("BondClass2::k3",n+1); + typename AT::tdual_ffloat_1d k_k4("BondClass2::k4",n+1); + typename AT::tdual_ffloat_1d k_r0("BondClass2::r0",n+1); d_k2 = k_k2.template view(); d_k3 = k_k3.template view(); diff --git a/src/KOKKOS/bond_class2_kokkos.h b/src/KOKKOS/bond_class2_kokkos.h index 52136030aa..529046845f 100644 --- a/src/KOKKOS/bond_class2_kokkos.h +++ b/src/KOKKOS/bond_class2_kokkos.h @@ -67,10 +67,11 @@ class BondClass2Kokkos : public BondClass2 { typename Kokkos::View::value,Kokkos::MemoryTraits > f; typename AT::t_int_2d bondlist; - Kokkos::DualView k_eatom; - Kokkos::DualView k_vatom; - Kokkos::View::value,Kokkos::MemoryTraits > d_eatom; - Kokkos::View::value,Kokkos::MemoryTraits > d_vatom; + typedef typename KKDevice::value KKDeviceType; + Kokkos::DualView k_eatom; + Kokkos::DualView k_vatom; + Kokkos::View > d_eatom; + Kokkos::View > d_vatom; int nlocal,newton_bond; int eflag,vflag; diff --git a/src/KOKKOS/compute_orientorder_atom_kokkos.cpp b/src/KOKKOS/compute_orientorder_atom_kokkos.cpp index 131e9933e8..f7ec879e3c 100644 --- a/src/KOKKOS/compute_orientorder_atom_kokkos.cpp +++ b/src/KOKKOS/compute_orientorder_atom_kokkos.cpp @@ -173,8 +173,6 @@ void ComputeOrientOrderAtomKokkos::compute_peratom() x = atomKK->k_x.view(); mask = atomKK->k_mask.view(); - Kokkos::deep_copy(d_qnm,{0.0,0.0}); - int vector_length_default = 1; int team_size_default = 1; if (!host_flag) @@ -185,6 +183,8 @@ void ComputeOrientOrderAtomKokkos::compute_peratom() if (chunk_size > inum - chunk_offset) chunk_size = inum - chunk_offset; + Kokkos::deep_copy(d_qnm,{0.0,0.0}); + //Neigh { int vector_length = vector_length_default; @@ -286,7 +286,7 @@ void ComputeOrientOrderAtomKokkos::operator() (TagComputeOrientOrder const int i = d_ilist[ii + chunk_offset]; const int ncount = d_ncount(ii); - // if not nnn neighbors, order parameter = 0; + // if not nnn neighbors, order parameter = 0 if ((ncount == 0) || (ncount < nnn)) { for (int jj = 0; jj < ncol; jj++) @@ -316,7 +316,7 @@ void ComputeOrientOrderAtomKokkos::operator() (TagComputeOrientOrder const int ncount = d_ncount(ii); if (jj >= ncount) return; - // if not nnn neighbors, order parameter = 0; + // if not nnn neighbors, order parameter = 0 if ((ncount == 0) || (ncount < nnn)) return; @@ -328,6 +328,12 @@ template KOKKOS_INLINE_FUNCTION void ComputeOrientOrderAtomKokkos::operator() (TagComputeOrientOrderAtomBOOP2,const int& ii) const { const int ncount = d_ncount(ii); + + // if not nnn neighbors, order parameter = 0 + + if ((ncount == 0) || (ncount < nnn)) + return; + calc_boop2(ncount, ii); } diff --git a/src/KOKKOS/fix_rx_kokkos.cpp b/src/KOKKOS/fix_rx_kokkos.cpp index 15b4a39849..caa79c77b1 100644 --- a/src/KOKKOS/fix_rx_kokkos.cpp +++ b/src/KOKKOS/fix_rx_kokkos.cpp @@ -54,7 +54,7 @@ namespace /* anonymous */ { typedef double TimerType; -TimerType getTimeStamp(void) { return MPI_Wtime(); } +TimerType getTimeStamp(void) { return platform::walltime(); } double getElapsedTime( const TimerType &t0, const TimerType &t1) { return t1-t0; } } // end namespace @@ -2075,7 +2075,7 @@ void FixRxKokkos::computeLocalTemperature() // Local list views. (This isn't working!) NeighListKokkos* k_list = static_cast*>(list); - if (not(list->kokkos)) + if (!list->kokkos) error->one(FLERR,"list is not a Kokkos list\n"); //typename ArrayTypes::t_neighbors_2d d_neighbors = k_list->d_neighbors; diff --git a/src/KOKKOS/kokkos.cpp b/src/KOKKOS/kokkos.cpp index be32604f94..63a18ec387 100644 --- a/src/KOKKOS/kokkos.cpp +++ b/src/KOKKOS/kokkos.cpp @@ -23,7 +23,15 @@ #include #include #include -#include + +#if defined(_WIN32) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include // for _getpid() +#else +#include // for getpid() +#endif #ifdef LMP_KOKKOS_GPU @@ -591,6 +599,10 @@ int KokkosLMP::neigh_count(int m) void KokkosLMP::my_signal_handler(int sig) { if (sig == SIGSEGV) { +#if defined(_WIN32) + kill(_getpid(),SIGABRT); +#else kill(getpid(),SIGABRT); +#endif } } diff --git a/src/KOKKOS/modify_kokkos.cpp b/src/KOKKOS/modify_kokkos.cpp index 868de3e11e..5545351f53 100644 --- a/src/KOKKOS/modify_kokkos.cpp +++ b/src/KOKKOS/modify_kokkos.cpp @@ -38,7 +38,20 @@ ModifyKokkos::ModifyKokkos(LAMMPS *lmp) : Modify(lmp) void ModifyKokkos::setup(int vflag) { // compute setup needs to come before fix setup - // b/c NH fixes need use DOF of temperature computes + // b/c NH fixes need DOF of temperature computes + // fix group setup() is special case since populates a dynamic group + // needs to be done before temperature compute setup + + for (int i = 0; i < nfix; i++) { + if (strcmp(fix[i]->style,"GROUP") == 0) { + atomKK->sync(fix[i]->execution_space,fix[i]->datamask_read); + int prev_auto_sync = lmp->kokkos->auto_sync; + if (!fix[i]->kokkosable) lmp->kokkos->auto_sync = 1; + fix[i]->setup(vflag); + lmp->kokkos->auto_sync = prev_auto_sync; + atomKK->modified(fix[i]->execution_space,fix[i]->datamask_modify); + } + } for (int i = 0; i < ncompute; i++) compute[i]->setup(); @@ -124,6 +137,37 @@ void ModifyKokkos::setup_pre_neighbor() } } +/* ---------------------------------------------------------------------- + setup post_neighbor call, only for fixes that define post_neighbor + called from Verlet, RESPA +------------------------------------------------------------------------- */ + +void ModifyKokkos::setup_post_neighbor() +{ + if (update->whichflag == 1) + for (int i = 0; i < n_post_neighbor; i++) { + atomKK->sync(fix[list_post_neighbor[i]]->execution_space, + fix[list_post_neighbor[i]]->datamask_read); + int prev_auto_sync = lmp->kokkos->auto_sync; + if (!fix[list_post_neighbor[i]]->kokkosable) lmp->kokkos->auto_sync = 1; + fix[list_post_neighbor[i]]->setup_post_neighbor(); + lmp->kokkos->auto_sync = prev_auto_sync; + atomKK->modified(fix[list_post_neighbor[i]]->execution_space, + fix[list_post_neighbor[i]]->datamask_modify); + } + else if (update->whichflag == 2) + for (int i = 0; i < n_min_post_neighbor; i++) { + atomKK->sync(fix[list_min_post_neighbor[i]]->execution_space, + fix[list_min_post_neighbor[i]]->datamask_read); + int prev_auto_sync = lmp->kokkos->auto_sync; + if (!fix[list_min_post_neighbor[i]]->kokkosable) lmp->kokkos->auto_sync = 1; + fix[list_min_post_neighbor[i]]->setup_post_neighbor(); + lmp->kokkos->auto_sync = prev_auto_sync; + atomKK->modified(fix[list_min_post_neighbor[i]]->execution_space, + fix[list_min_post_neighbor[i]]->datamask_modify); + } +} + /* ---------------------------------------------------------------------- setup pre_force call, only for fixes that define pre_force called from Verlet, RESPA, Min @@ -258,6 +302,24 @@ void ModifyKokkos::pre_neighbor() } } +/* ---------------------------------------------------------------------- + post_neighbor call, only for relevant fixes +------------------------------------------------------------------------- */ + +void ModifyKokkos::post_neighbor() +{ + for (int i = 0; i < n_post_neighbor; i++) { + atomKK->sync(fix[list_post_neighbor[i]]->execution_space, + fix[list_post_neighbor[i]]->datamask_read); + int prev_auto_sync = lmp->kokkos->auto_sync; + if (!fix[list_post_neighbor[i]]->kokkosable) lmp->kokkos->auto_sync = 1; + fix[list_post_neighbor[i]]->post_neighbor(); + lmp->kokkos->auto_sync = prev_auto_sync; + atomKK->modified(fix[list_post_neighbor[i]]->execution_space, + fix[list_post_neighbor[i]]->datamask_modify); + } +} + /* ---------------------------------------------------------------------- pre_force call, only for relevant fixes ------------------------------------------------------------------------- */ @@ -420,6 +482,12 @@ void ModifyKokkos::post_run() atomKK->modified(fix[i]->execution_space, fix[i]->datamask_modify); } + + // must reset this to its default value, since computes may be added + // or removed between runs and with this change we will redirect any + // calls to addstep_compute() to addstep_compute_all() instead. + n_timeflag = -1; + } /* ---------------------------------------------------------------------- @@ -567,6 +635,24 @@ void ModifyKokkos::min_pre_neighbor() } } +/* ---------------------------------------------------------------------- + minimizer post-neighbor call, only for relevant fixes +------------------------------------------------------------------------- */ + +void ModifyKokkos::min_post_neighbor() +{ + for (int i = 0; i < n_min_post_neighbor; i++) { + atomKK->sync(fix[list_min_post_neighbor[i]]->execution_space, + fix[list_min_post_neighbor[i]]->datamask_read); + int prev_auto_sync = lmp->kokkos->auto_sync; + if (!fix[list_min_post_neighbor[i]]->kokkosable) lmp->kokkos->auto_sync = 1; + fix[list_min_post_neighbor[i]]->min_post_neighbor(); + lmp->kokkos->auto_sync = prev_auto_sync; + atomKK->modified(fix[list_min_post_neighbor[i]]->execution_space, + fix[list_min_post_neighbor[i]]->datamask_modify); + } +} + /* ---------------------------------------------------------------------- minimizer pre-force call, only for relevant fixes ------------------------------------------------------------------------- */ @@ -646,7 +732,7 @@ double ModifyKokkos::min_energy(double *fextra) } /* ---------------------------------------------------------------------- - store current state of extra dof, only for relevant fixes + store current state of extra minimizer dof, only for relevant fixes ------------------------------------------------------------------------- */ void ModifyKokkos::min_store() @@ -664,7 +750,7 @@ void ModifyKokkos::min_store() } /* ---------------------------------------------------------------------- - mange state of extra dof on a stack, only for relevant fixes + manage state of extra minimizer dof on a stack, only for relevant fixes ------------------------------------------------------------------------- */ void ModifyKokkos::min_clearstore() @@ -710,7 +796,7 @@ void ModifyKokkos::min_popstore() } /* ---------------------------------------------------------------------- - displace extra dof along vector hextra, only for relevant fixes + displace extra minimizer dof along vector hextra, only for relevant fixes ------------------------------------------------------------------------- */ void ModifyKokkos::min_step(double alpha, double *hextra) @@ -755,7 +841,7 @@ double ModifyKokkos::max_alpha(double *hextra) } /* ---------------------------------------------------------------------- - extract extra dof for minimization, only for relevant fixes + extract extra minimizer dof, only for relevant fixes ------------------------------------------------------------------------- */ int ModifyKokkos::min_dof() @@ -775,7 +861,7 @@ int ModifyKokkos::min_dof() } /* ---------------------------------------------------------------------- - reset reference state of fix, only for relevant fixes + reset minimizer reference state of fix, only for relevant fixes ------------------------------------------------------------------------- */ int ModifyKokkos::min_reset_ref() @@ -788,8 +874,8 @@ int ModifyKokkos::min_reset_ref() int prev_auto_sync = lmp->kokkos->auto_sync; if (!fix[list_min_energy[i]]->kokkosable) lmp->kokkos->auto_sync = 1; itmp = fix[list_min_energy[i]]->min_reset_ref(); - lmp->kokkos->auto_sync = prev_auto_sync; if (itmp) itmpall = 1; + lmp->kokkos->auto_sync = prev_auto_sync; atomKK->modified(fix[list_min_energy[i]]->execution_space, fix[list_min_energy[i]]->datamask_modify); } diff --git a/src/KOKKOS/modify_kokkos.h b/src/KOKKOS/modify_kokkos.h index 9b75b7c607..25911743b2 100644 --- a/src/KOKKOS/modify_kokkos.h +++ b/src/KOKKOS/modify_kokkos.h @@ -26,6 +26,7 @@ class ModifyKokkos : public Modify { void setup(int); void setup_pre_exchange(); void setup_pre_neighbor(); + void setup_post_neighbor(); void setup_pre_force(int); void setup_pre_reverse(int, int); void initial_integrate(int); @@ -33,6 +34,7 @@ class ModifyKokkos : public Modify { void pre_decide(); void pre_exchange(); void pre_neighbor(); + void post_neighbor(); void pre_force(int); void pre_reverse(int,int); void post_force(int); @@ -52,6 +54,7 @@ class ModifyKokkos : public Modify { void min_pre_exchange(); void min_pre_neighbor(); + void min_post_neighbor(); void min_pre_force(int); void min_pre_reverse(int,int); void min_post_force(int); diff --git a/src/KOKKOS/pair_exp6_rx_kokkos.cpp b/src/KOKKOS/pair_exp6_rx_kokkos.cpp index 4da3a43243..0988cb4910 100644 --- a/src/KOKKOS/pair_exp6_rx_kokkos.cpp +++ b/src/KOKKOS/pair_exp6_rx_kokkos.cpp @@ -61,7 +61,7 @@ namespace /* anonymous */ { //typedef double TimerType; -//TimerType getTimeStamp(void) { return MPI_Wtime(); } +//TimerType getTimeStamp(void) { return platform::walltime(); } //double getElapsedTime( const TimerType &t0, const TimerType &t1) { return t1-t0; } typedef struct timespec TimerType; diff --git a/src/KOKKOS/pppm_kokkos.cpp b/src/KOKKOS/pppm_kokkos.cpp index d71d7d1bad..da18bba001 100644 --- a/src/KOKKOS/pppm_kokkos.cpp +++ b/src/KOKKOS/pppm_kokkos.cpp @@ -2857,7 +2857,7 @@ int PPPMKokkos::timing_1d(int n, double &time1d) copymode = 0; MPI_Barrier(world); - time1 = MPI_Wtime(); + time1 = platform::walltime(); for (int i = 0; i < n; i++) { fft1->timing1d(d_work1,nfft_both,FFT3dKokkos::FORWARD); @@ -2867,7 +2867,7 @@ int PPPMKokkos::timing_1d(int n, double &time1d) } MPI_Barrier(world); - time2 = MPI_Wtime(); + time2 = platform::walltime(); time1d = time2 - time1; return 4; @@ -2894,7 +2894,7 @@ int PPPMKokkos::timing_3d(int n, double &time3d) copymode = 0; MPI_Barrier(world); - time1 = MPI_Wtime(); + time1 = platform::walltime(); for (int i = 0; i < n; i++) { fft1->compute(d_work1,d_work1,FFT3dKokkos::FORWARD); @@ -2904,7 +2904,7 @@ int PPPMKokkos::timing_3d(int n, double &time3d) } MPI_Barrier(world); - time2 = MPI_Wtime(); + time2 = platform::walltime(); time3d = time2 - time1; return 4; diff --git a/src/KSPACE/pppm.cpp b/src/KSPACE/pppm.cpp index b6739d43fd..9d3a06f18e 100644 --- a/src/KSPACE/pppm.cpp +++ b/src/KSPACE/pppm.cpp @@ -2981,7 +2981,7 @@ int PPPM::timing_1d(int n, double &time1d) for (int i = 0; i < 2*nfft_both; i++) work1[i] = ZEROF; MPI_Barrier(world); - time1 = MPI_Wtime(); + time1 = platform::walltime(); for (int i = 0; i < n; i++) { fft1->timing1d(work1,nfft_both,FFT3d::FORWARD); @@ -2993,7 +2993,7 @@ int PPPM::timing_1d(int n, double &time1d) } MPI_Barrier(world); - time2 = MPI_Wtime(); + time2 = platform::walltime(); time1d = time2 - time1; if (differentiation_flag) return 2; @@ -3011,7 +3011,7 @@ int PPPM::timing_3d(int n, double &time3d) for (int i = 0; i < 2*nfft_both; i++) work1[i] = ZEROF; MPI_Barrier(world); - time1 = MPI_Wtime(); + time1 = platform::walltime(); for (int i = 0; i < n; i++) { fft1->compute(work1,work1,FFT3d::FORWARD); @@ -3023,7 +3023,7 @@ int PPPM::timing_3d(int n, double &time3d) } MPI_Barrier(world); - time2 = MPI_Wtime(); + time2 = platform::walltime(); time3d = time2 - time1; if (differentiation_flag) return 2; diff --git a/src/KSPACE/pppm_dipole.cpp b/src/KSPACE/pppm_dipole.cpp index a39973c6ae..16e06ed13e 100644 --- a/src/KSPACE/pppm_dipole.cpp +++ b/src/KSPACE/pppm_dipole.cpp @@ -2443,7 +2443,7 @@ int PPPMDipole::timing_1d(int n, double &time1d) for (int i = 0; i < 2*nfft_both; i++) work1[i] = ZEROF; MPI_Barrier(world); - time1 = MPI_Wtime(); + time1 = platform::walltime(); for (int i = 0; i < n; i++) { fft1->timing1d(work1,nfft_both,FFT3d::FORWARD); @@ -2461,7 +2461,7 @@ int PPPMDipole::timing_1d(int n, double &time1d) } MPI_Barrier(world); - time2 = MPI_Wtime(); + time2 = platform::walltime(); time1d = time2 - time1; return 12; @@ -2478,7 +2478,7 @@ int PPPMDipole::timing_3d(int n, double &time3d) for (int i = 0; i < 2*nfft_both; i++) work1[i] = ZEROF; MPI_Barrier(world); - time1 = MPI_Wtime(); + time1 = platform::walltime(); for (int i = 0; i < n; i++) { fft1->compute(work1,work1,FFT3d::FFT3d::FORWARD); @@ -2496,7 +2496,7 @@ int PPPMDipole::timing_3d(int n, double &time3d) } MPI_Barrier(world); - time2 = MPI_Wtime(); + time2 = platform::walltime(); time3d = time2 - time1; return 12; diff --git a/src/KSPACE/pppm_disp.cpp b/src/KSPACE/pppm_disp.cpp index a523fcce9e..fa14cb23f0 100644 --- a/src/KSPACE/pppm_disp.cpp +++ b/src/KSPACE/pppm_disp.cpp @@ -8183,7 +8183,7 @@ int PPPMDisp::timing_1d(int n, double &time1d) for (int i = 0; i < 2*nfft_both_6; i++) work1_6[i] = ZEROF; MPI_Barrier(world); - time1 = MPI_Wtime(); + time1 = platform::walltime(); if (function[0]) { for (int i = 0; i < n; i++) { @@ -8197,11 +8197,11 @@ int PPPMDisp::timing_1d(int n, double &time1d) } MPI_Barrier(world); - time2 = MPI_Wtime(); + time2 = platform::walltime(); time1d = time2 - time1; MPI_Barrier(world); - time1 = MPI_Wtime(); + time1 = platform::walltime(); if (function[1] + function[2] + function[3]) { for (int i = 0; i < n; i++) { @@ -8215,7 +8215,7 @@ int PPPMDisp::timing_1d(int n, double &time1d) } MPI_Barrier(world); - time2 = MPI_Wtime(); + time2 = platform::walltime(); time1d += (time2 - time1)*mixing; if (differentiation_flag) return 2; @@ -8238,7 +8238,7 @@ int PPPMDisp::timing_3d(int n, double &time3d) for (int i = 0; i < 2*nfft_both_6; i++) work1_6[i] = ZEROF; MPI_Barrier(world); - time1 = MPI_Wtime(); + time1 = platform::walltime(); if (function[0]) { for (int i = 0; i < n; i++) { @@ -8252,11 +8252,11 @@ int PPPMDisp::timing_3d(int n, double &time3d) } MPI_Barrier(world); - time2 = MPI_Wtime(); + time2 = platform::walltime(); time3d = time2 - time1; MPI_Barrier(world); - time1 = MPI_Wtime(); + time1 = platform::walltime(); if (function[1] + function[2] + function[3]) { for (int i = 0; i < n; i++) { @@ -8270,7 +8270,7 @@ int PPPMDisp::timing_3d(int n, double &time3d) } MPI_Barrier(world); - time2 = MPI_Wtime(); + time2 = platform::walltime(); time3d += (time2 - time1) * mixing; if (differentiation_flag) return 2; diff --git a/src/MANYBODY/pair_atm.cpp b/src/MANYBODY/pair_atm.cpp index 81adef5871..f7eda909e6 100644 --- a/src/MANYBODY/pair_atm.cpp +++ b/src/MANYBODY/pair_atm.cpp @@ -128,9 +128,9 @@ void PairATM::compute(int eflag, int vflag) rij[0] = x[j][0] - xi; if (rij[0] < 0.0) continue; rij[1] = x[j][1] - yi; - if (rij[0] == 0.0 and rij[1] < 0.0) continue; + if (rij[0] == 0.0 && rij[1] < 0.0) continue; rij[2] = x[j][2] - zi; - if (rij[0] == 0.0 and rij[1] == 0.0 and rij[2] < 0.0) continue; + if (rij[0] == 0.0 && rij[1] == 0.0 && rij[2] < 0.0) continue; rij2 = rij[0]*rij[0] + rij[1]*rij[1] + rij[2]*rij[2]; if (rij2 > cutoff_squared) continue; @@ -141,9 +141,9 @@ void PairATM::compute(int eflag, int vflag) rik[0] = x[k][0] - xi; if (rik[0] < 0.0) continue; rik[1] = x[k][1] - yi; - if (rik[0] == 0.0 and rik[1] < 0.0) continue; + if (rik[0] == 0.0 && rik[1] < 0.0) continue; rik[2] = x[k][2] - zi; - if (rik[0] == 0.0 and rik[1] == 0.0 and rik[2] < 0.0) continue; + if (rik[0] == 0.0 && rik[1] == 0.0 && rik[2] < 0.0) continue; rik2 = rik[0]*rik[0] + rik[1]*rik[1] + rik[2]*rik[2]; if (rik2 > cutoff_squared) continue; diff --git a/src/MANYBODY/pair_polymorphic.cpp b/src/MANYBODY/pair_polymorphic.cpp index f12d369e0d..ce476e1204 100644 --- a/src/MANYBODY/pair_polymorphic.cpp +++ b/src/MANYBODY/pair_polymorphic.cpp @@ -593,7 +593,7 @@ void PairPolymorphic::read_file(char *file) if ((ng == 0) || (nr == 0) || (nx == 0)) error->one(FLERR,"Error reading potential file header"); - } catch (TokenizerException &e) { + } catch (TokenizerException &) { error->one(FLERR,"Potential file incompatible with this pair style version"); } diff --git a/src/MDI/fix_mdi_engine.cpp b/src/MDI/fix_mdi_engine.cpp index 8024623e43..b08209080a 100644 --- a/src/MDI/fix_mdi_engine.cpp +++ b/src/MDI/fix_mdi_engine.cpp @@ -388,7 +388,7 @@ char *FixMDIEngine::engine_mode(const char *node) // respond to commands from the driver - while (not exit_flag and not local_exit_flag) { + while (!exit_flag && !local_exit_flag) { // read the next command from the driver // all procs call this, but only proc 0 receives the command diff --git a/src/MISC/fix_pair_tracker.cpp b/src/MISC/fix_pair_tracker.cpp index 95151375c4..3616855869 100644 --- a/src/MISC/fix_pair_tracker.cpp +++ b/src/MISC/fix_pair_tracker.cpp @@ -79,15 +79,14 @@ FixPairTracker::FixPairTracker(LAMMPS *lmp, int narg, char **arg) : } else if (strcmp(arg[iarg], "type/include") == 0) { if (iarg + 1 >= narg) error->all(FLERR, "Invalid keyword in fix pair/tracker command"); int ntypes = atom->ntypes; - - int i, j, itype, jtype, in, jn, infield, jnfield; + int i, j, itype, jtype; int inlo, inhi, jnlo, jnhi; - char *istr, *jstr; + if (!type_filter) { memory->create(type_filter, ntypes + 1, ntypes + 1, "fix/pair/tracker:type_filter"); for (i = 0; i <= ntypes; i++) { - for (j = 0; j <= ntypes; j++) { type_filter[i][j] = 0; } + for (j = 0; j <= ntypes; j++) type_filter[i][j] = 0; } } diff --git a/src/ML-IAP/mliap_model_python.cpp b/src/ML-IAP/mliap_model_python.cpp index 3d91107449..b89d17f289 100644 --- a/src/ML-IAP/mliap_model_python.cpp +++ b/src/ML-IAP/mliap_model_python.cpp @@ -132,7 +132,7 @@ void MLIAPModelPython::connect_param_counts() void MLIAPModelPython::compute_gradients(MLIAPData *data) { - if (not model_loaded) { error->all(FLERR, "Model not loaded."); } + if (!model_loaded) { error->all(FLERR, "Model not loaded."); } PyGILState_STATE gstate = PyGILState_Ensure(); MLIAPPY_compute_gradients(this, data); diff --git a/src/ML-SNAP/pair_snap.cpp b/src/ML-SNAP/pair_snap.cpp index d7cd953615..d6da639734 100644 --- a/src/ML-SNAP/pair_snap.cpp +++ b/src/ML-SNAP/pair_snap.cpp @@ -500,8 +500,7 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) nelemtmp = words.next_int(); ncoeffall = words.next_int(); } catch (TokenizerException &e) { - error->all(FLERR,"Incorrect format in SNAP coefficient " - "file: {}", e.what()); + error->all(FLERR,"Incorrect format in SNAP coefficient file: {}", e.what()); } // clean out old arrays and set up element lists @@ -538,7 +537,7 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) std::vector words; try { words = Tokenizer(utils::trim_comment(line),"\"' \t\n\r\f").as_vector(); - } catch (TokenizerException &e) { + } catch (TokenizerException &) { // ignore } if (words.size() != 3) @@ -599,8 +598,7 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) coeffelem[jelem][icoeff] = coeff.next_double(); } catch (TokenizerException &e) { - error->all(FLERR,"Incorrect format in SNAP coefficient " - "file: {}", e.what()); + error->all(FLERR,"Incorrect format in SNAP coefficient file: {}", e.what()); } } } @@ -609,8 +607,7 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) for (int jelem = 0; jelem < nelements; jelem++) { if (elementflags[jelem] == 0) - error->all(FLERR,"Element {} not found in SNAP coefficient " - "file", elements[jelem]); + error->all(FLERR,"Element {} not found in SNAP coefficient file", elements[jelem]); } delete[] elementflags; @@ -660,7 +657,7 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) std::vector words; try { words = Tokenizer(utils::trim_comment(line),"\"' \t\n\r\f").as_vector(); - } catch (TokenizerException &e) { + } catch (TokenizerException &) { // ignore } diff --git a/src/MOLECULE/angle_table.cpp b/src/MOLECULE/angle_table.cpp index 4299e375f1..a5ba07b779 100644 --- a/src/MOLECULE/angle_table.cpp +++ b/src/MOLECULE/angle_table.cpp @@ -412,7 +412,7 @@ void AngleTable::read_table(Table *tb, char *file, char *keyword) tb->afile[i] = values.next_double(); tb->efile[i] = values.next_double(); tb->ffile[i] = values.next_double(); - } catch (TokenizerException &e) { + } catch (TokenizerException &) { ++cerror; } } diff --git a/src/MOLECULE/bond_table.cpp b/src/MOLECULE/bond_table.cpp index 5637dfa699..db1314c76f 100644 --- a/src/MOLECULE/bond_table.cpp +++ b/src/MOLECULE/bond_table.cpp @@ -340,7 +340,7 @@ void BondTable::read_table(Table *tb, char *file, char *keyword) tb->rfile[i] = values.next_double(); tb->efile[i] = values.next_double(); tb->ffile[i] = values.next_double(); - } catch (TokenizerException &e) { + } catch (TokenizerException &) { ++cerror; } diff --git a/src/MOLFILE/dump_molfile.cpp b/src/MOLFILE/dump_molfile.cpp index 052fb444a4..35e87f94af 100644 --- a/src/MOLFILE/dump_molfile.cpp +++ b/src/MOLFILE/dump_molfile.cpp @@ -26,8 +26,8 @@ #include "memory.h" #include "update.h" -#include #include +#include #include "molfile_interface.h" @@ -131,9 +131,9 @@ DumpMolfile::~DumpMolfile() if (typenames) { for (int i = 1; i <= ntypes; i++) - delete [] typenames[i]; + delete[] typenames[i]; - delete [] typenames; + delete[] typenames; typenames = nullptr; } } @@ -152,8 +152,7 @@ void DumpMolfile::init_style() typenames = new char*[ntypes+1]; for (int itype = 1; itype <= ntypes; itype++) { /* a 32-bit int can be maximally 10 digits plus sign */ - typenames[itype] = new char[12]; - sprintf(typenames[itype],"%d",itype); + typenames[itype] = utils::strdup(std::to_string(itype)); } } @@ -207,6 +206,7 @@ void DumpMolfile::write() } } ntotal = 0; + reorderflag = 0; // if file per timestep, open new file @@ -430,9 +430,9 @@ int DumpMolfile::modify_param(int narg, char **arg) if (typenames) { for (int i = 1; i <= ntypes; i++) - delete [] typenames[i]; + delete[] typenames[i]; - delete [] typenames; + delete[] typenames; typenames = nullptr; } diff --git a/src/MOLFILE/molfile_interface.cpp b/src/MOLFILE/molfile_interface.cpp index 8e1174d8f4..808bc16ab4 100644 --- a/src/MOLFILE/molfile_interface.cpp +++ b/src/MOLFILE/molfile_interface.cpp @@ -17,20 +17,16 @@ ------------------------------------------------------------------------- */ #include "molfile_interface.h" + +#include "platform.h" +#include "tokenizer.h" +#include "utils.h" + #include "molfile_plugin.h" #include #include #include -#include -#include // for strcasecmp() - -#if defined(_WIN32) -#include -#else -#include -#include -#endif #if vmdplugin_ABIVERSION < 16 #error "unsupported VMD molfile plugin ABI version" @@ -199,172 +195,17 @@ extern "C" { return 0; } - // directory traversal helper functions - -#if defined(_WIN32) - - // Win32 directory traversal handle - typedef struct { - HANDLE h; - WIN32_FIND_DATA fd; - char *name; - char *searchname; - int dlen; - } dirhandle_t; - - // open a directory handle - static dirhandle_t *my_opendir(const char *dirname) - { - dirhandle_t *d; - int len; - - if (dirname == nullptr) - return nullptr; - d = new dirhandle_t; - - len = 2 + strlen(dirname); - d->name = new char[len]; - strcpy(d->name, dirname); - strcat(d->name, "\\"); - d->dlen = len; - - len += 1; - d->searchname = new char[len]; - strcpy(d->searchname, dirname); - strcat(d->searchname, "\\*"); - - d->h = FindFirstFile(d->searchname, &(d->fd)); - if (d->h == ((HANDLE)(-1))) { - delete[] d->searchname; - delete[] d->name; - delete d; - return nullptr; - } - return d; - } - - // get next file name from directory handle - static char *my_readdir(dirhandle_t *d) - { - if (FindNextFile(d->h, &(d->fd))) { - return d->fd.cFileName; - } - return nullptr; - } - - // close directory handle - static void my_closedir(dirhandle_t *d) - { - if (d->h != nullptr) { - FindClose(d->h); - } - delete[] d->searchname; - delete[] d->name; - delete d; - } - - // open a shared object file - static void *my_dlopen(const char *fname) { - return (void *)LoadLibrary(fname); - } - - // resolve a symbol in shared object - static void *my_dlsym(void *h, const char *sym) { - return (void *)GetProcAddress((HINSTANCE)h, sym); - } - - // close a shared object - static int my_dlclose(void *h) { - /* FreeLibrary returns nonzero on success */ - return !FreeLibrary((HINSTANCE)h); - } - -#else - - // Unix directory traversal handle - typedef struct { - DIR *d; - char *name; - int dlen; - } dirhandle_t; - - // open a directory handle - static dirhandle_t *my_opendir(const char *dirname) - { - dirhandle_t *d; - int len; - - if (dirname == nullptr) return nullptr; - - d = new dirhandle_t; - len = 2 + strlen(dirname); - d->name = new char[len]; - strcpy(d->name,dirname); - strcat(d->name,"/"); - d->dlen = len; - - d->d = opendir(d->name); - if (d->d == nullptr) { - delete[] d->name; - delete d; - return nullptr; - } - return d; - } - - // get next file name from directory handle - static char *my_readdir(dirhandle_t *d) - { - struct dirent *p; - - if ((p = readdir(d->d)) != nullptr) { - return p->d_name; - } - - return nullptr; - } - - // close directory handle - static void my_closedir(dirhandle_t *d) - { - if (d->d != nullptr) { - closedir(d->d); - } - delete[] d->name; - delete d; - return; - } - - // open a shared object file - static void *my_dlopen(const char *fname) { - return dlopen(fname, RTLD_NOW); - } - - // resolve a symbol in shared object - static void *my_dlsym(void *h, const char *sym) { - return dlsym(h, sym); - } - - // close a shared object - static int my_dlclose(void *h) { - return dlclose(h); - } - -#endif - } // end of extern "C" region using namespace LAMMPS_NS; // constructor. MolfileInterface::MolfileInterface(const char *type, const int mode) - : _plugin(0), _dso(0), _ptr(0), _info(0), _natoms(0), - _mode(mode), _caps(M_NONE) + : _plugin(nullptr), _dso(nullptr), _ptr(nullptr), _info(nullptr), _natoms(0), + _mode(mode), _caps(M_NONE), _props(0) { - _name = new char[5]; - strcpy(_name,"none"); - _type = new char[1+strlen(type)]; - strcpy(_type,type); + _name = utils::strdup("none"); + _type = utils::strdup(type); } // destructor. @@ -384,62 +225,21 @@ MolfileInterface::~MolfileInterface() // register the best matching plugin in a given directory int MolfileInterface::find_plugin(const char *pluginpath) { - dirhandle_t *dir; - char *filename, *ext, *next, *path, *plugindir; int retval = E_NONE; -#if defined(_WIN32) -#define MY_PATHSEP ';' -#else -#define MY_PATHSEP ':' -#endif if (pluginpath == nullptr) return E_DIR; - plugindir = path = strdup(pluginpath); - while (plugindir) { - // check if this a single directory or path. - next = strchr(plugindir,MY_PATHSEP); - if (next) { - *next = '\0'; - ++next; + // search for suitable file names in provided path and try to inspect them + // only look at .so files, since this is what VMD uses on all platforms + + for (const auto &dir : Tokenizer(pluginpath,":").as_vector()) { + for (const auto &filename : platform::list_directory(dir)) { + if (utils::strmatch(filename,"\\.so$")) { + int rv = load_plugin(platform::path_join(dir,filename).c_str()); + if (rv > retval) retval = rv; + } } - - dir = my_opendir(plugindir); - if (!dir) - retval = (retval > E_DIR) ? retval : E_DIR; - - // search for suitable file names and try to inspect them - while (dir) { - char *fullname; - int len; - - filename = my_readdir(dir); - if (filename == nullptr) break; - - // only look at .so files - ext = strrchr(filename, '.'); - if (ext == nullptr) continue; - if (strcasecmp(ext,".so") != 0) continue; - - // construct full pathname of potential DSO - len = dir->dlen; - len += strlen(filename); - fullname = new char[len]; - strcpy(fullname,dir->name); - strcat(fullname,filename); - - // try to register plugin at file name. - int rv = load_plugin(fullname); - if (rv > retval) retval = rv; - - delete[] fullname; - } - if (dir) - my_closedir(dir); - - plugindir = next; } - free(path); return retval; } @@ -447,25 +247,25 @@ int MolfileInterface::find_plugin(const char *pluginpath) int MolfileInterface::load_plugin(const char *filename) { void *dso; - int len, retval = E_NONE; + int retval = E_NONE; // access shared object - dso = my_dlopen(filename); + dso = platform::dlopen(filename); if (dso == nullptr) return E_FILE; // check for required plugin symbols - void *ifunc = my_dlsym(dso,"vmdplugin_init"); - void *rfunc = my_dlsym(dso,"vmdplugin_register"); - void *ffunc = my_dlsym(dso,"vmdplugin_fini"); + void *ifunc = platform::dlsym(dso,"vmdplugin_init"); + void *rfunc = platform::dlsym(dso,"vmdplugin_register"); + void *ffunc = platform::dlsym(dso,"vmdplugin_fini"); if (ifunc == nullptr || rfunc == nullptr || ffunc == nullptr) { - my_dlclose(dso); + platform::dlclose(dso); return E_SYMBOL; } // initialize plugin. skip plugin if it fails. if (((initfunc)(ifunc))()) { - my_dlclose(dso); + platform::dlclose(dso); return E_SYMBOL; } @@ -528,12 +328,8 @@ int MolfileInterface::load_plugin(const char *filename) forget_plugin(); delete[] _name; - len = 16; - len += strlen(plugin->prettyname); - len += strlen(plugin->author); - _name = new char[len]; - sprintf(_name,"%s v%d.%d by %s",plugin->prettyname, - plugin->majorv, plugin->minorv, plugin->author); + _name = utils::strdup(fmt::format("{} v{}.{} by {}", plugin->prettyname, + plugin->majorv, plugin->minorv, plugin->author)); // determine plugin capabilities _caps = M_NONE; @@ -569,7 +365,7 @@ int MolfileInterface::load_plugin(const char *filename) } // better luck next time. clean up and return. - my_dlclose(dso); + platform::dlclose(dso); return retval; } @@ -583,10 +379,10 @@ void MolfileInterface::forget_plugin() _plugin = nullptr; if (_dso) { - void *ffunc = my_dlsym(_dso,"vmdplugin_fini"); + void *ffunc = platform::dlsym(_dso,"vmdplugin_fini"); if (ffunc) ((finifunc)ffunc)(); - my_dlclose(_dso); + platform::dlclose(_dso); } _dso = nullptr; diff --git a/src/MOLFILE/reader_molfile.cpp b/src/MOLFILE/reader_molfile.cpp index e04b615018..5f75ae50f5 100644 --- a/src/MOLFILE/reader_molfile.cpp +++ b/src/MOLFILE/reader_molfile.cpp @@ -85,13 +85,7 @@ void ReaderMolfile::settings(int narg, char **arg) if (mf->find_plugin(path)!= MFI::E_MATCH) error->one(FLERR,"No suitable molfile plugin found"); - if (screen) - fprintf(screen,"Dump reader uses molfile plugin: %s\n", - mf->get_plugin_name()); - - if (logfile) - fprintf(logfile,"Dump reader uses molfile plugin: %s\n", - mf->get_plugin_name()); + utils::logmesg(lmp,"Dump reader uses molfile plugin: {}\n", mf->get_plugin_name()); } } @@ -100,30 +94,22 @@ void ReaderMolfile::settings(int narg, char **arg) only called by proc 0 ------------------------------------------------------------------------- */ -void ReaderMolfile::open_file(const char *file) +void ReaderMolfile::open_file(const std::string &file) { int rv; - char str[1024]; // close open file, if needed. if (mf->is_open()) mf->close(); - rv = mf->open(file,&natoms); + rv = mf->open(file.c_str(),&natoms); - if (rv != MFI::E_NONE) { - snprintf(str,1024,"Cannot open file %s",file); - error->one(FLERR,str); - } + if (rv != MFI::E_NONE) error->one(FLERR,"Cannot open file {}", file); - if (natoms < 1) { - snprintf(str,1024,"No atoms in file %s",file); - error->one(FLERR,str); - } + if (natoms < 1) error->one(FLERR,"No atoms in file {}", file); memory->create(types,natoms,"reader:types"); memory->create(coords,3*natoms,"reader:coords"); - if (mf->has_vels()) - memory->create(vels,3*natoms,"reader:vels"); + if (mf->has_vels()) memory->create(vels,3*natoms,"reader:vels"); // initialize system properties, if available if (mf->has_props()) { diff --git a/src/MOLFILE/reader_molfile.h b/src/MOLFILE/reader_molfile.h index 1f7fead9c0..4330eaf4eb 100644 --- a/src/MOLFILE/reader_molfile.h +++ b/src/MOLFILE/reader_molfile.h @@ -39,7 +39,7 @@ class ReaderMolfile : public Reader { int &, int &, int &); virtual void read_atoms(int, int, double **); - virtual void open_file(const char *); + virtual void open_file(const std::string &); virtual void close_file(); private: diff --git a/src/NETCDF/dump_netcdf.cpp b/src/NETCDF/dump_netcdf.cpp index 5702c94499..5f30c941ca 100644 --- a/src/NETCDF/dump_netcdf.cpp +++ b/src/NETCDF/dump_netcdf.cpp @@ -274,7 +274,7 @@ void DumpNetCDF::openfile() if (append_flag && !multifile) { // Fixme! Perform checks if dimensions and variables conform with // data structure standard. - if (not utils::file_is_readable(filecurrent)) + if (!platform::file_is_readable(filecurrent)) error->all(FLERR, "cannot append to non-existent file {}",filecurrent); if (singlefile_opened) return; diff --git a/src/NETCDF/dump_netcdf_mpiio.cpp b/src/NETCDF/dump_netcdf_mpiio.cpp index a6c3c535c9..0a76203f96 100644 --- a/src/NETCDF/dump_netcdf_mpiio.cpp +++ b/src/NETCDF/dump_netcdf_mpiio.cpp @@ -272,7 +272,7 @@ void DumpNetCDFMPIIO::openfile() if (append_flag && !multifile) { // Fixme! Perform checks if dimensions and variables conform with // data structure standard. - if (not utils::file_is_readable(filecurrent)) + if (!platform::file_is_readable(filecurrent)) error->all(FLERR, "cannot append to non-existent file {}", filecurrent); MPI_Offset index[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS]; diff --git a/src/OPENMP/npair_half_size_multi_newton_omp.cpp b/src/OPENMP/npair_half_size_multi_newton_omp.cpp index cdc68e1b42..bcf87d385c 100644 --- a/src/OPENMP/npair_half_size_multi_newton_omp.cpp +++ b/src/OPENMP/npair_half_size_multi_newton_omp.cpp @@ -108,7 +108,7 @@ void NPairHalfSizeMultiNewtonOmp::build(NeighList *list) // if j is ghost, only store if j coords are "above and to the right" of i for (j = js; j >= 0; j = bins[j]) { - if(icollection != jcollection and j < i) continue; + if(icollection != jcollection && j < i) continue; if (j >= nlocal) { if (x[j][2] < ztmp) continue; diff --git a/src/ORIENT/fix_orient_eco.cpp b/src/ORIENT/fix_orient_eco.cpp index 6ec4e278ec..55486adc37 100644 --- a/src/ORIENT/fix_orient_eco.cpp +++ b/src/ORIENT/fix_orient_eco.cpp @@ -550,7 +550,7 @@ int FixOrientECO::get_norm() { squared_distance = delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]; // check if atom is within cutoff region - if ((squared_distance != 0.0) and (squared_distance < squared_cutoff)) { + if ((squared_distance != 0.0) && (squared_distance < squared_cutoff)) { ++neigh; squared_distance *= inv_squared_cutoff; diff --git a/src/PHONON/dynamical_matrix.cpp b/src/PHONON/dynamical_matrix.cpp index f7cb3f7f44..e236e24a15 100644 --- a/src/PHONON/dynamical_matrix.cpp +++ b/src/PHONON/dynamical_matrix.cpp @@ -55,9 +55,12 @@ DynamicalMatrix::DynamicalMatrix(LAMMPS *lmp) : Command(lmp), fp(nullptr) DynamicalMatrix::~DynamicalMatrix() { - if (fp && me == 0) fclose(fp); + if (fp && me == 0) { + if (compressed) platform::pclose(fp); + else fclose(fp); memory->destroy(groupmap); fp = nullptr; + } } /* ---------------------------------------------------------------------- @@ -208,36 +211,28 @@ void DynamicalMatrix::options(int narg, char **arg) /* ---------------------------------------------------------------------- generic opening of a file - ASCII or binary or gzipped + ASCII or binary or compressed some derived classes override this function ------------------------------------------------------------------------- */ -void DynamicalMatrix::openfile(const char* filename) +void DynamicalMatrix::openfile(const char *filename) { // if file already opened, return - //if (me!=0) return; if (file_opened) return; + fp = nullptr; - if (compressed) { -#ifdef LAMMPS_GZIP - char gzip[128]; - sprintf(gzip,"gzip -6 > %s",filename); -#ifdef _WIN32 - fp = _popen(gzip,"wb"); -#else - fp = popen(gzip,"w"); -#endif -#else - error->one(FLERR,"Cannot open gzipped file"); -#endif - } else if (binaryflag) { + if (me == 0) { + if (compressed) { + fp = platform::compressed_write(std::string(filename)+".gz"); + if (!fp) error->one(FLERR,"Cannot open compressed file"); + } else if (binaryflag) { fp = fopen(filename,"wb"); - } else { + } else { fp = fopen(filename,"w"); + } + if (!fp) error->one(FLERR,"Cannot open dynmat file: {}", utils::getsyserror()); } - if (fp == nullptr) error->one(FLERR,"Cannot open dump file"); - file_opened = 1; } diff --git a/src/PHONON/third_order.cpp b/src/PHONON/third_order.cpp index 565e8b50e5..3206882a4a 100644 --- a/src/PHONON/third_order.cpp +++ b/src/PHONON/third_order.cpp @@ -55,7 +55,10 @@ ThirdOrder::ThirdOrder(LAMMPS *lmp) : Command(lmp), fp(nullptr) ThirdOrder::~ThirdOrder() { - if (fp && me == 0) fclose(fp); + if (fp && me == 0) { + if (compressed) platform::pclose(fp); + else fclose(fp); + } fp = nullptr; memory->destroy(groupmap); } @@ -200,14 +203,14 @@ void ThirdOrder::options(int narg, char **arg) iarg += 2; } else error->all(FLERR,"Illegal third_order command"); } - if (file_flag == 1 and me == 0) { + if (file_flag == 1 && me == 0) { openfile(filename); } } /* ---------------------------------------------------------------------- generic opening of a file - ASCII or binary or gzipped + ASCII or binary or compressed some derived classes override this function ------------------------------------------------------------------------- */ @@ -215,27 +218,19 @@ void ThirdOrder::openfile(const char* filename) { // if file already opened, return if (file_opened) return; + fp = nullptr; - if (compressed) { -#ifdef LAMMPS_GZIP - char gzip[128]; - sprintf(gzip,"gzip -6 > %s",filename); -#ifdef _WIN32 - fp = _popen(gzip,"wb"); -#else - fp = popen(gzip,"w"); -#endif -#else - error->one(FLERR,"Cannot open gzipped file"); -#endif - } else if (binaryflag) { - fp = fopen(filename,"wb"); - } else { - fp = fopen(filename,"w"); + if (me == 0) { + if (compressed) { + fp = platform::compressed_write(std::string(filename)+".gz"); + if (!fp) error->one(FLERR,"Cannot open compressed file"); + } else if (binaryflag) { + fp = fopen(filename,"wb"); + } else { + fp = fopen(filename,"w"); + } + if (!fp) error->one(FLERR,"Cannot open third_order file: {}", utils::getsyserror()); } - - if (fp == nullptr) error->one(FLERR,"Cannot open dump file"); - file_opened = 1; } diff --git a/src/PLUGIN/plugin.cpp b/src/PLUGIN/plugin.cpp index 270c9958f5..443fecc99f 100644 --- a/src/PLUGIN/plugin.cpp +++ b/src/PLUGIN/plugin.cpp @@ -25,12 +25,6 @@ #include #include -#ifdef _WIN32 -#include -#else -#include -#endif - namespace LAMMPS_NS { // list of plugin information data for loaded styles @@ -87,31 +81,28 @@ namespace LAMMPS_NS { #if defined(LMP_PLUGIN) int me = lmp->comm->me; -#if defined(WIN32) - lmp->error->all(FLERR,"Loading of plugins on Windows is not supported\n"); -#else // open DSO file from given path; load symbols globally - dlerror(); - void *dso = dlopen(file,RTLD_NOW|RTLD_GLOBAL); + platform::dlerror(); + void *dso = platform::dlopen(file); if (dso == nullptr) { if (me == 0) - utils::logmesg(lmp,"Open of file {} failed: {}\n",file,dlerror()); + utils::logmesg(lmp,"Open of file {} failed: {}\n",file,platform::dlerror()); return; } // look up lammpsplugin_init() function in DSO // function must have C bindings so there is no name mangling - dlerror(); - void *initfunc = dlsym(dso,"lammpsplugin_init"); + platform::dlerror(); + void *initfunc = platform::dlsym(dso,"lammpsplugin_init"); if (initfunc == nullptr) { - dlclose(dso); + platform::dlclose(dso); if (me == 0) utils::logmesg(lmp,"Plugin symbol lookup failure in file {}: {}\n", - file,dlerror()); + file,platform::dlerror()); return; } @@ -121,7 +112,6 @@ namespace LAMMPS_NS (*(lammpsplugin_initfunc)(initfunc))((void *)lmp, dso, (void *)&plugin_register); -#endif #endif } @@ -410,9 +400,7 @@ namespace LAMMPS_NS -- dso_refcounter[handle]; if (dso_refcounter[handle] == 0) { -#ifndef WIN32 - dlclose(handle); -#endif + platform::dlclose(handle); } #endif } diff --git a/src/PLUMED/fix_plumed.cpp b/src/PLUMED/fix_plumed.cpp index 7a142b57f8..137cd580a8 100644 --- a/src/PLUMED/fix_plumed.cpp +++ b/src/PLUMED/fix_plumed.cpp @@ -41,7 +41,7 @@ #if defined(__PLUMED_DEFAULT_KERNEL) #define PLUMED_QUOTE_DIRECT(name) #name #define PLUMED_QUOTE(macro) PLUMED_QUOTE_DIRECT(macro) -static char plumed_default_kernel[] = "PLUMED_KERNEL=" PLUMED_QUOTE(__PLUMED_DEFAULT_KERNEL); +static const char plumed_default_kernel[] = "PLUMED_KERNEL=" PLUMED_QUOTE(__PLUMED_DEFAULT_KERNEL); #endif /* -------------------------------------------------------------------- */ @@ -68,7 +68,7 @@ FixPlumed::FixPlumed(LAMMPS *lmp, int narg, char **arg) : #if defined(__PLUMED_DEFAULT_KERNEL) if (getenv("PLUMED_KERNEL") == nullptr) - putenv(plumed_default_kernel); + platform::putenv(plumed_default_kernel); #endif p=new PLMD::Plumed; diff --git a/src/QEQ/fix_qeq.cpp b/src/QEQ/fix_qeq.cpp index a0d012bb5b..e2cae80dd4 100644 --- a/src/QEQ/fix_qeq.cpp +++ b/src/QEQ/fix_qeq.cpp @@ -767,7 +767,7 @@ void FixQEq::read_file(char *file) for (int n=nlo; n <= nhi; ++n) zcore[n] = val; for (int n=nlo; n <= nhi; ++n) setflag[n] = 1; } - } catch (EOFException &e) { + } catch (EOFException &) { ; // catch and ignore to exit loop } catch (std::exception &e) { error->one(FLERR,e.what()); diff --git a/src/REAXFF/fix_reaxff_bonds.cpp b/src/REAXFF/fix_reaxff_bonds.cpp index f13056c5b6..740a32a0a6 100644 --- a/src/REAXFF/fix_reaxff_bonds.cpp +++ b/src/REAXFF/fix_reaxff_bonds.cpp @@ -45,30 +45,21 @@ FixReaxFFBonds::FixReaxFFBonds(LAMMPS *lmp, int narg, char **arg) : MPI_Comm_size(world,&nprocs); ntypes = atom->ntypes; nmax = atom->nmax; + compressed = 0; nevery = utils::inumeric(FLERR,arg[3],false,lmp); - if (nevery <= 0) - error->all(FLERR,"Illegal fix reaxff/bonds command"); + if (nevery <= 0) error->all(FLERR,"Illegal fix reaxff/bonds command"); if (me == 0) { - char *suffix = strrchr(arg[4],'.'); - if (suffix && strcmp(suffix,".gz") == 0) { -#ifdef LAMMPS_GZIP - auto gzip = fmt::format("gzip -6 > {}",arg[4]); -#ifdef _WIN32 - fp = _popen(gzip.c_str(),"wb"); -#else - fp = popen(gzip.c_str(),"w"); -#endif -#else - error->one(FLERR,"Cannot open gzipped file"); -#endif + if (platform::has_compress_extension(arg[4])) { + compressed = 1; + fp = platform::compressed_write(arg[4]); + if (!fp) error->one(FLERR,"Cannot open compressed file"); } else fp = fopen(arg[4],"w"); - if (!fp) - error->one(FLERR,fmt::format("Cannot open fix reaxff/bonds file {}: " - "{}",arg[4],utils::getsyserror())); + if (!fp) error->one(FLERR,fmt::format("Cannot open fix reaxff/bonds file {}: " + "{}",arg[4],utils::getsyserror())); } if (atom->tag_consecutive() == 0) diff --git a/src/REAXFF/fix_reaxff_bonds.h b/src/REAXFF/fix_reaxff_bonds.h index 4c2fd535ea..4c40017e43 100644 --- a/src/REAXFF/fix_reaxff_bonds.h +++ b/src/REAXFF/fix_reaxff_bonds.h @@ -36,7 +36,7 @@ class FixReaxFFBonds : public Fix { void end_of_step(); protected: - int me, nprocs, nmax, ntypes, maxsize; + int me, nprocs, nmax, ntypes, maxsize, compressed; int *numneigh; tagint **neighid; double **abo; diff --git a/src/REAXFF/fix_reaxff_species.cpp b/src/REAXFF/fix_reaxff_species.cpp index 4fc08975a8..7bf6f34aa7 100644 --- a/src/REAXFF/fix_reaxff_species.cpp +++ b/src/REAXFF/fix_reaxff_species.cpp @@ -56,6 +56,7 @@ FixReaxFFSpecies::FixReaxFFSpecies(LAMMPS *lmp, int narg, char **arg) : size_peratom_cols = 0; peratom_freq = 1; + compressed = 0; nvalid = -1; MPI_Comm_rank(world,&me); @@ -106,23 +107,14 @@ FixReaxFFSpecies::FixReaxFFSpecies(LAMMPS *lmp, int narg, char **arg) : strcpy(tmparg[2],arg[5]); if (me == 0) { - char *suffix = strrchr(arg[6],'.'); - if (suffix && strcmp(suffix,".gz") == 0) { -#ifdef LAMMPS_GZIP - auto gzip = fmt::format("gzip -6 > {}",arg[6]); -#ifdef _WIN32 - fp = _popen(gzip.c_str(),"wb"); -#else - fp = popen(gzip.c_str(),"w"); -#endif -#else - error->one(FLERR,"Cannot open gzipped file"); -#endif + if (platform::has_compress_extension(arg[6])) { + fp = platform::compressed_write(arg[6]); + compressed = 1; + if (!fp) error->one(FLERR,"Cannot open compressed file"); } else fp = fopen(arg[6],"w"); - if (!fp) - error->one(FLERR,fmt::format("Cannot open fix reaxff/species file {}: " - "{}",arg[6],utils::getsyserror())); + if (!fp) error->one(FLERR,fmt::format("Cannot open fix reaxff/species file {}: " + "{}",arg[6],utils::getsyserror())); } x0 = nullptr; @@ -256,8 +248,11 @@ FixReaxFFSpecies::~FixReaxFFSpecies() if (filepos) delete [] filepos; - if (me == 0) fclose(fp); - if (me == 0 && posflag && multipos_opened) fclose(pos); + if (me == 0) { + if (compressed) platform::pclose(fp); + else fclose(fp); + if (posflag && multipos_opened) fclose(pos); + } modify->delete_compute("SPECATOM"); modify->delete_fix("SPECBOND"); @@ -683,8 +678,7 @@ void FixReaxFFSpecies::OpenPos() char *ptr = strchr(filepos,'*'); *ptr = '\0'; if (padflag == 0) - sprintf(filecurrent,"%s" BIGINT_FORMAT "%s", - filepos,ntimestep,ptr+1); + sprintf(filecurrent,"%s" BIGINT_FORMAT "%s",filepos,ntimestep,ptr+1); else { char bif[8],pad[16]; strcpy(bif,BIGINT_FORMAT); diff --git a/src/REAXFF/fix_reaxff_species.h b/src/REAXFF/fix_reaxff_species.h index bcfcf2b6dd..91326273b6 100644 --- a/src/REAXFF/fix_reaxff_species.h +++ b/src/REAXFF/fix_reaxff_species.h @@ -45,7 +45,7 @@ class FixReaxFFSpecies : public Fix { protected: int me, nprocs, nmax, nlocal, ntypes, ntotal; - int nrepeat, nfreq, posfreq; + int nrepeat, nfreq, posfreq, compressed; int Nmoltype, vector_nmole, vector_nspec; int *Name, *MolName, *NMol, *nd, *MolType, *molmap; double *clusterID; diff --git a/src/REAXFF/pair_reaxff.cpp b/src/REAXFF/pair_reaxff.cpp index fdba9b98a3..1c6665b604 100644 --- a/src/REAXFF/pair_reaxff.cpp +++ b/src/REAXFF/pair_reaxff.cpp @@ -40,7 +40,6 @@ #include #include -#include // for strcasecmp() #include "reaxff_api.h" @@ -302,7 +301,7 @@ void PairReaxFF::coeff(int nargs, char **args) // pair_coeff element map for (int i = 3; i < nargs; i++) for (int j = 0; j < nreax_types; j++) - if (strcasecmp(args[i],api->system->reax_param.sbp[j].name) == 0) { + if (utils::lowercase(args[i]) == utils::lowercase(api->system->reax_param.sbp[j].name)) { map[i-2] = j; itmp ++; } diff --git a/src/REAXFF/reaxff_ffield.cpp b/src/REAXFF/reaxff_ffield.cpp index 7eab49fa44..605e077724 100644 --- a/src/REAXFF/reaxff_ffield.cpp +++ b/src/REAXFF/reaxff_ffield.cpp @@ -32,7 +32,6 @@ #include "text_file_reader.h" #include "utils.h" -#include #include #include #include @@ -40,6 +39,7 @@ using LAMMPS_NS::utils::open_potential; using LAMMPS_NS::utils::getsyserror; +using LAMMPS_NS::utils::uppercase; namespace ReaxFF { @@ -161,11 +161,10 @@ namespace ReaxFF { if (values.count() < 9) THROW_ERROR("Invalid force field file format"); - auto element = values.next_string(); - int len = MIN(element.size(),3); // truncate stored element symbol if necessary - for (j = 0; j < len; ++j) - sbp[i].name[j] = toupper(element[j]); - sbp[i].name[len] = '\0'; + // copy element symbol in uppercase and truncate stored element symbol if necessary + auto element = uppercase(values.next_string()); + strncpy(sbp[i].name,element.c_str(),4); + sbp[i].name[3] = '\0'; sbp[i].r_s = values.next_double(); sbp[i].valency = values.next_double(); diff --git a/src/REPLICA/fix_hyper_local.cpp b/src/REPLICA/fix_hyper_local.cpp index 4a477fad8d..ba91644c53 100644 --- a/src/REPLICA/fix_hyper_local.cpp +++ b/src/REPLICA/fix_hyper_local.cpp @@ -447,7 +447,7 @@ void FixHyperLocal::pre_reverse(int /* eflag */, int /* vflag */) int *ilist,*jlist,*numneigh,**firstneigh; //double time1,time2,time3,time4,time5,time6,time7,time8; - //time1 = MPI_Wtime(); + //time1 = platform::walltime(); nostrainyet = 0; @@ -520,7 +520,7 @@ void FixHyperLocal::pre_reverse(int /* eflag */, int /* vflag */) maxhalfstrain[iold] = halfstrain; } - //time2 = MPI_Wtime(); + //time2 = platform::walltime(); // reverse comm acquires maxstrain of all current owned atoms // needed b/c only saw half the bonds of each atom @@ -531,7 +531,7 @@ void FixHyperLocal::pre_reverse(int /* eflag */, int /* vflag */) comm->reverse_comm_fix(this); comm->forward_comm_fix(this); - //time3 = MPI_Wtime(); + //time3 = platform::walltime(); // ------------------------------------------------------------- // stage 2: @@ -636,7 +636,7 @@ void FixHyperLocal::pre_reverse(int /* eflag */, int /* vflag */) maxstrain_domain[i] = emax; } - //time4 = MPI_Wtime(); + //time4 = platform::walltime(); // reverse comm to acquire maxstrain_domain from ghost atoms // needed b/c neigh list may refer to old owned atoms that are now ghost @@ -646,7 +646,7 @@ void FixHyperLocal::pre_reverse(int /* eflag */, int /* vflag */) comm->reverse_comm_fix(this); comm->forward_comm_fix(this); - //time5 = MPI_Wtime(); + //time5 = platform::walltime(); // ------------------------------------------------------------- // stage 3: @@ -672,7 +672,7 @@ void FixHyperLocal::pre_reverse(int /* eflag */, int /* vflag */) bias[nbias++] = maxhalf[iold]; } - //time6 = MPI_Wtime(); + //time6 = platform::walltime(); // ------------------------------------------------------------- // stage 4: @@ -724,7 +724,7 @@ void FixHyperLocal::pre_reverse(int /* eflag */, int /* vflag */) // myboost += exp(beta * biascoeff[m]*vbias); } - //time7 = MPI_Wtime(); + //time7 = platform::walltime(); // ------------------------------------------------------------- // stage 5: @@ -887,7 +887,7 @@ void FixHyperLocal::build_bond_list(int natom) int *ilist,*jlist,*numneigh,**firstneigh; double time1,time2; - time1 = MPI_Wtime(); + time1 = platform::walltime(); if (natom) { nevent++; @@ -1185,7 +1185,7 @@ void FixHyperLocal::build_bond_list(int natom) // DEBUG //if (me == 0) printf("TOTAL BOND COUNT = %ld\n",allbonds); - time2 = MPI_Wtime(); + time2 = platform::walltime(); if (firstflag) nnewbond = 0; else { diff --git a/src/REPLICA/neb.cpp b/src/REPLICA/neb.cpp index 9e6e32772d..8cfc4b5c24 100644 --- a/src/REPLICA/neb.cpp +++ b/src/REPLICA/neb.cpp @@ -94,7 +94,10 @@ NEB::~NEB() MPI_Comm_free(&roots); memory->destroy(all); delete[] rdist; - if (fp) fclose(fp); + if (fp) { + if (compressed) platform::pclose(fp); + else fclose(fp); + } } /* ---------------------------------------------------------------------- @@ -525,12 +528,12 @@ void NEB::readfile(char *file, int flag) if (flag == 0) { if (me_universe == 0) { - if (compressed) pclose(fp); + if (compressed) platform::pclose(fp); else fclose(fp); } } else { if (me == 0 && ireplica) { - if (compressed) pclose(fp); + if (compressed) platform::pclose(fp); else fclose(fp); } } @@ -539,28 +542,17 @@ void NEB::readfile(char *file, int flag) /* ---------------------------------------------------------------------- universe proc 0 opens NEB data file - test if gzipped + test if compressed ------------------------------------------------------------------------- */ void NEB::open(char *file) { compressed = 0; - char *suffix = file + strlen(file) - 3; - if (suffix > file && strcmp(suffix,".gz") == 0) compressed = 1; - if (!compressed) fp = fopen(file,"r"); - else { -#ifdef LAMMPS_GZIP - auto gunzip = std::string("gzip -c -d ") + file; -#ifdef _WIN32 - fp = _popen(gunzip.c_str(),"rb"); -#else - fp = popen(gunzip.c_str(),"r"); -#endif - -#else - error->one(FLERR,"Cannot open gzipped file"); -#endif - } + if (platform::has_compress_extension(file)) { + compressed = 1; + fp = platform::compressed_read(file); + if (!fp) error->one(FLERR,"Cannot open compressed file"); + } else fp = fopen(file,"r"); if (fp == nullptr) error->one(FLERR,"Cannot open file {}: {}",file,utils::getsyserror()); diff --git a/src/REPLICA/tad.cpp b/src/REPLICA/tad.cpp index 9b6ecf0b0c..881ec1604c 100644 --- a/src/REPLICA/tad.cpp +++ b/src/REPLICA/tad.cpp @@ -710,7 +710,7 @@ void TAD::perform_neb(int ievent) // time_neb += timer->get_wall(Timer::TOTAL); MPI_Barrier(world); - double time_tmp = MPI_Wtime(); + double time_tmp = platform::walltime(); double dt_hold = update->dt; update->dt = dt_neb; @@ -718,7 +718,7 @@ void TAD::perform_neb(int ievent) update->dt = dt_hold; MPI_Barrier(world); - time_neb += MPI_Wtime() - time_tmp; + time_neb += platform::walltime() - time_tmp; if (universe->me == 0) { universe->ulogfile = ulogfile_lammps; diff --git a/src/RIGID/fix_rigid_small.cpp b/src/RIGID/fix_rigid_small.cpp index 7216c56c83..7a30c8b1c9 100644 --- a/src/RIGID/fix_rigid_small.cpp +++ b/src/RIGID/fix_rigid_small.cpp @@ -391,14 +391,14 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : // sets bodytag for owned atoms // body attributes are computed later by setup_bodies() - double time1 = MPI_Wtime(); + double time1 = platform::walltime(); create_bodies(bodyID); if (customflag) delete [] bodyID; if (comm->me == 0) utils::logmesg(lmp," create bodies CPU = {:.3f} seconds\n", - MPI_Wtime()-time1); + platform::walltime()-time1); // set nlocal_body and allocate bodies I own diff --git a/src/RIGID/fix_shake.cpp b/src/RIGID/fix_shake.cpp index f1c1d30fc5..9e45ec13d8 100644 --- a/src/RIGID/fix_shake.cpp +++ b/src/RIGID/fix_shake.cpp @@ -222,13 +222,13 @@ FixShake::FixShake(LAMMPS *lmp, int narg, char **arg) : // identify all SHAKE clusters - double time1 = MPI_Wtime(); + double time1 = platform::walltime(); find_clusters(); if (comm->me == 0) utils::logmesg(lmp," find clusters CPU = {:.3f} seconds\n", - MPI_Wtime()-time1); + platform::walltime()-time1); // initialize list of SHAKE clusters to constrain diff --git a/src/SMTBQ/pair_smtbq.cpp b/src/SMTBQ/pair_smtbq.cpp index 4b7a1f2ac5..8922173433 100644 --- a/src/SMTBQ/pair_smtbq.cpp +++ b/src/SMTBQ/pair_smtbq.cpp @@ -2426,7 +2426,7 @@ void PairSMTBQ::Charge() ilist = list->ilist; - if (me == 0) t_init = MPI_Wtime(); + if (me == 0) t_init = platform::walltime(); if (step == 0) cluster = 0; // --------------------------- @@ -2729,7 +2729,7 @@ void PairSMTBQ::Charge() printf (" convergence : %f - %f\n",enegchk[gp],enegmax[gp]); } - t_end = MPI_Wtime(); + t_end = platform::walltime(); dt = t_end - t_init; printf (" temps dans charges : %f seconde. \n",dt); printf (" ======================================================== \n"); diff --git a/src/SPIN/neb_spin.cpp b/src/SPIN/neb_spin.cpp index fe24235a98..1c987f8e7e 100644 --- a/src/SPIN/neb_spin.cpp +++ b/src/SPIN/neb_spin.cpp @@ -79,7 +79,10 @@ NEBSpin::~NEBSpin() MPI_Comm_free(&roots); memory->destroy(all); delete[] rdist; - if (fp) fclose(fp); + if (fp) { + if (compressed) platform::pclose(fp); + else fclose(fp); + } } /* ---------------------------------------------------------------------- @@ -552,12 +555,12 @@ void NEBSpin::readfile(char *file, int flag) if (flag == 0) { if (me_universe == 0) { - if (compressed) pclose(fp); + if (compressed) platform::pclose(fp); else fclose(fp); } } else { if (me == 0 && ireplica) { - if (compressed) pclose(fp); + if (compressed) platform::pclose(fp); else fclose(fp); } } @@ -684,28 +687,16 @@ int NEBSpin::initial_rotation(double *spi, double *sploc, double fraction) /* ---------------------------------------------------------------------- universe proc 0 opens NEBSpin data file - test if gzipped + test if compressed ------------------------------------------------------------------------- */ void NEBSpin::open(char *file) { compressed = 0; - char *suffix = file + strlen(file) - 3; - if (suffix > file && strcmp(suffix,".gz") == 0) compressed = 1; - if (!compressed) fp = fopen(file,"r"); - else { -#ifdef LAMMPS_GZIP - auto gunzip = std::string("gzip -c -d ") + file; -#ifdef _WIN32 - fp = _popen(gunzip.c_str(),"rb"); -#else - fp = popen(gunzip.c_str(),"r"); -#endif - -#else - error->one(FLERR,"Cannot open gzipped file"); -#endif - } + if (platform::has_compress_extension(file)) { + fp = platform::compressed_read(file); + if (!fp) error->one(FLERR,"Cannot open compressed file"); + } else fp = fopen(file,"r"); if (fp == nullptr) error->one(FLERR,"Cannot open file {}: {}",file,utils::getsyserror()); diff --git a/src/STUBS/mpi.cpp b/src/STUBS/mpi.cpp index e5cd50629e..3f4cc5964f 100644 --- a/src/STUBS/mpi.cpp +++ b/src/STUBS/mpi.cpp @@ -21,7 +21,13 @@ #include #include #include + +#if defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +#include +#else #include +#endif /* data structure for double/int */ @@ -167,7 +173,7 @@ int MPI_Finalize() double MPI_Wtime() { -#if defined(_MSC_VER) +#if defined(_WIN32) double t; t = GetTickCount(); diff --git a/src/balance.cpp b/src/balance.cpp index 06a3463db5..bd3ba007ef 100644 --- a/src/balance.cpp +++ b/src/balance.cpp @@ -259,7 +259,7 @@ void Balance::command(int narg, char **arg) // must reset atom map after exchange() since it clears it MPI_Barrier(world); - double start_time = MPI_Wtime(); + double start_time = platform::walltime(); lmp->init(); @@ -386,7 +386,7 @@ void Balance::command(int narg, char **arg) if (me == 0) { std::string mesg = fmt::format(" rebalancing time: {:.3f} seconds\n", - MPI_Wtime()-start_time); + platform::walltime()-start_time); mesg += fmt::format(" iteration count = {}\n",niter); for (int i = 0; i < nimbalance; ++i) mesg += imbalances[i]->info(); mesg += fmt::format(" initial/final maximal load/proc = {:.8} {:.8}\n" diff --git a/src/bond.cpp b/src/bond.cpp index e636ae9bf8..fb313f0170 100644 --- a/src/bond.cpp +++ b/src/bond.cpp @@ -270,7 +270,7 @@ void Bond::write_file(int narg, char **arg) // write out a line with "DATE:" and "UNITS:" tags // - if the file already exists, print a message about appending // while printing the date and check that units are consistent. - if (utils::file_is_readable(table_file)) { + if (platform::file_is_readable(table_file)) { std::string units = utils::get_potential_units(table_file,"table"); if (!units.empty() && (units != update->unit_style)) { error->one(FLERR,"Trying to append to a table file with UNITS: {} while units are {}", diff --git a/src/create_atoms.cpp b/src/create_atoms.cpp index 8baf6f88f7..e82be7d331 100644 --- a/src/create_atoms.cpp +++ b/src/create_atoms.cpp @@ -378,7 +378,7 @@ void CreateAtoms::command(int narg, char **arg) // Record wall time for atom creation MPI_Barrier(world); - double time1 = MPI_Wtime(); + double time1 = platform::walltime(); // clear ghost count and any ghost bonus data internal to AtomVec // same logic as beginning of Comm::exchange() @@ -591,7 +591,7 @@ void CreateAtoms::command(int narg, char **arg) if (scaleflag) domain->print_box(" using lattice units in "); else domain->print_box(" using box units in "); utils::logmesg(lmp," create_atoms CPU = {:.3f} seconds\n", - MPI_Wtime() - time1); + platform::walltime() - time1); } } diff --git a/src/dump.cpp b/src/dump.cpp index 647fd3d38d..d00c42086d 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -108,9 +108,8 @@ Dump::Dump(LAMMPS *lmp, int /*narg*/, char **arg) : Pointers(lmp) // if contains '%', write one file per proc and replace % with proc-ID // if contains '*', write one file per timestep and replace * with timestep // check file suffixes - // if ends in .bin = binary file - // else if ends in .gz = gzipped text file - // else if ends in .zst = Zstd compressed text file + // if ends in .bin -> binary file + // else if ends in .gz or other known extensions -> compressed text file // else ASCII text file fp = nullptr; @@ -144,8 +143,7 @@ Dump::Dump(LAMMPS *lmp, int /*narg*/, char **arg) : Pointers(lmp) if (strchr(filename,'*')) multifile = 1; if (utils::strmatch(filename, "\\.bin$")) binary = 1; - if (utils::strmatch(filename, "\\.gz$") - || utils::strmatch(filename, "\\.zst$")) compressed = 1; + if (platform::has_compress_extension(filename)) compressed = 1; } /* ---------------------------------------------------------------------- */ @@ -198,7 +196,7 @@ Dump::~Dump() if (multifile == 0 && fp != nullptr) { if (compressed) { - if (filewriter) pclose(fp); + if (filewriter) platform::pclose(fp); } else { if (filewriter) fclose(fp); } @@ -520,7 +518,7 @@ void Dump::write() if (multifile) { if (compressed) { - if (filewriter && fp != nullptr) pclose(fp); + if (filewriter && fp != nullptr) platform::pclose(fp); } else { if (filewriter && fp != nullptr) fclose(fp); } @@ -530,7 +528,7 @@ void Dump::write() /* ---------------------------------------------------------------------- generic opening of a dump file - ASCII or binary or gzipped + ASCII or binary or compressed some derived classes override this function ------------------------------------------------------------------------- */ @@ -580,16 +578,7 @@ void Dump::openfile() if (filewriter) { if (compressed) { -#ifdef LAMMPS_GZIP - auto gzip = fmt::format("gzip -6 > {}",filecurrent); -#ifdef _WIN32 - fp = _popen(gzip.c_str(),"wb"); -#else - fp = popen(gzip.c_str(),"w"); -#endif -#else - error->one(FLERR,"Cannot open gzipped file"); -#endif + fp = platform::compressed_write(filecurrent); } else if (binary) { fp = fopen(filecurrent,"wb"); } else if (append_flag) { diff --git a/src/dump_movie.cpp b/src/dump_movie.cpp index fb834b5fb0..52c0522289 100644 --- a/src/dump_movie.cpp +++ b/src/dump_movie.cpp @@ -41,28 +41,29 @@ DumpMovie::DumpMovie(LAMMPS *lmp, int narg, char **arg) : /* ---------------------------------------------------------------------- */ +DumpMovie::~DumpMovie() +{ + if (fp) platform::pclose(fp); + fp = nullptr; +} + +/* ---------------------------------------------------------------------- */ + void DumpMovie::openfile() { - char moviecmd[1024]; - if ((comm->me == 0) && (fp == nullptr)) { #ifdef LAMMPS_FFMPEG - sprintf(moviecmd,"ffmpeg -v error -y -r %.2f -f image2pipe -c:v ppm -i - " - "-r 24.0 -b:v %dk %s ", framerate, bitrate, filename); + auto moviecmd = fmt::format("ffmpeg -v error -y -r {:.2f} -f image2pipe -c:v ppm -i - " + "-r 24.0 -b:v {}k {}", framerate, bitrate, filename); + fp = platform::popen(moviecmd,"w"); #else + fp = nullptr; error->one(FLERR,"Support for writing movies not included"); #endif -#if defined(_WIN32) - fp = _popen(moviecmd,"wb"); -#else - fp = popen(moviecmd,"w"); -#endif - if (fp == nullptr) - error->one(FLERR,"Failed to open FFmpeg pipeline to " - "file {}",filename); + error->one(FLERR,"Failed to open FFmpeg pipeline to file {}",filename); } } /* ---------------------------------------------------------------------- */ @@ -100,4 +101,3 @@ int DumpMovie::modify_param(int narg, char **arg) return 0; } - diff --git a/src/dump_movie.h b/src/dump_movie.h index 1c41cb09b5..770193e039 100644 --- a/src/dump_movie.h +++ b/src/dump_movie.h @@ -27,6 +27,7 @@ namespace LAMMPS_NS { class DumpMovie : public DumpImage { public: DumpMovie(LAMMPS *, int, char **); + virtual ~DumpMovie(); virtual void openfile(); virtual void init_style(); diff --git a/src/error.cpp b/src/error.cpp index 9811a1d3eb..5338f41cca 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -58,7 +58,8 @@ void Error::universe_all(const std::string &file, int line, const std::string &s std::string mesg = "ERROR: " + str; try { mesg += fmt::format(" ({}:{})\n",truncpath(file),line); - } catch (fmt::format_error &e) { + } catch (fmt::format_error &) { + ; // do nothing } if (universe->me == 0) { if (universe->uscreen) fputs(mesg.c_str(),universe->uscreen); @@ -147,9 +148,9 @@ void Error::all(const std::string &file, int line, const std::string &str) std::string mesg = "ERROR: " + str; if (input && input->line) lastcmd = input->line; try { - mesg += fmt::format(" ({}:{})\nLast command: {}\n", - truncpath(file),line,lastcmd); - } catch (fmt::format_error &e) { + mesg += fmt::format(" ({}:{})\nLast command: {}\n", truncpath(file),line,lastcmd); + } catch (fmt::format_error &) { + ; // do nothing } utils::logmesg(lmp,mesg); } diff --git a/src/fix_ave_chunk.cpp b/src/fix_ave_chunk.cpp index 1328a27376..36c9eaf6fc 100644 --- a/src/fix_ave_chunk.cpp +++ b/src/fix_ave_chunk.cpp @@ -29,7 +29,6 @@ #include "variable.h" #include -#include using namespace LAMMPS_NS; using namespace FixConst; @@ -216,23 +215,23 @@ FixAveChunk::FixAveChunk(LAMMPS *lmp, int narg, char **arg) : iarg += 1; } else if (strcmp(arg[iarg],"format") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/chunk command"); - delete [] format_user; + delete[] format_user; format_user = utils::strdup(arg[iarg+1]); format = format_user; iarg += 2; } else if (strcmp(arg[iarg],"title1") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/chunk command"); - delete [] title1; + delete[] title1; title1 = utils::strdup(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title2") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/chunk command"); - delete [] title2; + delete[] title2; title2 = utils::strdup(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title3") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/chunk command"); - delete [] title3; + delete[] title3; title3 = utils::strdup(arg[iarg+1]); iarg += 2; } else error->all(FLERR,"Illegal fix ave/chunk command"); @@ -348,18 +347,18 @@ FixAveChunk::FixAveChunk(LAMMPS *lmp, int narg, char **arg) : if (ferror(fp)) error->one(FLERR,"Error writing file header"); - filepos = ftell(fp); + filepos = platform::ftell(fp); } - delete [] title1; - delete [] title2; - delete [] title3; + delete[] title1; + delete[] title2; + delete[] title3; // if wildcard expansion occurred, free earg memory from expand_args() // wait to do this until after file comment lines are printed if (expand) { - for (int i = 0; i < nargnew; i++) delete [] earg[i]; + for (int i = 0; i < nargnew; i++) delete[] earg[i]; memory->sfree(earg); } @@ -407,11 +406,11 @@ FixAveChunk::FixAveChunk(LAMMPS *lmp, int narg, char **arg) : FixAveChunk::~FixAveChunk() { - delete [] which; - delete [] argindex; - for (int i = 0; i < nvalues; i++) delete [] ids[i]; - delete [] ids; - delete [] value2index; + delete[] which; + delete[] argindex; + for (int i = 0; i < nvalues; i++) delete[] ids[i]; + delete[] ids; + delete[] value2index; if (fp && comm->me == 0) fclose(fp); @@ -438,7 +437,7 @@ FixAveChunk::~FixAveChunk() } } - delete [] idchunk; + delete[] idchunk; which = nullptr; argindex = nullptr; ids = nullptr; @@ -941,7 +940,7 @@ void FixAveChunk::end_of_step() if (fp && comm->me == 0) { clearerr(fp); - if (overwrite) fseek(fp,filepos,SEEK_SET); + if (overwrite) platform::fseek(fp,filepos); double count = 0.0; for (m = 0; m < nchunk; m++) count += count_total[m]; fprintf(fp,BIGINT_FORMAT " %d %g\n",ntimestep,nchunk,count); @@ -1027,9 +1026,9 @@ void FixAveChunk::end_of_step() fflush(fp); if (overwrite) { - long fileend = ftell(fp); - if ((fileend > 0) && (ftruncate(fileno(fp),fileend))) - perror("Error while tuncating output"); + bigint fileend = platform::ftell(fp); + if ((fileend > 0) && (platform::ftruncate(fp,fileend))) + error->warning(FLERR,"Error while tuncating output: {}", utils::getsyserror()); } } } diff --git a/src/fix_ave_chunk.h b/src/fix_ave_chunk.h index e7beed341f..69fdea0f06 100644 --- a/src/fix_ave_chunk.h +++ b/src/fix_ave_chunk.h @@ -61,7 +61,7 @@ class FixAveChunk : public Fix { class ComputeChunkAtom *cchunk; int lockforever; - long filepos; + bigint filepos; int maxvar; double *varatom; diff --git a/src/fix_ave_correlate.cpp b/src/fix_ave_correlate.cpp index 92b5ea3693..df6e33288e 100644 --- a/src/fix_ave_correlate.cpp +++ b/src/fix_ave_correlate.cpp @@ -30,7 +30,6 @@ #include "variable.h" #include -#include using namespace LAMMPS_NS; using namespace FixConst; @@ -139,17 +138,17 @@ FixAveCorrelate::FixAveCorrelate(LAMMPS * lmp, int narg, char **arg): iarg += 1; } else if (strcmp(arg[iarg],"title1") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/correlate command"); - delete [] title1; + delete[] title1; title1 = utils::strdup(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title2") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/correlate command"); - delete [] title2; + delete[] title2; title2 = utils::strdup(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title3") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/correlate command"); - delete [] title3; + delete[] title3; title3 = utils::strdup(arg[iarg+1]); iarg += 2; } else error->all(FLERR,"Illegal fix ave/correlate command"); @@ -256,18 +255,18 @@ FixAveCorrelate::FixAveCorrelate(LAMMPS * lmp, int narg, char **arg): if (ferror(fp)) error->one(FLERR,"Error writing file header"); - filepos = ftell(fp); + filepos = platform::ftell(fp); } - delete [] title1; - delete [] title2; - delete [] title3; + delete[] title1; + delete[] title2; + delete[] title3; // if wildcard expansion occurred, free earg memory from expand_args() // wait to do this until after file comment lines are printed if (expand) { - for (int i = 0; i < nargnew; i++) delete [] earg[i]; + for (int i = 0; i < nargnew; i++) delete[] earg[i]; memory->sfree(earg); } @@ -312,11 +311,11 @@ FixAveCorrelate::FixAveCorrelate(LAMMPS * lmp, int narg, char **arg): FixAveCorrelate::~FixAveCorrelate() { - delete [] which; - delete [] argindex; - delete [] value2index; - for (int i = 0; i < nvalues; i++) delete [] ids[i]; - delete [] ids; + delete[] which; + delete[] argindex; + delete[] value2index; + for (int i = 0; i < nvalues; i++) delete[] ids[i]; + delete[] ids; memory->destroy(values); memory->destroy(count); @@ -489,7 +488,7 @@ void FixAveCorrelate::end_of_step() if (fp && me == 0) { clearerr(fp); - if (overwrite) fseek(fp,filepos,SEEK_SET); + if (overwrite) platform::fseek(fp,filepos); fprintf(fp,BIGINT_FORMAT " %d\n",ntimestep,nrepeat); for (i = 0; i < nrepeat; i++) { fprintf(fp,"%d %d %d",i+1,i*nevery,count[i]); @@ -507,9 +506,9 @@ void FixAveCorrelate::end_of_step() fflush(fp); if (overwrite) { - long fileend = ftell(fp); - if ((fileend > 0) && (ftruncate(fileno(fp),fileend))) - perror("Error while tuncating output"); + bigint fileend = platform::ftell(fp); + if ((fileend > 0) && (platform::ftruncate(fp,fileend))) + error->warning(FLERR,"Error while tuncating output: {}", utils::getsyserror()); } } diff --git a/src/fix_ave_correlate.h b/src/fix_ave_correlate.h index d551ba7b92..6dde75c0d3 100644 --- a/src/fix_ave_correlate.h +++ b/src/fix_ave_correlate.h @@ -44,7 +44,7 @@ class FixAveCorrelate : public Fix { int type, ave, startstep, overwrite; double prefactor; - long filepos; + bigint filepos; int firstindex; // index in values ring of earliest time sample int lastindex; // index in values ring of latest time sample diff --git a/src/fix_ave_histo.cpp b/src/fix_ave_histo.cpp index 92b03035b3..8c55337074 100644 --- a/src/fix_ave_histo.cpp +++ b/src/fix_ave_histo.cpp @@ -25,7 +25,6 @@ #include "variable.h" #include -#include using namespace LAMMPS_NS; using namespace FixConst; @@ -168,7 +167,7 @@ FixAveHisto::FixAveHisto(LAMMPS *lmp, int narg, char **arg) : // if wildcard expansion occurred, free earg memory from expand_args() if (expand) { - for (int i = 0; i < nvalues; i++) delete [] earg[i]; + for (int i = 0; i < nvalues; i++) delete[] earg[i]; memory->sfree(earg); } @@ -434,12 +433,12 @@ FixAveHisto::FixAveHisto(LAMMPS *lmp, int narg, char **arg) : if (ferror(fp)) error->one(FLERR,"Error writing file header"); - filepos = ftell(fp); + filepos = platform::ftell(fp); } - delete [] title1; - delete [] title2; - delete [] title3; + delete[] title1; + delete[] title2; + delete[] title3; // allocate and initialize memory for averaging @@ -502,18 +501,18 @@ FixAveHisto::FixAveHisto(LAMMPS *lmp, int narg, char **arg) : FixAveHisto::~FixAveHisto() { - delete [] which; - delete [] argindex; - delete [] value2index; - for (int i = 0; i < nvalues; i++) delete [] ids[i]; - delete [] ids; + delete[] which; + delete[] argindex; + delete[] value2index; + for (int i = 0; i < nvalues; i++) delete[] ids[i]; + delete[] ids; if (fp && me == 0) fclose(fp); - delete [] bin; - delete [] bin_total; - delete [] bin_all; - delete [] coord; + delete[] bin; + delete[] bin_total; + delete[] bin_all; + delete[] coord; memory->destroy(stats_list); memory->destroy(bin_list); memory->destroy(vector); @@ -817,7 +816,7 @@ void FixAveHisto::end_of_step() if (fp && me == 0) { clearerr(fp); - if (overwrite) fseek(fp,filepos,SEEK_SET); + if (overwrite) platform::fseek(fp,filepos); fprintf(fp,BIGINT_FORMAT " %d %g %g %g %g\n",ntimestep,nbins, stats_total[0],stats_total[1],stats_total[2],stats_total[3]); if (stats_total[0] != 0.0) @@ -833,9 +832,9 @@ void FixAveHisto::end_of_step() fflush(fp); if (overwrite) { - long fileend = ftell(fp); - if ((fileend > 0) && (ftruncate(fileno(fp),fileend))) - perror("Error while tuncating output"); + bigint fileend = platform::ftell(fp); + if ((fileend > 0) && (platform::ftruncate(fp,fileend))) + error->warning(FLERR,"Error while tuncating output: {}",utils::getsyserror()); } } } @@ -993,17 +992,17 @@ void FixAveHisto::options(int iarg, int narg, char **arg) iarg += 1; } else if (strcmp(arg[iarg],"title1") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/histo command"); - delete [] title1; + delete[] title1; title1 = utils::strdup(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title2") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/histo command"); - delete [] title2; + delete[] title2; title2 = utils::strdup(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title3") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/histo command"); - delete [] title3; + delete[] title3; title3 = utils::strdup(arg[iarg+1]); iarg += 2; } else error->all(FLERR,"Illegal fix ave/histo command"); diff --git a/src/fix_ave_histo.h b/src/fix_ave_histo.h index 0158d04377..ef64ad74ff 100644 --- a/src/fix_ave_histo.h +++ b/src/fix_ave_histo.h @@ -44,7 +44,7 @@ class FixAveHisto : public Fix { FILE *fp; double lo, hi, binsize, bininv; int kind, beyond, overwrite; - long filepos; + bigint filepos; double stats[4], stats_total[4], stats_all[4]; double **stats_list; diff --git a/src/fix_ave_histo_weight.cpp b/src/fix_ave_histo_weight.cpp index 63321bf53e..7866490840 100644 --- a/src/fix_ave_histo_weight.cpp +++ b/src/fix_ave_histo_weight.cpp @@ -28,8 +28,6 @@ #include "update.h" #include "variable.h" -#include - using namespace LAMMPS_NS; using namespace FixConst; @@ -472,7 +470,7 @@ void FixAveHistoWeight::end_of_step() if (fp && me == 0) { clearerr(fp); - if (overwrite) fseek(fp,filepos,SEEK_SET); + if (overwrite) platform::fseek(fp,filepos); fprintf(fp,BIGINT_FORMAT " %d %g %g %g %g\n",ntimestep,nbins, stats_total[0],stats_total[1],stats_total[2],stats_total[3]); if (stats_total[0] != 0.0) @@ -488,9 +486,9 @@ void FixAveHistoWeight::end_of_step() fflush(fp); if (overwrite) { - long fileend = ftell(fp); - if ((fileend > 0) && (ftruncate(fileno(fp),fileend))) - perror("Error while tuncating output"); + bigint fileend = platform::ftell(fp); + if ((fileend > 0) && (platform::ftruncate(fp,fileend))) + error->warning(FLERR,"Error while tuncating output: {}", utils::getsyserror()); } } } diff --git a/src/fix_ave_time.cpp b/src/fix_ave_time.cpp index da9cd89e5e..a3da6e6a3d 100644 --- a/src/fix_ave_time.cpp +++ b/src/fix_ave_time.cpp @@ -28,7 +28,6 @@ #include "variable.h" #include -#include using namespace LAMMPS_NS; using namespace FixConst; @@ -274,18 +273,18 @@ FixAveTime::FixAveTime(LAMMPS *lmp, int narg, char **arg) : if (ferror(fp)) error->one(FLERR,"Error writing file header"); - filepos = ftell(fp); + filepos = platform::ftell(fp); } - delete [] title1; - delete [] title2; - delete [] title3; + delete[] title1; + delete[] title2; + delete[] title3; // if wildcard expansion occurred, free earg memory from expand_args() // wait to do this until after file comment lines are printed if (expand) { - for (int i = 0; i < nvalues; i++) delete [] earg[i]; + for (int i = 0; i < nvalues; i++) delete[] earg[i]; memory->sfree(earg); } @@ -446,24 +445,24 @@ FixAveTime::~FixAveTime() } } - delete [] format_user; + delete[] format_user; - delete [] which; - delete [] argindex; - delete [] value2index; - delete [] offcol; - delete [] varlen; - for (int i = 0; i < nvalues; i++) delete [] ids[i]; - delete [] ids; + delete[] which; + delete[] argindex; + delete[] value2index; + delete[] offcol; + delete[] varlen; + for (int i = 0; i < nvalues; i++) delete[] ids[i]; + delete[] ids; - delete [] extlist; + delete[] extlist; if (fp && me == 0) fclose(fp); memory->destroy(column); - delete [] vector; - delete [] vector_total; + delete[] vector; + delete[] vector_total; memory->destroy(array); memory->destroy(array_total); memory->destroy(array_list); @@ -673,7 +672,7 @@ void FixAveTime::invoke_scalar(bigint ntimestep) if (fp && me == 0) { clearerr(fp); - if (overwrite) fseek(fp,filepos,SEEK_SET); + if (overwrite) platform::fseek(fp,filepos); fprintf(fp,BIGINT_FORMAT,ntimestep); for (i = 0; i < nvalues; i++) fprintf(fp,format,vector_total[i]/norm); fprintf(fp,"\n"); @@ -683,9 +682,9 @@ void FixAveTime::invoke_scalar(bigint ntimestep) fflush(fp); if (overwrite) { - long fileend = ftell(fp); - if ((fileend > 0) && (ftruncate(fileno(fp),fileend))) - perror("Error while tuncating output"); + bigint fileend = platform::ftell(fp); + if ((fileend > 0) && (platform::ftruncate(fp,fileend))) + error->warning(FLERR,"Error while tuncating output: {}", utils::getsyserror()); } } } @@ -885,7 +884,7 @@ void FixAveTime::invoke_vector(bigint ntimestep) // output result to file if (fp && me == 0) { - if (overwrite) fseek(fp,filepos,SEEK_SET); + if (overwrite) platform::fseek(fp,filepos); fprintf(fp,BIGINT_FORMAT " %d\n",ntimestep,nrows); for (i = 0; i < nrows; i++) { fprintf(fp,"%d",i+1); @@ -894,9 +893,9 @@ void FixAveTime::invoke_vector(bigint ntimestep) } fflush(fp); if (overwrite) { - long fileend = ftell(fp); - if ((fileend > 0) && (ftruncate(fileno(fp),fileend))) - perror("Error while tuncating output"); + bigint fileend = platform::ftell(fp); + if ((fileend > 0) && (platform::ftruncate(fp,fileend))) + error->warning(FLERR,"Error while tuncating output: {}", utils::getsyserror()); } } } @@ -1066,23 +1065,23 @@ void FixAveTime::options(int iarg, int narg, char **arg) iarg += 1; } else if (strcmp(arg[iarg],"format") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/time command"); - delete [] format_user; + delete[] format_user; format_user = utils::strdup(arg[iarg+1]); format = format_user; iarg += 2; } else if (strcmp(arg[iarg],"title1") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/spatial command"); - delete [] title1; + delete[] title1; title1 = utils::strdup(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title2") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/spatial command"); - delete [] title2; + delete[] title2; title2 = utils::strdup(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"title3") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/spatial command"); - delete [] title3; + delete[] title3; title3 = utils::strdup(arg[iarg+1]); iarg += 2; } else error->all(FLERR,"Illegal fix ave/time command"); diff --git a/src/fix_ave_time.h b/src/fix_ave_time.h index 391a06f495..3a26dd6d70 100644 --- a/src/fix_ave_time.h +++ b/src/fix_ave_time.h @@ -54,7 +54,7 @@ class FixAveTime : public Fix { int *offlist; char *format, *format_user; char *title1, *title2, *title3; - long filepos; + bigint filepos; int norm, iwindow, window_limit; double *vector; diff --git a/src/info.cpp b/src/info.cpp index 137bf44b1a..3d24f9b56a 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -282,7 +282,7 @@ void Info::command(int narg, char **arg) fmt::print(out,"Git info: {} / {} / {}\n", lmp->git_branch, lmp->git_descriptor,lmp->git_commit); - fmt::print(out,"\nOS information: {}\n\n",get_os_info()); + fmt::print(out,"\nOS information: {}\n\n",platform::os_info()); fmt::print(out,"sizeof(smallint): {}-bit\n" "sizeof(imageint): {}-bit\n" @@ -292,7 +292,7 @@ void Info::command(int narg, char **arg) sizeof(tagint)*8, sizeof(bigint)*8); fmt::print(out,"\nCompiler: {} with {}\nC++ standard: {}\n", - get_compiler_info(),get_openmp_info(),get_cxx_info()); + platform::compiler_info(),platform::openmp_standard(),platform::cxx_standard()); fputs("\nActive compile time flags:\n\n",out); if (has_gzip_support()) fputs("-DLAMMPS_GZIP\n",out); @@ -353,7 +353,7 @@ void Info::command(int narg, char **arg) if (flags & COMM) { int major,minor; - std::string version = get_mpi_info(major,minor); + std::string version = platform::mpi_info(major,minor); fmt::print(out,"\nCommunication information:\n" "MPI library level: MPI v{}.{}\n" @@ -635,24 +635,8 @@ void Info::command(int narg, char **arg) } if (flags & TIME) { - double wallclock = MPI_Wtime() - lmp->initclock; - double cpuclock = 0.0; - -#if defined(_WIN32) - // from MSD docs. - FILETIME ct,et,kt,ut; - union { FILETIME ft; uint64_t ui; } cpu; - if (GetProcessTimes(GetCurrentProcess(),&ct,&et,&kt,&ut)) { - cpu.ft = ut; - cpuclock = cpu.ui * 0.0000001; - } -#else /* POSIX */ - struct rusage ru; - if (getrusage(RUSAGE_SELF, &ru) == 0) { - cpuclock = (double) ru.ru_utime.tv_sec; - cpuclock += (double) ru.ru_utime.tv_usec * 0.000001; - } -#endif /* ! _WIN32 */ + double wallclock = platform::walltime() - lmp->initclock; + double cpuclock = platform::cputime(); int cpuh,cpum,cpus,wallh,wallm,walls; cpus = fmod(cpuclock,60.0); @@ -1266,200 +1250,6 @@ bool Info::has_accelerator_feature(const std::string &package, return false; } -/* ---------------------------------------------------------------------- */ -#define _INFOBUF_SIZE 256 - -std::string Info::get_os_info() -{ - std::string buf; - -#if defined(_WIN32) - DWORD fullversion,majorv,minorv,buildv=0; - - fullversion = GetVersion(); - majorv = (DWORD) (LOBYTE(LOWORD(fullversion))); - minorv = (DWORD) (HIBYTE(LOWORD(fullversion))); - if (fullversion < 0x80000000) - buildv = (DWORD) (HIWORD(fullversion)); - - buf = fmt::format("Windows {}.{} ({}) on ",majorv,minorv,buildv); - - SYSTEM_INFO si; - GetSystemInfo(&si); - - switch (si.wProcessorArchitecture) { - case PROCESSOR_ARCHITECTURE_AMD64: - buf += "x86_64"; - break; - case PROCESSOR_ARCHITECTURE_ARM: - buf += "arm"; - break; - case PROCESSOR_ARCHITECTURE_IA64: - buf += "ia64"; - break; - case PROCESSOR_ARCHITECTURE_INTEL: - buf += "i386"; - break; - default: - buf += "(unknown)"; - } -#else - struct utsname ut; - uname(&ut); - - // try to get OS distribution name, if available - std::string distro = ut.sysname; - if (utils::file_is_readable("/etc/os-release")) { - try { - TextFileReader reader("/etc/os-release",""); - while (1) { - auto words = reader.next_values(0,"="); - if ((words.count() > 1) && (words.next_string() == "PRETTY_NAME")) { - distro += " " + utils::trim(words.next_string()); - break; - } - } - } catch (std::exception &e) { - ; // EOF but keyword not found - } - } - - buf = fmt::format("{} {} on {}", distro, ut.release, ut.machine); -#endif - return buf; -} - -std::string Info::get_compiler_info() -{ - std::string buf; -#if defined(__INTEL_LLVM_COMPILER) - constexpr double version = static_cast(__INTEL_LLVM_COMPILER)*0.01; - buf = fmt::format("Intel LLVM C++ {:.1f} / {}", version, __VERSION__); -#elif defined(__ibmxl__) - buf = fmt::format("IBM XL C/C++ (Clang) {}.{}.{}", - __ibmxl_version__, __ibmxl_release__, __ibmxl_modification__); -#elif defined(__clang__) - buf = fmt::format("Clang C++ {}", __VERSION__); -#elif defined(__PGI) - buf = fmt::format("PGI C++ {}.{}",__PGIC__, __PGIC_MINOR__); -#elif defined(__INTEL_COMPILER) - double version = static_cast(__INTEL_COMPILER)*0.01; - buf = fmt::format("Intel Classic C++ {:.2f}.{} / {}", version, - __INTEL_COMPILER_UPDATE, __VERSION__); -#elif defined(__MINGW64__) - buf = fmt::format("MinGW-w64 64bit {}.{} / GNU C++ {}", __MINGW64_VERSION_MAJOR, - __MINGW64_VERSION_MINOR, __VERSION__); -#elif defined(__MINGW32__) - buf = fmt::format("MinGW-w64 32bit {}.{} / GNU C++ {}", __MINGW32_MAJOR_VERSION, - __MINGW32_MINOR_VERSION, __VERSION__); -#elif defined(__GNUC__) - buf = fmt::format("GNU C++ {}", __VERSION__); -#elif defined(_MSC_VER) && (_MSC_VER > 1920) && (_MSC_VER < 2000) - constexpr int major = _MSC_VER / 100; - constexpr int minor = _MSC_VER - major *100; - buf = fmt::format("Microsoft Visual Studio 20{}, C/C++ {}.{}", major, major-5, minor); -#else - buf = "(Unknown)"; -#endif - return buf; -} - -std::string Info::get_openmp_info() -{ - -#if !defined(_OPENMP) - return "OpenMP not enabled"; -#else - -// Supported OpenMP version corresponds to the release date of the -// specifications as posted at https://www.openmp.org/specifications/ - -#if _OPENMP > 202011 - return "OpenMP newer than version 5.1"; -#elif _OPENMP == 202011 - return "OpenMP 5.1"; -#elif _OPENMP == 201811 - return "OpenMP 5.0"; -#elif _OPENMP == 201611 - return "OpenMP 5.0 preview 1"; -#elif _OPENMP == 201511 - return "OpenMP 4.5"; -#elif _OPENMP == 201307 - return "OpenMP 4.0"; -#elif _OPENMP == 201107 - return "OpenMP 3.1"; -#elif _OPENMP == 200805 - return "OpenMP 3.0"; -#elif _OPENMP == 200505 - return "OpenMP 2.5"; -#elif _OPENMP == 200203 - return "OpenMP 2.0"; -#else - return "unknown OpenMP version"; -#endif - -#endif -} - -std::string Info::get_mpi_vendor() { - #if defined(MPI_STUBS) - return "MPI STUBS"; - #elif defined(OPEN_MPI) - return "Open MPI"; - #elif defined(MPICH_NAME) - return "MPICH"; - #elif defined(I_MPI_VERSION) - return "Intel MPI"; - #elif defined(PLATFORM_MPI) - return "Platform MPI"; - #elif defined(HP_MPI) - return "HP MPI"; - #elif defined(MSMPI_VER) - return "Microsoft MPI"; - #else - return "Unknown MPI implementation"; - #endif -} - -std::string Info::get_mpi_info(int &major, int &minor) -{ - int len; -#if (defined(MPI_VERSION) && (MPI_VERSION > 2)) || defined(MPI_STUBS) - static char version[MPI_MAX_LIBRARY_VERSION_STRING]; - MPI_Get_library_version(version,&len); -#else - static char version[32]; - strcpy(version,get_mpi_vendor().c_str()); - len = strlen(version); -#endif - - MPI_Get_version(&major,&minor); - if (len > 80) { - char *ptr = strchr(version+80,'\n'); - if (ptr) *ptr = '\0'; - } - return std::string(version); -} - -std::string Info::get_cxx_info() -{ -#if __cplusplus > 202002L - return "newer than C++20"; -#elif __cplusplus == 202002L - return "C++20"; -#elif __cplusplus == 201703L - return "C++17"; -#elif __cplusplus == 201402L - return "C++14"; -#elif __cplusplus == 201103L - return "C++11"; -#elif __cplusplus == 199711L - return "C++98"; -#else - return "unknown"; -#endif -} - std::string Info::get_accelerator_info(const std::string &package) { std::string mesg(""); diff --git a/src/info.h b/src/info.h index d000b3c443..0e7bfb68f3 100644 --- a/src/info.h +++ b/src/info.h @@ -48,13 +48,6 @@ class Info : public Command { const std::string &); static bool has_gpu_device(); static std::string get_gpu_device_info(); - - static std::string get_os_info(); - static std::string get_compiler_info(); - static std::string get_openmp_info(); - static std::string get_mpi_vendor(); - static std::string get_mpi_info(int &, int &); - static std::string get_cxx_info(); static std::string get_accelerator_info(const std::string &pkg = ""); void get_memory_info(double *); diff --git a/src/input.cpp b/src/input.cpp index 833dbaa6df..21c092f356 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -49,11 +49,6 @@ #include #include #include -#include - -#ifdef _WIN32 -#include -#endif using namespace LAMMPS_NS; @@ -1164,15 +1159,6 @@ void Input::quit() /* ---------------------------------------------------------------------- */ -char *shell_failed_message(const char* cmd, int errnum) -{ - std::string errmsg = fmt::format("Shell command '{}' failed with error '{}'", - cmd, strerror(errnum)); - char *msg = new char[errmsg.size()+1]; - strcpy(msg, errmsg.c_str()); - return msg; -} - void Input::shell() { int rv,err; @@ -1181,89 +1167,59 @@ void Input::shell() if (strcmp(arg[0],"cd") == 0) { if (narg != 2) error->all(FLERR,"Illegal shell cd command"); - rv = (chdir(arg[1]) < 0) ? errno : 0; + rv = (platform::chdir(arg[1]) < 0) ? errno : 0; MPI_Reduce(&rv,&err,1,MPI_INT,MPI_MAX,0,world); + errno = err; if (me == 0 && err != 0) { - char *message = shell_failed_message("cd",err); - error->warning(FLERR,message); - delete[] message; + error->warning(FLERR, "Shell command 'cd {}' failed with error '{}'", arg[1], utils::getsyserror()); } - } else if (strcmp(arg[0],"mkdir") == 0) { if (narg < 2) error->all(FLERR,"Illegal shell mkdir command"); - if (me == 0) + if (me == 0) { for (int i = 1; i < narg; i++) { -#if defined(_WIN32) - rv = _mkdir(arg[i]); -#else - rv = mkdir(arg[i], S_IRWXU | S_IRGRP | S_IXGRP); -#endif - if (rv < 0) { - char *message = shell_failed_message("mkdir",errno); - error->warning(FLERR,message); - delete[] message; - } + if (platform::mkdir(arg[i]) < 0) + error->warning(FLERR, "Shell command 'mkdir {}' failed with error '{}'", + arg[i],utils::getsyserror()); } - + } } else if (strcmp(arg[0],"mv") == 0) { if (narg != 3) error->all(FLERR,"Illegal shell mv command"); - rv = (rename(arg[1],arg[2]) < 0) ? errno : 0; - MPI_Reduce(&rv,&err,1,MPI_INT,MPI_MAX,0,world); - if (me == 0 && err != 0) { - char *message = shell_failed_message("mv",err); - error->warning(FLERR,message); - delete[] message; + if (me == 0) { + if (rename(arg[1],arg[2]) < 0) { + error->warning(FLERR, "Shell command 'mv {} {}' failed with error '{}'", + arg[1],arg[2],utils::getsyserror()); + } } - } else if (strcmp(arg[0],"rm") == 0) { if (narg < 2) error->all(FLERR,"Illegal shell rm command"); - if (me == 0) + if (me == 0) { for (int i = 1; i < narg; i++) { - if (unlink(arg[i]) < 0) { - char *message = shell_failed_message("rm",errno); - error->warning(FLERR,message); - delete[] message; - } + if (platform::unlink(arg[i]) < 0) + error->warning(FLERR, "Shell command 'rm {}' failed with error '{}'", + arg[i], utils::getsyserror()); } - + } } else if (strcmp(arg[0],"rmdir") == 0) { if (narg < 2) error->all(FLERR,"Illegal shell rmdir command"); - if (me == 0) + if (me == 0) { for (int i = 1; i < narg; i++) { - if (rmdir(arg[i]) < 0) { - char *message = shell_failed_message("rmdir",errno); - error->warning(FLERR,message); - delete[] message; - } + if (platform::rmdir(arg[i]) < 0) + error->warning(FLERR, "Shell command 'rmdir {}' failed with error '{}'", + arg[i], utils::getsyserror()); } - + } } else if (strcmp(arg[0],"putenv") == 0) { if (narg < 2) error->all(FLERR,"Illegal shell putenv command"); for (int i = 1; i < narg; i++) { rv = 0; -#ifdef _WIN32 - if (arg[i]) rv = _putenv(utils::strdup(arg[i])); -#else - if (arg[i]) { - std::string vardef(arg[i]); - auto found = vardef.find_first_of('='); - if (found == std::string::npos) { - rv = setenv(vardef.c_str(),"",1); - } else { - rv = setenv(vardef.substr(0,found).c_str(), - vardef.substr(found+1).c_str(),1); - } - } -#endif + if (arg[i]) rv = platform::putenv(arg[i]); rv = (rv < 0) ? errno : 0; MPI_Reduce(&rv,&err,1,MPI_INT,MPI_MAX,0,world); - if (me == 0 && err != 0) { - char *message = shell_failed_message("putenv",err); - error->warning(FLERR,message); - delete[] message; - } + errno = err; + if (me == 0 && err != 0) + error->warning(FLERR, "Shell command 'putenv {}' failed with error '{}'", + arg[i], utils::getsyserror()); } - // use work string to concat args back into one string separated by spaces // invoke string in shell via system() diff --git a/src/lammps.cpp b/src/lammps.cpp index d9bb56d882..f4dd4e5708 100644 --- a/src/lammps.cpp +++ b/src/lammps.cpp @@ -56,12 +56,6 @@ #include #include -#if defined(_WIN32) -#include -#else -#include // for isatty() -#endif - #include "lmpinstalledpkgs.h" #include "lmpgitversion.h" @@ -135,20 +129,21 @@ LAMMPS::LAMMPS(int narg, char **arg, MPI_Comm communicator) : logfile = nullptr; infile = nullptr; - initclock = MPI_Wtime(); + initclock = platform::walltime(); init_pkg_lists(); #if defined(LMP_PYTHON) && defined(_WIN32) - // if the LAMMPSHOME environment variable is set, it should point + // If the LAMMPSHOME environment variable is set, it should point // to the location of the LAMMPS installation tree where we bundle // the matching Python installation for use with the PYTHON package. - // this is currently only used on Windows with the windows installer packages + // This is currently only used on Windows with the Windows installer packages const char *lmpenv = getenv("LAMMPSHOME"); if (lmpenv) { - _putenv(utils::strdup(fmt::format("PYTHONHOME={}",lmpenv))); + platform::putenv(fmt::format("PYTHONHOME={}",lmpenv)); } #endif + // check if -mpicolor is first arg // if so, then 2 apps were launched with one mpirun command // this means passed communicator (e.g. MPI_COMM_WORLD) is bigger than LAMMPS @@ -662,7 +657,7 @@ LAMMPS::LAMMPS(int narg, char **arg, MPI_Comm communicator) : int n = plast[i] - pfirst[i]; packargs[i] = new char*[n+1]; for (int j=0; j < n; ++j) - packargs[i][j] = strdup(arg[pfirst[i]+j]); + packargs[i][j] = utils::strdup(arg[pfirst[i]+j]); packargs[i][n] = nullptr; } memory->destroy(pfirst); @@ -716,7 +711,7 @@ LAMMPS::~LAMMPS() if (num_package) { for (int i = 0; i < num_package; i++) { for (char **ptr = packargs[i]; *ptr != nullptr; ++ptr) - free(*ptr); + delete[] *ptr; delete[] packargs[i]; } delete[] packargs; @@ -724,7 +719,7 @@ LAMMPS::~LAMMPS() num_package = 0; packargs = nullptr; - double totalclock = MPI_Wtime() - initclock; + double totalclock = platform::walltime() - initclock; if ((me == 0) && (screen || logfile)) { int seconds = fmod(totalclock,60.0); totalclock = (totalclock - seconds) / 60.0; @@ -1118,11 +1113,7 @@ void _noopt LAMMPS::help() // user. scrollback buffers are often not large enough. this is most // beneficial to windows users, who are not used to command line. -#if defined(_WIN32) - int use_pager = _isatty(fileno(fp)); -#else - int use_pager = isatty(fileno(fp)); -#endif + int use_pager = platform::is_console(fp); // cannot use this with OpenMPI since its console is non-functional @@ -1133,11 +1124,7 @@ void _noopt LAMMPS::help() if (use_pager) { pager = getenv("PAGER"); if (pager == nullptr) pager = "more"; -#if defined(_WIN32) - fp = _popen(pager,"w"); -#else - fp = popen(pager,"w"); -#endif + fp = platform::popen(pager,"w"); // reset to original state, if pipe command failed if (fp == nullptr) { @@ -1299,7 +1286,7 @@ void _noopt LAMMPS::help() // close pipe to pager, if active - if (pager != nullptr) pclose(fp); + if (pager != nullptr) platform::pclose(fp); } /* ---------------------------------------------------------------------- @@ -1340,14 +1327,14 @@ void LAMMPS::print_config(FILE *fp) const char *pkg; int ncword, ncline = 0; - fmt::print(fp,"OS: {}\n\n",Info::get_os_info()); + fmt::print(fp,"OS: {}\n\n",platform::os_info()); fmt::print(fp,"Compiler: {} with {}\nC++ standard: {}\n", - Info::get_compiler_info(),Info::get_openmp_info(), - Info::get_cxx_info()); + platform::compiler_info(),platform::openmp_standard(), + platform::cxx_standard()); int major,minor; - std::string infobuf = Info::get_mpi_info(major,minor); + std::string infobuf = platform::mpi_info(major,minor); fmt::print(fp,"MPI v{}.{}: {}\n\n",major,minor,infobuf); fmt::print(fp,"Accelerator configuration:\n\n{}\n", diff --git a/src/library.cpp b/src/library.cpp index 13f480ed03..ed208413e6 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -4394,9 +4394,9 @@ void lammps_get_os_info(char *buffer, int buf_size) { if (buf_size <=0) return; buffer[0] = buffer[buf_size-1] = '\0'; - std::string txt = Info::get_os_info() + "\n"; - txt += Info::get_compiler_info(); - txt += " with " + Info::get_openmp_info() + "\n"; + std::string txt = platform::os_info() + "\n"; + txt += platform::compiler_info(); + txt += " with " + platform::openmp_standard() + "\n"; strncpy(buffer, txt.c_str(), buf_size-1); } @@ -4420,15 +4420,16 @@ int lammps_config_has_mpi_support() /* ---------------------------------------------------------------------- */ -/** Check if the LAMMPS library supports compressed files via a pipe to gzip +/** Check if the LAMMPS library supports reading or writing compressed + * files via a pipe to gzip or similar compression programs \verbatim embed:rst Several LAMMPS commands (e.g. :doc:`read_data`, :doc:`write_data`, :doc:`dump styles atom, custom, and xyz `) support reading and writing compressed files via creating a pipe to the ``gzip`` program. This function checks whether this feature was :ref:`enabled at compile -time `. It does **not** check whether the ``gzip`` itself is -installed and usable. +time `. It does **not** check whether``gzip`` or any other +supported compression programs themselves are installed and usable. \endverbatim * * \return 1 if yes, otherwise 0 diff --git a/src/main.cpp b/src/main.cpp index 568da132e2..095e1752da 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -79,7 +79,7 @@ int main(int argc, char **argv) KokkosLMP::finalize(); Python::finalize(); MPI_Abort(ae.universe, 1); - } catch (LAMMPSException &e) { + } catch (LAMMPSException &) { KokkosLMP::finalize(); Python::finalize(); MPI_Barrier(lammps_comm); diff --git a/src/pair.cpp b/src/pair.cpp index 6805166150..1039875718 100644 --- a/src/pair.cpp +++ b/src/pair.cpp @@ -1799,7 +1799,7 @@ void Pair::write_file(int narg, char **arg) // write out a line with "DATE:" and "UNITS:" tags // - if the file already exists, print a message about appending // while printing the date and check that units are consistent. - if (utils::file_is_readable(table_file)) { + if (platform::file_is_readable(table_file)) { std::string units = utils::get_potential_units(table_file,"table"); if (!units.empty() && (units != update->unit_style)) { error->one(FLERR,"Trying to append to a table file " diff --git a/src/pair_table.cpp b/src/pair_table.cpp index 60272b5276..7b77a847f1 100644 --- a/src/pair_table.cpp +++ b/src/pair_table.cpp @@ -407,7 +407,7 @@ void PairTable::read_table(Table *tb, char *file, char *keyword) rfile = values.next_double(); tb->efile[i] = conversion_factor * values.next_double(); tb->ffile[i] = conversion_factor * values.next_double(); - } catch (TokenizerException &e) { + } catch (TokenizerException &) { ++cerror; } diff --git a/src/platform.cpp b/src/platform.cpp new file mode 100644 index 0000000000..b057c6415b --- /dev/null +++ b/src/platform.cpp @@ -0,0 +1,974 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, 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. +------------------------------------------------------------------------- */ +/** \file platform.cpp + * This file provides abstractions for a variety of platform specific + * functionality in a namespace "platform". This is a companion to + * the "utils" namespace with convenience and utility functions. */ + +#include "platform.h" +#include "text_file_reader.h" +#include "utils.h" + +#if HAVE_MPI +#include +#endif + +//////////////////////////////////////////////////////////////////////// +// include system headers and tweak system settings +#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 +#include // for _get_osfhandle() +#include +#include + +#else // not Windows /////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#if defined(__APPLE__) +#include +#include +#endif +//////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +/* ------------------------------------------------------------------ */ + +/// Struct for listing on-the-fly compression/decompression commands +struct compress_info { + /// identifier for the different compression algorithms + enum styles { NONE, GZIP, BZIP2, ZSTD, XZ, LZMA, LZ4 }; + const std::string extension; ///< filename extension for the current algorithm + const std::string command; ///< command to perform compression or decompression + const std::string compressflags; ///< flags to append to compress from stdin to stdout + const std::string uncompressflags; ///< flags to decompress file to stdout + const int style; ///< compression style flag +}; + +// clang-format off +static const std::vector compress_styles = { + {"", "", "", "", compress_info::NONE}, + {"gz", "gzip", " > ", " -cdf ", compress_info::GZIP}, + {"bz2", "bzip2", " > ", " -cdf ", compress_info::BZIP2}, + {"zst", "zstd", " -q > ", " -cdf ", compress_info::ZSTD}, + {"xz", "xz", " > ", " -cdf ", compress_info::XZ}, + {"lzma", "xz", " --format=lzma > ", " --format=lzma -cdf ", compress_info::LZMA}, + {"lz4", "lz4", " > ", " -cdf ", compress_info::LZ4}, +}; +// clang-format on + +/* ------------------------------------------------------------------ */ + +static const compress_info &find_compress_type(const std::string &file) +{ + std::size_t dot = file.find_last_of('.'); + if (dot != std::string::npos) { + const std::string ext = file.substr(dot + 1); + for (const auto &i : compress_styles) { + if (i.extension == ext) return i; + } + } + return compress_styles[0]; +} + +/* ------------------------------------------------------------------ */ + +// set reference time stamp during executable/library init. +// should provide better resolution than using epoch, if the system clock supports it. +static auto initial_time = std::chrono::steady_clock::now(); + +using namespace LAMMPS_NS; + +// get CPU time + +// clang-format off +// clang compilers are optimizing this function too aggressively returning always 0 +#if defined(__clang__) +[[clang::optnone]] +#elif defined(_MSC_VER) +#pragma optimize("",off) +#endif +double platform::cputime() +// clang-format on +{ + double rv = 0.0; + +#ifdef _WIN32 + + // from MSD docs. + FILETIME ct, et, kt, ut; + union { + FILETIME ft; + uint64_t ui; + } cpu; + if (GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) { + cpu.ft = ut; + rv = cpu.ui * 0.0000001; + } + +#else /* ! _WIN32 */ + + struct rusage ru; + if (getrusage(RUSAGE_SELF, &ru) == 0) { + rv = (double) ru.ru_utime.tv_sec; + rv += (double) ru.ru_utime.tv_usec * 0.000001; + } + +#endif + + return rv; +} +#if defined(_MSC_VER) +#pragma optimize("", on) +#endif + +/* ---------------------------------------------------------------------- + get wall time +------------------------------------------------------------------------ */ +double platform::walltime() +{ + return std::chrono::duration(std::chrono::steady_clock::now() - initial_time).count(); +} + +/* ---------------------------------------------------------------------- + sleep with microsecond resolution +------------------------------------------------------------------------ */ +void platform::usleep(int usec) +{ + return std::this_thread::sleep_for(std::chrono::microseconds(usec)); +} + +/* ---------------------------------------------------------------------- + get Operating system and version info +------------------------------------------------------------------------- */ + +std::string platform::os_info() +{ + std::string buf; + +#if defined(_WIN32) + + // Get Windows Edition name from registry + char value[1024]; + DWORD value_length = 1024; + const char *subkey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"; + const char *entry = "ProductName"; + RegGetValue(HKEY_LOCAL_MACHINE, subkey, entry, RRF_RT_REG_SZ, nullptr, &value, + (LPDWORD) &value_length); + // enforce zero termination + value[1023] = '\0'; + buf = value; + + DWORD fullversion, majorv, minorv, buildv = 0; + fullversion = GetVersion(); + majorv = (DWORD) (LOBYTE(LOWORD(fullversion))); + minorv = (DWORD) (HIBYTE(LOWORD(fullversion))); + if (fullversion < 0x80000000) buildv = (DWORD) (HIWORD(fullversion)); + + buf += ", Windows ABI " + std::to_string(majorv) + "." + std::to_string(minorv) + " (" + + std::to_string(buildv) + ") on "; + + SYSTEM_INFO si; + GetSystemInfo(&si); + + switch (si.wProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_AMD64: + buf += "x86_64"; + break; + case PROCESSOR_ARCHITECTURE_ARM: + buf += "arm"; + break; + case PROCESSOR_ARCHITECTURE_IA64: + buf += "ia64"; + break; + case PROCESSOR_ARCHITECTURE_INTEL: + buf += "i386"; + break; + default: + buf += "(unknown)"; + } +#else + struct utsname ut; + uname(&ut); + + // try to get OS distribution name, if available + buf = ut.sysname; + + if (platform::file_is_readable("/etc/os-release")) { + try { + TextFileReader reader("/etc/os-release",""); + while (1) { + auto words = reader.next_values(0,"="); + if ((words.count() > 1) && (words.next_string() == "PRETTY_NAME")) { + buf += " " + utils::trim(words.next_string()); + break; + } + } + } catch (std::exception &e) { + ; // EOF but keyword not found + } + } + + buf += std::string(" ") + ut.release + " " + ut.machine; +#endif + return buf; +} + +/* ---------------------------------------------------------------------- + identify C++ standard version +------------------------------------------------------------------------- */ + +std::string platform::cxx_standard() +{ +#if __cplusplus > 202002L + return "newer than C++20"; +#elif __cplusplus == 202002L + return "C++20"; +#elif __cplusplus == 201703L + return "C++17"; +#elif __cplusplus == 201402L + return "C++14"; +#elif __cplusplus == 201103L + return "C++11"; +#elif __cplusplus == 199711L + return "C++98"; +#else + return "unknown"; +#endif +} + +/* ---------------------------------------------------------------------- + identify compiler and its version +------------------------------------------------------------------------- */ + +std::string platform::compiler_info() +{ + std::string buf = "(Unknown)"; +#if defined(__INTEL_LLVM_COMPILER) + double version = static_cast(__INTEL_LLVM_COMPILER) * 0.01; + buf = fmt::format("Intel LLVM C++ {:.1f} / {}", version, __VERSION__); +#elif defined(__ibmxl__) + buf = fmt::format("IBM XL C/C++ (Clang) {}.{}.{}", __ibmxl_version__, __ibmxl_release__, + __ibmxl_modification__); +#elif defined(__clang__) + buf = fmt::format("Clang C++ {}", __VERSION__); +#elif defined(__PGI) + buf = fmt::format("PGI C++ {}.{}", __PGIC__, __PGIC_MINOR__); +#elif defined(__INTEL_COMPILER) +#if !defined(__VERSION__) +#define __VERSION__ __INTEL_COMPILER_BUILD_DATE +#endif + double version = static_cast(__INTEL_COMPILER) * 0.01; + buf = fmt::format("Intel Classic C++ {:.2f}.{} / {}", version, __INTEL_COMPILER_UPDATE, + __VERSION__); +#elif defined(__MINGW64__) + buf = fmt::format("MinGW-w64 64bit {}.{} / GNU C++ {}", __MINGW64_VERSION_MAJOR, + __MINGW64_VERSION_MINOR, __VERSION__); +#elif defined(__MINGW32__) + buf = fmt::format("MinGW-w64 32bit {}.{} / GNU C++ {}", __MINGW32_MAJOR_VERSION, + __MINGW32_MINOR_VERSION, __VERSION__); +#elif defined(__GNUC__) + buf = fmt::format("GNU C++ {}", __VERSION__); +#elif defined(_MSC_VER) && (_MSC_VER > 1920) && (_MSC_VER < 2000) + constexpr int major = _MSC_VER / 100; + constexpr int minor = _MSC_VER - major * 100; + buf = "Microsoft Visual Studio 20" + std::to_string(major) + ", C/C++ " + + std::to_string(major - 5) + "." + std::to_string(minor); +#else + buf = "(Unknown)"; +#endif + return buf; +} + +/* ---------------------------------------------------------------------- + detect OpenMP standard +------------------------------------------------------------------------- */ + +std::string platform::openmp_standard() +{ + +#if !defined(_OPENMP) + return "OpenMP not enabled"; +#else + + // Supported OpenMP version corresponds to the release date of the + // specifications as posted at https://www.openmp.org/specifications/ + +#if _OPENMP > 202011 + return "OpenMP newer than version 5.1"; +#elif _OPENMP == 202011 + return "OpenMP 5.1"; +#elif _OPENMP == 201811 + return "OpenMP 5.0"; +#elif _OPENMP == 201611 + return "OpenMP 5.0 preview 1"; +#elif _OPENMP == 201511 + return "OpenMP 4.5"; +#elif _OPENMP == 201307 + return "OpenMP 4.0"; +#elif _OPENMP == 201107 + return "OpenMP 3.1"; +#elif _OPENMP == 200805 + return "OpenMP 3.0"; +#elif _OPENMP == 200505 + return "OpenMP 2.5"; +#elif _OPENMP == 200203 + return "OpenMP 2.0"; +#else + return "unknown OpenMP version"; +#endif + +#endif +} + +/* ---------------------------------------------------------------------- + identify MPI vendor from defines in the mpi.h file. +------------------------------------------------------------------------- */ + +std::string platform::mpi_vendor() +{ +#if defined(MPI_STUBS) + return "MPI STUBS"; +#elif defined(OPEN_MPI) + return "Open MPI"; +#elif defined(MPICH_NAME) + return "MPICH"; +#elif defined(I_MPI_VERSION) + return "Intel MPI"; +#elif defined(PLATFORM_MPI) + return "Platform MPI"; +#elif defined(HP_MPI) + return "HP MPI"; +#elif defined(MSMPI_VER) + // Get Microsoft MPI version from registry + char value[1024]; + DWORD value_length = 1024; + const char *subkey = "SOFTWARE\\Microsoft\\MPI"; + const char *entry = "Version"; + auto rv = RegGetValueA(HKEY_LOCAL_MACHINE, subkey, entry, RRF_RT_REG_SZ, nullptr, &value, + (LPDWORD) &value_length); + std::string buf = "Microsoft MPI"; + if (rv == ERROR_SUCCESS) buf += std::string(" v") + value; + return buf; +#else + return "Unknown MPI implementation"; +#endif +} + +/* ---------------------------------------------------------------------- + detect MPI version info +------------------------------------------------------------------------- */ + +std::string platform::mpi_info(int &major, int &minor) +{ + int len = 0; +#if (defined(MPI_VERSION) && (MPI_VERSION > 2)) || defined(MPI_STUBS) + static char version[MPI_MAX_LIBRARY_VERSION_STRING]; + MPI_Get_library_version(version, &len); + if (len > 80) { + char *ptr = strchr(version + 80, '\n'); + if (ptr) *ptr = '\0'; + } +#else + constexpr int MAX_VERSION_STRING = 32; + static char version[MAX_VERSION_STRING]; + strncpy(version, mpi_vendor().c_str(), MAX_VERSION_STRING); +#endif + +#if defined(MPI_VERSION) + MPI_Get_version(&major, &minor); +#else + major = 1; + minor = 0; +#endif + return std::string(version); +} + +/* ---------------------------------------------------------------------- + set environment variable +------------------------------------------------------------------------- */ + +int platform::putenv(const std::string &vardef) +{ + if (vardef.size() == 0) return -1; + + auto found = vardef.find_first_of('='); +#ifdef _WIN32 + // must assign a value to variable with _putenv() + if (found == std::string::npos) + return _putenv(utils::strdup(vardef + "=1")); + else + return _putenv(utils::strdup(vardef)); +#else + if (found == std::string::npos) + return setenv(vardef.c_str(), "", 1); + else + return setenv(vardef.substr(0, found).c_str(), vardef.substr(found + 1).c_str(), 1); +#endif + return -1; +} + +/* ---------------------------------------------------------------------- + split a "path" environment variable into a list +------------------------------------------------------------------------- */ + +std::vector platform::list_pathenv(const std::string &var) +{ + std::vector dirs; + const char *ptr = getenv(var.c_str()); + if (ptr == nullptr) return dirs; + + std::string pathvar = ptr; + std::size_t first = 0, next; + while (true) { + next = pathvar.find_first_of(pathvarsep, first); + if (next == std::string::npos) { + dirs.push_back(pathvar.substr(first)); + break; + } else { + dirs.push_back(pathvar.substr(first, next - first)); + first = next + 1; + } + } + return dirs; +} + +/* ---------------------------------------------------------------------- + find the full path name of an executable +------------------------------------------------------------------------- */ + +std::string platform::find_exe_path(const std::string &cmd) +{ + if (cmd.size() == 0) return ""; + auto pathdirs = list_pathenv("PATH"); +#ifdef _WIN32 + // windows always looks in "." and does it first + pathdirs.insert(pathdirs.begin(), "."); +#else + struct stat info; +#endif + for (const auto &dir : pathdirs) { + std::string exe = path_join(dir, cmd); +#ifdef _WIN32 + const char *extensions[] = {".exe", ".com", ".bat", nullptr}; + for (auto ext = extensions; *ext != nullptr; ++ext) { + auto exe_path = exe + *ext; + if (file_is_readable(exe_path)) return exe_path; + } +#else + memset(&info, 0, sizeof(info)); + if (stat(exe.c_str(), &info) != 0) continue; + if ((info.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) != 0) return exe; +#endif + } + return ""; +} + +/* ---------------------------------------------------------------------- + wrapper functions for loading shared objects and libraries +------------------------------------------------------------------------- */ + +#ifdef _WIN32 + +// open a shared object file +void *platform::dlopen(const std::string &fname) +{ + return (void *) LoadLibrary(fname.c_str()); +} + +// return dynamic linker error string + +std::string platform::dlerror() +{ + return ""; +} + +// close a shared object +int platform::dlclose(void *handle) +{ + /* FreeLibrary returns nonzero on success unlike dlclose() */ + return (FreeLibrary((HINSTANCE) handle) == 0); +} + +// resolve a symbol in shared object +void *platform::dlsym(void *handle, const std::string &symbol) +{ + return (void *) GetProcAddress((HINSTANCE) handle, symbol.c_str()); +} + +#else + +// open a shared object file +void *platform::dlopen(const std::string &fname) +{ + return ::dlopen(fname.c_str(), RTLD_NOW | RTLD_GLOBAL); +} + +// return dynamic linker error string + +std::string platform::dlerror() +{ + const char *errmesg = ::dlerror(); + if (errmesg) return std::string(errmesg); + else return ""; +} + +// close a shared object +int platform::dlclose(void *handle) +{ + return ::dlclose(handle); +} + +// resolve a symbol in shared object +void *platform::dlsym(void *handle, const std::string &symbol) +{ + return ::dlsym(handle, symbol.c_str()); +} +#endif + +/* ---------------------------------------------------------------------- */ + +/** On Linux the folder /proc/self/fd holds symbolic links to the actual + * pathnames associated with each open file descriptor of the current process. + * On MacOS the same kind of information can be obtained using ``fcntl(fd,F_GETPATH,buf)``. + * On Windows we use ``GetFinalPathNameByHandleA()`` which is available with + * Windows Vista and later. If the buffer is too small (< 16 bytes) a null pointer is returned. + * + * This function is used to provide a filename with error messages in functions + * where the filename is not passed as an argument, but the FILE * pointer. */ + +const char *platform::guesspath(FILE *fp, char *buf, int len) +{ + // no point in guessing a path with a short buffer or NULL pointer as buffer + if ((buf == nullptr) || (len < 16)) return nullptr; + + // zero buffer and reserve last character in buffer for terminating '\0' + memset(buf, 0, len); + len--; + +#if defined(__linux__) + + int fd = fileno(fp); + // get pathname from /proc or copy (unknown) + if (readlink((std::string("/proc/self/fd/") + std::to_string(fd)).c_str(), buf, len) <= 0) + strncpy(buf, "(unknown)", len); + +#elif defined(__APPLE__) + + int fd = fileno(fp); + char filepath[PATH_MAX]; + if (fcntl(fd, F_GETPATH, filepath) != -1) + strncpy(buf, filepath, len); + else + strncpy(buf, "(unknown)", len); + +#elif defined(_WIN32) + + char filepath[MAX_PATH]; + HANDLE h = (HANDLE) _get_osfhandle(_fileno(fp)); + if (GetFinalPathNameByHandleA(h, filepath, MAX_PATH, FILE_NAME_NORMALIZED) > 0) + strncpy(buf, filepath, len); + else + strncpy(buf, "(unknown)", len); + +#else // unsupported OS + + strncpy(buf, "(unknown)", len); + +#endif + + return buf; +} + +/* ---------------------------------------------------------------------- + detect terminal, e.g. for using a pager automatically +------------------------------------------------------------------------- */ + +bool platform::is_console(FILE *fp) +{ + if (!fp) return false; +#if defined(_WIN32) + return (_isatty(_fileno(fp)) == 1); +#else + return (isatty(fileno(fp)) == 1); +#endif +} + +/* ---------------------------------------------------------------------- + Get string with path to the current directory + PATH_MAX may not be a compile time constant, so we must allocate and delete a buffer. +------------------------------------------------------------------------- */ + +std::string platform::current_directory() +{ + std::string cwd = ""; + +#if defined(_WIN32) + char *buf = new char[MAX_PATH]; + if (_getcwd(buf, MAX_PATH)) { cwd = buf; } + delete[] buf; +#else + char *buf = new char[PATH_MAX]; + if (::getcwd(buf, PATH_MAX)) { cwd = buf; } + delete[] buf; +#endif + return cwd; +} + +/* ---------------------------------------------------------------------- + check if a path is a directory +------------------------------------------------------------------------- */ + +bool platform::path_is_directory(const std::string &path) +{ +#if defined(_WIN32) + struct _stat info; + memset(&info, 0, sizeof(info)); + if (_stat(path.c_str(), &info) != 0) return false; +#else + struct stat info; + memset(&info, 0, sizeof(info)); + if (stat(path.c_str(), &info) != 0) return false; +#endif + return ((info.st_mode & S_IFDIR) != 0); +} + +/* ---------------------------------------------------------------------- + get directory listing in string vector +------------------------------------------------------------------------- */ + +std::vector platform::list_directory(const std::string &dir) +{ + std::vector files; + if (!path_is_directory(dir)) return files; + +#if defined(_WIN32) + HANDLE handle; + WIN32_FIND_DATA fd; + std::string searchname = dir + filepathsep[0] + "*"; + handle = FindFirstFile(searchname.c_str(), &fd); + if (handle == ((HANDLE) -1)) return files; + while (FindNextFile(handle, &fd)) { + std::string entry(fd.cFileName); + if ((entry == "..") || (entry == ".")) continue; + files.push_back(entry); + } + FindClose(handle); +#else + std::string dirname = dir + filepathsep[0]; + DIR *handle = opendir(dirname.c_str()); + if (handle == nullptr) return files; + struct dirent *fd; + while ((fd = readdir(handle)) != nullptr) { + std::string entry(fd->d_name); + if ((entry == "..") || (entry == ".")) continue; + files.push_back(entry); + } + closedir(handle); +#endif + return files; +} + +/* ---------------------------------------------------------------------- + Change current directory +------------------------------------------------------------------------- */ + +int platform::chdir(const std::string &path) +{ +#if defined(_WIN32) + return ::_chdir(path.c_str()); +#else + return ::chdir(path.c_str()); +#endif +} + +/* ---------------------------------------------------------------------- + Create a directory +------------------------------------------------------------------------- */ + +int platform::mkdir(const std::string &path) +{ +#if defined(_WIN32) + return ::_mkdir(path.c_str()); +#else + return ::mkdir(path.c_str(), S_IRWXU | S_IRGRP | S_IXGRP); +#endif +} + +/* ---------------------------------------------------------------------- + Delete a directory and its contents recursively +------------------------------------------------------------------------- */ + +int platform::rmdir(const std::string &path) +{ + // recurse through directory tree deleting files and directories + auto entries = list_directory(path); + for (const auto &entry : entries) { + const auto newpath = path_join(path, entry); + if (path_is_directory(newpath)) + rmdir(newpath); + else + unlink(newpath); + } +#if defined(_WIN32) + return ::_rmdir(path.c_str()); +#else + return ::rmdir(path.c_str()); +#endif +} + +/* ---------------------------------------------------------------------- + Delete a file +------------------------------------------------------------------------- */ + +int platform::unlink(const std::string &path) +{ +#if defined(_WIN32) + return ::_unlink(path.c_str()); +#else + return ::unlink(path.c_str()); +#endif +} + +/* ---------------------------------------------------------------------- + Get current file stream position +------------------------------------------------------------------------- */ + +bigint platform::ftell(FILE *fp) +{ +#if defined(_WIN32) + return (bigint)::_ftelli64(fp); +#else + return (bigint)::ftell(fp); +#endif +} + +/* ---------------------------------------------------------------------- + Set current file stream position +------------------------------------------------------------------------- */ + +int platform::fseek(FILE *fp, bigint pos) +{ +#if defined(_WIN32) + if (pos == platform::END_OF_FILE) + return ::_fseeki64(fp, 0, SEEK_END); + else + return ::_fseeki64(fp, (__int64) pos, SEEK_SET); +#else + if (pos == platform::END_OF_FILE) + return ::fseek(fp, 0, SEEK_END); + else + return ::fseek(fp, (long) pos, SEEK_SET); +#endif +} + +/* ---------------------------------------------------------------------- + Truncate opened file to given length +------------------------------------------------------------------------- */ + +int platform::ftruncate(FILE *fp, bigint length) +{ +#if defined(_WIN32) + HANDLE h = (HANDLE) _get_osfhandle(_fileno(fp)); + LARGE_INTEGER li_start, li_length; + li_start.QuadPart = (int64_t) 0; + li_length.QuadPart = (int64_t) length; + if (SetFilePointerEx(h, li_start, NULL, FILE_CURRENT) && + SetFilePointerEx(h, li_length, NULL, FILE_BEGIN) && SetEndOfFile(h)) { + return 0; + } else { + return 1; + } +#else + platform::fseek(fp, length); + return ::ftruncate(fileno(fp), (off_t) length); +#endif +} + +/* ---------------------------------------------------------------------- + open pipe +------------------------------------------------------------------------- */ + +FILE *platform::popen(const std::string &cmd, const std::string &mode) +{ + FILE *fp = nullptr; +#if defined(_WIN32) + if (mode == "r") + fp = ::_popen(cmd.c_str(), "rb"); + else if (mode == "w") + fp = ::_popen(cmd.c_str(), "wb"); +#else + if (mode == "r") + fp = ::popen(cmd.c_str(), "r"); + else if (mode == "w") + fp = ::popen(cmd.c_str(), "w"); +#endif + return fp; +} + +/* ---------------------------------------------------------------------- + close pipe +------------------------------------------------------------------------- */ + +int platform::pclose(FILE *fp) +{ +#if defined(_WIN32) + return ::_pclose(fp); +#else + return ::pclose(fp); +#endif +} + +/* ---------------------------------------------------------------------- + strip off leading part of path, return just the filename +------------------------------------------------------------------------- */ + +std::string platform::path_basename(const std::string &path) +{ + size_t start = path.find_last_of(platform::filepathsep); + + if (start == std::string::npos) { + start = 0; + } else { + start += 1; + } + + return path.substr(start); +} + +/* ---------------------------------------------------------------------- + Return only the leading part of a path, return just the directory +------------------------------------------------------------------------- */ + +std::string platform::path_dirname(const std::string &path) +{ + size_t start = path.find_last_of(platform::filepathsep); + + if (start == std::string::npos) return "."; + + return path.substr(0, start); +} + +/* ---------------------------------------------------------------------- + join two paths. + if one of the two is an empty string just return the other unmodified + if the first string ends in the separator or the second begins with one, trim them +------------------------------------------------------------------------- */ + +std::string platform::path_join(const std::string &a, const std::string &b) +{ + if (a.empty()) return b; + if (b.empty()) return a; + + // remove trailing separator(s) in first part + std::string joined = a; + while (joined.find_last_of(platform::filepathsep) == joined.size() - 1) { + for (const auto &s : platform::filepathsep) + if (joined.back() == s) joined.pop_back(); + } + + // skip over leading separator(s) in second part + std::size_t skip = 0; + while (b.find_first_of(platform::filepathsep, skip) == skip) ++skip; + + // combine and return + joined += platform::filepathsep[0] + b.substr(skip); + return joined; +} + +/* ---------------------------------------------------------------------- + try to open file for reading to prove if it exists and is accessible +------------------------------------------------------------------------- */ + +bool platform::file_is_readable(const std::string &path) +{ + FILE *fp = fopen(path.c_str(), "r"); + if (fp) { + fclose(fp); + return true; + } + return false; +} + +/* ---------------------------------------------------------------------- + check if filename has a known compression extension +------------------------------------------------------------------------- */ + +bool platform::has_compress_extension(const std::string &file) +{ + return find_compress_type(file).style != compress_info::NONE; +} + +/* ---------------------------------------------------------------------- + open pipe to read a compressed file +------------------------------------------------------------------------- */ + +FILE *platform::compressed_read(const std::string &file) +{ + FILE *fp = nullptr; + +#if defined(LAMMPS_GZIP) + auto compress = find_compress_type(file); + if (compress.style == compress_info::NONE) return nullptr; + + if (find_exe_path(compress.command).size()) + // put quotes around file name so that they may contain blanks + fp = popen((compress.command + compress.uncompressflags + "\"" + file + "\""), "r"); +#endif + return fp; +} + +/* ---------------------------------------------------------------------- + open pipe to write a compressed file +------------------------------------------------------------------------- */ + +FILE *platform::compressed_write(const std::string &file) +{ + FILE *fp = nullptr; + +#if defined(LAMMPS_GZIP) + auto compress = find_compress_type(file); + if (compress.style == compress_info::NONE) return nullptr; + + if (find_exe_path(compress.command).size()) + // put quotes around file name so that they may contain blanks + fp = popen((compress.command + compress.compressflags + "\"" + file + "\""), "w"); +#endif + return fp; +} + +/* ---------------------------------------------------------------------- */ diff --git a/src/platform.h b/src/platform.h new file mode 100644 index 0000000000..de8ecce016 --- /dev/null +++ b/src/platform.h @@ -0,0 +1,383 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, 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 LMP_PLATFORM_H +#define LMP_PLATFORM_H + +/*! \file platform.h */ + +#include "lmptype.h" + +#include +#include + +namespace LAMMPS_NS { +namespace platform { + + /*! Return the consumed CPU time for the current process in seconds + * + * This is a wrapper around the POSIX function getrusage() and its Windows equivalent. + * It is to be used in a similar fashion than MPI_Wtime(). Its resolution may + * be rather low so it can only be trusted when observing processes consuming at + * seconds or more of CPU time. + * + * \return used CPU time in seconds */ + + double cputime(); + + /*! Return the wall clock state for the current process in seconds + * + * This this clock is counting continuous time is initialized during + * Load of the executable/library. Its absolute value must be considered + * arbitrary and thus elapsed wall times are measured in taking differences. + * It is therefore to be used in a similar fashion as MPI_Wtime() but + * has a different offset, usually leading to better resolution. + * + * \return wall clock time in seconds */ + + double walltime(); + + /*! Suspend execution for a microsecond interval + * + * This emulates the usleep(3) BSD function call also mentioned in POSIX.1-2001. + * This is not a precise delay; it may be longer, but not shorter. + * + * \param usec length of delay in microseconds */ + + void usleep(int usec); + + /*! Return string with the operating system version and architecture info + * + * \return string with info about the OS and the platform is is running on */ + + std::string os_info(); + + /*! Return string with C++ standard version used to compile LAMMPS. + * + * This function uses predefined compiler macros to identify + * the C++ standard version used to compile LAMMPS with. + * + * \return string with the C++ standard version or "unknown" */ + + std::string cxx_standard(); + + /*! Return string with compiler version info + * + * This function uses predefined compiler macros to identify + * Compilers and their version and configuration info. + * + * \return string with the compiler information text */ + + std::string compiler_info(); + + /*! Return string with OpenMP standard version info + * + * This function uses predefined compiler macros to identify + * OpenMP support and the supported version of the standard. + * + * \return string with the openmp information text */ + + std::string openmp_standard(); + + /*! Return string with MPI vendor info + * + * This function uses predefined macros to identify + * the vendor of the MPI library used. + * + * \return string with the MPI vendor information text */ + + std::string mpi_vendor(); + + /*! Return string with MPI version info + * + * This function uses predefined macros and MPI function + * calls to identify the version of the MPI library used. + * + * \param major major version of the MPI standard (set on exit) + * \param minor minor version of the MPI standard (set on exit) + * \return string with the MPI version information text */ + + std::string mpi_info(int &major, int &minor); + + /*! Add variable to the environment + * + * \param vardef variable name or variable definition (NAME=value) + * \return -1 if failure otherwise 0 */ + + int putenv(const std::string &vardef); + + /*! Get list of entries in a path environment variable + * + * This provides a list of strings of the entries in an environment + * variable that is containing a "path" like "PATH" or "LD_LIBRARY_PATH". + * + * \param var name of the environment variable + * \return vector with strings of all entries in that path variable */ + + std::vector list_pathenv(const std::string &var); + + /*! Open a shared object file or library + * + * \param fname name or path of the shared object + * \return handle to the shared object or null */ + + void *dlopen(const std::string &fname); + + /*! Obtain error diagnostic info after dynamic linking function calls + * + * Return a human-readable string describing the most recent error that + * occurred when using one of the functions for dynamic loading objects + * the last call to this function. The string is empty, if there was no error. + * + * \return string with error message or empty */ + + std::string dlerror(); + + /*! Close a shared object + * + * This releases the object corresponding to the provided handle. + * Resolved symbols associated with this handle may not be used + * after this call + * + * \param handle handle to an opened shared object + * \return 0 if successful, non-zero of not */ + + int dlclose(void *handle); + + /*! Resolve a symbol in shared object + * + * \param handle handle to an opened shared object + * \param symbol name of the symbol to extract + * \return pointer to the resolved symbol or null */ + + void *dlsym(void *handle, const std::string &symbol); + + /*! Platform specific file path component separator + * + * This is a string with the character that separates directories and filename in paths on + * a platform. If multiple are characters are provided, the first is the preferred one. */ + +#if !defined(_WIN32) + constexpr char filepathsep[] = "/"; +#else + constexpr char filepathsep[] = "\\/"; +#endif + + /*! Platform specific path environment variable component separator + * + * This is the character that separates entries in "PATH"-style environment variables. */ + +#if !defined(_WIN32) + constexpr char pathvarsep = ':'; +#else + constexpr char pathvarsep = ';'; +#endif + + /*! Try to detect pathname from FILE pointer + * + * Currently only supported on Linux, MacOS, and Windows. Otherwise will report "(unknown)". + * + * \param fp FILE pointer struct from STDIO library for which we want to detect the name + * \param buf storage buffer for pathname. output will be truncated if not large enough + * \param len size of storage buffer. output will be truncated to this length - 1 + * \return pointer to the storage buffer with path or a NULL pointer if buf is invalid + * or the buffer size is too small */ + + const char *guesspath(FILE *fp, char *buf, int len); + + /*! Check if a file pointer may be connected to a console + * + * \param fp file pointer + * \return true if the file pointer is flagged as a TTY */ + + bool is_console(FILE *fp); + + /*! Get string with path to the current directory + * + * \return path to the current directory or empty string */ + + std::string current_directory(); + + /*! Check if a path is a directory + * + * \param path directory path + * \return true if the directory exists */ + + bool path_is_directory(const std::string &path); + + /*! Get list of entries in a directory + * + * This provides a list of strings of the entries in the directory + * without the leading path name while also skipping over ".." and ".". + * + * \param dir path to directory + * \return vector with strings of all directory entries */ + + std::vector list_directory(const std::string &dir); + + /*! Find pathname of an executable in the standard search path + * + * This function will traverse the list of directories in the PATH + * environment variable and look for the executable *cmd*. If the + * file exists and is executable the full path is returned as string, + * otherwise and empty string is returned. + * + * On Windows the *cmd* string must not include and extension as + * this function will automatically append the extensions ".exe", + * ".com" and ".bat" and look for those paths. On Windows also the + * current directory is checked (and first), while otherwise not unless + * "." exists in the PATH environment variable. + * + * Because of the nature of the check, this will not detect shell functions + * built-in command or aliases. + * + * \param cmd name of command + * \return vector with strings of all directory entries */ + + std::string find_exe_path(const std::string &cmd); + + /*! Change current directory + * + * \param path new current working directory path + * \return -1 if unsuccessful, otherwise >= 0 */ + + int chdir(const std::string &path); + + /*! Create a directory + * + * \param path directory path + * \return -1 if unsuccessful, otherwise >= 0 */ + + int mkdir(const std::string &path); + + /*! Delete a directory + * + * \param path directory path + * \return -1 if unsuccessful, otherwise >= 0 */ + + int rmdir(const std::string &path); + + /*! Delete a directory and its contents + * + * Unlike the the ``rmdir()`` or ``_rmdir()`` function of the + * C library, this function will check for the contents of the + * folder and recurse into any sub-folders, if necessary and + * delete all contained folders and their contents before + * deleting the folder *path*. + * + * \param path path to file to be deleted + * \return 0 on success, -1 on error */ + + int unlink(const std::string &path); + + /*! Get current file position + * + * \param fp FILE pointer of the given file + * \return current FILE pointer position cast to a bigint */ + + bigint ftell(FILE *fp); + + /*! constant to seek to the end of the file */ + constexpr bigint END_OF_FILE = -1; + + /*! Set absolute file position + * + * If the absolute position is END_OF_FILE, then position at the end of the file. + * + * \param fp FILE pointer of the given file + * \param pos new position of the FILE pointer + * \return 0 if successful, otherwise -1 */ + + int fseek(FILE *fp, bigint pos); + + /*! Truncate file to a given length and re-position file pointer + * + * \param fp FILE pointer of the given file + * \param length length to which the file is being truncated to + * \return 0 if successful, otherwise -1 */ + + int ftruncate(FILE *fp, bigint length); + + /*! Open a pipe to a command for reading or writing + * + * \param cmd command for the pipe + * \param mode "r" for reading from *cmd* or "w" for writing to *cmd* + * \return file pointer to the pipe if successful or null */ + + FILE *popen(const std::string &cmd, const std::string &mode); + + /*! Close a previously opened pipe + * + * \param fp FILE pointer for the pipe + * \return exit status of the pipe command or -1 in case of errors */ + + int pclose(FILE *fp); + + /*! Strip off leading part of path, return just the filename + * + * \param path file path + * \return file name */ + + std::string path_basename(const std::string &path); + + /*! Return the directory part of a path. Return "." if empty + * + * \param path file path + * \return directory name */ + + std::string path_dirname(const std::string &path); + + /*! Join two pathname segments + * + * This uses the forward slash '/' character unless LAMMPS is compiled + * for Windows where it uses the backward slash '\\' + * + * \param a first path + * \param b second path + * \return combined path */ + + std::string path_join(const std::string &a, const std::string &b); + + /*! Check if file exists and is readable + * + * \param path file path + * \return true if file exists and is readable */ + + bool file_is_readable(const std::string &path); + + /*! Check if a file name ends in a known extension for a compressed file format + * + * Currently supported file extensions are: .gz, .bz2, .zst, .xz, .lzma, lz4 + * + * \param file name of the file to check + * \return true if the file has a known extension, otherwise false */ + + bool has_compress_extension(const std::string &file); + + /*! Open pipe to compressed text file for reading + * + * \param file name of the file to open + * \return FILE pointer to pipe using for reading the compressed file. */ + + FILE *compressed_read(const std::string &file); + + /*! Open pipe to compressed text file for writing + * + * \param file name of the file to open + * \return FILE pointer to pipe using for reading the compressed file. */ + + FILE *compressed_write(const std::string &file); + +} // namespace platform +} // namespace LAMMPS_NS +#endif diff --git a/src/pointers.h b/src/pointers.h index 4ae50715c1..55033aae3e 100644 --- a/src/pointers.h +++ b/src/pointers.h @@ -30,6 +30,7 @@ #include "lammps.h" // IWYU pragma: export #include "utils.h" // IWYU pragma: export #include "fmt/format.h" // IWYU pragma: export +#include "platform.h" // IWYU pragma: export namespace LAMMPS_NS { diff --git a/src/read_data.cpp b/src/read_data.cpp index 574117e93e..c17ab97229 100644 --- a/src/read_data.cpp +++ b/src/read_data.cpp @@ -114,7 +114,7 @@ void ReadData::command(int narg, char **arg) if (narg < 1) error->all(FLERR,"Illegal read_data command"); MPI_Barrier(world); - double time1 = MPI_Wtime(); + double time1 = platform::walltime(); // optional args @@ -308,7 +308,7 @@ void ReadData::command(int narg, char **arg) // check if data file is available and readable - if (!utils::file_is_readable(arg[0])) + if (!platform::file_is_readable(arg[0])) error->all(FLERR,fmt::format("Cannot open file {}: {}", arg[0], utils::getsyserror())); @@ -741,7 +741,7 @@ void ReadData::command(int narg, char **arg) // close file if (me == 0) { - if (compressed) pclose(fp); + if (compressed) platform::pclose(fp); else fclose(fp); fp = nullptr; } @@ -914,7 +914,7 @@ void ReadData::command(int narg, char **arg) MPI_Barrier(world); if (comm->me == 0) - utils::logmesg(lmp," read_data CPU = {:.3f} seconds\n",MPI_Wtime()-time1); + utils::logmesg(lmp," read_data CPU = {:.3f} seconds\n",platform::walltime()-time1); } /* ---------------------------------------------------------------------- @@ -1951,34 +1951,20 @@ int ReadData::reallocate(int **pcount, int cmax, int amax) /* ---------------------------------------------------------------------- proc 0 opens data file - test if gzipped + test if compressed ------------------------------------------------------------------------- */ -void ReadData::open(char *file) +void ReadData::open(const std::string &file) { - if (utils::strmatch(file,"\\.gz$")) { + if (platform::has_compress_extension(file)) { compressed = 1; - -#ifdef LAMMPS_GZIP - auto gunzip = fmt::format("gzip -c -d {}",file); - -#ifdef _WIN32 - fp = _popen(gunzip.c_str(),"rb"); -#else - fp = popen(gunzip.c_str(),"r"); -#endif - -#else - error->one(FLERR,"Cannot open gzipped file without gzip support"); -#endif + fp = platform::compressed_read(file); + if (!fp) error->one(FLERR,"Cannot open compressed file {}", file); } else { compressed = 0; - fp = fopen(file,"r"); + fp = fopen(file.c_str(),"r"); + if (!fp) error->one(FLERR,"Cannot open file {}: {}", file, utils::getsyserror()); } - - if (fp == nullptr) - error->one(FLERR,"Cannot open file {}: {}", - file, utils::getsyserror()); } /* ---------------------------------------------------------------------- diff --git a/src/read_data.h b/src/read_data.h index 482c45e6e6..3374f48be0 100644 --- a/src/read_data.h +++ b/src/read_data.h @@ -78,7 +78,7 @@ class ReadData : public Command { // methods - void open(char *); + void open(const std::string &); void scan(int &, int &, int &, int &); int reallocate(int **, int, int); void header(int); diff --git a/src/read_restart.cpp b/src/read_restart.cpp index bbd3bd3359..0eab44baaa 100644 --- a/src/read_restart.cpp +++ b/src/read_restart.cpp @@ -35,7 +35,6 @@ #include "update.h" #include -#include #include "lmprestart.h" @@ -55,7 +54,7 @@ void ReadRestart::command(int narg, char **arg) error->all(FLERR,"Cannot read_restart after simulation box is defined"); MPI_Barrier(world); - double time1 = MPI_Wtime(); + double time1 = platform::walltime(); MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); @@ -117,6 +116,7 @@ void ReadRestart::command(int narg, char **arg) magic_string(); endian(); format_revision(); + check_eof_magic(); // read header info which creates simulation box @@ -522,7 +522,7 @@ void ReadRestart::command(int narg, char **arg) MPI_Barrier(world); if (comm->me == 0) - utils::logmesg(lmp," read_restart CPU = {:.3f} seconds\n",MPI_Wtime()-time1); + utils::logmesg(lmp," read_restart CPU = {:.3f} seconds\n",platform::walltime()-time1); delete mpiio; } @@ -540,8 +540,8 @@ std::string ReadRestart::file_search(const std::string &inpfile) { // separate inpfile into dir + filename - auto dirname = utils::path_dirname(inpfile); - auto filename = utils::path_basename(inpfile); + auto dirname = platform::path_dirname(inpfile); + auto filename = platform::path_basename(inpfile); // if filename contains "%" replace "%" with "base" @@ -557,24 +557,20 @@ std::string ReadRestart::file_search(const std::string &inpfile) if (loc != std::string::npos) { // convert pattern to equivalent regexp pattern.replace(loc,1,"\\d+"); - struct dirent *ep; - DIR *dp = opendir(dirname.c_str()); - if (dp == nullptr) - error->one(FLERR,"Cannot open directory {} to search for restart file: {}", - dirname, utils::getsyserror()); - while ((ep = readdir(dp))) { - std::string candidate(ep->d_name); + if (!platform::path_is_directory(dirname)) + error->one(FLERR,"Cannot open directory {} to search for restart file: {}",dirname); + + for (const auto &candidate : platform::list_directory(dirname)) { if (utils::strmatch(candidate,pattern)) { bigint num = ATOBIGINT(utils::strfind(candidate.substr(loc),"\\d+").c_str()); if (num > maxnum) maxnum = num; } } - closedir(dp); if (maxnum < 0) error->one(FLERR,"Found no restart file matching pattern"); filename.replace(filename.find('*'),1,std::to_string(maxnum)); } - return utils::path_join(dirname,filename); + return platform::path_join(dirname,filename); } /* ---------------------------------------------------------------------- @@ -1084,11 +1080,11 @@ void ReadRestart::file_layout() flag = read_int(); } - // if MPI-IO file, broadcast the end of the header offste + // if MPI-IO file, broadcast the end of the header offset // this allows all ranks to compute offset to their data if (mpiioflag) { - if (me == 0) headerOffset = ftell(fp); + if (me == 0) headerOffset = platform::ftell(fp); MPI_Bcast(&headerOffset,1,MPI_LMP_BIGINT,0,world); } } @@ -1152,10 +1148,12 @@ void ReadRestart::check_eof_magic() // read magic string at end of file and restore file pointer if (me == 0) { - long curpos = ftell(fp); - fseek(fp,(long)-n,SEEK_END); + bigint curpos = platform::ftell(fp); + platform::fseek(fp,platform::END_OF_FILE); + bigint offset = platform::ftell(fp) - n; + platform::fseek(fp,offset); utils::sfread(FLERR,str,sizeof(char),n,fp,nullptr,error); - fseek(fp,curpos,SEEK_SET); + platform::fseek(fp,curpos); } MPI_Bcast(str,n,MPI_CHAR,0,world); diff --git a/src/reader.cpp b/src/reader.cpp index 71036e7444..f2652d868d 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -32,33 +32,20 @@ Reader::Reader(LAMMPS *lmp) : Pointers(lmp) generic version for ASCII files that may be compressed ------------------------------------------------------------------------- */ -void Reader::open_file(const char *file) +void Reader::open_file(const std::string &file) { if (fp != nullptr) close_file(); - if (utils::strmatch(file,"\\.gz$")) { + if (platform::has_compress_extension(file)) { compressed = 1; - -#ifdef LAMMPS_GZIP - auto gunzip = fmt::format("gzip -c -d {}",file); - -#ifdef _WIN32 - fp = _popen(gunzip.c_str(),"rb"); -#else - fp = popen(gunzip.c_str(),"r"); -#endif - -#else - error->one(FLERR,"Cannot open gzipped file without gzip support"); -#endif + fp = platform::compressed_read(file); + if (!fp) error->one(FLERR,"Cannot open compressed file for reading"); } else { compressed = 0; - fp = fopen(file,"r"); + fp = fopen(file.c_str(),"r"); } - if (fp == nullptr) - error->one(FLERR,"Cannot open file {}: {}", - file, utils::getsyserror()); + if (!fp) error->one(FLERR,"Cannot open file {}: {}", file, utils::getsyserror()); } /* ---------------------------------------------------------------------- @@ -69,7 +56,7 @@ void Reader::open_file(const char *file) void Reader::close_file() { if (fp == nullptr) return; - if (compressed) pclose(fp); + if (compressed) platform::pclose(fp); else fclose(fp); fp = nullptr; } diff --git a/src/reader.h b/src/reader.h index 2d71750f98..18977790cd 100644 --- a/src/reader.h +++ b/src/reader.h @@ -33,7 +33,7 @@ class Reader : protected Pointers { int &, int &, int &) = 0; virtual void read_atoms(int, int, double **) = 0; - virtual void open_file(const char *); + virtual void open_file(const std::string &); virtual void close_file(); protected: diff --git a/src/replicate.cpp b/src/replicate.cpp index 2c2b512026..80edd7bcbc 100644 --- a/src/replicate.cpp +++ b/src/replicate.cpp @@ -79,7 +79,7 @@ void Replicate::command(int narg, char **arg) // record wall time for atom replication MPI_Barrier(world); - double time1 = MPI_Wtime(); + double time1 = platform::walltime(); // maxtag = largest atom tag across all existing atoms @@ -799,5 +799,5 @@ void Replicate::command(int narg, char **arg) MPI_Barrier(world); if (me == 0) - utils::logmesg(lmp," replicate CPU = {:.3f} seconds\n",MPI_Wtime()-time1); + utils::logmesg(lmp," replicate CPU = {:.3f} seconds\n",platform::walltime()-time1); } diff --git a/src/reset_mol_ids.cpp b/src/reset_mol_ids.cpp index 424b4bcb6c..4c973f543f 100644 --- a/src/reset_mol_ids.cpp +++ b/src/reset_mol_ids.cpp @@ -96,7 +96,7 @@ void ResetMolIDs::command(int narg, char **arg) // record wall time for resetting molecule IDs MPI_Barrier(world); - double time1 = MPI_Wtime(); + double time1 = platform::walltime(); // initialize system since comm->borders() will be invoked @@ -132,7 +132,7 @@ void ResetMolIDs::command(int narg, char **arg) else utils::logmesg(lmp," number of new molecule IDs = {}\n",nchunk); utils::logmesg(lmp," reset_mol_ids CPU = {:.3f} seconds\n", - MPI_Wtime()-time1); + platform::walltime()-time1); } } diff --git a/src/special.cpp b/src/special.cpp index dcc0d0c0ad..9f480da78f 100644 --- a/src/special.cpp +++ b/src/special.cpp @@ -56,7 +56,7 @@ Special::~Special() void Special::build() { MPI_Barrier(world); - double time1 = MPI_Wtime(); + double time1 = platform::walltime(); if (me == 0) { const double * const special_lj = force->special_lj; @@ -1303,5 +1303,5 @@ void Special::timer_output(double time1) { if (comm->me == 0) utils::logmesg(lmp," special bonds CPU = {:.3f} seconds\n", - MPI_Wtime()-time1); + platform::walltime()-time1); } diff --git a/src/timer.cpp b/src/timer.cpp index b01a7aa9d6..0cbf687137 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -20,50 +20,8 @@ #include -#ifdef _WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#include -#else -#include -#include -#endif - using namespace LAMMPS_NS; - -// Return the CPU time for the current process in seconds very -// much in the same way as MPI_Wtime() returns the wall time. - -static double CPU_Time() -{ - double rv = 0.0; - -#ifdef _WIN32 - - // from MSD docs. - FILETIME ct,et,kt,ut; - union { FILETIME ft; uint64_t ui; } cpu; - if (GetProcessTimes(GetCurrentProcess(),&ct,&et,&kt,&ut)) { - cpu.ft = ut; - rv = cpu.ui * 0.0000001; - } - -#else /* ! _WIN32 */ - - struct rusage ru; - if (getrusage(RUSAGE_SELF, &ru) == 0) { - rv = (double) ru.ru_utime.tv_sec; - rv += (double) ru.ru_utime.tv_usec * 0.000001; - } - -#endif /* ! _WIN32 */ - - return rv; -} - /* ---------------------------------------------------------------------- */ Timer::Timer(LAMMPS *lmp) : Pointers(lmp) @@ -93,8 +51,8 @@ void Timer::_stamp(enum ttype which) { double current_cpu=0.0, current_wall=0.0; - if (_level > NORMAL) current_cpu = CPU_Time(); - current_wall = MPI_Wtime(); + if (_level > NORMAL) current_cpu = platform::cputime(); + current_wall = platform::walltime(); if ((which > TOTAL) && (which < NUM_TIMER)) { const double delta_cpu = current_cpu - previous_cpu; @@ -117,8 +75,8 @@ void Timer::_stamp(enum ttype which) if (_sync) { MPI_Barrier(world); - if (_level > NORMAL) current_cpu = CPU_Time(); - current_wall = MPI_Wtime(); + if (_level > NORMAL) current_cpu = platform::cputime(); + current_wall = platform::walltime(); cpu_array[SYNC] += current_cpu - previous_cpu; wall_array[SYNC] += current_wall - previous_wall; @@ -137,8 +95,8 @@ void Timer::barrier_start() if (_level < LOOP) return; - current_cpu = CPU_Time(); - current_wall = MPI_Wtime(); + current_cpu = platform::cputime(); + current_wall = platform::walltime(); cpu_array[TOTAL] = current_cpu; wall_array[TOTAL] = current_wall; @@ -156,8 +114,8 @@ void Timer::barrier_stop() if (_level < LOOP) return; - current_cpu = CPU_Time(); - current_wall = MPI_Wtime(); + current_cpu = platform::cputime(); + current_wall = platform::walltime(); cpu_array[TOTAL] = current_cpu - cpu_array[TOTAL]; wall_array[TOTAL] = current_wall - wall_array[TOTAL]; @@ -167,7 +125,7 @@ void Timer::barrier_stop() double Timer::cpu(enum ttype which) { - double current_cpu = CPU_Time(); + double current_cpu = platform::cputime(); return (current_cpu - cpu_array[which]); } @@ -176,7 +134,7 @@ double Timer::cpu(enum ttype which) double Timer::elapsed(enum ttype which) { if (_level == OFF) return 0.0; - double current_wall = MPI_Wtime(); + double current_wall = platform::walltime(); return (current_wall - wall_array[which]); } @@ -207,7 +165,7 @@ void Timer::print_timeout(FILE *fp) // format timeout setting if (_timeout > 0) { // time since init_timeout() - const double d = MPI_Wtime() - timeout_start; + const double d = platform::walltime() - timeout_start; // remaining timeout in seconds int s = _timeout - d; // remaining 1/100ths of seconds @@ -226,7 +184,7 @@ void Timer::print_timeout(FILE *fp) bool Timer::_check_timeout() { - double walltime = MPI_Wtime() - timeout_start; + double walltime = platform::walltime() - timeout_start; // broadcast time to insure all ranks act the same. MPI_Bcast(&walltime,1,MPI_DOUBLE,0,world); @@ -244,7 +202,7 @@ bool Timer::_check_timeout() /* ---------------------------------------------------------------------- */ double Timer::get_timeout_remain() { - return (_timeout < 0.0) ? 0.0 : _timeout + timeout_start - MPI_Wtime(); + return (_timeout < 0.0) ? 0.0 : _timeout + timeout_start - platform::walltime(); } /* ---------------------------------------------------------------------- @@ -285,7 +243,7 @@ void Timer::modify_params(int narg, char **arg) ++iarg; } - timeout_start = MPI_Wtime(); + timeout_start = platform::walltime(); if (comm->me == 0) { // format timeout setting diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 43660d68ec..71b4ad610e 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -46,8 +46,8 @@ TokenizerException::TokenizerException(const std::string &msg, const std::string \endverbatim * - * \param str string to be processed - * \param separators string with separator characters (default: " \t\r\n\f") */ + * \param str string to be processed + * \param _separators string with separator characters (default: " \t\r\n\f") */ Tokenizer::Tokenizer(const std::string &str, const std::string &_separators) : text(str), separators(_separators), start(0), ntokens(std::string::npos) diff --git a/src/utils.cpp b/src/utils.cpp index 2feba5db97..035b68d660 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -31,25 +31,6 @@ #include #include -#if defined(__linux__) -#include // for readlink -#endif - -#if defined(__APPLE__) -#include // for fcntl -#include -#endif - -#if defined(_WIN32) -// target Windows version is Windows 7 and later -#if defined(_WIN32_WINNT) -#undef _WIN32_WINNT -#endif -#define _WIN32_WINNT _WIN32_WINNT_WIN7 -#include -#include -#endif - /*! \file utils.cpp */ /* @@ -165,44 +146,6 @@ std::string utils::getsyserror() return std::string(strerror(errno)); } -/** On Linux the folder /proc/self/fd holds symbolic links to the actual - * pathnames associated with each open file descriptor of the current process. - * On MacOS the same kind of information can be obtained using ``fcntl(fd,F_GETPATH,buf)``. - * On Windows we use ``GetFinalPathNameByHandleA()`` which is available with - * Windows Vista and later. - * - * This function is used to provide a filename with error messages in functions - * where the filename is not passed as an argument, but the FILE * pointer. - */ -const char *utils::guesspath(char *buf, int len, FILE *fp) -{ - memset(buf, 0, len); - -#if defined(__linux__) - int fd = fileno(fp); - // get pathname from /proc or copy (unknown) - if (readlink(fmt::format("/proc/self/fd/{}", fd).c_str(), buf, len - 1) <= 0) - strncpy(buf, "(unknown)", len - 1); -#elif defined(__APPLE__) - int fd = fileno(fp); - char filepath[PATH_MAX]; - if (fcntl(fd, F_GETPATH, filepath) != -1) - strncpy(buf, filepath, len - 1); - else - strncpy(buf, "(unknown)", len - 1); -#elif defined(_WIN32) - char filepath[MAX_PATH]; - HANDLE h = (HANDLE) _get_osfhandle(_fileno(fp)); - if (GetFinalPathNameByHandleA(h, filepath, PATH_MAX, FILE_NAME_NORMALIZED) > 0) - strncpy(buf, filepath, len - 1); - else - strncpy(buf, "(unknown)", len - 1); -#else - strncpy(buf, "(unknown)", len - 1); -#endif - return buf; -} - // read line into buffer. if line is too long keep reading until EOL or EOF // but return only the first part with a newline at the end. @@ -256,7 +199,7 @@ void utils::sfgets(const char *srcname, int srcline, char *s, int size, FILE *fp std::string errmsg; // try to figure out the file name from the file pointer - if (!filename) filename = guesspath(buf, MAXPATHLENBUF, fp); + if (!filename) filename = platform::guesspath(fp, buf, MAXPATHLENBUF); if (feof(fp)) { errmsg = "Unexpected end of file while reading file '"; @@ -285,7 +228,7 @@ void utils::sfread(const char *srcname, int srcline, void *s, size_t size, size_ std::string errmsg; // try to figure out the file name from the file pointer - if (!filename) filename = guesspath(buf, MAXPATHLENBUF, fp); + if (!filename) filename = platform::guesspath(fp, buf, MAXPATHLENBUF); if (feof(fp)) { errmsg = "Unexpected end of file while reading file '"; @@ -369,7 +312,7 @@ int utils::logical(const char *file, int line, const char *str, bool do_abort, L lmp->error->all(file, line, msg); } - // convert to ascii and lowercase + // convert to ascii std::string buf(str); if (has_utf8(buf)) buf = utf8_subst(buf); @@ -751,6 +694,28 @@ char *utils::strdup(const std::string &text) return tmp; } +/* ---------------------------------------------------------------------- + Return string converted to lowercase +------------------------------------------------------------------------- */ + +std::string utils::lowercase(const std::string &text) +{ + std::string converted(text); + for (auto &c : converted) c = ::tolower(c); + return converted; +} + +/* ---------------------------------------------------------------------- + Return string converted to uppercase +------------------------------------------------------------------------- */ + +std::string utils::uppercase(const std::string &text) +{ + std::string converted(text); + for (auto &c : converted) c = ::toupper(c); + return converted; +} + /* ---------------------------------------------------------------------- Return string without leading or trailing whitespace ------------------------------------------------------------------------- */ @@ -920,7 +885,7 @@ size_t utils::count_words(const std::string &text, const std::string &separators size_t utils::trim_and_count_words(const std::string &text, const std::string &separators) { - return utils::count_words(utils::trim_comment(text), separators); + return utils::count_words(trim_comment(text), separators); } /* ---------------------------------------------------------------------- @@ -1065,71 +1030,6 @@ bool utils::is_id(const std::string &str) return true; } -/* ---------------------------------------------------------------------- - strip off leading part of path, return just the filename -------------------------------------------------------------------------- */ - -std::string utils::path_basename(const std::string &path) -{ -#if defined(_WIN32) - size_t start = path.find_last_of("/\\"); -#else - size_t start = path.find_last_of('/'); -#endif - - if (start == std::string::npos) { - start = 0; - } else { - start += 1; - } - - return path.substr(start); -} - -/* ---------------------------------------------------------------------- - Return only the leading part of a path, return just the directory -------------------------------------------------------------------------- */ - -std::string utils::path_dirname(const std::string &path) -{ -#if defined(_WIN32) - size_t start = path.find_last_of("/\\"); -#else - size_t start = path.find_last_of('/'); -#endif - - if (start == std::string::npos) return "."; - - return path.substr(0, start); -} - -/* ---------------------------------------------------------------------- - join two paths -------------------------------------------------------------------------- */ - -std::string utils::path_join(const std::string &a, const std::string &b) -{ -#if defined(_WIN32) - return fmt::format("{}\\{}", a, b); -#else - return fmt::format("{}/{}", a, b); -#endif -} - -/* ---------------------------------------------------------------------- - try to open file for reading -------------------------------------------------------------------------- */ - -bool utils::file_is_readable(const std::string &path) -{ - FILE *fp = fopen(path.c_str(), "r"); - if (fp) { - fclose(fp); - return true; - } - return false; -} - /* ---------------------------------------------------------------------- try to find potential file as specified by name search current directory and the LAMMPS_POTENTIALS directory if @@ -1138,28 +1038,13 @@ bool utils::file_is_readable(const std::string &path) std::string utils::get_potential_file_path(const std::string &path) { - std::string filepath = path; - std::string filename = utils::path_basename(path); - - if (utils::file_is_readable(filepath)) { - return filepath; + if (platform::file_is_readable(path)) { + return path; } else { - // try the environment variable directory - const char *var = getenv("LAMMPS_POTENTIALS"); - - if (var != nullptr) { -#if defined(_WIN32) - Tokenizer dirs(var, ";"); -#else - Tokenizer dirs(var, ":"); -#endif - while (dirs.has_next()) { - auto pot = utils::path_basename(filepath); - auto dir = dirs.next(); - filepath = utils::path_join(dir, pot); - - if (utils::file_is_readable(filepath)) { return filepath; } - } + for (const auto &dir : platform::list_pathenv("LAMMPS_POTENTIALS")) { + auto pot = platform::path_basename(path); + auto filepath = platform::path_join(dir, pot); + if (platform::file_is_readable(filepath)) return filepath; } } return ""; @@ -1309,7 +1194,7 @@ double utils::timespec2seconds(const std::string ×pec) if (!values.has_next()) break; vals[i] = values.next_int(); } - } catch (TokenizerException &e) { + } catch (TokenizerException &) { return -1.0; } diff --git a/src/utils.h b/src/utils.h index 4dd4eea090..1feee26f27 100644 --- a/src/utils.h +++ b/src/utils.h @@ -282,6 +282,20 @@ namespace utils { char *strdup(const std::string &text); + /*! Convert string to lowercase + * + * \param line string that should be converted + * \return new string with all lowercase characters */ + + std::string lowercase(const std::string &line); + + /*! Convert string to uppercase + * + * \param line string that should be converted + * \return new string with all uppercase characters */ + + std::string uppercase(const std::string &line); + /*! Trim leading and trailing whitespace. Like TRIM() in Fortran. * * \param line string that should be trimmed @@ -417,49 +431,6 @@ namespace utils { bool is_id(const std::string &str); - /*! Try to detect pathname from FILE pointer. - * - * Currently supported on Linux, MacOS, and Windows, otherwise will report "(unknown)". - * - * \param buf storage buffer for pathname. output will be truncated if not large enough - * \param len size of storage buffer. output will be truncated to this length - 1 - * \param fp FILE pointer struct from STDIO library for which we want to detect the name - * \return pointer to the storage buffer, i.e. buf */ - - const char *guesspath(char *buf, int len, FILE *fp); - - /*! Strip off leading part of path, return just the filename - * - * \param path file path - * \return file name */ - - std::string path_basename(const std::string &path); - - /*! Return the directory part of a path. Return "." if empty - * - * \param path file path - * \return directory name */ - - std::string path_dirname(const std::string &path); - - /*! Join two pathname segments - * - * This uses the forward slash '/' character unless LAMMPS is compiled - * for Windows where it used the equivalent backward slash '\\'. - * - * \param a first path - * \param b second path - * \return combined path */ - - std::string path_join(const std::string &a, const std::string &b); - - /*! Check if file exists and is readable - * - * \param path file path - * \return true if file exists and is readable */ - - bool file_is_readable(const std::string &path); - /*! Determine full path of potential file. If file is not found in current directory, * search directories listed in LAMMPS_POTENTIALS environment variable * diff --git a/src/variable.cpp b/src/variable.cpp index 1981d000c3..22f792b5ec 100644 --- a/src/variable.cpp +++ b/src/variable.cpp @@ -39,7 +39,6 @@ #include #include #include -#include #include using namespace LAMMPS_NS; @@ -692,11 +691,11 @@ int Variable::next(int narg, char **arg) int seed = 12345 + universe->me + which[find(arg[0])]; if (!random) random = new RanMars(lmp,seed); int delay = (int) (1000000*random->uniform()); - usleep(delay); + platform::usleep(delay); while (1) { if (!rename("tmp.lammps.variable","tmp.lammps.variable.lock")) break; delay = (int) (1000000*random->uniform()); - usleep(delay); + platform::usleep(delay); } // if the file cannot be found, we may have a race with some @@ -719,7 +718,7 @@ int Variable::next(int narg, char **arg) break; } delay = (int) (1000000*random->uniform()); - usleep(delay); + platform::usleep(delay); } delete random; random = nullptr; diff --git a/src/write_coeff.cpp b/src/write_coeff.cpp index e030148901..6f53a97e8f 100644 --- a/src/write_coeff.cpp +++ b/src/write_coeff.cpp @@ -26,7 +26,6 @@ #include #include -#include using namespace LAMMPS_NS; @@ -170,8 +169,8 @@ void WriteCoeff::command(int narg, char **arg) } fclose(one); fclose(two); - unlink(file); + platform::unlink(file); } - delete [] file; + delete[] file; } diff --git a/src/write_restart.cpp b/src/write_restart.cpp index 7f73d868ff..4333fa5416 100644 --- a/src/write_restart.cpp +++ b/src/write_restart.cpp @@ -595,7 +595,7 @@ void WriteRestart::file_layout(int send_size) // this allows all ranks to compute offset to their data if (mpiioflag) { - if (me == 0) headerOffset = ftell(fp); + if (me == 0) headerOffset = platform::ftell(fp); MPI_Bcast(&headerOffset,1,MPI_LMP_BIGINT,0,world); } } diff --git a/tools/lammps-shell/lammps-shell.cpp b/tools/lammps-shell/lammps-shell.cpp index 2ee62df920..936b539d43 100644 --- a/tools/lammps-shell/lammps-shell.cpp +++ b/tools/lammps-shell/lammps-shell.cpp @@ -1,11 +1,12 @@ // LAMMPS Shell. An improved interactive LAMMPS session with // command line editing, history, TAB expansion and shell escapes -// Copyright (c) 2020 Axel Kohlmeyer +// Copyright (c) 2020, 2021 Axel Kohlmeyer // This software is distributed under the GNU General Public License. #include "library.h" +#include "platform.h" #include "utils.h" #include @@ -14,21 +15,12 @@ #include #include -#if !defined(_WIN32) -#include -#else +#if defined(_WIN32) #if !defined(WIN32_LEAN_AND_MEAN) #define WIN32_LEAN_AND_MEAN #endif -#include -#include #include -#define chdir(x) _chdir(x) -#define getcwd(buf, len) _getcwd(buf, len) -#define isatty(x) _isatty(x) -#endif - -#if !defined(_WIN32) +#else #include #endif @@ -41,10 +33,10 @@ using namespace LAMMPS_NS; -char *omp_threads = nullptr; -const int buflen = 512; -char buf[buflen]; void *lmp = nullptr; +char *omp_threads = nullptr; +constexpr int BUFLEN = 512; +char buf[BUFLEN]; enum { ATOM_STYLE, @@ -213,7 +205,7 @@ template char *style_generator(const char *text, int state) } while (idx < num) { - lammps_style_name(lmp, lmp_style[STYLE], idx, buf, buflen); + lammps_style_name(lmp, lmp_style[STYLE], idx, buf, BUFLEN); ++idx; if ((len == 0) || (strncmp(text, buf, len) == 0)) return dupstring(buf); } @@ -230,7 +222,7 @@ template char *id_generator(const char *text, int state) } while (idx < num) { - lammps_id_name(lmp, lmp_id[ID], idx, buf, buflen); + lammps_id_name(lmp, lmp_id[ID], idx, buf, BUFLEN); ++idx; if ((len == 0) || (strncmp(text, buf, len) == 0)) return dupstring(buf); } @@ -388,8 +380,8 @@ static char *plugin_name_generator(const char *text, int state) nmax = lammps_plugin_count(); while (idx < nmax) { - char style[buflen], name[buflen]; - lammps_plugin_name(idx, style, name, buflen); + char style[BUFLEN], name[BUFLEN]; + lammps_plugin_name(idx, style, name, BUFLEN); ++idx; if (words[2] == style) { if (strncmp(name, words[3].c_str(), len) == 0) @@ -474,7 +466,7 @@ char *group_generator(const char *text, int state) } while (idx < num) { - lammps_id_name(lmp, "group", idx, buf, buflen); + lammps_id_name(lmp, "group", idx, buf, BUFLEN); ++idx; if ((len == 0) || (strncmp(text, buf, len) == 0)) return dupstring(buf); } @@ -576,7 +568,7 @@ static void init_commands() // store optional commands from command styles ncmds = lammps_style_count(lmp, "command"); for (int i = 0; i < ncmds; ++i) { - if (lammps_style_name(lmp, "command", i, buf, buflen)) commands.push_back(buf); + if (lammps_style_name(lmp, "command", i, buf, BUFLEN)) commands.push_back(buf); } // store LAMMPS shell specific command names @@ -598,7 +590,7 @@ static void init_commands() // otherwise any tabs in redirected input will cause havoc. const char *test_mode = getenv("LAMMPS_SHELL_TESTING"); if (test_mode) std::cout << "*TESTING* using LAMMPS Shell in test mode *TESTING*\n"; - if (isatty(fileno(stdin)) || test_mode) { + if (platform::is_console(stdin) || test_mode) { rl_attempted_completion_function = cmd_completion; } else { rl_bind_key('\t', rl_insert); @@ -607,10 +599,11 @@ static void init_commands() // read saved history, but not in test mode. if (!test_mode) read_history(".lammps_history"); -#if !defined(_WIN32) - signal(SIGINT, ctrl_c_handler); -#else + // intercept CTRL-C +#if defined(_WIN32) SetConsoleCtrlHandler(ctrl_c_handler, TRUE); +#else + signal(SIGINT, ctrl_c_handler); #endif } @@ -684,7 +677,7 @@ static int shell_cmd(const std::string &cmd) free(text); return 0; } else if ((words[0] == "pwd") || ((words[0] == "cd") && (words.size() == 1))) { - if (getcwd(buf, buflen)) std::cout << buf << "\n"; + std::cout << platform::current_directory() << "\n"; free(text); return 0; } else if (words[0] == "cd") { @@ -740,28 +733,19 @@ int main(int argc, char **argv) #if defined(_WIN32) // Special hack for Windows: if the current working directory is // the "system folder" (because that is where cmd.exe lives) - // switch to the user's documents directory. Avoid buffer overflow - // and skip this step if the path is too long for our buffer. - if (getcwd(buf, buflen)) { - if ((strstr(buf, "System32") || strstr(buf, "system32"))) { - char *drive = getenv("HOMEDRIVE"); - char *path = getenv("HOMEPATH"); - buf[0] = '\0'; - int len = strlen("\\Documents"); - if (drive) len += strlen(drive); - if (path) len += strlen(path); - if (len < buflen) { - if (drive) strcat(buf, drive); - if (path) strcat(buf, path); - strcat(buf, "\\Documents"); - chdir(buf); - } - } + // switch to the user's documents directory. + + auto curdir = platform::current_directory(); + if (utils::strmatch(curdir,"[Ss]ystem32")) { + std::string docdir = getenv("HOMEDRIVE"); + docdir += getenv("HOMEPATH"); + docdir += "\\Documents"; + platform::chdir(docdir); } #endif - lammps_get_os_info(buf, buflen); - std::cout << "LAMMPS Shell version 1.1 OS: " << buf; + lammps_get_os_info(buf, BUFLEN); + std::cout << "LAMMPS Shell version 1.2 OS: " << buf; if (!lammps_config_has_exceptions()) std::cout << "WARNING: LAMMPS was compiled without exceptions\n" @@ -776,7 +760,7 @@ int main(int argc, char **argv) // to use the maximum number of threads available since this is // not intended to be run with MPI. omp_threads = dupstring(std::string("OMP_NUM_THREADS=" + std::to_string(nthreads))); - putenv(omp_threads); + platform::putenv(omp_threads); // handle the special case where the first argument is not a flag but a file // this happens for example when using file type associations on Windows. @@ -785,8 +769,8 @@ int main(int argc, char **argv) std::string input_file; if ((argc > 1) && (argv[1][0] != '-')) { --argc; - input_file = utils::path_basename(argv[1]); - chdir(utils::path_dirname(input_file).c_str()); + input_file = platform::path_basename(argv[1]); + platform::chdir(platform::path_dirname(input_file)); for (int i = 1; i < argc; ++i) argv[i] = argv[i + 1]; } diff --git a/tools/msi2lmp/src/SearchAndFill.c b/tools/msi2lmp/src/SearchAndFill.c index 1a85ee111f..ff05ff13d0 100644 --- a/tools/msi2lmp/src/SearchAndFill.c +++ b/tools/msi2lmp/src/SearchAndFill.c @@ -13,6 +13,10 @@ #include #include +#if defined(_WIN32) +#define strdup(x) _strdup(x) +#endif + static int blank_line(char *line) { while (*line != '\0') { diff --git a/unittest/commands/test_groups.cpp b/unittest/commands/test_groups.cpp index e238e630d5..0c8a7cd83c 100644 --- a/unittest/commands/test_groups.cpp +++ b/unittest/commands/test_groups.cpp @@ -316,7 +316,7 @@ int main(int argc, char **argv) MPI_Init(&argc, &argv); ::testing::InitGoogleMock(&argc, argv); - if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) + if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) std::cout << "Warning: using OpenMPI without exceptions. " "Death tests will be skipped\n"; diff --git a/unittest/commands/test_kim_commands.cpp b/unittest/commands/test_kim_commands.cpp index a70176cc92..183d333ab4 100644 --- a/unittest/commands/test_kim_commands.cpp +++ b/unittest/commands/test_kim_commands.cpp @@ -684,7 +684,7 @@ int main(int argc, char **argv) MPI_Init(&argc, &argv); ::testing::InitGoogleMock(&argc, argv); - if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) + if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) std::cout << "Warning: using OpenMPI without exceptions. " "Death tests will be skipped\n"; diff --git a/unittest/commands/test_lattice_region.cpp b/unittest/commands/test_lattice_region.cpp index 5fbabcf173..47b69a15e0 100644 --- a/unittest/commands/test_lattice_region.cpp +++ b/unittest/commands/test_lattice_region.cpp @@ -20,7 +20,6 @@ #include "lammps.h" #include "lattice.h" #include "region.h" -#include "utils.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -631,7 +630,7 @@ int main(int argc, char **argv) MPI_Init(&argc, &argv); ::testing::InitGoogleMock(&argc, argv); - if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) + if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) std::cout << "Warning: using OpenMPI without exceptions. " "Death tests will be skipped\n"; diff --git a/unittest/commands/test_reset_ids.cpp b/unittest/commands/test_reset_ids.cpp index 221859e5c3..c67f90b341 100644 --- a/unittest/commands/test_reset_ids.cpp +++ b/unittest/commands/test_reset_ids.cpp @@ -686,7 +686,7 @@ int main(int argc, char **argv) MPI_Init(&argc, &argv); ::testing::InitGoogleMock(&argc, argv); - if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) + if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) std::cout << "Warning: using OpenMPI without exceptions. " "Death tests will be skipped\n"; diff --git a/unittest/commands/test_simple_commands.cpp b/unittest/commands/test_simple_commands.cpp index 31acf6d460..0ad47f4e96 100644 --- a/unittest/commands/test_simple_commands.cpp +++ b/unittest/commands/test_simple_commands.cpp @@ -20,7 +20,6 @@ #include "input.h" #include "output.h" #include "update.h" -#include "utils.h" #include "variable.h" #include "../testing/core.h" @@ -217,7 +216,7 @@ TEST_F(SimpleCommandsTest, Quit) TEST_FAILURE(".*ERROR: Expected integer .*", command("quit xxx");); // the following tests must be skipped with OpenMPI due to using threads - if (Info::get_mpi_vendor() == "Open MPI") GTEST_SKIP(); + if (platform::mpi_vendor() == "Open MPI") GTEST_SKIP(); ASSERT_EXIT(command("quit"), ExitedWithCode(0), ""); ASSERT_EXIT(command("quit 9"), ExitedWithCode(9), ""); } @@ -528,7 +527,7 @@ int main(int argc, char **argv) MPI_Init(&argc, &argv); ::testing::InitGoogleMock(&argc, argv); - if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) + if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) std::cout << "Warning: using OpenMPI without exceptions. " "Death tests will be skipped\n"; diff --git a/unittest/commands/test_variables.cpp b/unittest/commands/test_variables.cpp index 9d8932d0f0..4f603df5ac 100644 --- a/unittest/commands/test_variables.cpp +++ b/unittest/commands/test_variables.cpp @@ -517,7 +517,7 @@ int main(int argc, char **argv) MPI_Init(&argc, &argv); ::testing::InitGoogleMock(&argc, argv); - if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) + if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) std::cout << "Warning: using OpenMPI without exceptions. " "Death tests will be skipped\n"; diff --git a/unittest/cplusplus/test_error_class.cpp b/unittest/cplusplus/test_error_class.cpp index 489b085b1b..f4f0d3b28b 100644 --- a/unittest/cplusplus/test_error_class.cpp +++ b/unittest/cplusplus/test_error_class.cpp @@ -128,7 +128,7 @@ int main(int argc, char **argv) MPI_Init(&argc, &argv); ::testing::InitGoogleMock(&argc, argv); - if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) + if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) std::cout << "Warning: using OpenMPI without exceptions. " "Death tests will be skipped\n"; diff --git a/unittest/cplusplus/test_lammps_class.cpp b/unittest/cplusplus/test_lammps_class.cpp index d25b232fa7..fa7f6b30a9 100644 --- a/unittest/cplusplus/test_lammps_class.cpp +++ b/unittest/cplusplus/test_lammps_class.cpp @@ -325,7 +325,7 @@ TEST_F(LAMMPS_kokkos, InitMembers) TEST(LAMMPS_init, OpenMP) { if (!LAMMPS::is_installed_pkg("OPENMP")) GTEST_SKIP(); - if (Info::get_openmp_info() == "OpenMP not enabled") GTEST_SKIP(); + if (platform::openmp_standard() == "OpenMP not enabled") GTEST_SKIP(); FILE *fp = fopen("in.lammps_empty", "w"); fputs("\n", fp); diff --git a/unittest/formats/test_file_operations.cpp b/unittest/formats/test_file_operations.cpp index 08baed2e54..bb26dff391 100644 --- a/unittest/formats/test_file_operations.cpp +++ b/unittest/formats/test_file_operations.cpp @@ -491,7 +491,7 @@ int main(int argc, char **argv) MPI_Init(&argc, &argv); ::testing::InitGoogleMock(&argc, argv); - if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) + if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) std::cout << "Warning: using OpenMPI without exceptions. " "Death tests will be skipped\n"; diff --git a/unittest/formats/test_molecule_file.cpp b/unittest/formats/test_molecule_file.cpp index 5a3e3ca750..2cca7a6832 100644 --- a/unittest/formats/test_molecule_file.cpp +++ b/unittest/formats/test_molecule_file.cpp @@ -17,7 +17,6 @@ #include "input.h" #include "lammps.h" #include "molecule.h" -#include "utils.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -257,7 +256,7 @@ int main(int argc, char **argv) MPI_Init(&argc, &argv); ::testing::InitGoogleMock(&argc, argv); - if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) + if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) std::cout << "Warning: using OpenMPI without exceptions. " "Death tests will be skipped\n"; diff --git a/unittest/formats/test_potential_file_reader.cpp b/unittest/formats/test_potential_file_reader.cpp index 5f7148b7e4..7cd61d25a4 100644 --- a/unittest/formats/test_potential_file_reader.cpp +++ b/unittest/formats/test_potential_file_reader.cpp @@ -326,7 +326,7 @@ int main(int argc, char **argv) MPI_Init(&argc, &argv); ::testing::InitGoogleMock(&argc, argv); - if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) + if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) std::cout << "Warning: using OpenMPI without exceptions. " "Death tests will be skipped\n"; diff --git a/unittest/formats/test_text_file_reader.cpp b/unittest/formats/test_text_file_reader.cpp index 4e1f608d25..f0f695ae54 100644 --- a/unittest/formats/test_text_file_reader.cpp +++ b/unittest/formats/test_text_file_reader.cpp @@ -160,7 +160,7 @@ int main(int argc, char **argv) MPI_Init(&argc, &argv); ::testing::InitGoogleMock(&argc, argv); - if (Info::get_mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) + if (platform::mpi_vendor() == "Open MPI" && !LAMMPS_NS::Info::has_exceptions()) std::cout << "Warning: using OpenMPI without exceptions. " "Death tests will be skipped\n"; diff --git a/unittest/testing/core.h b/unittest/testing/core.h index 6867d88587..c922e96cc0 100644 --- a/unittest/testing/core.h +++ b/unittest/testing/core.h @@ -17,6 +17,7 @@ #include "info.h" #include "input.h" #include "lammps.h" +#include "platform.h" #include "variable.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -36,7 +37,7 @@ using ::testing::MatchesRegex; auto mesg = ::testing::internal::GetCapturedStdout(); \ ASSERT_THAT(mesg, MatchesRegex(errmsg)); \ } else { \ - if (Info::get_mpi_vendor() != "Open MPI") { \ + if (platform::mpi_vendor() != "Open MPI") { \ ::testing::internal::CaptureStdout(); \ ASSERT_DEATH({__VA_ARGS__}, ""); \ auto mesg = ::testing::internal::GetCapturedStdout(); \ diff --git a/unittest/utils/CMakeLists.txt b/unittest/utils/CMakeLists.txt index c1ce7c136f..9f708861cc 100644 --- a/unittest/utils/CMakeLists.txt +++ b/unittest/utils/CMakeLists.txt @@ -13,7 +13,25 @@ add_test(ArgUtils test_argutils) add_executable(test_utils test_utils.cpp) target_link_libraries(test_utils PRIVATE lammps GTest::GMockMain GTest::GMock GTest::GTest) add_test(Utils test_utils) -set_tests_properties(Utils PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}") + +add_executable(test_platform test_platform.cpp) +target_link_libraries(test_platform PRIVATE lammps GTest::GMockMain GTest::GMock GTest::GTest) +add_test(Platform test_platform) + +set_tests_properties(Utils Platform PROPERTIES + ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}") + +if(BUILD_SHARED_LIBS) + enable_language(C) + add_library(testsharedobj MODULE testshared.c) + set_target_properties(testsharedobj PROPERTIES PREFIX "" WINDOWS_EXPORT_ALL_SYMBOLS TRUE) + add_library(testsharedlib SHARED testshared.c) + set_target_properties(testsharedlib PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE) + add_dependencies(test_platform testsharedobj testsharedlib) + target_compile_definitions(test_platform PRIVATE TEST_SHARED_LOAD=1 + TEST_SHARED_LIB=$ + TEST_SHARED_OBJ=$) +endif() add_executable(test_fmtlib test_fmtlib.cpp) target_link_libraries(test_fmtlib PRIVATE lammps GTest::GMockMain GTest::GMock GTest::GTest) diff --git a/unittest/utils/test_platform.cpp b/unittest/utils/test_platform.cpp new file mode 100644 index 0000000000..0f39534c31 --- /dev/null +++ b/unittest/utils/test_platform.cpp @@ -0,0 +1,402 @@ + +#include "platform.h" +#include "utils.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include + +using namespace LAMMPS_NS; +using testing::EndsWith; +using testing::Eq; +using testing::IsEmpty; +using testing::StartsWith; +using testing::StrEq; + +TEST(Platform, clock) +{ + const double wt_start = platform::walltime(); + const double ct_start = platform::cputime(); + + // spend some time computing pi + constexpr double known_pi = 3.141592653589793238462643; + constexpr int n = 10000000; + constexpr double h = 1.0 / (double)n; + double my_pi = 0.0, x; + for (int i = 0; i < n; ++i) { + x = h * ((double)i + 0.5); + my_pi += 4.0 / (1.0 + x * x); + } + my_pi *= h; + const double wt_used = platform::walltime() - wt_start; + const double ct_used = platform::cputime() - ct_start; + + ASSERT_NEAR(my_pi, known_pi, 1e-12); + ASSERT_GT(wt_used, 1e-4); + ASSERT_GT(ct_used, 1e-4); +} + +TEST(Platform, putenv) +{ + const char *var = getenv("UNITTEST_VAR1"); + ASSERT_EQ(var, nullptr); + int rv = platform::putenv("UNITTEST_VAR1"); + var = getenv("UNITTEST_VAR1"); + ASSERT_EQ(rv, 0); + ASSERT_NE(var, nullptr); + // we cannot set environment variables without a value on windows with _putenv() +#if defined(_WIN32) + ASSERT_THAT(var, StrEq("1")); +#else + ASSERT_THAT(var, StrEq("")); +#endif + + rv = platform::putenv("UNITTEST_VAR1=one"); + var = getenv("UNITTEST_VAR1"); + ASSERT_EQ(rv, 0); + ASSERT_NE(var, nullptr); + ASSERT_THAT(var, StrEq("one")); + + rv = platform::putenv("UNITTEST_VAR1=one=two"); + var = getenv("UNITTEST_VAR1"); + ASSERT_EQ(rv, 0); + ASSERT_NE(var, nullptr); + ASSERT_THAT(var, StrEq("one=two")); + + ASSERT_EQ(platform::putenv(""), -1); +} + +TEST(Platform, list_pathenv) +{ + auto dirs = platform::list_pathenv("PATH"); + ASSERT_GT(dirs.size(), 1); +} + +TEST(Platform, find_cmd_path) +{ +#if defined(_WIN32) + ASSERT_THAT(platform::find_exe_path("notepad"), EndsWith("\\notepad.exe")); + ASSERT_THAT(platform::find_exe_path("cmd"), EndsWith("\\cmd.exe")); + ASSERT_THAT(platform::find_exe_path("some_bogus_command"), IsEmpty()); +#else + ASSERT_THAT(platform::find_exe_path("ls"), EndsWith("bin/ls")); + ASSERT_THAT(platform::find_exe_path("sh"), EndsWith("bin/sh")); + ASSERT_THAT(platform::find_exe_path("some_bogus_command"), IsEmpty()); +#endif +} + +#if defined(TEST_SHARED_LOAD) +#define stringify(s) mkstring(s) +#define mkstring(s) #s +TEST(Platform, sharedload) +{ + const std::vector objs = {stringify(TEST_SHARED_OBJ), stringify(TEST_SHARED_LIB)}; + const int *intvar; + const double *doublevar; + void *handle; + int (*intfunc)(int); + double (*doublefunc)(double, int); + + for (const auto &obj : objs) { + handle = platform::dlopen(obj.c_str()); + EXPECT_NE(handle, nullptr); + intvar = (int *)platform::dlsym(handle, "some_int_val"); + EXPECT_NE(intvar, nullptr); + EXPECT_EQ(*intvar, 12345); + doublevar = (double *)platform::dlsym(handle, "some_double_val"); + EXPECT_NE(doublevar, nullptr); + EXPECT_DOUBLE_EQ(*doublevar, 6.78e-9); + intfunc = (int (*)(int))platform::dlsym(handle, "some_int_function"); + EXPECT_NE(intfunc, nullptr); + EXPECT_EQ((*intfunc)(12), 144); + doublefunc = (double (*)(double, int))platform::dlsym(handle, "some_double_function"); + EXPECT_NE(doublefunc, nullptr); + EXPECT_DOUBLE_EQ((*doublefunc)(0.5, 6), 3.0); + EXPECT_EQ(platform::dlsym(handle, "some_nonexisting_symbol"), nullptr); + EXPECT_EQ(platform::dlclose(handle), 0); + } +} +#undef stringify +#undef mkstring +#endif + +TEST(Platform, guesspath) +{ + char buf[256]; + FILE *fp = fopen("test_guesspath.txt", "w"); +#if defined(__linux__) || defined(__APPLE__) || defined(_WIN32) + const char *path = platform::guesspath(fp, buf, sizeof(buf)); + ASSERT_THAT(path, EndsWith("test_guesspath.txt")); +#else + const char *path = platform::guesspath(fp, buf, sizeof(buf)); + ASSERT_THAT(path, EndsWith("(unknown)")); +#endif + fclose(fp); + platform::unlink("test_guesspath.txt"); +} + +TEST(Platform, unlink) +{ + const char test[] = "12345678901234567890"; + platform::unlink("unlink.dat"); + ASSERT_EQ(platform::unlink("dummy.dat"), -1); + FILE *fp = fopen("unlink.dat", "w"); + fwrite(test, sizeof(test), 1, fp); + fclose(fp); + ASSERT_EQ(platform::unlink("unlink.dat"), 0); + ASSERT_EQ(platform::unlink("unlink.dat"), -1); + fp = fopen("unlink.dat", "r"); + ASSERT_EQ(fp, nullptr); + + platform::mkdir("unlink.dir"); + ASSERT_EQ(platform::unlink("unlink.dir"), -1); + platform::rmdir("unlink.dir"); +} + +TEST(Platform, fseek_ftell) +{ + const char test[] = "12345678901234567890"; + platform::unlink("seek_tell.dat"); + FILE *fp = fopen("seek_tell.dat", "w"); + fwrite(test, sizeof(test), 1, fp); + fflush(fp); + ASSERT_EQ(platform::ftell(fp), sizeof(test)); + fclose(fp); + fp = fopen("seek_tell.dat", "r+"); + ASSERT_EQ(fgetc(fp), '1'); + ASSERT_EQ(fgetc(fp), '2'); + ASSERT_EQ(platform::ftell(fp), 2); + ASSERT_EQ(platform::fseek(fp, 15), 0); + ASSERT_EQ(fgetc(fp), '6'); + fflush(fp); + ASSERT_EQ(platform::fseek(fp, platform::END_OF_FILE), 0); + ASSERT_EQ(platform::ftell(fp), 21); + ASSERT_EQ(platform::fseek(fp, 20), 0); + ASSERT_EQ(fgetc(fp), 0); + ASSERT_EQ(platform::ftell(fp), 21); + fclose(fp); + platform::unlink("seek_tell.dat"); +} + +TEST(Platform, ftruncate) +{ + platform::unlink("truncate.dat"); + FILE *fp = fopen("truncate.dat", "w"); + fputs("header one\n", fp); + fputs("header two\n", fp); + fflush(fp); + bigint filepos = platform::ftell(fp); + fputs("line one\n", fp); + fputs("line two\n", fp); + fputs("line three\n", fp); + fflush(fp); + ASSERT_EQ(platform::ftruncate(fp, filepos), 0); + fputs("line four\n", fp); + ASSERT_GT(platform::ftell(fp), filepos); + fputs("line five\n", fp); + fflush(fp); + fclose(fp); + + // check file + fp = fopen("truncate.dat", "r"); + char buf[128]; + char *ptr = fgets(buf, 127, fp); + ASSERT_THAT(ptr, StartsWith("header one")); + ptr = fgets(buf, 127, fp); + ASSERT_THAT(ptr, StartsWith("header two")); + ptr = fgets(buf, 127, fp); + ASSERT_THAT(ptr, StartsWith("line four")); + ptr = fgets(buf, 127, fp); + ASSERT_THAT(ptr, StartsWith("line five")); + ptr = fgets(buf, 127, fp); + ASSERT_EQ(ptr, nullptr); + fclose(fp); + platform::unlink("truncate.dat"); +} + +TEST(Platform, path_basename) +{ +#if defined(_WIN32) + ASSERT_THAT(platform::path_basename("c:\\parent\\folder\\filename"), Eq("filename")); + ASSERT_THAT(platform::path_basename("folder\\"), Eq("")); + ASSERT_THAT(platform::path_basename("c:/parent/folder/filename"), Eq("filename")); +#else + ASSERT_THAT(platform::path_basename("/parent/folder/filename"), Eq("filename")); + ASSERT_THAT(platform::path_basename("/parent/folder/"), Eq("")); +#endif +} + +TEST(Platform, path_dirname) +{ +#if defined(_WIN32) + ASSERT_THAT(platform::path_dirname("c:/parent/folder/filename"), Eq("c:/parent/folder")); + ASSERT_THAT(platform::path_dirname("c:\\parent\\folder\\filename"), Eq("c:\\parent\\folder")); + ASSERT_THAT(platform::path_dirname("c:filename"), Eq(".")); +#else + ASSERT_THAT(platform::path_dirname("/parent/folder/filename"), Eq("/parent/folder")); +#endif + ASSERT_THAT(platform::path_dirname("filename"), Eq(".")); +} + +TEST(Platform, path_join) +{ +#if defined(_WIN32) + ASSERT_THAT(platform::path_join("c:\\folder", "filename"), Eq("c:\\folder\\filename")); + ASSERT_THAT(platform::path_join("c:\\folder\\", "filename"), Eq("c:\\folder\\filename")); + ASSERT_THAT(platform::path_join("c:\\folder", "\\filename"), Eq("c:\\folder\\filename")); + ASSERT_THAT(platform::path_join("c:\\folder\\", "\\filename"), Eq("c:\\folder\\filename")); + ASSERT_THAT(platform::path_join("c:\\folder", "/filename"), Eq("c:\\folder\\filename")); + ASSERT_THAT(platform::path_join("c:\\folder\\\\", "\\filename"), Eq("c:\\folder\\filename")); + ASSERT_THAT(platform::path_join("c:\\folder\\", "\\\\filename"), Eq("c:\\folder\\filename")); + ASSERT_THAT(platform::path_join("c:\\folder/\\", "/\\filename"), Eq("c:\\folder\\filename")); + ASSERT_THAT(platform::path_join("c:\\folder\\/", "\\/filename"), Eq("c:\\folder\\filename")); + ASSERT_THAT(platform::path_join("c:\\folder", ""), Eq("c:\\folder")); + ASSERT_THAT(platform::path_join("", "\\/filename"), Eq("\\/filename")); +#else + ASSERT_THAT(platform::path_join("/parent/folder", "filename"), Eq("/parent/folder/filename")); + ASSERT_THAT(platform::path_join("/parent/folder/", "filename"), Eq("/parent/folder/filename")); + ASSERT_THAT(platform::path_join("/parent/folder", "/filename"), Eq("/parent/folder/filename")); + ASSERT_THAT(platform::path_join("/parent/folder/", "/filename"), Eq("/parent/folder/filename")); + ASSERT_THAT(platform::path_join("/parent/folder//", "filename"), Eq("/parent/folder/filename")); + ASSERT_THAT(platform::path_join("/parent/folder", "//filename"), Eq("/parent/folder/filename")); + ASSERT_THAT(platform::path_join("/parent/folder///", "/filename"), + Eq("/parent/folder/filename")); + ASSERT_THAT(platform::path_join("/parent/folder/", "///filename"), + Eq("/parent/folder/filename")); + ASSERT_THAT(platform::path_join("/parent/folder/", ""), Eq("/parent/folder/")); + ASSERT_THAT(platform::path_join("", "\\/filename"), Eq("\\/filename")); +#endif +} + +TEST(Platform, is_console) +{ + platform::unlink("file_is_no_console.txt"); + FILE *fp = fopen("file_is_no_console.txt", "w"); + fputs("some text\n", fp); + EXPECT_FALSE(platform::is_console(fp)); + fclose(fp); + platform::unlink("file_is_no_console.txt"); +} + +TEST(Platform, path_and_directory) +{ + platform::unlink("path_is_directory"); + platform::rmdir("path_is_directory"); + platform::unlink("path_is_file"); + platform::mkdir("path_is_directory"); + FILE *fp = fopen("path_is_file", "w"); + fputs("some text\n", fp); + fclose(fp); + + ASSERT_TRUE(platform::path_is_directory("path_is_directory")); + ASSERT_FALSE(platform::path_is_directory("path_is_file")); + ASSERT_FALSE(platform::path_is_directory("path_does_not_exist")); + platform::unlink("path_is_file"); + +#if defined(_WIN32) + fp = fopen("path_is_directory\\path_is_file", "w"); +#else + fp = fopen("path_is_directory/path_is_file", "w"); +#endif + fputs("some text\n", fp); + fclose(fp); +#if defined(_WIN32) + platform::mkdir("path_is_directory\\path_is_directory"); + fp = fopen("path_is_directory\\path_is_other_file", "w"); +#else + platform::mkdir("path_is_directory/path_is_directory"); + fp = fopen("path_is_directory/path_is_other_file", "w"); +#endif + fputs("some text\n", fp); + fclose(fp); + auto dirs = platform::list_directory("path_is_directory"); + ASSERT_EQ(dirs.size(), 3); + platform::rmdir("path_is_directory"); + ASSERT_FALSE(platform::path_is_directory("path_is_directory")); +} + +TEST(Platform, get_change_directory) +{ + platform::unlink("working_directory"); + platform::rmdir("working_directory"); + + auto cwd = platform::current_directory(); + ASSERT_GT(cwd.size(), 0); + + platform::mkdir("working_directory"); + ASSERT_EQ(platform::chdir("working_directory"), 0); + ASSERT_THAT(platform::current_directory(), EndsWith("working_directory")); + + ASSERT_EQ(platform::chdir(".."), 0); + ASSERT_THAT(platform::current_directory(), StrEq(cwd)); + platform::rmdir("working_directory"); +} + +TEST(Platform, file_is_readable) +{ + platform::unlink("file_is_readable.txt"); + FILE *fp = fopen("file_is_readable.txt", "w"); + fputs("some text\n", fp); + fclose(fp); + + ASSERT_TRUE(platform::file_is_readable("file_is_readable.txt")); + ASSERT_FALSE(platform::file_is_readable("file_does_not_exist.txt")); + platform::unlink("file_is_readable.txt"); + + // windows does not have permission flags +#if !defined(_WIN32) + platform::unlink("file_is_not_readable.txt"); + fp = fopen("file_is_not_readable.txt", "w"); + fputs("some text\n", fp); + fclose(fp); + chmod("file_is_not_readable.txt", 0); + ASSERT_FALSE(platform::file_is_readable("file_is_not_readable.txt")); + platform::unlink("file_is_not_readable.txt"); +#endif +} + +TEST(Platform, has_compress_extension) +{ + ASSERT_FALSE(platform::has_compress_extension("dummy")); + ASSERT_FALSE(platform::has_compress_extension("dum.my")); + ASSERT_TRUE(platform::has_compress_extension("dummy.gz")); + ASSERT_TRUE(platform::has_compress_extension("dummy.bz2")); + ASSERT_TRUE(platform::has_compress_extension("dummy.zst")); + ASSERT_TRUE(platform::has_compress_extension("dummy.xz")); + ASSERT_TRUE(platform::has_compress_extension("dummy.lzma")); + ASSERT_TRUE(platform::has_compress_extension("dummy.lz4")); +} + +TEST(Platform, compress_read_write) +{ + const std::vector test_files = {"zip_test.zip", "zip_test.gz", "zip_test.bz2", + "zip_test.zst", "zip_test.xz", "zip_test.lzma", + "zip_test.lz4", "zip_test.unk", "zip test.gz"}; + for (const auto &file : test_files) { + platform::unlink(file); + FILE *fp = platform::compressed_write(file); + if (!fp) { + platform::unlink(file); + continue; + } + + clearerr(fp); + fputs("line one\n", fp); + fputs("line two\n", fp); + ASSERT_EQ(ferror(fp), 0); + fflush(fp); + platform::pclose(fp); + + fp = platform::compressed_read(file); + ASSERT_NE(fp, nullptr); + char buf[128]; + char *ptr = fgets(buf, 128, fp); + EXPECT_THAT(ptr, StartsWith("line one")); + ptr = fgets(buf, 128, fp); + EXPECT_THAT(ptr, StartsWith("line two")); + ASSERT_EQ(ferror(fp), 0); + platform::pclose(fp); + platform::unlink(file); + } +} diff --git a/unittest/utils/test_utils.cpp b/unittest/utils/test_utils.cpp index e0bc4984cc..72a90a95a0 100644 --- a/unittest/utils/test_utils.cpp +++ b/unittest/utils/test_utils.cpp @@ -13,14 +13,12 @@ #include "lmptype.h" #include "pointers.h" -#include "utils.h" #include "tokenizer.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include -#include #include #include @@ -66,6 +64,14 @@ TEST(Utils, trim) ASSERT_THAT(trimmed, StrEq("")); } +TEST(Utils, casemod) +{ + ASSERT_THAT(utils::lowercase("Gba35%*zAKgRvr"), StrEq("gba35%*zakgrvr")); + ASSERT_THAT(utils::lowercase("A BC DEFG"), StrEq("a bc defg")); + ASSERT_THAT(utils::uppercase("Gba35%*zAKgRvr"), StrEq("GBA35%*ZAKGRVR")); + ASSERT_THAT(utils::uppercase("a bc defg"), StrEq("A BC DEFG")); +} + TEST(Utils, trim_comment) { auto trimmed = utils::trim_comment("some text # comment"); @@ -721,54 +727,6 @@ TEST(Utils, boundsbig_case3) ASSERT_EQ(nhi, -1); } -TEST(Utils, guesspath) -{ - char buf[256]; - FILE *fp = fopen("test_guesspath.txt", "w"); -#if defined(__linux__) || defined(__APPLE__) || defined(_WIN32) - const char *path = utils::guesspath(buf, sizeof(buf), fp); - ASSERT_THAT(path, EndsWith("test_guesspath.txt")); -#else - const char *path = utils::guesspath(buf, sizeof(buf), fp); - ASSERT_THAT(path, EndsWith("(unknown)")); -#endif - fclose(fp); -} - -TEST(Utils, path_join) -{ -#if defined(_WIN32) - ASSERT_THAT(utils::path_join("c:\\parent\\folder", "filename"), - Eq("c:\\parent\\folder\\filename")); -#else - ASSERT_THAT(utils::path_join("/parent/folder", "filename"), Eq("/parent/folder/filename")); -#endif -} - -TEST(Utils, path_basename) -{ -#if defined(_WIN32) - ASSERT_THAT(utils::path_basename("c:\\parent\\folder\\filename"), Eq("filename")); - ASSERT_THAT(utils::path_basename("folder\\"), Eq("")); - ASSERT_THAT(utils::path_basename("c:/parent/folder/filename"), Eq("filename")); -#else - ASSERT_THAT(utils::path_basename("/parent/folder/filename"), Eq("filename")); - ASSERT_THAT(utils::path_basename("/parent/folder/"), Eq("")); -#endif -} - -TEST(Utils, path_dirname) -{ -#if defined(_WIN32) - ASSERT_THAT(utils::path_dirname("c:/parent/folder/filename"), Eq("c:/parent/folder")); - ASSERT_THAT(utils::path_dirname("c:\\parent\\folder\\filename"), Eq("c:\\parent\\folder")); - ASSERT_THAT(utils::path_dirname("c:filename"), Eq(".")); -#else - ASSERT_THAT(utils::path_dirname("/parent/folder/filename"), Eq("/parent/folder")); -#endif - ASSERT_THAT(utils::path_dirname("filename"), Eq(".")); -} - TEST(Utils, getsyserror) { #if defined(__linux__) @@ -792,16 +750,16 @@ TEST(Utils, potential_file) fputs("# CONTRIBUTOR: Pippo\n", fp); fclose(fp); - ASSERT_TRUE(utils::file_is_readable("ctest1.txt")); - ASSERT_TRUE(utils::file_is_readable("ctest2.txt")); - ASSERT_FALSE(utils::file_is_readable("no_such_file.txt")); + ASSERT_TRUE(platform::file_is_readable("ctest1.txt")); + ASSERT_TRUE(platform::file_is_readable("ctest2.txt")); + ASSERT_FALSE(platform::file_is_readable("no_such_file.txt")); ASSERT_THAT(utils::get_potential_file_path("ctest1.txt"), Eq("ctest1.txt")); ASSERT_THAT(utils::get_potential_file_path("no_such_file.txt"), Eq("")); const char *folder = getenv("LAMMPS_POTENTIALS"); if (folder != nullptr) { - std::string path = utils::path_join(folder, "Cu_u3.eam"); + std::string path = platform::path_join(folder, "Cu_u3.eam"); EXPECT_THAT(utils::get_potential_file_path("Cu_u3.eam"), Eq(path)); EXPECT_THAT(utils::get_potential_units(path, "EAM"), Eq("metal")); } diff --git a/unittest/utils/testshared.c b/unittest/utils/testshared.c new file mode 100644 index 0000000000..869be91c2a --- /dev/null +++ b/unittest/utils/testshared.c @@ -0,0 +1,20 @@ +/* file for testing loading of shared objects and libraries */ + +int some_int_val = 12345; +double some_double_val = 6.78e-9; + +int some_int_function(int arg) +{ + return arg*arg; +} + +double some_double_function(double arg1, int arg2) +{ + double sum = 0; + for (int i = 0; i < arg2; ++i) + sum += arg1; + return sum; +} + + +