diff --git a/.github/release_steps.md b/.github/release_steps.md index 71388e115a..857acfdb85 100644 --- a/.github/release_steps.md +++ b/.github/release_steps.md @@ -28,14 +28,14 @@ Create a 'next\_release' branch off 'develop' and make the following changes: ..versionadded:: or ..versionchanged:: are missing and need to be added -Submit this pull request, rebase if needed. This is the last pull -request merged for the release and should not contain any other -changes. (Exceptions: this document, last minute trivial(!) changes). +Submit this pull request. This is the last pull request merged for the +release and should not contain any other changes. (Exceptions: this +document, last minute trivial(!) changes). This PR shall not be merged before **all** pending tests have completed and cleared. We currently use a mix of automated tests running on either Temple's Jenkins cluster or GitHub workflows. Those include time -consuming tests not run on pull requests. If needed, a bugfix pull +consuming tests not run on pull requests. If needed, a bug-fix pull request should be created and merged to clear all tests. ### Create release on GitHub @@ -56,7 +56,7 @@ git pull git checkout release git pull git merge --ff-only develop -git tag -s -m "LAMMPS feature release 19 November 2024" patch_19Nov2024 +git tag -s -m "LAMMPS feature release 4 February 2025" patch_4Feb2025 git push git@github.com:lammps/lammps.git --tags develop release ``` @@ -77,7 +77,7 @@ release page with a summary of all the changes included and references to the pull requests they were merged from or check the existing draft for any necessary changes from pull requests that were merged but are not listed. Then select the applied tag for the release in the "Choose -a tag" dropdown list. Go to the bottom of the list and select the "Set +a tag" drop-down list. Go to the bottom of the list and select the "Set as pre-release" checkbox. The "Set as the latest release" button is reserved for stable releases and updates to them. @@ -87,12 +87,18 @@ you can return to edit the release page and publish it. ### Prepare pre-compiled packages, update packages to GitHub -Build a fully static LAMMPS installation using a musl-libc -cross-compiler, install into a lammps-static folder, and create a -tarball called lammps-linux-x86_64-19Nov2024.tar.gz (or using a -corresponding date with a future release) from the lammps-static folder. A suitable build environment is provided with the -https://download.lammps.org/static/fedora37_musl.sif container image. +https://download.lammps.org/static/fedora41_musl_mingw.sif container +image. The corresponding container build definition file is maintained +in the tools/singularity folder of the LAMMPS source distribution. + +#### Fully portable static Linux x86_64 non-MPI binaries + +The following commands use the Fedora container to build a fully static +LAMMPS installation using a musl-libc cross-compiler, install it into a +`lammps-static` folder, and create a tarball called +`lammps-linux-x86_64-4Feb2025.tar.gz` (or using a corresponding date +with a future release) from the `lammps-static` folder. ``` sh rm -rf release-packages @@ -105,49 +111,173 @@ cmake -S lammps-release/cmake -B build-release -G Ninja -D CMAKE_INSTALL_PREFIX= cmake --build build-release --target all cmake --build build-release --target install /usr/musl/bin/x86_64-linux-musl-strip lammps-static/bin/* -tar -czvvf lammps-linux-x86_64-19Nov2024.tar.gz lammps-static +tar -czvvf ../lammps-linux-x86_64-4Feb2025.tar.gz lammps-static exit # fedora 41 container +cd .. ``` The resulting tar archive can be uploaded to the GitHub release page with: -``` -gh release upload patch_19Nov2024 lammps-linux-x86_64-19Nov2024.tar.gz +``` sh +gh release upload patch_4Feb2025 lammps-linux-x86_64-4Feb2025.tar.gz ``` +#### Linux x86_64 Flatpak bundle with GUI included + Make sure you have the `flatpak` and `flatpak-builder` packages -installed locally (they cannot be used from the container) and build a +installed locally (they require binaries that run with elevated +privileges and thus cannot be used from the container) and build a LAMMPS and LAMMPS-GUI flatpak bundle in the `release-packages` folder with: ``` sh +cd release-packages flatpak --user remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo flatpak-builder --force-clean --verbose --repo=$PWD/flatpak-repo --install-deps-from=flathub --state-dir=$PWD --user --ccache --default-branch=release flatpak-build lammps-release/tools/lammps-gui/org.lammps.lammps-gui.yml -flatpak build-bundle --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo --verbose $PWD/flatpak-repo LAMMPS-Linux-x86_64-GUI-19Nov2024.flatpak org.lammps.lammps-gui release +flatpak build-bundle --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo --verbose $PWD/flatpak-repo ../LAMMPS-Linux-x86_64-GUI-4Feb2025.flatpak org.lammps.lammps-gui release +cd .. ``` The resulting flatpak bundle file can be uploaded to the GitHub release page with: -``` -gh release upload patch_19Nov2024 LAMMPS-Linux-x86_64-GUI-19Nov2024.flatpak +``` sh +gh release upload patch_4Feb2025 LAMMPS-Linux-x86_64-GUI-4Feb2025.flatpak ``` -Also build serial executable packages that also include LAMMPS-GUI for -Linux, macOS, and Windows, and upload them to the GitHub release. +#### LAMMPS Source tarball -Clean up: +The container for the static binary can also be used to prepare the source +tarball including the HTML and PDF manual (this is currently done automatically +when the releases is created and the tarball uploaded to https://download.lammps.org/tars/). +The steps are as follows: + +``` sh +cd release-packages +apptainer shell fedora41_musl_mingw.sif +cd lammps-release +rm -f ../release.tar* +git archive --output=../release.tar --prefix=lammps-4Feb2025/ HEAD +cd doc +make clean-all +make html pdf +tar -rf ../../release.tar --transform 's,^,lammps-4Feb2025/doc/,' html Manual.pdf +gzip -9v ../../release.tar +mv ../../release.tar.gz ../../lammps-src-4Feb2025.tar.gz +exit # fedora41 container +cd .. +``` + +The resulting source tarball can be uploaded to the GitHub release page with: + +``` sh +gh release upload patch_4Feb2025 lammps-src-4Feb2025.tar.gz +``` + +#### Build Windows Installer Packages with MinGW Linux-to-Windows Cross-compiler + +The various Windows installer packages can also be built with +apptainer container image. + +``` sh +cd release-packages +apptainer shell fedora41_musl_mingw.sif +git clone --depth 10 https://github.com/lammps/lammps-packages.git lammps-packages +cd lammps-packages/mingw-cross +ln -sf ../../lammps-release lammps +./buildall.sh release >& mk.log & less +F mk.log +``` + +The installer with the GUI included can be uploaded to the GitHub release page with: + +``` sh +ln -sf LAMMPS-64bit-GUI-4Feb2025.exe LAMMPS-Win10-64bit-GUI-4Feb2025.exe +gh release upload patch_4Feb2025 LAMMPS-Win10-64bit-GUI-4Feb2025.exe +``` + +The symbolic link is used to have a consistent naming scheme for the packages +attached to the GitHub release page. + +#### Clean up: ``` sh cd .. rm -r release-packages ``` -TODO: -- add detailed commands for building GUI packages on Ubuntu 20.04LTS (move to 22.04LTS?), - macOS, and Windows cross-compiler and upload to GitHub -- build all Windows cross-compiled installer packages using lammps-packages repo +#### Build Multi-arch App-bundle for macOS -### Update download website +Building app-bundles for macOS is not as easily automated and portable +as some of the other steps. It requires a machine actually running +macOS. In that machine the Xcode compiler package needs to be +installed. This also includes tools for building and manipulating disk +images. This compiler supports building executables for both, the +x86_64 and the arm64 architectures. This requires building with CMake +and using the CMake settings: + +``` sh +-D CMAKE_OSX_ARCHITECTURES=arm64;x86_64 +-D CMAKE_OSX_DEPLOYMENT_TARGER=11.0 +``` + +This will add the compiler flags `-arch arm64 -arch x86_64 +-mmacosx-version-min=11.0` and thus produce object for both +architectures and support for macOS versions back to version 11 (aka Big +Sur). With these settings the following libraries should be compiled +and installed (e.g. to `$HOME/.local`) as static libraries only: +- libomp taken from the LLVM/Clang source distribution (to support OpenMP) +- jpeg +- zlib +- png +- Qt (for LAMMPS-GUI) + +When configuring LAMMPS the `cmake/presets/clang.cmake` should be used +and as many packages as possible enabled. For LAMMPS-GUI, MPI should be +disabled with `-D BUILD_MPI=OFF` and LAMMPS-GUI enabled with +`-D BUILD_LAMMPS_GUI=ON`. If the CMake configuration is successful, +settings for building a macOS app-bundle are enabled and with `cmake +--build build --target dmg` extra steps will be executed that will build +a macOS application installer image under the name +`LAMMPS_GUI-macOS-multiarch-4Feb2025.dmg` + +The application image can be uploaded to the GitHub release page with: + +``` sh +ln -sf LAMMPS_GUI-macOS-multiarch-4Feb2025.dmg LAMMPS-macOS-multiarch-GUI-4Feb2025.dmg +gh release upload patch_4Feb2025 LAMMPS-macOS-multiarch-GUI-4Feb2025.dmg +``` + +The symbolic link is used to have a consistent naming scheme for the packages +attached to the GitHub release page. + +We are currently building the application images on macOS 12 (aka Monterey). + +#### Build Linux x86_64 binary tarball on Ubuntu 20.04LTS + +While the flatpak Linux version uses portable runtime libraries provided +by the flatpak environment, we also build regular Linux executables that +use a wrapper script and matching shared libraries in a tarball. To be +compatible with many Linux distributions, one has to build this on a +very old Linux distribution, since most Linux system libraries are +usually backward compatible but not forward compatible. This is +currently done on an Ubuntu 20.04LTS system. Once LAMMPS moves to +require CMake 3.20 and C++17, we will have to move to Ubuntu 22.04LTS. +This installation (either on a real or a virtual machine) should have +the packages installed that are indicated in +`tools/singularity/ubuntu20.04.def` plus Qt version 5.x with development +headers, so that LAMMPS-GUI can be compiled. + +Also the building of the binary tarball and setup of the bundled +libraries and wrapper scripts is automated and can executed with `cmake +--build build --target tgz`. This should produce a file +`LAMMPS_GUI-Linux-amd64-4Feb2025.tar.gz` which can be uploaded to the +GitHub release page with: + +``` sh +ln -sf LAMMPS_GUI-Linux-amd64-4Feb2025.tar.gz LAMMPS-Linux-x86_64-GUI-4Feb2025.tar.gz +gh release upload patch_4Feb2025 LAMMPS-Linux-x86_64-GUI-4Feb2025.tar.gz +``` + +### Update download page on LAMMPS website Check out the LAMMPS website repo https://github.com/lammps/lammps-website.git and edit the file @@ -156,7 +286,7 @@ html` and review `html/download.html` Then add and commit to git and push the changes to GitHub. The Temple Jenkis cluster will automatically update https://www.lammps.org/download.html accordingly. -Notify Steve of the release so he can update `src/bug.txt` on the +Also notify Steve of the release so he can update `src/bug.txt` on the website from the available release notes. ## LAMMPS Stable Release diff --git a/.github/workflows/check-vla.yml b/.github/workflows/check-vla.yml index ab89018a3d..94e367be33 100644 --- a/.github/workflows/check-vla.yml +++ b/.github/workflows/check-vla.yml @@ -77,7 +77,7 @@ jobs: -D PKG_MDI=on \ -D PKG_MANIFOLD=on \ -D PKG_ML-PACE=on \ - -D PKG_ML-RANN=off \ + -D PKG_ML-RANN=on \ -D PKG_MOLFILE=on \ -D PKG_RHEO=on \ -D PKG_PTM=on \ diff --git a/README b/README index c25506e2c0..6477eb41d3 100644 --- a/README +++ b/README @@ -23,17 +23,20 @@ more information about the code and its uses. The LAMMPS distribution includes the following files and directories: README this file -LICENSE the GNU General Public License (GPL) -bench benchmark problems +LICENSE the GNU General Public License (GPLv2) +CITATION.cff Citation information for LAMMPS in CFF format +bench benchmark inputs cmake CMake build files doc documentation -examples simple test problems -fortran Fortran wrapper for LAMMPS +examples example inputs for many LAMMPS commands +fortran Fortran 2003 module for LAMMPS lib additional provided or external libraries potentials interatomic potential files -python Python wrappers for LAMMPS +python Python module for LAMMPS src source files tools pre- and post-processing tools +unittest test programs for use with CTest +.github Git and GitHub related files and tools Point your browser at any of these files to get started: @@ -42,6 +45,8 @@ https://docs.lammps.org/Intro.html hi-level introduction https://docs.lammps.org/Build.html how to build LAMMPS https://docs.lammps.org/Run_head.html how to run LAMMPS https://docs.lammps.org/Commands_all.html Table of available commands +https://docs.lammps.org/Howto.html Short tutorials and HowTo discussions +https://docs.lammps.org/Errors.html How to interpret and debug errors https://docs.lammps.org/Library.html LAMMPS library interfaces https://docs.lammps.org/Modify.html how to modify and extend LAMMPS https://docs.lammps.org/Developer.html LAMMPS developer info diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index ff0d69e316..c1a0875c15 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -209,7 +209,7 @@ endif() ######################################################################## # User input options # ######################################################################## -# backward compatibility with CMake before 3.12 and older LAMMPS documentation +# backward compatibility with older LAMMPS documentation if (PYTHON_EXECUTABLE) set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}") endif() @@ -225,6 +225,12 @@ if(DEFINED ENV{VIRTUAL_ENV} AND NOT Python_EXECUTABLE) " Setting Python interpreter to: ${Python_EXECUTABLE}") endif() +find_package(Python COMPONENTS Interpreter QUIET) +# NOTE: RHEL 8.0 and Ubuntu 18.04LTS ship with Python 3.6, Python 3.8 was EOL in 2024 +if(Python_VERSION VERSION_LESS 3.6) + message(FATAL_ERROR "LAMMPS requires Python 3.6 or later") +endif() + set(LAMMPS_MACHINE "" CACHE STRING "Suffix to append to lmp binary (WON'T enable any features automatically") mark_as_advanced(LAMMPS_MACHINE) if(LAMMPS_MACHINE) @@ -930,7 +936,7 @@ endif() include(Testing) include(CodeCoverage) include(CodingStandard) -find_package(ClangFormat 11.0) +find_package(ClangFormat 11.0 QUIET) if(ClangFormat_FOUND) add_custom_target(format-src diff --git a/cmake/Modules/CodeCoverage.cmake b/cmake/Modules/CodeCoverage.cmake index 21a651e519..885b5cba6d 100644 --- a/cmake/Modules/CodeCoverage.cmake +++ b/cmake/Modules/CodeCoverage.cmake @@ -7,76 +7,76 @@ # For Python coverage the coverage package needs to be installed ############################################################################### if(ENABLE_COVERAGE) - find_program(GCOVR_BINARY gcovr) - find_package_handle_standard_args(GCOVR DEFAULT_MSG GCOVR_BINARY) + find_program(GCOVR_BINARY gcovr) + find_package_handle_standard_args(GCOVR DEFAULT_MSG GCOVR_BINARY) - find_program(COVERAGE_BINARY coverage) - find_package_handle_standard_args(COVERAGE DEFAULT_MSG COVERAGE_BINARY) + find_program(COVERAGE_BINARY coverage) + find_package_handle_standard_args(COVERAGE DEFAULT_MSG COVERAGE_BINARY) - if(GCOVR_FOUND) - get_filename_component(ABSOLUTE_LAMMPS_SOURCE_DIR ${LAMMPS_SOURCE_DIR} ABSOLUTE) + if(GCOVR_FOUND) + get_filename_component(ABSOLUTE_LAMMPS_SOURCE_DIR ${LAMMPS_SOURCE_DIR} ABSOLUTE) - add_custom_target( - gen_coverage_xml - COMMAND ${GCOVR_BINARY} -s -x -r ${ABSOLUTE_LAMMPS_SOURCE_DIR} --object-directory=${CMAKE_BINARY_DIR} -o coverage.xml - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - COMMENT "Generating XML coverage report..." - ) + add_custom_target( + gen_coverage_xml + COMMAND ${GCOVR_BINARY} -s -x -r ${ABSOLUTE_LAMMPS_SOURCE_DIR} --object-directory=${CMAKE_BINARY_DIR} -o coverage.xml + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Generating XML coverage report..." + ) - set(COVERAGE_HTML_DIR ${CMAKE_BINARY_DIR}/coverage_html) + set(COVERAGE_HTML_DIR ${CMAKE_BINARY_DIR}/coverage_html) - add_custom_target(coverage_html_folder - COMMAND ${CMAKE_COMMAND} -E make_directory ${COVERAGE_HTML_DIR}) + add_custom_target(coverage_html_folder + COMMAND ${CMAKE_COMMAND} -E make_directory ${COVERAGE_HTML_DIR}) - add_custom_target( - gen_coverage_html - COMMAND ${GCOVR_BINARY} -s --html --html-details -r ${ABSOLUTE_LAMMPS_SOURCE_DIR} --object-directory=${CMAKE_BINARY_DIR} -o ${COVERAGE_HTML_DIR}/index.html - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - COMMENT "Generating HTML coverage report..." - ) - add_dependencies(gen_coverage_html coverage_html_folder) + add_custom_target( + gen_coverage_html + COMMAND ${GCOVR_BINARY} -s --html --html-details -r ${ABSOLUTE_LAMMPS_SOURCE_DIR} --object-directory=${CMAKE_BINARY_DIR} -o ${COVERAGE_HTML_DIR}/index.html + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Generating HTML coverage report..." + ) + add_dependencies(gen_coverage_html coverage_html_folder) - add_custom_target(clean_coverage_html - ${CMAKE_COMMAND} -E remove_directory ${COVERAGE_HTML_DIR} - COMMENT "Deleting HTML coverage report..." - ) + add_custom_target(clean_coverage_html + ${CMAKE_COMMAND} -E remove_directory ${COVERAGE_HTML_DIR} + COMMENT "Deleting HTML coverage report..." + ) - add_custom_target(reset_coverage - ${CMAKE_COMMAND} -E remove -f */*.gcda */*/*.gcda */*/*/*.gcda - */*/*/*/*.gcda */*/*/*/*/*.gcda */*/*/*/*/*/*.gcda - */*/*/*/*/*/*/*.gcda */*/*/*/*/*/*/*/*.gcda - */*/*/*/*/*/*/*/*/*.gcda */*/*/*/*/*/*/*/*/*/*.gcda - WORKIND_DIRECTORY ${CMAKE_BINARY_DIR} - COMMENT "Deleting coverage data files..." - ) - add_dependencies(reset_coverage clean_coverage_html) - endif() + add_custom_target(reset_coverage + ${CMAKE_COMMAND} -E remove -f */*.gcda */*/*.gcda */*/*/*.gcda + */*/*/*/*.gcda */*/*/*/*/*.gcda */*/*/*/*/*/*.gcda + */*/*/*/*/*/*/*.gcda */*/*/*/*/*/*/*/*.gcda + */*/*/*/*/*/*/*/*/*.gcda */*/*/*/*/*/*/*/*/*/*.gcda + WORKIND_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Deleting coverage data files..." + ) + add_dependencies(reset_coverage clean_coverage_html) + endif() - if(COVERAGE_FOUND) - set(PYTHON_COVERAGE_HTML_DIR ${CMAKE_BINARY_DIR}/python_coverage_html) - configure_file(.coveragerc.in ${CMAKE_BINARY_DIR}/.coveragerc @ONLY) + if(COVERAGE_FOUND) + set(PYTHON_COVERAGE_HTML_DIR ${CMAKE_BINARY_DIR}/python_coverage_html) + configure_file(.coveragerc.in ${CMAKE_BINARY_DIR}/.coveragerc @ONLY) - add_custom_command( - OUTPUT ${CMAKE_BINARY_DIR}/unittest/python/.coverage - COMMAND ${COVERAGE_BINARY} combine - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittest/python - COMMENT "Combine Python coverage files..." - ) + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/unittest/python/.coverage + COMMAND ${COVERAGE_BINARY} combine + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittest/python + COMMENT "Combine Python coverage files..." + ) - add_custom_target( - gen_python_coverage_html - COMMAND ${COVERAGE_BINARY} html --rcfile=${CMAKE_BINARY_DIR}/.coveragerc -d ${PYTHON_COVERAGE_HTML_DIR} - DEPENDS ${CMAKE_BINARY_DIR}/unittest/python/.coverage ${CMAKE_BINARY_DIR}/.coveragerc - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittest/python - COMMENT "Generating HTML Python coverage report..." - ) + add_custom_target( + gen_python_coverage_html + COMMAND ${COVERAGE_BINARY} html --rcfile=${CMAKE_BINARY_DIR}/.coveragerc -d ${PYTHON_COVERAGE_HTML_DIR} + DEPENDS ${CMAKE_BINARY_DIR}/unittest/python/.coverage ${CMAKE_BINARY_DIR}/.coveragerc + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittest/python + COMMENT "Generating HTML Python coverage report..." + ) - add_custom_target( - gen_python_coverage_xml - COMMAND ${COVERAGE_BINARY} xml --rcfile=${CMAKE_BINARY_DIR}/.coveragerc -o ${CMAKE_BINARY_DIR}/python_coverage.xml - DEPENDS ${CMAKE_BINARY_DIR}/unittest/python/.coverage ${CMAKE_BINARY_DIR}/.coveragerc - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittest/python - COMMENT "Generating XML Python coverage report..." - ) - endif() + add_custom_target( + gen_python_coverage_xml + COMMAND ${COVERAGE_BINARY} xml --rcfile=${CMAKE_BINARY_DIR}/.coveragerc -o ${CMAKE_BINARY_DIR}/python_coverage.xml + DEPENDS ${CMAKE_BINARY_DIR}/unittest/python/.coverage ${CMAKE_BINARY_DIR}/.coveragerc + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittest/python + COMMENT "Generating XML Python coverage report..." + ) + endif() endif() diff --git a/cmake/Modules/CodingStandard.cmake b/cmake/Modules/CodingStandard.cmake index 94639c7771..4e99c2e39c 100644 --- a/cmake/Modules/CodingStandard.cmake +++ b/cmake/Modules/CodingStandard.cmake @@ -1,40 +1,39 @@ -# use default (or custom) Python executable, if version is sufficient -if(Python_VERSION VERSION_GREATER_EQUAL 3.6) +# use default (or custom) Python executable. +# Python version check is in main CMakeLists.txt file +if(Python_EXECUTABLE) set(Python3_EXECUTABLE ${Python_EXECUTABLE}) endif() find_package(Python3 COMPONENTS Interpreter) if(Python3_EXECUTABLE) - if(Python3_VERSION VERSION_GREATER_EQUAL 3.6) - add_custom_target( - check-whitespace - ${Python3_EXECUTABLE} ${LAMMPS_TOOLS_DIR}/coding_standard/whitespace.py . - WORKING_DIRECTORY ${LAMMPS_DIR} - COMMENT "Check for whitespace errors") - add_custom_target( - check-homepage - ${Python3_EXECUTABLE} ${LAMMPS_TOOLS_DIR}/coding_standard/homepage.py . - WORKING_DIRECTORY ${LAMMPS_DIR} - COMMENT "Check for homepage URL errors") - add_custom_target( - check-permissions - ${Python3_EXECUTABLE} ${LAMMPS_TOOLS_DIR}/coding_standard/permissions.py . - WORKING_DIRECTORY ${LAMMPS_DIR} - COMMENT "Check for permission errors") - add_custom_target( - fix-whitespace - ${Python3_EXECUTABLE} ${LAMMPS_TOOLS_DIR}/coding_standard/whitespace.py -f . - WORKING_DIRECTORY ${LAMMPS_DIR} - COMMENT "Fix whitespace errors") - add_custom_target( - fix-homepage - ${Python3_EXECUTABLE} ${LAMMPS_TOOLS_DIR}/coding_standard/homepage.py -f . - WORKING_DIRECTORY ${LAMMPS_DIR} - COMMENT "Fix homepage URL errors") - add_custom_target( - fix-permissions - ${Python3_EXECUTABLE} ${LAMMPS_TOOLS_DIR}/coding_standard/permissions.py -f . - WORKING_DIRECTORY ${LAMMPS_DIR} - COMMENT "Fix permission errors") - endif() + add_custom_target( + check-whitespace + ${Python3_EXECUTABLE} ${LAMMPS_TOOLS_DIR}/coding_standard/whitespace.py . + WORKING_DIRECTORY ${LAMMPS_DIR} + COMMENT "Check for whitespace errors") + add_custom_target( + check-homepage + ${Python3_EXECUTABLE} ${LAMMPS_TOOLS_DIR}/coding_standard/homepage.py . + WORKING_DIRECTORY ${LAMMPS_DIR} + COMMENT "Check for homepage URL errors") + add_custom_target( + check-permissions + ${Python3_EXECUTABLE} ${LAMMPS_TOOLS_DIR}/coding_standard/permissions.py . + WORKING_DIRECTORY ${LAMMPS_DIR} + COMMENT "Check for permission errors") + add_custom_target( + fix-whitespace + ${Python3_EXECUTABLE} ${LAMMPS_TOOLS_DIR}/coding_standard/whitespace.py -f . + WORKING_DIRECTORY ${LAMMPS_DIR} + COMMENT "Fix whitespace errors") + add_custom_target( + fix-homepage + ${Python3_EXECUTABLE} ${LAMMPS_TOOLS_DIR}/coding_standard/homepage.py -f . + WORKING_DIRECTORY ${LAMMPS_DIR} + COMMENT "Fix homepage URL errors") + add_custom_target( + fix-permissions + ${Python3_EXECUTABLE} ${LAMMPS_TOOLS_DIR}/coding_standard/permissions.py -f . + WORKING_DIRECTORY ${LAMMPS_DIR} + COMMENT "Fix permission errors") endif() diff --git a/cmake/Modules/Documentation.cmake b/cmake/Modules/Documentation.cmake index dfaf7bdb39..511d54114c 100644 --- a/cmake/Modules/Documentation.cmake +++ b/cmake/Modules/Documentation.cmake @@ -13,7 +13,7 @@ if(BUILD_DOC) endif() find_package(Python3 REQUIRED COMPONENTS Interpreter) if(Python3_VERSION VERSION_LESS 3.8) - message(FATAL_ERROR "Python 3.8 and up is required to build the HTML documentation") + message(FATAL_ERROR "Python 3.8 and up is required to build the LAMMPS HTML documentation") endif() set(VIRTUALENV ${Python3_EXECUTABLE} -m venv) @@ -65,8 +65,8 @@ if(BUILD_DOC) find_package(Sphinx) endif() - set(MATHJAX_URL "https://github.com/mathjax/MathJax/archive/3.1.3.tar.gz" CACHE STRING "URL for MathJax tarball") - set(MATHJAX_MD5 "b81661c6e6ba06278e6ae37b30b0c492" CACHE STRING "MD5 checksum of MathJax tarball") + set(MATHJAX_URL "https://github.com/mathjax/MathJax/archive/3.2.2.tar.gz" CACHE STRING "URL for MathJax tarball") + set(MATHJAX_MD5 "08dd6ef33ca08870220d9aade2a62845" CACHE STRING "MD5 checksum of MathJax tarball") mark_as_advanced(MATHJAX_URL) GetFallbackURL(MATHJAX_URL MATHJAX_FALLBACK) diff --git a/cmake/Modules/LAMMPSInterfacePlugin.cmake b/cmake/Modules/LAMMPSInterfacePlugin.cmake index 151e0a04f7..fcaf604778 100644 --- a/cmake/Modules/LAMMPSInterfacePlugin.cmake +++ b/cmake/Modules/LAMMPSInterfacePlugin.cmake @@ -34,8 +34,26 @@ if(MSVC) add_compile_definitions(_CRT_SECURE_NO_WARNINGS) endif() -# C++11 is required -set(CMAKE_CXX_STANDARD 11) +if(NOT CMAKE_CXX_STANDARD) + if(cxx_std_17 IN_LIST CMAKE_CXX_COMPILE_FEATURES) + set(CMAKE_CXX_STANDARD 17) + else() + set(CMAKE_CXX_STANDARD 11) + endif() +endif() +if(CMAKE_CXX_STANDARD LESS 11) + message(FATAL_ERROR "C++ standard must be set to at least 11") +endif() +if(CMAKE_CXX_STANDARD LESS 17) + message(WARNING "Selecting C++17 standard is preferred over C++${CMAKE_CXX_STANDARD}") +endif() +if(PKG_KOKKOS AND (CMAKE_CXX_STANDARD LESS 17)) + set(CMAKE_CXX_STANDARD 17) +endif() +# turn off C++17 check in lmptype.h +if(LAMMPS_CXX11) + add_compile_definitions(LAMMPS_CXX11) +endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) # Need -restrict with Intel compilers diff --git a/cmake/Modules/Packages/ML-IAP.cmake b/cmake/Modules/Packages/ML-IAP.cmake index 91b772efb5..1691af8d95 100644 --- a/cmake/Modules/Packages/ML-IAP.cmake +++ b/cmake/Modules/Packages/ML-IAP.cmake @@ -24,9 +24,7 @@ if(MLIAP_ENABLE_PYTHON) if(NOT PKG_PYTHON) message(FATAL_ERROR "Must enable PYTHON package for including Python support in ML-IAP") endif() - if(Python_VERSION VERSION_LESS 3.6) - message(FATAL_ERROR "Python support in ML-IAP requires Python 3.6 or later") - endif() + # Python version check is in main CMakeLists.txt file set(MLIAP_BINARY_DIR ${CMAKE_BINARY_DIR}/cython) file(GLOB MLIAP_CYTHON_SRC CONFIGURE_DEPENDS ${LAMMPS_SOURCE_DIR}/ML-IAP/*.pyx) diff --git a/cmake/Modules/Packages/ML-QUIP.cmake b/cmake/Modules/Packages/ML-QUIP.cmake index 9106ff54ef..aad6ee5e34 100644 --- a/cmake/Modules/Packages/ML-QUIP.cmake +++ b/cmake/Modules/Packages/ML-QUIP.cmake @@ -37,7 +37,7 @@ if(DOWNLOAD_QUIP) endforeach() # Fix cmake crashing when MATH_LINKOPTS not set, required for e.g. recent Cray Programming Environment set(temp "${temp} -L/_DUMMY_PATH_\n") - set(temp "${temp}PYTHON=python\nPIP=pip\nEXTRA_LINKOPTS=\n") + set(temp "${temp}PYTHON=${Python_EXECUTABLE}\nPIP=pip\nEXTRA_LINKOPTS=\n") set(temp "${temp}HAVE_CP2K=0\nHAVE_VASP=0\nHAVE_TB=0\nHAVE_PRECON=1\nHAVE_LOTF=0\nHAVE_ONIOM=0\n") set(temp "${temp}HAVE_LOCAL_E_MIX=0\nHAVE_QC=0\nHAVE_GAP=1\nHAVE_DESCRIPTORS_NONCOMMERCIAL=1\n") set(temp "${temp}HAVE_TURBOGAP=0\nHAVE_QR=1\nHAVE_THIRDPARTY=0\nHAVE_FX=0\nHAVE_SCME=0\nHAVE_MTP=0\n") diff --git a/cmake/Modules/Packages/PLUMED.cmake b/cmake/Modules/Packages/PLUMED.cmake index 5e5d110626..1b4845d259 100644 --- a/cmake/Modules/Packages/PLUMED.cmake +++ b/cmake/Modules/Packages/PLUMED.cmake @@ -40,6 +40,13 @@ mark_as_advanced(PLUMED_URL) mark_as_advanced(PLUMED_MD5) GetFallbackURL(PLUMED_URL PLUMED_FALLBACK) +# adjust C++ standard support for self-compiled Plumed2 +if(CMAKE_CXX_STANDARD GREATER 11) + set(PLUMED_CXX_STANDARD 14) +else() + set(PLUMED_CXX_STANDARD 11) +endif() + if((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND (CMAKE_CROSSCOMPILING)) if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") set(CROSS_CONFIGURE mingw64-configure) @@ -55,7 +62,7 @@ if((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND (CMAKE_CROSSCOMPILING)) URL_MD5 ${PLUMED_MD5} BUILD_IN_SOURCE 1 CONFIGURE_COMMAND ${CROSS_CONFIGURE} --disable-shared --disable-bsymbolic - --disable-python --enable-cxx=11 + --disable-python --enable-cxx=${PLUMED_CXX_STANDARD} --enable-modules=-adjmat:+crystallization:-dimred:+drr:+eds:-fisst:+funnel:+logmfd:+manyrestraints:+maze:+opes:+multicolvar:-pamm:-piv:+s2cm:-sasa:-ves ${PLUMED_CONFIG_OMP} ${PLUMED_CONFIG_MPI} @@ -142,7 +149,7 @@ else() CONFIGURE_COMMAND /configure --prefix= ${CONFIGURE_REQUEST_PIC} --enable-modules=all - --enable-cxx=11 + --enable-cxx=${PLUMED_CXX_STANDARD} --disable-python ${PLUMED_CONFIG_MPI} ${PLUMED_CONFIG_OMP} diff --git a/cmake/Modules/Packages/PYTHON.cmake b/cmake/Modules/Packages/PYTHON.cmake index e05edadbf3..0879382ed7 100644 --- a/cmake/Modules/Packages/PYTHON.cmake +++ b/cmake/Modules/Packages/PYTHON.cmake @@ -1,6 +1,6 @@ if(NOT Python_INTERPRETER) - # backward compatibility with CMake before 3.12 and older LAMMPS documentation + # backward compatibility with older LAMMPS documentation if(PYTHON_EXECUTABLE) set(Python_EXECUTABLE ${PYTHON_EXECUTABLE}) endif() diff --git a/doc/README b/doc/README index de956a96bb..f96e0b14da 100644 --- a/doc/README +++ b/doc/README @@ -22,12 +22,12 @@ doxygen-warn.log logfile with warnings from running doxygen and: github-development-workflow.md notes on the LAMMPS development workflow -include-file-conventions.md notes on LAMMPS' include file conventions documentation_conventions.md notes on writing documentation for LAMMPS If you downloaded a LAMMPS tarball from www.lammps.org, then the html folder and the PDF manual should be included. If you downloaded LAMMPS -from GitHub then you either need to build them. +using GitHub then you either need to build them yourself or read the +online version at https://docs.lammps.org/ You can build the HTML and PDF files yourself, by typing "make html" or by "make pdf", respectively. This requires various tools and files. @@ -39,10 +39,10 @@ environment and local folders. Installing prerequisites for the documentation build -To run the HTML documention build toolchain, python 3.x, doxygen, git, -and the venv python module have to be installed if not already available. -Also internet access is initially required to download external files -and tools. +To run the HTML documention build toolchain, python 3.8 or later, +doxygen 1.8.10 or later, git, and the venv python module have to be +installed if not already available. Also internet access is initially +required to download external files and tools. Building the PDF format manual requires in addition a compatible LaTeX installation with support for PDFLaTeX and several add-on LaTeX packages @@ -52,16 +52,24 @@ installed. This includes: - babel - capt-of - cmap +- dvipng +- ellipse - fncychap +- fontawesom - framed - geometry +- gyre - hyperref - hypcap - needspace +- pict2e - times - tabulary +- titlesec - upquote - wrapfig +- xindy + Also the latexmk script is required to run PDFLaTeX and related tools. the required number of times to have self-consistent output and include updated bibliography and indices. diff --git a/doc/src/Build.rst b/doc/src/Build.rst index 7ca8cd428e..ff09ee5678 100644 --- a/doc/src/Build.rst +++ b/doc/src/Build.rst @@ -14,6 +14,29 @@ As an alternative, you can download a package with pre-built executables or automated build trees, as described in the :doc:`Install ` section of the manual. +Prerequisites +------------- + +Which software you need to compile and use LAMMPS strongly depends on +which :doc:`features and settings ` and which +:doc:`optional packages ` you are trying to include. +Common to all is that you need a C++ and C compiler, where the C++ +compiler has to support at least the C++11 standard (note that some +compilers require command-line flag to activate C++11 support). +Furthermore, if you are building with CMake, you need at least CMake +version 3.20 and a compatible build tool (make or ninja-build); if you +are building the the legacy GNU make based build system you need GNU +make (other make variants are not going to work since the build system +uses features unique to GNU make) and a Unix-like build environment with +a Bourne shell, and shell tools like "sed", "grep", "touch", "test", +"tr", "cp", "mv", "rm", "ln", "diff" and so on. Parts of LAMMPS +interface with or use Python version 3.6 or later. + +The LAMMPS developers aim to keep LAMMPS very portable and usable - +at least in parts - on most operating systems commonly used for +running MD simulations. Please see the :doc:`section on portablility +` for more details. + .. toctree:: :maxdepth: 1 diff --git a/doc/src/Build_cmake.rst b/doc/src/Build_cmake.rst index 56b8e450f3..a38b42b4f4 100644 --- a/doc/src/Build_cmake.rst +++ b/doc/src/Build_cmake.rst @@ -52,9 +52,9 @@ software or for people that want to modify or extend LAMMPS. compilers can be configured and built concurrently from the same source tree. - Simplified packaging of LAMMPS for Linux distributions, environment - modules, or automated build tools like `Homebrew `_. -- Integration of automated unit and regression testing (the LAMMPS side - of this is still under active development). + modules, or automated build tools like `Spack `_ + or `Homebrew `_. +- Integration of automated unit and regression testing. .. _cmake_build: diff --git a/doc/src/Build_extras.rst b/doc/src/Build_extras.rst index dab2267ee8..f57407f9c1 100644 --- a/doc/src/Build_extras.rst +++ b/doc/src/Build_extras.rst @@ -1139,11 +1139,10 @@ POEMS package PYTHON package --------------------------- -Building with the PYTHON package requires you have a the Python development -headers and library available on your system, which needs to be a Python 2.7 -version or a Python 3.x version. Since support for Python 2.x has ended, -using Python 3.x is strongly recommended. See ``lib/python/README`` for -additional details. +Building with the PYTHON package requires you have a the Python +development headers and library available on your system, which +needs to be Python version 3.6 or later. See ``lib/python/README`` +for additional details. .. tabs:: @@ -1159,7 +1158,7 @@ additional details. set the Python_EXECUTABLE variable to specify which Python interpreter should be used. Note note that you will also need to have the development headers installed for this version, - e.g. python2-devel. + e.g. python3-devel. .. tab:: Traditional make diff --git a/doc/src/Build_make.rst b/doc/src/Build_make.rst index 00f2f0b24d..477c1c6e34 100644 --- a/doc/src/Build_make.rst +++ b/doc/src/Build_make.rst @@ -30,9 +30,9 @@ additional tools to be available and functioning. * A Bourne shell compatible "Unix" shell program (frequently this is ``bash``) * A few shell utilities: ``ls``, ``mv``, ``ln``, ``rm``, ``grep``, ``sed``, ``tr``, ``cat``, ``touch``, ``diff``, ``dirname`` * Python (optional, required for ``make lib-`` in the ``src`` - folder). Python scripts are currently tested with python 2.7 and - 3.6 to 3.11. The procedure for :doc:`building the documentation - ` *requires* Python 3.5 or later. + folder). Python scripts are currently tested with 3.6 to 3.11. + The procedure for :doc:`building the documentation ` + *requires* Python 3.8 or later. Getting started ^^^^^^^^^^^^^^^ diff --git a/doc/src/Build_manual.rst b/doc/src/Build_manual.rst index 4b4bfa5a45..7a969877a1 100644 --- a/doc/src/Build_manual.rst +++ b/doc/src/Build_manual.rst @@ -116,9 +116,9 @@ environment variable. Prerequisites for HTML ---------------------- -To run the HTML documentation build toolchain, python 3, git, doxygen, -and virtualenv have to be installed locally. Here are instructions for -common setups: +To run the HTML documentation build toolchain, Python 3.8 or later, git, +doxygen, and virtualenv have to be installed locally. Here are +instructions for common setups: .. tabs:: @@ -128,13 +128,7 @@ common setups: sudo apt-get install git doxygen - .. tab:: RHEL or CentOS (Version 7.x) - - .. code-block:: bash - - sudo yum install git doxygen - - .. tab:: Fedora or RHEL/CentOS (8.x or later) + .. tab:: Fedora or RHEL/AlmaLinux/RockyLinux (8.x or later) .. code-block:: bash @@ -154,7 +148,36 @@ Prerequisites for PDF In addition to the tools needed for building the HTML format manual, a working LaTeX installation with support for PDFLaTeX and a selection -of LaTeX styles/packages are required. To run the PDFLaTeX translation +of LaTeX styles/packages are required. Apart from LaTeX packages that +are usually installed by default, the following packages are required: + +.. table_from_list:: + :columns: 11 + + - amsmath + - anysize + - babel + - capt-of + - cmap + - dvipng + - ellipse + - fncychap + - fontawesome + - framed + - geometry + - gyre + - hyperref + - hypcap + - needspace + - pict2e + - times + - tabulary + - titlesec + - upquote + - wrapfig + - xindy + +To run the PDFLaTeX translation the ``latexmk`` script needs to be installed as well. Prerequisites for ePUB and MOBI diff --git a/doc/src/Build_settings.rst b/doc/src/Build_settings.rst index e4a53ddee7..fb3ebf4b48 100644 --- a/doc/src/Build_settings.rst +++ b/doc/src/Build_settings.rst @@ -8,7 +8,7 @@ Optional build settings LAMMPS can be built with several optional settings. Each subsection explains how to do this for building both with CMake and make. -* `C++11 standard compliance`_ when building all of LAMMPS +* `C++11 and C++17 standard compliance`_ when building all of LAMMPS * `FFT library`_ for use with the :doc:`kspace_style pppm ` command * `Size of LAMMPS integer types and size limits`_ * `Read or write compressed files`_ @@ -23,14 +23,15 @@ explains how to do this for building both with CMake and make. .. _cxx11: -C++11 standard compliance -------------------------- +C++11 and C++17 standard compliance +----------------------------------- -A C++11 standard compatible compiler is a requirement for compiling LAMMPS. -LAMMPS version 3 March 2020 is the last version compatible with the previous -C++98 standard for the core code and most packages. Most currently used -C++ compilers are compatible with C++11, but some older ones may need extra -flags to enable C++11 compliance. Example for GNU c++ 4.8.x: +A C++11 standard compatible compiler is currently the minimum +requirement for compiling LAMMPS. LAMMPS version 3 March 2020 is the +last version compatible with the previous C++98 standard for the core +code and most packages. Most currently used C++ compilers are compatible +with C++11, but some older ones may need extra flags to enable C++11 +compliance. Example for GNU c++ 4.8.x: .. code-block:: make @@ -40,6 +41,17 @@ Individual packages may require compliance with a later C++ standard like C++14 or C++17. These requirements will be documented with the :doc:`individual packages `. +.. versionchanged:: 4Feb2025 + +Starting with LAMMPS version 4 February 2025 we are starting a +transition to require the C++17 standard. Most current compilers are +compatible and if the C++17 standard is available by default, LAMMPS +will enable C++17 and will compile normally. If the chosen compiler is +not compatible with C++17, but only supports C++11, then the define +-DLAMMPS_CXX11 is required to fall back to compiling with a C++11 +compiler. After the next stable release of LAMMPS in summer 2025, the +LAMMPS development branch and future releases will require C++17. + ---------- .. _fft: diff --git a/doc/src/Commands_compute.rst b/doc/src/Commands_compute.rst index 7c73583a4f..b53d9d6820 100644 --- a/doc/src/Commands_compute.rst +++ b/doc/src/Commands_compute.rst @@ -178,6 +178,7 @@ KOKKOS, o = OPENMP, t = OPT. * :doc:`ti ` * :doc:`torque/chunk ` * :doc:`vacf ` + * :doc:`vacf/chunk ` * :doc:`vcm/chunk ` * :doc:`viscosity/cos ` * :doc:`voronoi/atom ` diff --git a/doc/src/Intro_portability.rst b/doc/src/Intro_portability.rst index 036529ff9d..8bb716833f 100644 --- a/doc/src/Intro_portability.rst +++ b/doc/src/Intro_portability.rst @@ -13,10 +13,14 @@ Programming language standards Most of the C++ code currently requires a compiler compatible with the C++11 standard, the KOKKOS package currently requires C++17. Most of -the Python code is written to be compatible with Python 3.5 or later or -Python 2.7. Some Python scripts *require* Python 3 and a few others -still need to be ported from Python 2 to Python 3. +the Python code is written to be compatible with Python 3.6 or later. +.. deprecated:: TBD + +Python 2.x is no longer supported and trying to use it, e.g. for the +LAMMPS Python module should result in an error. If you come across +some part of the LAMMPS distribution that is not (yet) compatible with +Python 3, please notify the LAMMPS developers. Build systems ^^^^^^^^^^^^^ @@ -24,8 +28,8 @@ Build systems LAMMPS can be compiled from source code using a (traditional) build system based on shell scripts, a few shell utilities (grep, sed, cat, tr) and the GNU make program. This requires running within a Bourne -shell (``/bin/sh``). Alternatively, a build system with different back ends -can be created using CMake. CMake must be at least version 3.16. +shell (``/bin/sh``). Alternatively, a build system with different back +ends can be created using CMake. CMake must be at least version 3.16. Operating systems ^^^^^^^^^^^^^^^^^ diff --git a/doc/src/Modify_requirements.rst b/doc/src/Modify_requirements.rst index c3e514a423..850fbf95c1 100644 --- a/doc/src/Modify_requirements.rst +++ b/doc/src/Modify_requirements.rst @@ -189,10 +189,8 @@ of the contribution. As of January 2023, all previously included Fortran code for the LAMMPS executable has been replaced by equivalent C++ code. -Python code must be compatible with Python 3.5 and later. Large parts -of LAMMPS (including the :ref:`PYTHON package `) are also -compatible with Python 2.7. Compatibility with Python 2.7 is desirable, -but compatibility with Python 3.5 is **required**. +Python code currently must be compatible with Python 3.6. If a later +version or Python is required, it needs to be documented. Compatibility with older programming language standards is very important to maintain portability and availability of LAMMPS on many diff --git a/doc/src/Packages_details.rst b/doc/src/Packages_details.rst index baefee0185..870dc8fbf7 100644 --- a/doc/src/Packages_details.rst +++ b/doc/src/Packages_details.rst @@ -2428,7 +2428,7 @@ ways to use LAMMPS and Python together. Building with the PYTHON package assumes you have a Python development environment (headers and libraries) available on your system, which needs - to be either Python version 2.7 or Python 3.5 and later. + to be Python version 3.6 or later. **Install:** diff --git a/doc/src/Python_install.rst b/doc/src/Python_install.rst index 01610b84f0..1e53a99914 100644 --- a/doc/src/Python_install.rst +++ b/doc/src/Python_install.rst @@ -7,6 +7,10 @@ LAMMPS shared library through the Python `ctypes `_ module. Because of the dynamic loading, it is required that LAMMPS is compiled in :ref:`"shared" mode `. +.. versionchanged:: TBD + +LAMMPS currently only supports Python version 3.6 or later. + Two components are necessary for Python to be able to invoke LAMMPS code: * The LAMMPS Python Package (``lammps``) from the ``python`` folder @@ -136,11 +140,6 @@ folder that the dynamic loader searches or inside of the installed # create virtual environment in folder $HOME/myenv python3 -m venv $HOME/myenv - For Python versions prior 3.3 you can use `virtualenv - `_ - command instead of "python3 -m venv". This step has to be done - only once. - To activate the virtual environment type: .. code-block:: bash @@ -245,14 +244,14 @@ make MPI calls directly from Python in your script, if you desire. We have tested this with `MPI for Python `_ (aka mpi4py) and you will find installation instruction for it below. -Installation of mpi4py (version 3.0.3 as of Sep 2020) can be done as +Installation of mpi4py (version 4.0.1 as of Feb 2025) can be done as follows: - Via ``pip`` into a local user folder with: .. code-block:: bash - pip install --user mpi4py + python3 -m pip install --user mpi4py - Via ``dnf`` into a system folder for RedHat/Fedora systems: @@ -261,20 +260,20 @@ follows: # for use with OpenMPI sudo dnf install python3-mpi4py-openmpi # for use with MPICH - sudo dnf install python3-mpi4py-openmpi + sudo dnf install python3-mpi4py-mpich - Via ``pip`` into a virtual environment (see above): .. code-block:: console $ source $HOME/myenv/activate - (myenv)$ pip install mpi4py + (myenv)$ python -m pip install mpi4py - Via ``pip`` into a system folder (not recommended): .. code-block:: bash - sudo pip install mpi4py + sudo python3 -m pip install mpi4py For more detailed installation instructions and additional options, please see the `mpi4py installation `_ page. diff --git a/doc/src/Python_overview.rst b/doc/src/Python_overview.rst index 85bc0d3bfa..57b9ee6145 100644 --- a/doc/src/Python_overview.rst +++ b/doc/src/Python_overview.rst @@ -44,15 +44,11 @@ Below is an example output for Python version 3.8.5. .. warning:: The options described in this section of the manual for using Python - with LAMMPS currently support either Python 2 or 3. Specifically - version 2.7 or later and 3.6 or later. Since the Python community no - longer maintains Python 2 (see `this notice - `_), we recommend use of - Python 3 with LAMMPS. While Python 2 code should continue to work, - that is not something we can guarantee long-term. If you notice - Python code in the LAMMPS distribution that is not compatible with - Python 3, please contact the LAMMPS developers or submit `and issue - on GitHub `_ + with LAMMPS support only Python 3.6 or later. For use with Python + 2.x you will need to use an older LAMMPS version like 29 Aug 2024 + or older. If you notice Python code in the LAMMPS distribution that + is not compatible with Python 3, please contact the LAMMPS developers + or submit `and issue on GitHub `_ --------- diff --git a/doc/src/compute.rst b/doc/src/compute.rst index 9a8a1734fb..323f3ed3e5 100644 --- a/doc/src/compute.rst +++ b/doc/src/compute.rst @@ -356,6 +356,7 @@ The individual style names on the :doc:`Commands compute ` pag * :doc:`ti ` - thermodynamic integration free energy values * :doc:`torque/chunk ` - torque applied on each chunk * :doc:`vacf ` - velocity auto-correlation function of group of atoms +* :doc:`vacf/chunk ` - velocity auto-correlation for the center of mass velocities of chunks of atoms * :doc:`vcm/chunk ` - velocity of center-of-mass for each chunk * :doc:`viscosity/cos ` - velocity profile under cosine-shaped acceleration * :doc:`voronoi/atom ` - Voronoi volume and neighbors for each atom diff --git a/doc/src/compute_msd.rst b/doc/src/compute_msd.rst index bc16a3de6f..8f2726e8a3 100644 --- a/doc/src/compute_msd.rst +++ b/doc/src/compute_msd.rst @@ -116,7 +116,9 @@ Compute *msd* cannot be used with a dynamic group. Related commands """""""""""""""" -:doc:`compute msd/nongauss `, :doc:`compute displace_atom `, :doc:`fix store/state `, :doc:`compute msd/chunk ` +:doc:`compute msd/nongauss `, +:doc:`compute displace_atom `, :doc:`fix store/state `, +:doc:`compute msd/chunk ` Default """"""" diff --git a/doc/src/compute_msd_chunk.rst b/doc/src/compute_msd_chunk.rst index db6e1e6fc2..863be4db35 100644 --- a/doc/src/compute_msd_chunk.rst +++ b/doc/src/compute_msd_chunk.rst @@ -131,7 +131,7 @@ Restrictions Related commands """""""""""""""" -:doc:`compute msd ` +:doc:`compute msd `, :doc:`compute vacf/chunk ` Default """"""" diff --git a/doc/src/compute_vacf.rst b/doc/src/compute_vacf.rst index 704e597e18..72f675360c 100644 --- a/doc/src/compute_vacf.rst +++ b/doc/src/compute_vacf.rst @@ -76,7 +76,7 @@ Restrictions Related commands """""""""""""""" -:doc:`compute msd ` +:doc:`compute msd `, :doc:`compute vacf/chunk ` Default """"""" diff --git a/doc/src/compute_vacf_chunk.rst b/doc/src/compute_vacf_chunk.rst new file mode 100644 index 0000000000..f9d22e22a1 --- /dev/null +++ b/doc/src/compute_vacf_chunk.rst @@ -0,0 +1,124 @@ +.. index:: compute vacf/chunk + +compute vacf/chunk command +========================== + +Syntax +"""""" + +.. code-block:: LAMMPS + + compute ID group-ID vacf/chunk chunkID + +* ID, group-ID are documented in :doc:`compute ` command +* vacf/chunk = style name of this compute command +* chunkID = ID of :doc:`compute chunk/atom ` command + +Examples +"""""""" + +.. code-block:: LAMMPS + + compute 1 all vacf/chunk molchunk + +Description +""""""""""" + +.. versionadded:: TBD + +Define a computation that calculates the velocity auto-correlation +function (VACF) for multiple chunks of atoms. + +In LAMMPS, chunks are collections of atoms defined by a :doc:`compute +chunk/atom ` command, which assigns each atom to a +single chunk (or no chunk). The ID for this command is specified as +chunkID. For example, a single chunk could be the atoms in a molecule +or atoms in a spatial bin. See the :doc:`compute chunk/atom +` and :doc:`Howto chunk ` doc pages for +details of how chunks can be defined and examples of how they can be +used to measure properties of a system. + +Four quantities are calculated by this compute for each chunk. The +first 3 quantities are the product of the initial center of mass +velocity (VCM) for each chunk in *x*, *y*, and *z* direction with the +current center of mass velocity in the same direction. The fourth +component is the total VACF, i.e. the sum of the three components. + +Note that only atoms in the specified group contribute to the +calculation. The :doc:`compute chunk/atom ` command +defines its own group; atoms will have a chunk ID = 0 if they are not in +that group, signifying they are not assigned to a chunk, and will thus +also not contribute to this calculation. You can specify the "all" +group for this command if you simply want to include atoms with non-zero +chunk IDs. + +The integral of the VACF versus time is proportional to the diffusion +coefficient of the diffusing chunks. + +.. note:: + + The number of chunks *Nchunk* calculated by the + :doc:`compute chunk/atom ` command must remain constant + each time this compute is invoked, so that the dot product for each chunk + from its original position can be computed consistently. If *Nchunk* + does not remain constant, an error will be generated. If needed, you + can enforce a constant *Nchunk* by using the *nchunk once* or *ids once* + options when specifying the :doc:`compute chunk/atom ` + command. + +.. note:: + + This compute stores the original center-of-mass velocities of each + chunk. When a VACF is calculated on a later timestep, it is assumed + that the same atoms are assigned to the same chunk ID. However + LAMMPS has no simple way to ensure this is the case, though you can + use the *ids once* option when specifying the :doc:`compute + chunk/atom ` command. Note that if this is not + the case, the VACF calculation does not have a sensible meaning. + +.. note:: + + If you want the quantities calculated by this compute to be + continuous when running from a :doc:`restart file `, then + you should use the same ID for this compute, as in the original run. + This is so that the fix this compute creates to store per-chunk + quantities will also have the same ID, and thus be initialized + correctly with chunk reference positions from the restart file. + +The simplest way to output the results of the compute vacf/chunk +calculation to a file is to use the :doc:`fix ave/time ` +command, for example: + +.. code-block:: LAMMPS + + compute cc1 all chunk/atom molecule + compute myChunk all vacf/chunk cc1 + fix 1 all ave/time 100 1 100 c_myChunk[*] file tmp.out mode vector + +Output info +""""""""""" + +This compute calculates a global array where the number of rows = the +number of chunks *Nchunk* as calculated by the specified :doc:`compute +chunk/atom ` command. The number of columns = 4 for +the *x*, *y*, *z*, component and the total VACF. These values can be +accessed by any command that uses global array values from a compute as +input. See the :doc:`Howto output ` page for an overview +of LAMMPS output options. + +The array values are "intensive". The array values will be in +distance\ :math:`^2` divided by time\ :math:`^2` :doc:`units `. + +Restrictions +"""""""""""" + none + +Related commands +"""""""""""""""" + +:doc:`compute vacf `, :doc:`compute msd/chunk ` + +Default +""""""" + +none diff --git a/doc/src/region2vmd.rst b/doc/src/region2vmd.rst index 6cea199760..54216bb925 100644 --- a/doc/src/region2vmd.rst +++ b/doc/src/region2vmd.rst @@ -166,11 +166,7 @@ Only the following region styles are currently supported: *block*, *cone*, *cylinder*, *ellipsoid*, *prism*, and *sphere*. Regions formed from unions or intersections of other regions are not supported. -For region style *cone* one of the two radii must be zero, since the -equivalent VMD graphics primitive does not support truncated cones. -Also the VMD graphics primitive does not support open cones. - -Rotating regions are not supported. +Rotating regions are currently not supported. Related commands """""""""""""""" diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 730c6dd53f..f94d528cfe 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -99,6 +99,7 @@ AMD amino Amirjalayer Amit +amsmath amu Amzallag analytical @@ -128,6 +129,7 @@ Antisymmetrized antisymmetry anton Antonelli +anysize api apolar Apoorva @@ -613,6 +615,7 @@ Courant covalent covalently covariance +cp cpp cpu cradius @@ -905,6 +908,7 @@ dUs Duval dV dvector +dvipng dVx dW dx @@ -1215,12 +1219,14 @@ fmz fN Fn fname +fncychap fno Fnudge foces Fock Fogarty Foiles +fontawesome fopenmp forceclear forestgreen @@ -1407,6 +1413,7 @@ Gunsteren Gunzenmuller Guo gw +gyre gyromagnetic gz gzip @@ -1532,10 +1539,12 @@ hydrostatically hydroxyl Hynninen Hyoungki +hypcap hyperdynamics hyperparameters hyperplane hyperradius +hyperref hyperspherical hysteretic hz @@ -2514,6 +2523,7 @@ Ndof Ndouble ndx neb +needspace neel Neel Neelov @@ -2918,6 +2928,7 @@ picogram picograms picosecond picoseconds +pict pid piecewise Pieniazek @@ -3689,6 +3700,7 @@ Sz Tabbernor tabinner tabstyle +tabulary Tadmor Tafipolsky tagID @@ -3786,6 +3798,7 @@ timestamps timestep timestepping timesteps +titlesec TiN TiO Tirado @@ -3962,6 +3975,7 @@ untilted Unwin uparrow upenn +upquote upto Urbakh Urbana @@ -4148,6 +4162,7 @@ Workum Worley wormlike wpbe +wrapfig Wriggers writedata Wuppertal @@ -4178,6 +4193,7 @@ Xia Xiaohu Xiaowang Xie +xindy xk xlat xlattice diff --git a/lib/python/Makefile.lammps.python2 b/lib/python/Makefile.lammps.python2 deleted file mode 100644 index 7b54b4c3df..0000000000 --- a/lib/python/Makefile.lammps.python2 +++ /dev/null @@ -1,7 +0,0 @@ -# Settings that the LAMMPS build will import when this package library is used -# See the README file for more explanation - -python_SYSINC = $(shell which python2-config > /dev/null 2>&1 && python2-config --includes || (which python-config > /dev/null 2>&1 && python-config --includes || :)) -python_SYSLIB = $(shell which python2-config > /dev/null 2>&1 && python2-config --ldflags || (which python-config > /dev/null 2>&1 && python-config --ldflags || :)) -python_SYSPATH = -PYTHON=$(shell which python2 > /dev/null 2>&1 && echo python2 || echo python) diff --git a/lib/python/Makefile.lammps.python2.7 b/lib/python/Makefile.lammps.python3.13 similarity index 100% rename from lib/python/Makefile.lammps.python2.7 rename to lib/python/Makefile.lammps.python3.13 diff --git a/lib/python/README b/lib/python/README index 8de2bc4bd7..c84b291f05 100644 --- a/lib/python/README +++ b/lib/python/README @@ -9,30 +9,29 @@ installation. If needed, you can copy one of the other provided Makefile.lammps.* files to to Makefile.lammps before building LAMMPS itself. -The files Makefile.lammps.python2 and Makefile.lammps.python3 are -similar to the default file, but meant for the case that both, -python 2 and python 3, are installed simultaneously and you want -to prefer one over the other. If neither of these files work, you -may have to create a custom Makefile.lammps file suitable for -the version of Python on your system. To illustrate, these are -example settings from the Makefile.lammps.python2.7 file: +The file Makefile.lammps.python3 is similar to the default file, but +meant for the case that both, python 2 and python 3, are installed +simultaneously. LAMMPS only supports python 3. If neither of these +files work, you may have to create a custom Makefile.lammps file +suitable for the version of Python on your system. To illustrate, these +are example settings from the Makefile.lammps.python3.13 file: -python_SYSINC = -I/usr/local/include/python2.7 -python_SYSLIB = -lpython2.7 -lnsl -ldl -lreadline -ltermcap -lpthread -lutil -lm -python_SYSPATH = -PYTHON=python2.7 +python_SYSINC = -I/usr/local/include/python3.13 +python_SYSLIB = -lpython3.13 -ldl -lm +python_SYSPATH = -L/usr/lib64 +PYTHON=python3.13 python_SYSINC refers to the directory where Python's Python.h file is found. LAMMPS includes this file. python_SYSLIB refers to the libraries needed to link to from an application (LAMMPS in this case) to "embed" Python in the -application. The Python library itself is listed (-lpython2.7) are +application. The Python library itself is listed (-lpython3.13) are are several system libraries needed by Python. python_SYSPATH refers to the path (e.g. -L/usr/local/lib) where the Python library can be found. You may not need this setting if the -path is already included in your LD_LIBRARY_PATH environment variable. +path is already included in your LIBRARY_PATH environment variable. PYTHON is the name of the python interpreter. It is used for installing the LAMMPS python module with "make install-python" @@ -45,7 +44,7 @@ run in embedded mode on your machine. Here is what this Python doc page says about it: -https://docs.python.org/2/extending/embedding.html#compiling-and-linking-under-unix-like-systems +https://docs.python.org/3/extending/embedding.html#compiling-and-linking-under-unix-like-systems "It is not necessarily trivial to find the right flags to pass to your compiler (and linker) in order to embed the Python interpreter into diff --git a/python/README b/python/README index 0757a84cd6..97f47b2a36 100644 --- a/python/README +++ b/python/README @@ -1,20 +1,27 @@ -This directory contains Python code which wraps LAMMPS as a library -and allows the LAMMPS library interface to be invoked from Python, -either from a Python script or using Python interactively. +This directory contains the LAMMPS Python module that allows the LAMMPS +C library interface to be invoked from Python, either from a Python +script or using Python interactively. Details on the Python interface to LAMMPS and how to build LAMMPS as a shared library, for use with Python, are given in -doc/Section_python.html and in doc/Section_start.html#start_5. +https://docs.lammps.org/Build_basics.html#exe +and +https://docs.lammps.org/Python_install.html -Basically you need to follow these steps in the src directory: +Basically you need to use the flag -D BUILD_SHARED_LIBS=ON when +configuring LAMMPS with CMake and then in the build folder use the +command % cmake --build . --target install-python + +or for the legacy GNU build system execute these steps in the src folder: % make g++ mode=shlib # build for whatever machine target you wish % make install-python # install into site-packages folder You can replace the last step by a one-time setting of environment -variables in your shell script. Or you can run the python/install.py -script directly to give you more control over where the two relevant -files are installed. See doc/Python_install.html for details. +variables in your shell environment. Or you can run the +python/install.py script directly to give you more control over where +the two relevant files are installed. See +https://docs.lammps.org/Python_install.html for details. You should then be able to launch Python and instantiate an instance of LAMMPS: @@ -24,39 +31,41 @@ of LAMMPS: >>> lmp = lammps() If that gives no errors, you have successfully wrapped LAMMPS with -Python. See doc/Section_python.html#py_7 for tests you can then use -to run LAMMPS both in serial or parallel thru Python. +Python. See https://docs.lammps.org/Python_launch.html for examples how +to run LAMMPS both in serial or parallel from Python. Note that you can also invoke Python code from within a LAMMPS input -script, using the "python" command. See the doc/python.html doc page -for details. The Python code you invoke can also call back to LAMMPS -using the same interface described here for wrapping LAMMPS. +script, using the "python" command. See the +https://docs.lammps.org/python.html doc page for details. The Python +code you invoke can also call back to LAMMPS using the same interface +described here for wrapping LAMMPS. ------------------------------------------------------------------- Once you have successfully wrapped LAMMPS, you can run the Python scripts in the examples sub-directory: -trivial.py read/run a LAMMPS input script thru Python -demo.py invoke various LAMMPS library interface routines -simple.py parallel example, mimicing examples/COUPLE/simple/simple.cpp -split.py parallel example -mc.py Monte Carlo energy relaxation wrapper on LAMMPS -gui.py GUI go/stop/temperature-slider to control LAMMPS -plot.py real-time temperature plot with GnuPlot via Pizza.py -matplotlib_plot.py real-time temperature plot with Matplotlib via Pizza.py -viz_tool.py real-time viz via some viz package -vizplotgui_tool.py combination of viz.py and plot.py and gui.py +trivial.py read/run a LAMMPS input script thru Python +demo.py invoke various LAMMPS library interface routines +simple.py parallel example, mimicing examples/COUPLE/simple/simple.cpp +split.py parallel example +mc.py Monte Carlo energy relaxation wrapper on LAMMPS +gui.py GUI go/stop/temperature-slider to control LAMMPS +plot.py real-time temperature plot with GnuPlot via Pizza.py +matplotlib_plot.py real-time temperature plot with Matplotlib via Pizza.py +viz_.py real-time viz via some viz package +vizplotgui_.py combination of viz.py and plot.py and gui.py -For the viz_tool.py and vizplotgui_tool.py commands, replace "tool" -with "gl" or "atomeye" or "pymol", depending on what visualization -package you have installed. We hope to add a VMD option soon. +For the viz_.py and vizplotgui_.py commands, replace +"" with "gl" or "atomeye" or "pymol", depending on what +visualization package you have installed. We hope to add a VMD option +soon. Note that for GL, you need to be able to run the Pizza.py GL tool, which is included in the pizza sub-directory. See the Pizza.py doc pages for more info: -http://www.sandia.gov/~sjplimp/pizza.html +https://lammps.github.io/pizza/ Note that for AtomEye, you need version 3, and their is a line in the scripts that specifies the path and name of the executable. See @@ -115,17 +124,14 @@ one-processor run, where both Python and LAMMPS will run on single processors. Each running job will read the same input file, and write to same log.lammps file, which isn't too useful. -However, if you have the mpi4py Python package installed and uncomment mpi4py -code in simple.py, then the above commands will invoke 1 instance of a -P-processor run. Both Python and LAMMPS will run on P processors. The job will -read the input file and write a single log.lammps file. - -The split.py script can also be run in parallel. It uses mpi4py -version 2.0.0 (or later), which makes it possible to pass a -communicator when creating the LAMMPS object and thus run multiple -instances of LAMMPS at the same time, each on a different subset of -MPI ranks. Or run LAMMPS on one subset and some other program on the -rest of the MPI ranks, concurrently. See comments in the split.py -script for more details. - +However, if you have the mpi4py Python package installed and uncomment +mpi4py code in simple.py, then the above commands will invoke 1 instance +of a P-processor run. Both Python and LAMMPS will run on P processors. +The job will read the input file and write a single log.lammps file. +The split.py script can also be run in parallel. It uses mpi4py version +2.0.0 (or later), which makes it possible to pass a communicator when +creating the LAMMPS object and thus run multiple instances of LAMMPS at +the same time, each on a different subset of MPI ranks. Or run LAMMPS +on one subset and some other program on the rest of the MPI ranks, +concurrently. See comments in the split.py script for more details. diff --git a/python/lammps/__init__.py b/python/lammps/__init__.py index fc35e45225..0cc658371f 100644 --- a/python/lammps/__init__.py +++ b/python/lammps/__init__.py @@ -23,6 +23,9 @@ def get_version_number(): if __file__.find(join('python', 'lammps', '__init__.py')) > 0: return 0 + if version_info.major < 3 or (version_info.major == 3 and version_info.minor < 6): + raise SystemError('LAMMPS only supports Python version 3.6 or later') + vstring = None if version_info.major == 3 and version_info.minor >= 8: from importlib.metadata import version, PackageNotFoundError diff --git a/python/lammps/core.py b/python/lammps/core.py index 43d142c7de..d4609d3b5d 100644 --- a/python/lammps/core.py +++ b/python/lammps/core.py @@ -17,7 +17,6 @@ from __future__ import print_function import os -import sys from ctypes import CDLL, POINTER, RTLD_GLOBAL, CFUNCTYPE, py_object, byref, cast, sizeof, \ create_string_buffer, c_int, c_int32, c_int64, c_double, c_void_p, c_char_p, c_char, \ pythonapi @@ -83,8 +82,6 @@ class command_wrapper(object): def _wrap_args(self, x): if callable(x): - if sys.version_info < (3,): - raise Exception("Passing functions or lambdas directly as arguments is only supported in Python 3 or newer") import hashlib import __main__ sha = hashlib.sha256() @@ -105,11 +102,6 @@ class command_wrapper(object): all the arguments, concatinates them to a single string, and executes it using :py:meth:`lammps.command`. - Starting with Python 3.6 it also supports keyword arguments. key=value is - transformed into 'key value'. Note, since these have come last in the - parameter list, only a subset of LAMMPS commands can be used with this - syntax. - LAMMPS commands that accept callback functions (such as fix python/invoke) can be passed functions and lambdas directly. The first argument of such callbacks will be an lammps object constructed from the passed LAMMPS @@ -121,9 +113,6 @@ class command_wrapper(object): def handler(*args, **kwargs): cmd_args = [name] + [str(self._wrap_args(x)) for x in args] - if len(kwargs) > 0 and sys.version_info < (3,6): - raise Exception("Keyword arguments are only supported in Python 3.6 or newer") - # Python 3.6+ maintains ordering of kwarg keys for k in kwargs.keys(): cmd_args.append(k) @@ -530,16 +519,10 @@ class lammps(object): else: # magic to convert ptr to ctypes ptr - if sys.version_info >= (3, 0): - # Python 3 (uses PyCapsule API) - pythonapi.PyCapsule_GetPointer.restype = c_void_p - pythonapi.PyCapsule_GetPointer.argtypes = [py_object, c_char_p] - self.lmp = c_void_p(pythonapi.PyCapsule_GetPointer(ptr, None)) - else: - # Python 2 (uses PyCObject API) - pythonapi.PyCObject_AsVoidPtr.restype = c_void_p - pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object] - self.lmp = c_void_p(pythonapi.PyCObject_AsVoidPtr(ptr)) + # Python 3 (uses PyCapsule API) + pythonapi.PyCapsule_GetPointer.restype = c_void_p + pythonapi.PyCapsule_GetPointer.argtypes = [py_object, c_char_p] + self.lmp = c_void_p(pythonapi.PyCapsule_GetPointer(ptr, None)) # check if library initilialization failed if not self.lmp: diff --git a/src/BOCS/compute_pressure_bocs.cpp b/src/BOCS/compute_pressure_bocs.cpp index 16d6c91a1f..c5f828fdfd 100644 --- a/src/BOCS/compute_pressure_bocs.cpp +++ b/src/BOCS/compute_pressure_bocs.cpp @@ -43,7 +43,7 @@ ComputePressureBocs::ComputePressureBocs(LAMMPS *lmp, int narg, char **arg) : vptr(nullptr), id_temp(nullptr) { if (narg < 4) utils::missing_cmd_args(FLERR,"compute pressure/bocs", error); - if (igroup) error->all(FLERR,"Compute pressure/bocs must use group all"); + if (igroup) error->all(FLERR, 1, "Compute pressure/bocs must use group all"); scalar_flag = vector_flag = 1; size_vector = 6; @@ -64,9 +64,9 @@ ComputePressureBocs::ComputePressureBocs(LAMMPS *lmp, int narg, char **arg) : temperature = modify->get_compute_by_id(id_temp); if (!temperature) - error->all(FLERR,"Could not find compute pressure/bocs temperature compute {}", id_temp); + error->all(FLERR, 3, "Could not find compute pressure/bocs temperature compute {}", id_temp); if (temperature->tempflag == 0) - error->all(FLERR,"Compute pressure/bocs temperature compute {} does not compute " + error->all(FLERR, 3, "Compute pressure/bocs temperature compute {} does not compute " "temperature", id_temp); } @@ -104,8 +104,8 @@ ComputePressureBocs::ComputePressureBocs(LAMMPS *lmp, int narg, char **arg) : // error check if (keflag && id_temp == nullptr) - error->all(FLERR,"Compute pressure/bocs requires temperature ID " - "to include kinetic energy"); + error->all(FLERR, 3, + "Compute pressure/bocs requires temperature ID to include kinetic energy"); vector = new double[size_vector]; nvirial = 0; @@ -119,9 +119,9 @@ ComputePressureBocs::ComputePressureBocs(LAMMPS *lmp, int narg, char **arg) : ComputePressureBocs::~ComputePressureBocs() { - delete [] id_temp; - delete [] vector; - delete [] vptr; + delete[] id_temp; + delete[] vector; + delete[] vptr; if (phi_coeff) free(phi_coeff); } @@ -139,7 +139,8 @@ void ComputePressureBocs::init() if (keflag) { temperature = modify->get_compute_by_id(id_temp); if (!temperature) - error->all(FLERR,"Could not find compute pressure/bocs temperature compute {}", id_temp); + error->all(FLERR, Error::NOLASTLINE, + "Could not find compute pressure/bocs temperature compute {}", id_temp); } // detect contributions to virial @@ -214,10 +215,10 @@ double ComputePressureBocs::find_index(double * grid, double value) if (value >= grid[i] && value <= (grid[i] + spacing)) { return i; } - error->all(FLERR,"find_index could not find value in grid for value: {}", value); - for (int i = 0; i < gridsize; ++i) - { - fprintf(stderr, "grid %d: %f\n",i,grid[i]); + error->all(FLERR, Error::NOLASTLINE, + "find_index could not find value in grid for value: {}", value); + for (int i = 0; i < gridsize; ++i) { + fprintf(stderr, "grid %d: %f\n", i, grid[i]); } exit(1); @@ -237,7 +238,7 @@ double ComputePressureBocs::get_cg_p_corr(double ** grid, int basis_type, return grid[1][i] + (deltax) * ( grid[1][i+1] - grid[1][i] ) / ( grid[0][i+1] - grid[0][i] ); else if (basis_type == BASIS_CUBIC_SPLINE) return grid[1][i] + (grid[2][i] * deltax) + (grid[3][i] * pow(deltax,2)) + (grid[4][i] * pow(deltax,3)); - else error->all(FLERR,"bad spline type passed to get_cg_p_corr()\n"); + else error->all(FLERR, Error::NOLASTLINE, "bad spline type passed to get_cg_p_corr()"); return 0.0; } @@ -251,7 +252,7 @@ void ComputePressureBocs::send_cg_info(int basis_type, int sent_N_basis, double sent_vavg) { if (basis_type == BASIS_ANALYTIC) p_basis_type = BASIS_ANALYTIC; - else error->all(FLERR,"Incorrect basis type passed to ComputePressureBocs\n"); + else error->all(FLERR, Error::NOLASTLINE, "Incorrect basis type passed to ComputePressureBocs"); p_match_flag = 1; @@ -276,7 +277,7 @@ void ComputePressureBocs::send_cg_info(int basis_type, else if (basis_type == BASIS_CUBIC_SPLINE) { p_basis_type = BASIS_CUBIC_SPLINE; } else { - error->all(FLERR,"Incorrect basis type passed to ComputePressureBocs\n"); + error->all(FLERR, Error::NOLASTLINE, "Incorrect basis type passed to ComputePressureBocs"); } splines = in_splines; spline_length = gridsize; @@ -293,7 +294,7 @@ double ComputePressureBocs::compute_scalar() { invoked_scalar = update->ntimestep; if (update->vflag_global != invoked_scalar) - error->all(FLERR,"Virial was not tallied on needed timestep"); + error->all(FLERR, Error::NOLASTLINE, "Virial was not tallied on needed timestep"); // invoke temperature if it hasn't been already @@ -328,9 +329,8 @@ double ComputePressureBocs::compute_scalar() scalar = (virial[0] + virial[1] + virial[2]) / 3.0 * inv_volume * nktv2p + (correction); } else { - if (p_match_flag) - { - error->all(FLERR,"Pressure matching not implemented in 2-d.\n"); + if (p_match_flag) { + error->all(FLERR, Error::NOLASTLINE, "Pressure matching not implemented in 2-d."); exit(1); } // The rest of this can probably be deleted. inv_volume = 1.0 / (domain->xprd * domain->yprd); @@ -354,10 +354,10 @@ void ComputePressureBocs::compute_vector() { invoked_vector = update->ntimestep; if (update->vflag_global != invoked_vector) - error->all(FLERR,"Virial was not tallied on needed timestep"); + error->all(FLERR, Error::NOLASTLINE, "Virial was not tallied on needed timestep"); if (force->kspace && kspace_virial && force->kspace->scalar_pressure_flag) - error->all(FLERR,"Must use 'kspace_modify pressure/scalar no' for " + error->all(FLERR, Error::NOLASTLINE, "Must use 'kspace_modify pressure/scalar no' for " "tensor components with kspace_style msm"); // invoke temperature if it hasn't been already diff --git a/src/EXTRA-COMMAND/region2vmd.cpp b/src/EXTRA-COMMAND/region2vmd.cpp index 3a0570ac79..ade531f964 100644 --- a/src/EXTRA-COMMAND/region2vmd.cpp +++ b/src/EXTRA-COMMAND/region2vmd.cpp @@ -20,22 +20,30 @@ #include "comm.h" #include "domain.h" #include "error.h" +#include "math_const.h" +#include "math_extra.h" #include "region.h" +#include "safe_pointers.h" #include "region_block.h" #include "region_cone.h" #include "region_cylinder.h" #include "region_ellipsoid.h" +#include "region_plane.h" #include "region_prism.h" #include "region_sphere.h" +#include #include #include using namespace LAMMPS_NS; +using MathConst::MY_2PI; static constexpr double SMALL = 1.0e-10; static constexpr double DELTA = 1.0e-5; +static constexpr int RESOLUTION = 20; +static constexpr double RADINC = MY_2PI / RESOLUTION; static const std::unordered_set vmdcolors{ "blue", "red", "gray", "orange", "yellow", "tan", "silver", "green", "white", @@ -158,30 +166,14 @@ static constexpr char draw_ellipsoid_function[] = " return $gid\n" "}\n\n"; -// class that "owns" the file pointer and closes it when going out of scope. -// this avoids a lot of redundant checks and calls. -class AutoClose { - public: - AutoClose() = delete; - AutoClose(const AutoClose &) = delete; - AutoClose(const AutoClose &&) = delete; - explicit AutoClose(FILE *_fp) : fp(_fp) {}; - ~AutoClose() - { - if (fp) fclose(fp); - } - - private: - FILE *fp; -}; - /* ---------------------------------------------------------------------- */ void Region2VMD::command(int narg, char **arg) { if (narg < 3) utils::missing_cmd_args(FLERR, "region2vmd", error); - FILE *fp = nullptr; + // automatically close file when it goes out of scope + SafeFilePtr fp; if (comm->me == 0) { fp = fopen(arg[0], "w"); if (fp == nullptr) { @@ -193,9 +185,6 @@ void Region2VMD::command(int narg, char **arg) } } - // automatically close fp when fpowner goes out of scope - AutoClose fpowner(fp); - // defaults std::string color = "silver"; std::string material = "Transparent"; @@ -277,6 +266,9 @@ void Region2VMD::write_region(FILE *fp, Region *region) return; } + // update internal variables + region->prematch(); + // compute position offset for moving regions double dx = 0.0; @@ -323,136 +315,441 @@ void Region2VMD::write_region(FILE *fp, Region *region) if (!cone) { error->one(FLERR, Error::NOLASTLINE, "Region {} is not of style 'cone'", region->id); } else { - if (cone->open_faces[0] || cone->open_faces[1]) - error->warning(FLERR, "Drawing open-faced cones is not supported"); - // The VMD cone primitive requires one radius set to zero - if (cone->radiuslo < SMALL) { - // a VMD cone uses a single cone primitive - if (cone->axis == 'x') { - utils::print(fp, "draw cone {{{1} {2} {3}}} {{{0} {2} {3}}} radius {4} resolution 20\n", - cone->lo + dx, cone->hi + dx, cone->c1 + dy, cone->c2 + dz, cone->radiushi); - } else if (cone->axis == 'y') { - utils::print(fp, "draw cone {{{2} {1} {3}}} {{{2} {0} {3}}} radius {4} resolution 20\n", - cone->lo + dy, cone->hi + dy, cone->c1 + dx, cone->c2 + dz, cone->radiushi); - } else if (cone->axis == 'z') { - utils::print(fp, "draw cone {{{2} {3} {1}}} {{{2} {3} {0}}} radius {4} resolution 20\n", - cone->lo + dz, cone->hi + dz, cone->c1 + dx, cone->c2 + dy, cone->radiushi); + // draw cone + if (!cone->open_faces[2]) { + + // both radii too small + if ((cone->radiuslo < SMALL) && (cone->radiushi < SMALL)) { + ; // nothing to draw + + // lo end has a tip + } else if (cone->radiuslo < SMALL) { + double v1[3], v2[3], v3[3], v4[3], v5[3]; + + if (cone->axis == 'x') { + // set tip coordinate + v1[0] = cone->lo + dx; + v1[1] = cone->c1 + dy; + v1[2] = cone->c2 + dz; + + // loop around radius + for (int i = 0; i < RESOLUTION; ++i) { + v2[0] = cone->hi + dx; + v2[1] = cone->c1 + cone->radiushi * sin(RADINC * i) + dy; + v2[2] = cone->c2 + cone->radiushi * cos(RADINC * i) + dz; + v3[0] = cone->hi + dx; + v3[1] = cone->c1 + cone->radiushi * sin(RADINC * (i + 1.0)) + dy; + v3[2] = cone->c2 + cone->radiushi * cos(RADINC * (i + 1.0)) + dz; + v4[0] = 0.0; + v4[1] = sin(RADINC * i); + v4[2] = cos(RADINC * i); + v5[0] = 0.0; + v5[1] = sin(RADINC * (i + 1.0)); + v5[2] = cos(RADINC * (i + 1.0)); + + utils::print(fp, + "draw trinorm {{{} {} {}}} {{{} {} {}}} {{{} {} {}}} " + "{{{} {} {}}} {{{} {} {}}} {{{} {} {}}}\n", + v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], v3[0], v3[1], v3[2], 1.0, 0.0, + 0.0, v4[0], v4[1], v4[2], v5[0], v5[1], v5[2]); + } + + } else if (cone->axis == 'y') { + // set tip coordinate + v1[0] = cone->c1 + dx; + v1[1] = cone->lo + dy; + v1[2] = cone->c2 + dz; + + // loop around radius + for (int i = 0; i < RESOLUTION; ++i) { + v2[0] = cone->c1 + cone->radiushi * sin(RADINC * i) + dx; + v2[1] = cone->hi + dy; + v2[2] = cone->c2 + cone->radiushi * cos(RADINC * i) + dz; + v3[0] = cone->c1 + cone->radiushi * sin(RADINC * (i + 1.0)) + dx; + v3[1] = cone->hi + dy; + v3[2] = cone->c2 + cone->radiushi * cos(RADINC * (i + 1.0)) + dz; + v4[0] = sin(RADINC * i); + v4[1] = 0.0; + v4[2] = cos(RADINC * i); + v5[0] = sin(RADINC * (i + 1.0)); + v5[1] = 0.0; + v5[2] = cos(RADINC * (i + 1.0)); + + utils::print(fp, + "draw trinorm {{{} {} {}}} {{{} {} {}}} {{{} {} {}}} " + "{{{} {} {}}} {{{} {} {}}} {{{} {} {}}}\n", + v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], v3[0], v3[1], v3[2], 0.0, 1.0, + 0.0, v4[0], v4[1], v4[2], v5[0], v5[1], v5[2]); + } + + } else if (cone->axis == 'z') { + // set tip coordinate + v1[0] = cone->c1 + dx; + v1[1] = cone->c2 + dy; + v1[2] = cone->lo + dz; + + // loop around radius + for (int i = 0; i < RESOLUTION; ++i) { + v2[0] = cone->c1 + cone->radiushi * sin(RADINC * i) + dx; + v2[1] = cone->c2 + cone->radiushi * cos(RADINC * i) + dy; + v2[2] = cone->hi + dz; + v3[0] = cone->c1 + cone->radiushi * sin(RADINC * (i + 1.0)) + dx; + v3[1] = cone->c2 + cone->radiushi * cos(RADINC * (i + 1.0)) + dy; + v3[2] = cone->hi + dz; + v4[0] = sin(RADINC * i); + v4[1] = cos(RADINC * i); + v4[2] = 0.0; + v5[0] = sin(RADINC * (i + 1.0)); + v5[1] = cos(RADINC * (i + 1.0)); + v5[2] = 0.0; + utils::print(fp, + "draw trinorm {{{} {} {}}} {{{} {} {}}} {{{} {} {}}} " + "{{{} {} {}}} {{{} {} {}}} {{{} {} {}}}\n", + v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], v3[0], v3[1], v3[2], 0.0, 0.0, + 1.0, v4[0], v4[1], v4[2], v5[0], v5[1], v5[2]); + } + } + + // hi end has a tip + } else if (cone->radiushi < SMALL) { + double v1[3], v2[3], v3[3], v4[3], v5[3]; + + if (cone->axis == 'x') { + // set tip coordinate + v1[0] = cone->hi + dx; + v1[1] = cone->c1 + dy; + v1[2] = cone->c2 + dz; + + // loop around radius + for (int i = 0; i < RESOLUTION; ++i) { + v2[0] = cone->lo + dx; + v2[1] = cone->c1 + cone->radiuslo * sin(RADINC * i) + dy; + v2[2] = cone->c2 + cone->radiuslo * cos(RADINC * i) + dz; + v3[0] = cone->lo + dx; + v3[1] = cone->c1 + cone->radiuslo * sin(RADINC * (i + 1.0)) + dy; + v3[2] = cone->c2 + cone->radiuslo * cos(RADINC * (i + 1.0)) + dz; + v4[0] = 0.0; + v4[1] = sin(RADINC * i); + v4[2] = cos(RADINC * i); + v5[0] = 0.0; + v5[1] = sin(RADINC * (i + 1.0)); + v5[2] = cos(RADINC * (i + 1.0)); + + utils::print(fp, + "draw trinorm {{{} {} {}}} {{{} {} {}}} {{{} {} {}}} " + "{{{} {} {}}} {{{} {} {}}} {{{} {} {}}}\n", + v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], v3[0], v3[1], v3[2], 1.0, 0.0, + 0.0, v4[0], v4[1], v4[2], v5[0], v5[1], v5[2]); + } + + } else if (cone->axis == 'y') { + // set tip coordinate + v1[0] = cone->c1 + dx; + v1[1] = cone->hi + dy; + v1[2] = cone->c2 + dz; + + // loop around radius + for (int i = 0; i < RESOLUTION; ++i) { + v2[0] = cone->c1 + cone->radiuslo * sin(RADINC * i) + dx; + v2[1] = cone->lo + dy; + v2[2] = cone->c2 + cone->radiuslo * cos(RADINC * i) + dz; + v3[0] = cone->c1 + cone->radiuslo * sin(RADINC * (i + 1.0)) + dx; + v3[1] = cone->lo + dy; + v3[2] = cone->c2 + cone->radiuslo * cos(RADINC * (i + 1.0)) + dz; + v4[0] = sin(RADINC * i); + v4[1] = 0.0; + v4[2] = cos(RADINC * i); + v5[0] = sin(RADINC * (i + 1.0)); + v5[1] = 0.0; + v5[2] = cos(RADINC * (i + 1.0)); + + utils::print(fp, + "draw trinorm {{{} {} {}}} {{{} {} {}}} {{{} {} {}}} " + "{{{} {} {}}} {{{} {} {}}} {{{} {} {}}}\n", + v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], v3[0], v3[1], v3[2], 0.0, 1.0, + 0.0, v4[0], v4[1], v4[2], v5[0], v5[1], v5[2]); + } + + } else if (cone->axis == 'z') { + // set tip coordinate + v1[0] = cone->c1 + dx; + v1[1] = cone->c2 + dy; + v1[2] = cone->hi + dz; + + // loop around radius + for (int i = 0; i < RESOLUTION; ++i) { + v2[0] = cone->c1 + cone->radiuslo * sin(RADINC * i) + dx; + v2[1] = cone->c2 + cone->radiuslo * cos(RADINC * i) + dy; + v2[2] = cone->lo + dz; + v3[0] = cone->c1 + cone->radiuslo * sin(RADINC * (i + 1.0)) + dx; + v3[1] = cone->c2 + cone->radiuslo * cos(RADINC * (i + 1.0)) + dy; + v3[2] = cone->lo + dz; + v4[0] = sin(RADINC * i); + v4[1] = cos(RADINC * i); + v4[2] = 0.0; + v5[0] = sin(RADINC * (i + 1.0)); + v5[1] = cos(RADINC * (i + 1.0)); + v5[2] = 0.0; + utils::print(fp, + "draw trinorm {{{} {} {}}} {{{} {} {}}} {{{} {} {}}} " + "{{{} {} {}}} {{{} {} {}}} {{{} {} {}}}\n", + v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], v3[0], v3[1], v3[2], 0.0, 0.0, + 1.0, v4[0], v4[1], v4[2], v5[0], v5[1], v5[2]); + } + } + + // truncated cone + } else if (!cone->open_faces[2]) { + double v1[3], v2[3], v3[3], v4[3], v5[3], v6[3], v7[3], v8[3]; + + if (cone->axis == 'x') { + + // loop around radii + for (int i = 0; i < RESOLUTION; ++i) { + v1[0] = cone->hi + dx; + v1[1] = cone->c1 + cone->radiushi * sin(RADINC * (i - 0.5)) + dy; + v1[2] = cone->c2 + cone->radiushi * cos(RADINC * (i - 0.5)) + dz; + v2[0] = cone->lo + dx; + v2[1] = cone->c1 + cone->radiuslo * sin(RADINC * i) + dy; + v2[2] = cone->c2 + cone->radiuslo * cos(RADINC * i) + dz; + v3[0] = cone->hi + dx; + v3[1] = cone->c1 + cone->radiushi * sin(RADINC * (i + 0.5)) + dy; + v3[2] = cone->c2 + cone->radiushi * cos(RADINC * (i + 0.5)) + dz; + v4[0] = cone->lo + dx; + v4[1] = cone->c1 + cone->radiuslo * sin(RADINC * (i + 1.0)) + dy; + v4[2] = cone->c2 + cone->radiuslo * cos(RADINC * (i + 1.0)) + dz; + v5[0] = 0.0; + v5[1] = sin(RADINC * (i - 0.5)); + v5[2] = cos(RADINC * (i - 0.5)); + v6[0] = 0.0; + v6[1] = sin(RADINC * i); + v6[2] = cos(RADINC * i); + v7[0] = 0.0; + v7[1] = sin(RADINC * (i + 0.5)); + v7[2] = cos(RADINC * (i + 0.5)); + v8[0] = 0.0; + v8[1] = sin(RADINC * (i + 1.0)); + v8[2] = cos(RADINC * (i + 1.0)); + + utils::print(fp, + "draw trinorm {{{} {} {}}} {{{} {} {}}} {{{} {} {}}} " + "{{{} {} {}}} {{{} {} {}}} {{{} {} {}}}\n", + v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], v3[0], v3[1], v3[2], v5[0], + v5[1], v5[2], v6[0], v6[1], v6[2], v7[0], v7[1], v7[2]); + utils::print(fp, + "draw trinorm {{{} {} {}}} {{{} {} {}}} {{{} {} {}}} " + "{{{} {} {}}} {{{} {} {}}} {{{} {} {}}}\n", + v2[0], v2[1], v2[2], v4[0], v4[1], v4[2], v3[0], v3[1], v3[2], v6[0], + v6[1], v6[2], v8[0], v8[1], v8[2], v7[0], v7[1], v7[2]); + } + + } else if (cone->axis == 'y') { + + // loop around radii + for (int i = 0; i < RESOLUTION; ++i) { + v1[0] = cone->c1 + cone->radiushi * sin(RADINC * (i - 0.5)) + dx; + v1[1] = cone->hi + dy; + v1[2] = cone->c2 + cone->radiushi * cos(RADINC * (i - 0.5)) + dz; + v2[0] = cone->c1 + cone->radiuslo * sin(RADINC * i) + dx; + v2[1] = cone->lo + dy; + v2[2] = cone->c2 + cone->radiuslo * cos(RADINC * i) + dz; + v3[0] = cone->c1 + cone->radiushi * sin(RADINC * (i + 0.5)) + dx; + v3[1] = cone->hi + dy; + v3[2] = cone->c2 + cone->radiushi * cos(RADINC * (i + 0.5)) + dz; + v4[0] = cone->c1 + cone->radiuslo * sin(RADINC * (i + 1.0)) + dx; + v4[1] = cone->lo + dy; + v4[2] = cone->c2 + cone->radiuslo * cos(RADINC * (i + 1.0)) + dz; + v5[0] = sin(RADINC * (i - 0.5)); + v5[1] = 0.0; + v5[2] = cos(RADINC * (i - 0.5)); + v6[0] = sin(RADINC * i); + v6[1] = 0.0; + v6[2] = cos(RADINC * i); + v7[0] = sin(RADINC * (i + 0.5)); + v7[1] = 0.0; + v7[2] = cos(RADINC * (i + 0.5)); + v8[0] = sin(RADINC * (i + 1.0)); + v8[1] = 0.0; + v8[2] = cos(RADINC * (i + 1.0)); + + utils::print(fp, + "draw trinorm {{{} {} {}}} {{{} {} {}}} {{{} {} {}}} " + "{{{} {} {}}} {{{} {} {}}} {{{} {} {}}}\n", + v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], v3[0], v3[1], v3[2], v5[0], + v5[1], v5[2], v6[0], v6[1], v6[2], v7[0], v7[1], v7[2]); + utils::print(fp, + "draw trinorm {{{} {} {}}} {{{} {} {}}} {{{} {} {}}} " + "{{{} {} {}}} {{{} {} {}}} {{{} {} {}}}\n", + v2[0], v2[1], v2[2], v4[0], v4[1], v4[2], v3[0], v3[1], v3[2], v6[0], + v6[1], v6[2], v8[0], v8[1], v8[2], v7[0], v7[1], v7[2]); + } + + } else if (cone->axis == 'z') { + + // loop around radii + for (int i = 0; i < RESOLUTION; ++i) { + v1[0] = cone->c1 + cone->radiushi * sin(RADINC * (i - 0.5)) + dx; + v1[1] = cone->c2 + cone->radiushi * cos(RADINC * (i - 0.5)) + dy; + v1[2] = cone->hi + dz; + v2[0] = cone->c1 + cone->radiuslo * sin(RADINC * i) + dx; + v2[1] = cone->c2 + cone->radiuslo * cos(RADINC * i) + dy; + v2[2] = cone->lo + dz; + v3[0] = cone->c1 + cone->radiushi * sin(RADINC * (i + 0.5)) + dx; + v3[1] = cone->c2 + cone->radiushi * cos(RADINC * (i + 0.5)) + dy; + v3[2] = cone->hi + dz; + v4[0] = cone->c1 + cone->radiuslo * sin(RADINC * (i + 1.0)) + dx; + v4[1] = cone->c2 + cone->radiuslo * cos(RADINC * (i + 1.0)) + dy; + v4[2] = cone->lo + dz; + v5[0] = sin(RADINC * (i - 0.5)); + v5[1] = cos(RADINC * (i - 0.5)); + v5[2] = 0.0; + v6[0] = sin(RADINC * i); + v6[1] = cos(RADINC * i); + v6[2] = 0.0; + v7[0] = sin(RADINC * (i + 0.5)); + v7[1] = cos(RADINC * (i + 0.5)); + v7[2] = 0.0; + v8[0] = sin(RADINC * (i + 1.0)); + v8[1] = cos(RADINC * (i + 1.0)); + v8[2] = 0.0; + + utils::print(fp, + "draw trinorm {{{} {} {}}} {{{} {} {}}} {{{} {} {}}} " + "{{{} {} {}}} {{{} {} {}}} {{{} {} {}}}\n", + v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], v3[0], v3[1], v3[2], v5[0], + v5[1], v5[2], v6[0], v6[1], v6[2], v7[0], v7[1], v7[2]); + utils::print(fp, + "draw trinorm {{{} {} {}}} {{{} {} {}}} {{{} {} {}}} " + "{{{} {} {}}} {{{} {} {}}} {{{} {} {}}}\n", + v2[0], v2[1], v2[2], v4[0], v4[1], v4[2], v3[0], v3[1], v3[2], v6[0], + v6[1], v6[2], v8[0], v8[1], v8[2], v7[0], v7[1], v7[2]); + } + } } - } else if (cone->radiushi < SMALL) { - // a VMD cone uses a single cone primitive + } + + // draw lids + if ((cone->radiuslo > SMALL) && !cone->open_faces[0]) { + double lid = cone->lo; if (cone->axis == 'x') { - utils::print(fp, "draw cone {{{0} {2} {3}}} {{{1} {2} {3}}} radius {4} resolution 20\n", - cone->lo + dx, cone->hi + dx, cone->c1 + dy, cone->c2 + dz, cone->radiuslo); + lid += dx; + utils::print(fp, + "draw cylinder {{{0} {2} {3}}} {{{1:.15} {2} {3}}} radius {4} " + "resolution {5} filled yes\n", + lid, lid + DELTA, cone->c1 + dy, cone->c2 + dz, cone->radiuslo, RESOLUTION); } else if (cone->axis == 'y') { - utils::print(fp, "draw cone {{{2} {0} {3}}} {{{2} {1} {3}}} radius {4} resolution 20\n", - cone->lo + dy, cone->hi + dy, cone->c1 + dx, cone->c2 + dz, cone->radiuslo); + lid += dy; + utils::print(fp, + "draw cylinder {{{2} {0} {3}}} {{{2} {1:.15} {3}}} radius {4} " + "resolution {5} filled yes\n", + lid, lid + DELTA, cone->c1 + dx, cone->c2 + dz, cone->radiuslo, RESOLUTION); } else if (cone->axis == 'z') { - utils::print(fp, "draw cone {{{2} {3} {0}}} {{{2} {3} {1}}} radius {4} resolution 20\n", - cone->lo + dz, cone->hi + dz, cone->c1 + dx, cone->c2 + dy, cone->radiuslo); + lid += dz; + utils::print(fp, + "draw cylinder {{{2} {3} {0}}} {{{2} {3} {1:.15}}} radius {4} " + "resolution {5} filled yes\n", + lid, lid + DELTA, cone->c1 + dx, cone->c2 + dy, cone->radiuslo, RESOLUTION); + } + } + if ((cone->radiushi > SMALL) && !cone->open_faces[1]) { + double lid = cone->hi; + if (cone->axis == 'x') { + lid += dx; + utils::print(fp, + "draw cylinder {{{0} {2} {3}}} {{{1:.15} {2} {3}}} radius {4} " + "resolution {5} filled yes\n", + lid, lid + DELTA, cone->c1 + dy, cone->c2 + dz, cone->radiushi, RESOLUTION); + } else if (cone->axis == 'y') { + lid += dy; + utils::print(fp, + "draw cylinder {{{2} {0} {3}}} {{{2} {1:.15} {3}}} radius {4} " + "resolution {5} filled yes\n", + lid, lid + DELTA, cone->c1 + dx, cone->c2 + dz, cone->radiushi, RESOLUTION); + } else if (cone->axis == 'z') { + lid += dz; + utils::print(fp, + "draw cylinder {{{2} {3} {0}}} {{{2} {3} {1:.15}}} radius {4} " + "resolution {5} filled yes\n", + lid, lid + DELTA, cone->c1 + dx, cone->c2 + dy, cone->radiushi, RESOLUTION); } - } else { - utils::logmesg(lmp, - "Cannot (yet) translate a truncated cone to VMD graphics. Skipping...\n"); } } } else if (regstyle == "cylinder") { - const auto cylinder = dynamic_cast(region); - if (!cylinder) { + const auto cyl = dynamic_cast(region); + if (!cyl) { error->one(FLERR, Error::NOLASTLINE, "Region {} is not of style 'cylinder'", region->id); } else { - std::string filled = "yes"; - if (cylinder->open_faces[0] && cylinder->open_faces[1]) { - filled = "no"; - } else if (cylinder->open_faces[0] != cylinder->open_faces[1]) { - filled = "no"; - // we put a single "lid" on an open cylinder by adding a filled cylinder of zero height - double lid = cylinder->lo; - if (cylinder->open_faces[0]) lid = cylinder->hi; - if (cylinder->axis == 'x') { - utils::print(fp, - "draw cylinder {{{0} {2} {3}}} {{{1:.15} {2} {3}}} radius {4} resolution 20 " - "filled yes\n", - lid + dx, lid + dx + DELTA, cylinder->c1 + dy, cylinder->c2 + dz, - cylinder->radius); - } else if (cylinder->axis == 'y') { - utils::print(fp, - "draw cylinder {{{2} {0} {3}}} {{{2} {1:.15} {3}}} radius {4} resolution 20 " - "filled yes\n", - lid + dy, lid + dy + DELTA, cylinder->c1 + dx, cylinder->c2 + dz, - cylinder->radius); - } else if (cylinder->axis == 'z') { - utils::print(fp, - "draw cylinder {{{2} {3} {0}}} {{{2} {3} {1:.15}}} radius {4} resolution 20 " - "filled yes\n", - lid + dz, lid + dz + DELTA, cylinder->c1 + dx, cylinder->c2 + dy, - cylinder->radius); + // first draw the cylinder. filled only when *all* faces are closed. + // with any open face we draw each part separately + std::string filled = "filled no"; + if (!cyl->open_faces[0] && !cyl->open_faces[1] && !cyl->open_faces[2]) { + filled = "filled yes"; + } + + // the cylinder uses a single cylinder primitive + if (!cyl->open_faces[2]) { + if (cyl->axis == 'x') { + utils::print( + fp, "draw cylinder {{{0} {2} {3}}} {{{1} {2} {3}}} radius {4} resolution {5} {6}\n", + cyl->lo + dx, cyl->hi + dx, cyl->c1 + dy, cyl->c2 + dz, cyl->radius, RESOLUTION, + filled); + } else if (cyl->axis == 'y') { + utils::print( + fp, "draw cylinder {{{2} {0} {3}}} {{{2} {1} {3}}} radius {4} resolution {5} {6}\n", + cyl->lo + dy, cyl->hi + dy, cyl->c1 + dx, cyl->c2 + dz, cyl->radius, RESOLUTION, + filled); + } else if (cyl->axis == 'z') { + utils::print( + fp, "draw cylinder {{{2} {3} {0}}} {{{2} {3} {1}}} radius {4} resolution {5} {6}\n", + cyl->lo + dz, cyl->hi + dz, cyl->c1 + dx, cyl->c2 + dy, cyl->radius, RESOLUTION, + filled); } } - if (cylinder->open_faces[2]) { - // need to handle two lids case only. Single lid is already done - if (!cylinder->open_faces[0] && !cylinder->open_faces[1]) { - if (cylinder->axis == 'x') { - utils::print( - fp, - "draw cylinder {{{0} {2} {3}}} {{{1:.15} {2} {3}}} radius {4} resolution 20 " - "filled yes\n", - cylinder->lo + dx, cylinder->lo + dx + DELTA, cylinder->c1 + dy, cylinder->c2 + dz, - cylinder->radius); - utils::print( - fp, - "draw cylinder {{{0} {2} {3}}} {{{1:.15} {2} {3}}} radius {4} resolution 20 " - "filled yes\n", - cylinder->hi + dx, cylinder->hi + dx + DELTA, cylinder->c1 + dy, cylinder->c2 + dz, - cylinder->radius); - } else if (cylinder->axis == 'y') { - utils::print( - fp, - "draw cylinder {{{2} {0} {3}}} {{{2} {1:.15} {3}}} radius {4} resolution 20 " - "filled yes\n", - cylinder->lo + dy, cylinder->lo + dy + DELTA, cylinder->c1 + dx, cylinder->c2 + dz, - cylinder->radius); - utils::print( - fp, - "draw cylinder {{{2} {0} {3}}} {{{2} {1:.15} {3}}} radius {4} resolution 20 " - "filled yes\n", - cylinder->hi + dy, cylinder->hi + dy + DELTA, cylinder->c1 + dx, cylinder->c2 + dz, - cylinder->radius); - } else if (cylinder->axis == 'z') { - utils::print( - fp, - "draw cylinder {{{2} {3} {0}}} {{{2} {3} {1:.15}}} radius {4} resolution 20 " - "filled yes\n", - cylinder->lo + dz, cylinder->lo + dz + DELTA, cylinder->c1 + dx, cylinder->c2 + dy, - cylinder->radius); - utils::print( - fp, - "draw cylinder {{{2} {3} {0}}} {{{2} {3} {1:.15}}} radius {4} resolution 20 " - "filled yes\n", - cylinder->hi + dz, cylinder->hi + dz + DELTA, cylinder->c1 + dx, cylinder->c2 + dy, - cylinder->radius); - } + + // draw lids + if ((filled == "filled no") && !cyl->open_faces[0]) { + double lid = cyl->lo; + if (cyl->axis == 'x') { + lid += dx; + utils::print(fp, + "draw cylinder {{{0} {2} {3}}} {{{1:.15} {2} {3}}} radius {4} " + "resolution {5} filled yes\n", + lid, lid + DELTA, cyl->c1 + dy, cyl->c2 + dz, cyl->radius, RESOLUTION); + } else if (cyl->axis == 'y') { + lid += dy; + utils::print(fp, + "draw cylinder {{{2} {0} {3}}} {{{2} {1:.15} {3}}} radius {4} " + "resolution {5} filled yes\n", + lid, lid + DELTA, cyl->c1 + dx, cyl->c2 + dz, cyl->radius, RESOLUTION); + } else if (cyl->axis == 'z') { + lid += dz; + utils::print(fp, + "draw cylinder {{{2} {3} {0}}} {{{2} {3} {1:.15}}} radius {4} " + "resolution {5} filled yes\n", + lid, lid + DELTA, cyl->c1 + dx, cyl->c2 + dy, cyl->radius, RESOLUTION); } - } else { - // a cylinder uses a single cylinder primitive and possibly a single "lid" - if (cylinder->axis == 'x') { - utils::print( - fp, - "draw cylinder {{{0} {2} {3}}} {{{1} {2} {3}}} radius {4} resolution 20 filled {5}\n", - cylinder->lo + dx, cylinder->hi + dx, cylinder->c1 + dy, cylinder->c2 + dz, - cylinder->radius, filled); - } else if (cylinder->axis == 'y') { - utils::print( - fp, - "draw cylinder {{{2} {0} {3}}} {{{2} {1} {3}}} radius {4} resolution 20 filled {5}\n", - cylinder->lo + dy, cylinder->hi + dy, cylinder->c1 + dx, cylinder->c2 + dz, - cylinder->radius, filled); - } else if (cylinder->axis == 'z') { - utils::print( - fp, - "draw cylinder {{{2} {3} {0}}} {{{2} {3} {1}}} radius {4} resolution 20 filled {5}\n", - cylinder->lo + dz, cylinder->hi + dz, cylinder->c1 + dx, cylinder->c2 + dy, - cylinder->radius, filled); + } + if ((filled == "filled no") && !cyl->open_faces[1]) { + double lid = cyl->hi; + if (cyl->axis == 'x') { + lid += dx; + utils::print(fp, + "draw cylinder {{{0} {2} {3}}} {{{1:.15} {2} {3}}} radius {4} " + "resolution {5} filled yes\n", + lid, lid + DELTA, cyl->c1 + dy, cyl->c2 + dz, cyl->radius, RESOLUTION); + } else if (cyl->axis == 'y') { + lid += dy; + utils::print(fp, + "draw cylinder {{{2} {0} {3}}} {{{2} {1:.15} {3}}} radius {4} " + "resolution {5} filled yes\n", + lid, lid + DELTA, cyl->c1 + dx, cyl->c2 + dz, cyl->radius, RESOLUTION); + } else if (cyl->axis == 'z') { + lid += dz; + utils::print(fp, + "draw cylinder {{{2} {3} {0}}} {{{2} {3} {1:.15}}} radius {4} " + "resolution {5} filled yes\n", + lid, lid + DELTA, cyl->c1 + dx, cyl->c2 + dy, cyl->radius, RESOLUTION); } } } @@ -504,8 +801,8 @@ void Region2VMD::write_region(FILE *fp, Region *region) error->one(FLERR, Error::NOLASTLINE, "Region {} is not of style 'sphere'", region->id); } else { // a sphere uses a single sphere primitive - utils::print(fp, "draw sphere {{{} {} {}}} radius {} resolution 20\n", sphere->xc, sphere->yc, - sphere->zc, sphere->radius); + utils::print(fp, "draw sphere {{{} {} {}}} radius {} resolution {}\n", sphere->xc, sphere->yc, + sphere->zc, sphere->radius, RESOLUTION); } } else { diff --git a/src/EXTRA-COMPUTE/compute_hma.cpp b/src/EXTRA-COMPUTE/compute_hma.cpp index 8ddc413477..38677c9176 100644 --- a/src/EXTRA-COMPUTE/compute_hma.cpp +++ b/src/EXTRA-COMPUTE/compute_hma.cpp @@ -75,10 +75,10 @@ using namespace LAMMPS_NS; ComputeHMA::ComputeHMA(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), id_temp(nullptr), deltaR(nullptr) { - if (narg < 4) error->all(FLERR,"Illegal compute hma command"); - if (igroup) error->all(FLERR,"Compute hma must use group all"); + if (narg < 4) utils::missing_cmd_args(FLERR,"compute hma", error); + if (igroup) error->all(FLERR, 1, "Compute hma must use group all"); if (strcmp(arg[3],"NULL") == 0) - error->all(FLERR,"fix ID specifying the set temperature of canonical simulation is required"); + error->all(FLERR, 3, "fix ID specifying the set temperature of canonical simulation is required"); else id_temp = utils::strdup(arg[3]); create_attribute = 1; @@ -139,7 +139,7 @@ ComputeHMA::ComputeHMA(LAMMPS *lmp, int narg, char **arg) : // the first time we're called, we'll grab lattice pressure and energy returnAnharmonic = -1; } else { - error->all(FLERR,"Illegal compute hma command"); + error->all(FLERR, iarg, "Unknown compute hma keyword {}", arg[iarg]); } } @@ -172,9 +172,9 @@ ComputeHMA::~ComputeHMA() void ComputeHMA::init() { if (computeCv>-1) { if (force->pair == nullptr) - error->all(FLERR,"No pair style is defined for compute hma cv"); + error->all(FLERR, Error::NOLASTLINE, "No pair style is defined for compute hma cv"); if (force->pair->single_enable == 0) - error->all(FLERR,"Pair style does not support compute hma cv"); + error->all(FLERR, Error::NOLASTLINE, "Pair style does not support compute hma cv"); } neighbor->add_request(this, NeighConst::REQ_OCCASIONAL); @@ -189,15 +189,19 @@ void ComputeHMA::setup() { int dummy=0; Fix *ifix = modify->get_fix_by_id(id_temp); - if (!ifix) error->all(FLERR,"Could not find compute hma temperature fix ID {}", id_temp); + if (!ifix) + error->all(FLERR, Error::NOLASTLINE, "Could not find compute hma temperature fix ID {}", + id_temp); auto temperat = (double *) ifix->extract("t_target",dummy); - if (temperat == nullptr) error->all(FLERR,"Fix ID {} is not a thermostat {}", id_temp); + if (temperat == nullptr) + error->all(FLERR, Error::NOLASTLINE, "Fix ID {} is not a thermostat {}", id_temp); finaltemp = *temperat; // set fix which stores original atom coords fix = dynamic_cast(modify->get_fix_by_id(id_fix)); - if (!fix) error->all(FLERR,"Could not find hma per-atom store fix ID {}", id_fix); + if (!fix) + error->all(FLERR, Error::NOLASTLINE, "Could not find hma per-atom store fix ID {}", id_fix); } /* ---------------------------------------------------------------------- */ diff --git a/src/EXTRA-FIX/fix_numdiff_virial.cpp b/src/EXTRA-FIX/fix_numdiff_virial.cpp index 895c10b581..826d1975c0 100644 --- a/src/EXTRA-FIX/fix_numdiff_virial.cpp +++ b/src/EXTRA-FIX/fix_numdiff_virial.cpp @@ -41,8 +41,8 @@ using namespace FixConst; FixNumDiffVirial::FixNumDiffVirial(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), id_pe(nullptr), pe(nullptr), temp_x(nullptr), temp_f(nullptr) { - if (narg < 5) error->all(FLERR, "Illegal fix numdiff/virial command"); - if (igroup) error->all(FLERR, "Compute numdiff/virial must use group all"); + if (narg < 5) utils::missing_cmd_args(FLERR, "numdiff/virial", error); + if (igroup) error->all(FLERR, 1, "Compute numdiff/virial must use group all"); peratom_freq = nevery; respa_level_support = 1; @@ -121,10 +121,12 @@ void FixNumDiffVirial::init() pe = modify->get_compute_by_id(id_pe); if (!pe) { - error->all(FLERR, "Potential energy compute ID {} for fix {} does not exist", id_pe, style); + error->all(FLERR, Error::NOLASTLINE, "Potential energy compute ID {} for fix {} does not exist", + id_pe, style); } else { if (pe->peflag == 0) - error->all(FLERR, "Compute ID {} for fix {} does not compute potential energy", id_pe, style); + error->all(FLERR, Error::NOLASTLINE, + "Compute ID {} for fix {} does not compute potential energy", id_pe, style); } if (force->pair && force->pair->compute_flag) diff --git a/src/KOKKOS/comm_kokkos.cpp b/src/KOKKOS/comm_kokkos.cpp index 5bf7464ac0..22800a1376 100644 --- a/src/KOKKOS/comm_kokkos.cpp +++ b/src/KOKKOS/comm_kokkos.cpp @@ -793,7 +793,10 @@ void CommKokkos::exchange() } atomKK->sync(Host,ALL_MASK); + int prev_auto_sync = lmp->kokkos->auto_sync; + lmp->kokkos->auto_sync = 1; CommBrick::exchange(); + lmp->kokkos->auto_sync = prev_auto_sync; atomKK->modified(Host,ALL_MASK); } diff --git a/src/KOKKOS/mliap_model_python_kokkos.cpp b/src/KOKKOS/mliap_model_python_kokkos.cpp index 4435a0371a..1b010cc286 100644 --- a/src/KOKKOS/mliap_model_python_kokkos.cpp +++ b/src/KOKKOS/mliap_model_python_kokkos.cpp @@ -68,12 +68,12 @@ MLIAPModelPythonKokkos::MLIAPModelPythonKokkos(LAMMPS *lmp, char *co // Recipe from lammps/src/pair_python.cpp : // add current directory to PYTHONPATH PyObject *py_path = PySys_GetObject((char *) "path"); - PyList_Append(py_path, PY_STRING_FROM_STRING(".")); + PyList_Append(py_path, PyUnicode_FromString(".")); // if LAMMPS_POTENTIALS environment variable is set, add it to PYTHONPATH as well const char *potentials_path = getenv("LAMMPS_POTENTIALS"); if (potentials_path != nullptr) { - PyList_Append(py_path, PY_STRING_FROM_STRING(potentials_path)); + PyList_Append(py_path, PyUnicode_FromString(potentials_path)); } PyGILState_Release(gstate); if (coefffilename) read_coeffs(coefffilename); diff --git a/src/KOKKOS/nbin_kokkos.cpp b/src/KOKKOS/nbin_kokkos.cpp index 79ae9c6632..6a663fb0f0 100644 --- a/src/KOKKOS/nbin_kokkos.cpp +++ b/src/KOKKOS/nbin_kokkos.cpp @@ -109,7 +109,7 @@ void NBinKokkos::bin_atoms() if (h_resize()) { atoms_per_bin += 16; - k_bins = DAT::tdual_int_2d("bins", mbins, atoms_per_bin); + k_bins = DAT::tdual_int_2d("Neighbor::bins", mbins, atoms_per_bin); bins = k_bins.view(); c_bins = bins; } diff --git a/src/ML-IAP/mliap_model_python.cpp b/src/ML-IAP/mliap_model_python.cpp index c06bbdc121..c1c534401a 100644 --- a/src/ML-IAP/mliap_model_python.cpp +++ b/src/ML-IAP/mliap_model_python.cpp @@ -62,12 +62,12 @@ MLIAPModelPython::MLIAPModelPython(LAMMPS *lmp, char *coefffilename, bool is_chi // Recipe from lammps/src/pair_python.cpp : // add current directory to PYTHONPATH PyObject *py_path = PySys_GetObject((char *) "path"); - PyList_Append(py_path, PY_STRING_FROM_STRING(".")); + PyList_Append(py_path, PyUnicode_FromString(".")); // if LAMMPS_POTENTIALS environment variable is set, add it to PYTHONPATH as well const char *potentials_path = getenv("LAMMPS_POTENTIALS"); if (potentials_path != nullptr) { - PyList_Append(py_path, PY_STRING_FROM_STRING(potentials_path)); + PyList_Append(py_path, PyUnicode_FromString(potentials_path)); } PyGILState_Release(gstate); if (coefffilename) read_coeffs(coefffilename); diff --git a/src/ML-RANN/rann_fingerprint_bond.cpp b/src/ML-RANN/rann_fingerprint_bond.cpp index acc3318ba0..536859dc8f 100644 --- a/src/ML-RANN/rann_fingerprint_bond.cpp +++ b/src/ML-RANN/rann_fingerprint_bond.cpp @@ -36,6 +36,8 @@ DISTRIBUTION A. Approved for public release; distribution unlimited. OPSEC#4918 using namespace LAMMPS_NS::RANN; +static constexpr double SMALL = 1.0e-12; + Fingerprint_bond::Fingerprint_bond(PairRANN *_pair) : Fingerprint(_pair) { n_body_type = 3; @@ -317,7 +319,8 @@ void Fingerprint_bond::do3bodyfeatureset_singleneighborloop(double * features,do i = ilist[ii]; itype = pair->map[type[i]]; int f = pair->net[itype].dimensions[0]; - double expr[jnum][kmax+12]; + std::vector row(kmax+12, 0.0); + std::vector> expr(jnum, row); int p = kmax; int countmb=((mlength)*(mlength+1))>>1; // calculate interpolation expr, rinvs and dfc, for each neighbor @@ -354,13 +357,13 @@ void Fingerprint_bond::do3bodyfeatureset_singleneighborloop(double * features,do expr[jj][p+1]=dely*rinvs; expr[jj][p+2]=delz*rinvs; //Hack to avoid nan when x y or z component of radial vector is exactly 0. Shouldn't affect accuracy. - if (expr[jj][p]*expr[jj][p]<0.000000000001) { + if (expr[jj][p]*expr[jj][p] < SMALL) { expr[jj][p] = 0.000001; } - if (expr[jj][p+1]*expr[jj][p+1]<0.000000000001) { + if (expr[jj][p+1]*expr[jj][p+1] < SMALL) { expr[jj][p+1] = 0.000001; } - if (expr[jj][p+2]*expr[jj][p+2]<0.000000000001) { + if (expr[jj][p+2]*expr[jj][p+2] < SMALL) { expr[jj][p+2] = 0.000001; } expr[jj][p+3] = -dfc*expr[jj][p]; @@ -377,7 +380,7 @@ void Fingerprint_bond::do3bodyfeatureset_singleneighborloop(double * features,do int kb = kmax; int mb = mlength; count = startingneuron; - double Bb[mb]; + std::vector Bb(mb, 0.0); double dBbx; double dBby; double dBbz; @@ -397,7 +400,7 @@ void Fingerprint_bond::do3bodyfeatureset_singleneighborloop(double * features,do } for (n=0;n Bg(mb, 0.0); ai = n; double y1 = alpha_k[ai]/re; //loop over ktype to get Bg @@ -433,7 +433,7 @@ void Fingerprint_bond::do3bodyfeatureset_singleneighborloop(double * features,do continue; } double yprod = expr[jj][ai]; - double *y4 = &expr[jj][p]; + double *y4 = expr[jj].data() + p; for (a2=0;a2map[type[i]]; int f = pair->net[itype].dimensions[0]; - double expr[jnum][kmax]; - double y[jnum][3]; - double ri[jnum]; - double dfc[jnum]; + std::vector row(kmax, 0.0); + std::vector> expr(jnum, row); + std::vector yrow(3, 0.0); + std::vector> y(jnum, yrow); + std::vector ri(jnum, 0.0); + std::vector dfc(jnum, 0.0); int kb = kmax; int mb = mlength; - double c41[kmax]; - double c51[kmax]; - double c61[kmax]; - double ct[kmax]; + std::vector c41(kmax, 0.0); + std::vector c51(kmax, 0.0); + std::vector c61(kmax, 0.0); + std::vector ct(kmax, 0.0); for (jj = 0; jj < jnum; jj++) { jtype = tn[jj]; if (jtypes != nelements && jtypes != jtype && ktypes != nelements && ktypes != jtype) { diff --git a/src/ML-RANN/rann_fingerprint_bondscreened.cpp b/src/ML-RANN/rann_fingerprint_bondscreened.cpp index 8dcc2e4389..018bbc6df1 100644 --- a/src/ML-RANN/rann_fingerprint_bondscreened.cpp +++ b/src/ML-RANN/rann_fingerprint_bondscreened.cpp @@ -36,6 +36,8 @@ DISTRIBUTION A. Approved for public release; distribution unlimited. OPSEC#4918 using namespace LAMMPS_NS::RANN; +static constexpr double SMALL = 1.0e-12; + Fingerprint_bondscreened::Fingerprint_bondscreened(PairRANN *_pair) : Fingerprint(_pair) { n_body_type = 3; @@ -319,7 +321,8 @@ void Fingerprint_bondscreened::do3bodyfeatureset_singleneighborloop(double * fea i = ilist[ii]; itype = pair->map[type[i]]; int f = pair->net[itype].dimensions[0]; - double expr[jnum][kmax+12]; + std::vector row(kmax+12, 0.0); + std::vector> expr(jnum, row); int p = kmax; int countmb=((mlength)*(mlength+1))>>1; // calculate interpolation expr, rinvs and dfc, for each neighbor @@ -358,13 +361,13 @@ void Fingerprint_bondscreened::do3bodyfeatureset_singleneighborloop(double * fea expr[jj][p+1]=dely*rinvs; expr[jj][p+2]=delz*rinvs; //Hack to avoid nan when x y or z component of radial vector is exactly 0. Shouldn't affect accuracy. - if (expr[jj][p]*expr[jj][p]<0.000000000001) { + if (expr[jj][p]*expr[jj][p] < SMALL) { expr[jj][p] = 0.000001; } - if (expr[jj][p+1]*expr[jj][p+1]<0.000000000001) { + if (expr[jj][p+1]*expr[jj][p+1] < SMALL) { expr[jj][p+1] = 0.000001; } - if (expr[jj][p+2]*expr[jj][p+2]<0.000000000001) { + if (expr[jj][p+2]*expr[jj][p+2] < SMALL) { expr[jj][p+2] = 0.000001; } expr[jj][p+3] = -dfc*expr[jj][p]-dSikx[jj]; @@ -381,20 +384,20 @@ void Fingerprint_bondscreened::do3bodyfeatureset_singleneighborloop(double * fea int kb = kmax; int mb = mlength; count = startingneuron; - double Bb[mb]; + std::vector Bb(mb, 0.0); double dBbx; double dBby; double dBbz; - double dBbx1[mb]; - double dBby1[mb]; - double dBbz1[mb]; + std::vector dBbx1(mb, 0.0); + std::vector dBby1(mb, 0.0); + std::vector dBbz1(mb, 0.0); double yprod; for (mcount=0;mcount Bg(mb, 0.0); ai = n; double y1 = alpha_k[ai]/re; //loop over ktype to get Bg @@ -445,7 +445,7 @@ void Fingerprint_bondscreened::do3bodyfeatureset_singleneighborloop(double * fea continue; } double yprod = expr[jj][ai]; - double *y4 = &expr[jj][p]; + double *y4 = expr[jj].data() + p; for (a2=0;a2map[type[i]]; int f = pair->net[itype].dimensions[0]; - double expr[jnum][kmax]; - double y[jnum][3]; - double ri[jnum]; - double dfc[jnum]; + std::vector row(kmax, 0.0); + std::vector> expr(jnum, row); + std::vector yrow(3, 0.0); + std::vector> y(jnum, yrow); + std::vector ri(jnum, 0.0); + std::vector dfc(jnum, 0.0); int kb = kmax; int mb = mlength; - double Bijk[kb][mb]; - double c41[kmax]; - double c51[kmax]; - double c61[kmax]; - double ct[kmax]; + std::vector brow(mb, 0.0); + std::vector> Bijk(kb, brow); + std::vector c41(kmax, 0.0); + std::vector c51(kmax, 0.0); + std::vector c61(kmax, 0.0); + std::vector ct(kmax, 0.0); for (jj = 0; jj < jnum; jj++) { if (Bij[jj]==false) {continue;} jtype = tn[jj]; diff --git a/src/ML-RANN/rann_fingerprint_bondscreenedspin.cpp b/src/ML-RANN/rann_fingerprint_bondscreenedspin.cpp index cbd3b2a6dc..26fa46b4eb 100644 --- a/src/ML-RANN/rann_fingerprint_bondscreenedspin.cpp +++ b/src/ML-RANN/rann_fingerprint_bondscreenedspin.cpp @@ -35,6 +35,8 @@ DISTRIBUTION A. Approved for public release; distribution unlimited. OPSEC#4918 using namespace LAMMPS_NS::RANN; +static constexpr double SMALL = 1.0e-12; + Fingerprint_bondscreenedspin::Fingerprint_bondscreenedspin(PairRANN *_pair) : Fingerprint(_pair) { n_body_type = 3; @@ -320,7 +322,8 @@ void Fingerprint_bondscreenedspin::do3bodyfeatureset_singleneighborloop(double * i = ilist[ii]; itype = pair->map[type[i]]; int f = pair->net[itype].dimensions[0]; - double expr[jnum][kmax+12]; + std::vector row(kmax+12, 0.0); + std::vector> expr(jnum, row); int p = kmax; int countmb=((mlength)*(mlength+1))>>1; double *si = sim->s[i]; @@ -360,13 +363,13 @@ void Fingerprint_bondscreenedspin::do3bodyfeatureset_singleneighborloop(double * expr[jj][p+1]=dely*rinvs; expr[jj][p+2]=delz*rinvs; //Hack to avoid nan when x y or z component of radial vector is exactly 0. Shouldn't affect accuracy. - if (expr[jj][p]*expr[jj][p]<0.000000000001) { + if (expr[jj][p]*expr[jj][p] < SMALL) { expr[jj][p] = 0.000001; } - if (expr[jj][p+1]*expr[jj][p+1]<0.000000000001) { + if (expr[jj][p+1]*expr[jj][p+1] < SMALL) { expr[jj][p+1] = 0.000001; } - if (expr[jj][p+2]*expr[jj][p+2]<0.000000000001) { + if (expr[jj][p+2]*expr[jj][p+2] < SMALL) { expr[jj][p+2] = 0.000001; } expr[jj][p+3] = -dfc*expr[jj][p]-dSikx[jj]; @@ -383,8 +386,8 @@ void Fingerprint_bondscreenedspin::do3bodyfeatureset_singleneighborloop(double * int kb = kmax; int mb = mlength; count = startingneuron; - double Bb[mb]; - double Bbs[mb]; + std::vector Bb(mb, 0.0); + std::vector Bbs(mb, 0.0); double dBbx; double dBby; double dBbz; @@ -421,7 +424,7 @@ void Fingerprint_bondscreenedspin::do3bodyfeatureset_singleneighborloop(double * double *sj = sim->s[j]; double sp = si[0]*sj[0]+si[1]*sj[1]+si[2]*sj[2]; double yprod = expr[jj][ai]; - double *y4 = &expr[jj][p]; + double *y4 = expr[jj].data() + p; for (a2=0;a2 Bg(mb, 0.0); + std::vector Bgs(mb, 0.0); ai = n; double y1 = alpha_k[ai]/re; //loop over ktype to get Bg @@ -452,7 +451,7 @@ void Fingerprint_bondscreenedspin::do3bodyfeatureset_singleneighborloop(double * double *sj = sim->s[j]; double sp = si[0]*sj[0]+si[1]*sj[1]+si[2]*sj[2]; double yprod = expr[jj][ai]; - double *y4 = &expr[jj][p]; + double *y4 = expr[jj].data() + p; for (a2=0;a2s[j]; double sp = si[0]*sj[0]+si[1]*sj[1]+si[2]*sj[2]; - double *y3 = &expr[jj][p+3]; - double *y4 = &expr[jj][p]; + double *y3 = expr[jj].data() + p + 3; + double *y4 = expr[jj].data() + p; ai = n; yprod = expr[jj][ai]; for (a2=0;a2s[j]; double sp = si[0]*sj[0]+si[1]*sj[1]+si[2]*sj[2]; - double *y3 = &expr[jj][p+3]; - double *y4 = &expr[jj][p]; + double *y3 = expr[jj].data() + p + 3; + double *y4 = expr[jj].data() + p; ai = n; yprod = expr[jj][ai]; for (a2=0;a2s[j]; double sp = si[0]*sj[0]+si[1]*sj[1]+si[2]*sj[2]; - double *y3 = &expr[jj][p+3]; - double *y4 = &expr[jj][p]; + double *y3 = expr[jj].data() + p + 3; + double *y4 = expr[jj].data() + p; ai = n; yprod = expr[jj][ai]; for (a2=0;a2map[type[i]]; int f = pair->net[itype].dimensions[0]; - double expr[jnum][kmax]; - double y[jnum][3]; - double ri[jnum]; - double dfc[jnum]; + std::vector row(kmax, 0.0); + std::vector> expr(jnum, row); + std::vector yrow(3, 0.0); + std::vector> y(jnum, yrow); + std::vector ri(jnum, 0.0); + std::vector dfc(jnum, 0.0); int kb = kmax; int mb = mlength; - double Bijk[kb][mb]; - double c41[kmax]; - double c51[kmax]; - double c61[kmax]; - double ct[kmax]; double *si = sim->s[i]; + std::vector brow(mb, 0.0); + std::vector> Bijk(kb, brow); + std::vector c41(kmax, 0.0); + std::vector c51(kmax, 0.0); + std::vector c61(kmax, 0.0); + std::vector ct(kmax, 0.0); for (jj = 0; jj < jnum; jj++) { if (Bij[jj]==false) {continue;} jtype = tn[jj]; diff --git a/src/ML-RANN/rann_fingerprint_bondspin.cpp b/src/ML-RANN/rann_fingerprint_bondspin.cpp index 1ccdf8ff62..5ecd37b89c 100644 --- a/src/ML-RANN/rann_fingerprint_bondspin.cpp +++ b/src/ML-RANN/rann_fingerprint_bondspin.cpp @@ -35,6 +35,8 @@ DISTRIBUTION A. Approved for public release; distribution unlimited. OPSEC#4918 using namespace LAMMPS_NS::RANN; +static constexpr double SMALL = 1.0e-12; + Fingerprint_bondspin::Fingerprint_bondspin(PairRANN *_pair) : Fingerprint(_pair) { n_body_type = 3; @@ -317,7 +319,8 @@ void Fingerprint_bondspin::do3bodyfeatureset_singleneighborloop(double * feature i = ilist[ii]; itype = pair->map[type[i]]; int f = pair->net[itype].dimensions[0]; - double expr[jnum][kmax+12]; + std::vector row(kmax+12, 0.0); + std::vector> expr(jnum, row); int p = kmax; int countmb=((mlength)*(mlength+1))>>1; double *si = sim->s[i]; @@ -355,13 +358,13 @@ void Fingerprint_bondspin::do3bodyfeatureset_singleneighborloop(double * feature expr[jj][p+1]=dely*rinvs; expr[jj][p+2]=delz*rinvs; //Hack to avoid nan when x y or z component of radial vector is exactly 0. Shouldn't affect accuracy. - if (expr[jj][p]*expr[jj][p]<0.000000000001) { + if (expr[jj][p]*expr[jj][p] < SMALL) { expr[jj][p] = 0.000001; } - if (expr[jj][p+1]*expr[jj][p+1]<0.000000000001) { + if (expr[jj][p+1]*expr[jj][p+1] < SMALL) { expr[jj][p+1] = 0.000001; } - if (expr[jj][p+2]*expr[jj][p+2]<0.000000000001) { + if (expr[jj][p+2]*expr[jj][p+2] < SMALL) { expr[jj][p+2] = 0.000001; } expr[jj][p+3] = -dfc*expr[jj][p]; @@ -378,8 +381,8 @@ void Fingerprint_bondspin::do3bodyfeatureset_singleneighborloop(double * feature int kb = kmax; int mb = mlength; count = startingneuron; - double Bb[mb]; - double Bbs[mb]; + std::vector Bb(mb, 0.0); + std::vector Bbs(mb, 0.0); double dBbx; double dBby; double dBbz; @@ -415,7 +418,7 @@ void Fingerprint_bondspin::do3bodyfeatureset_singleneighborloop(double * feature double *sj = sim->s[j]; double sp = si[0]*sj[0]+si[1]*sj[1]+si[2]*sj[2]; double yprod = expr[jj][ai]; - double *y4 = &expr[jj][p]; + double *y4 = expr[jj].data() + p; for (a2=0;a2 Bg(mb, 0.0); + std::vector Bgs(mb, 0.0); ai = n; double y1 = alpha_k[ai]/re; //loop over ktype to get Bg @@ -445,7 +444,7 @@ void Fingerprint_bondspin::do3bodyfeatureset_singleneighborloop(double * feature double *sj = sim->s[j]; double sp = si[0]*sj[0]+si[1]*sj[1]+si[2]*sj[2]; double yprod = expr[jj][ai]; - double *y4 = &expr[jj][p]; + double *y4 = expr[jj].data() + p; for (a2=0;a2s[j]; double sp = si[0]*sj[0]+si[1]*sj[1]+si[2]*sj[2]; - double *y3 = &expr[jj][p+3]; - double *y4 = &expr[jj][p]; + double *y3 = expr[jj].data() + p + 3; + double *y4 = expr[jj].data() + p; ai = n; yprod = expr[jj][ai]; for (a2=0;a2s[j]; double sp = si[0]*sj[0]+si[1]*sj[1]+si[2]*sj[2]; - double *y3 = &expr[jj][p+3]; - double *y4 = &expr[jj][p]; + double *y3 = expr[jj].data() + p + 3; + double *y4 = expr[jj].data() + p; ai = n; yprod = expr[jj][ai]; for (a2=0;a2s[j]; double sp = si[0]*sj[0]+si[1]*sj[1]+si[2]*sj[2]; - double *y3 = &expr[jj][p+3]; - double *y4 = &expr[jj][p]; + double *y3 = expr[jj].data() + p + 3; + double *y4 = expr[jj].data() + p; ai = n; yprod = expr[jj][ai]; for (a2=0;a2map[type[i]]; int f = pair->net[itype].dimensions[0]; - double expr[jnum][kmax]; - double y[jnum][3]; - double ri[jnum]; - double dfc[jnum]; + std::vector row(kmax, 0.0); + std::vector> expr(jnum, row); + std::vector yrow(3, 0.0); + std::vector> y(jnum, yrow); + std::vector ri(jnum, 0.0); + std::vector dfc(jnum, 0.0); int kb = kmax; int mb = mlength; - double c41[kmax]; - double c51[kmax]; - double c61[kmax]; - double ct[kmax]; + std::vector c41(kmax, 0.0); + std::vector c51(kmax, 0.0); + std::vector c61(kmax, 0.0); + std::vector ct(kmax, 0.0); double *si = sim->s[i]; for (jj = 0; jj < jnum; jj++) { jtype = tn[jj]; diff --git a/src/Makefile b/src/Makefile index 3de8eb85d5..f4eafbf299 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,6 +2,12 @@ SHELL = /bin/bash PYTHON = python +PYTHON_VERSION=$(word 2,$(shell $(PYTHON) -V 2>&1 | tr '.' ' ')) +ifeq ($(PYTHON_VERSION),2) +PYTHON_CHECK=@echo LAMMPS requires Python 3. Try: 'make PYTHON=python3 ...' ; exit 1 +else +PYTHON_CHECK=@echo +endif DYN_LIB = -ldl #.IGNORE: @@ -276,7 +282,7 @@ LIBDIR = $(@:lib-%=%) # List of all targets help: - @echo '' + $(PYTHON_CHECK) @echo 'make clean-all delete all object files' @echo 'make clean-machine delete object files for one machine' @echo 'make mpi-stubs build dummy MPI library in STUBS' @@ -378,6 +384,7 @@ gitversion: # shared = shared compile in Obj_shared_machine .DEFAULT: + $(PYTHON_CHECK) @if [ $@ = "serial" ]; \ then cd STUBS; $(MAKE); cd ..; fi @test -f MAKE/Makefile.$@ -o -f MAKE/OPTIONS/Makefile.$@ -o \ @@ -465,6 +472,7 @@ mpi-stubs: sinclude ../lib/python/Makefile.lammps install-python: + $(PYTHON_CHECK) @rm -rf ../python/build @$(PYTHON) ../python/install.py -p ../python/lammps -l ../src/liblammps.so -w $(PWD) -v $(PWD)/version.h @@ -483,49 +491,59 @@ tar: check: check-whitespace check-permissions check-homepage check-errordocs check-fmtlib check-docs check-version check-whitespace: + $(PYTHON_CHECK) $(PYTHON) ../tools/coding_standard/whitespace.py .. fix-whitespace: + $(PYTHON_CHECK) $(PYTHON) ../tools/coding_standard/whitespace.py .. -f check-permissions: + $(PYTHON_CHECK) $(PYTHON) ../tools/coding_standard/permissions.py .. fix-permissions: + $(PYTHON_CHECK) $(PYTHON) ../tools/coding_standard/permissions.py .. -f check-homepage: + $(PYTHON_CHECK) $(PYTHON) ../tools/coding_standard/homepage.py .. fix-homepage: + $(PYTHON_CHECK) $(PYTHON) ../tools/coding_standard/homepage.py .. -f check-errordocs: + $(PYTHON_CHECK) $(PYTHON) ../tools/coding_standard/errordocs.py .. fix-errordocs: + $(PYTHON_CHECK) $(PYTHON) ../tools/coding_standard/errordocs.py .. -f check-fmtlib: + $(PYTHON_CHECK) $(PYTHON) ../tools/coding_standard/fmtlib.py .. fix-fmtlib: + $(PYTHON_CHECK) $(PYTHON) ../tools/coding_standard/fmtlib.py .. -f check-docs: + $(PYTHON_CHECK) $(MAKE) $(MFLAGS) -C ../doc anchor_check style_check package_check role_check check-version: + $(PYTHON_CHECK) $(PYTHON) ../tools/coding_standard/versiontags.py .. || echo - format-src: clang-format -i --verbose --style=file *.cpp *.h */*.cpp */*.h format-tests: clang-format -i --verbose --style=file ../unittest/*/*.cpp ../unittest/*/*.h - # Package management package: diff --git a/src/PYTHON/fix_python_invoke.cpp b/src/PYTHON/fix_python_invoke.cpp index 6f27831438..2485371690 100644 --- a/src/PYTHON/fix_python_invoke.cpp +++ b/src/PYTHON/fix_python_invoke.cpp @@ -70,7 +70,7 @@ FixPythonInvoke::FixPythonInvoke(LAMMPS *lmp, int narg, char **arg) : error->all(FLERR,"Could not find Python function"); } - lmpPtr = PY_VOID_POINTER(lmp); + lmpPtr = PyCapsule_New((void *)lmp, nullptr, nullptr); // nvalid = next step on which end_of_step or post_force does something // add nextvalid() to all computes that store invocation times diff --git a/src/PYTHON/fix_python_move.cpp b/src/PYTHON/fix_python_move.cpp index caa1557503..c0be31dee6 100644 --- a/src/PYTHON/fix_python_move.cpp +++ b/src/PYTHON/fix_python_move.cpp @@ -44,7 +44,7 @@ FixPythonMove::FixPythonMove(LAMMPS *lmp, int narg, char **arg) : // add current directory to PYTHONPATH PyObject *py_path = PySys_GetObject((char *)"path"); - PyList_Append(py_path, PY_STRING_FROM_STRING(".")); + PyList_Append(py_path, PyUnicode_FromString(".")); // create integrator instance @@ -73,7 +73,7 @@ FixPythonMove::FixPythonMove(LAMMPS *lmp, int narg, char **arg) : error->all(FLERR,"Could not find integrator class {} in module {}", cls_name, module_name); } - PyObject *ptr = PY_VOID_POINTER(lmp); + PyObject *ptr = PyCapsule_New((void *)lmp, nullptr, nullptr); PyObject *py_move_obj = PyObject_CallFunction(py_move_type, (char *)"O", ptr); Py_CLEAR(ptr); diff --git a/src/PYTHON/pair_python.cpp b/src/PYTHON/pair_python.cpp index 695954604c..0f7baa0104 100644 --- a/src/PYTHON/pair_python.cpp +++ b/src/PYTHON/pair_python.cpp @@ -54,14 +54,14 @@ PairPython::PairPython(LAMMPS *lmp) : Pair(lmp) { PyUtils::GIL lock; PyObject *py_path = PySys_GetObject((char *)"path"); - PyList_Append(py_path, PY_STRING_FROM_STRING(".")); + PyList_Append(py_path, PyUnicode_FromString(".")); // if LAMMPS_POTENTIALS environment variable is set, // add it to PYTHONPATH as well const char *potentials_path = getenv("LAMMPS_POTENTIALS"); if (potentials_path != nullptr) { - PyList_Append(py_path, PY_STRING_FROM_STRING(potentials_path)); + PyList_Append(py_path, PyUnicode_FromString(potentials_path)); } } diff --git a/src/PYTHON/python_compat.h b/src/PYTHON/python_compat.h index d1194056d8..88c0969a59 100644 --- a/src/PYTHON/python_compat.h +++ b/src/PYTHON/python_compat.h @@ -16,22 +16,11 @@ #include -// Wrap API changes between Python 2 and 3 using macros -#if PY_MAJOR_VERSION == 2 -#if defined(_MSC_VER) || defined(__MINGW32__) -#define PY_INT_FROM_LONG(X) PyLong_FromLongLong(X) -#define PY_INT_AS_LONG(X) PyLong_AsLongLong(X) -#define PY_LONG_FROM_STRING(X) std::stoll(X) -#else -#define PY_INT_FROM_LONG(X) PyInt_FromLong(X) -#define PY_INT_AS_LONG(X) PyInt_AsLong(X) -#define PY_LONG_FROM_STRING(X) std::stol(X) +#if PY_VERSION_HEX < 0x030600f0 +#error Python version 3.6 or later is required by LAMMPS #endif -#define PY_STRING_FROM_STRING(X) PyString_FromString(X) -#define PY_VOID_POINTER(X) PyCObject_FromVoidPtr((void *) X, nullptr) -#define PY_STRING_AS_STRING(X) PyString_AsString(X) -#elif PY_MAJOR_VERSION == 3 +// Wrap API differences between platforms using macros #if defined(_MSC_VER) || defined(__MINGW32__) #define PY_INT_FROM_LONG(X) PyLong_FromLongLong(X) #define PY_INT_AS_LONG(X) PyLong_AsLongLong(X) @@ -41,9 +30,5 @@ #define PY_INT_AS_LONG(X) PyLong_AsLong(X) #define PY_LONG_FROM_STRING(X) std::stol(X) #endif -#define PY_STRING_FROM_STRING(X) PyUnicode_FromString(X) -#define PY_VOID_POINTER(X) PyCapsule_New((void *) X, nullptr, nullptr) -#define PY_STRING_AS_STRING(X) PyUnicode_AsUTF8(X) -#endif #endif diff --git a/src/PYTHON/python_impl.cpp b/src/PYTHON/python_impl.cpp index 91e0a7abe5..e4ec8d74d8 100644 --- a/src/PYTHON/python_impl.cpp +++ b/src/PYTHON/python_impl.cpp @@ -361,12 +361,12 @@ void PythonImpl::invoke_function(int ifunc, char *result) if (!str) error->all(FLERR, "Could not evaluate Python function {} input variable: {}", pfuncs[ifunc].name, pfuncs[ifunc].svalue[i]); - pValue = PY_STRING_FROM_STRING(str); + pValue = PyUnicode_FromString(str); } else { - pValue = PY_STRING_FROM_STRING(pfuncs[ifunc].svalue[i]); + pValue = PyUnicode_FromString(pfuncs[ifunc].svalue[i]); } } else if (itype == PTR) { - pValue = PY_VOID_POINTER(lmp); + pValue = PyCapsule_New((void *)lmp, nullptr, nullptr); } else { error->all(FLERR, "Unsupported variable type: {}", itype); } @@ -397,7 +397,7 @@ void PythonImpl::invoke_function(int ifunc, char *result) auto value = fmt::format("{:.15g}", PyFloat_AsDouble(pValue)); strncpy(result, value.c_str(), Variable::VALUELENGTH - 1); } else if (otype == STRING) { - const char *pystr = PY_STRING_AS_STRING(pValue); + const char *pystr = PyUnicode_AsUTF8(pValue); if (pfuncs[ifunc].longstr) strncpy(pfuncs[ifunc].longstr, pystr, pfuncs[ifunc].length_longstr); else diff --git a/src/REAXFF/fix_reaxff_species.cpp b/src/REAXFF/fix_reaxff_species.cpp index 09c3884c34..5b32ca0528 100644 --- a/src/REAXFF/fix_reaxff_species.cpp +++ b/src/REAXFF/fix_reaxff_species.cpp @@ -965,6 +965,7 @@ void FixReaxFFSpecies::DeleteSpecies(int Nmole, int Nspec) int *mask = atom->mask; double *mass = atom->mass; double *rmass = atom->rmass; + int *type = atom->type; double localmass, totalmass; std::string species_str; @@ -1013,12 +1014,12 @@ void FixReaxFFSpecies::DeleteSpecies(int Nmole, int Nspec) if (!(mask[i] & groupbit)) continue; cid = nint(clusterID[i]); if (cid == m) { - itype = ele2uele[atom->type[i] - 1]; + itype = ele2uele[type[i] - 1]; Name[itype]++; count++; marklist[nmarklist++] = i; if (rmass) localmass += rmass[i]; - else localmass += atom->mass[atom->type[i]]; + else localmass += mass[type[i]]; } } diff --git a/src/REPLICA/compute_pressure_alchemy.cpp b/src/REPLICA/compute_pressure_alchemy.cpp index bad2785fb8..a612f4672a 100644 --- a/src/REPLICA/compute_pressure_alchemy.cpp +++ b/src/REPLICA/compute_pressure_alchemy.cpp @@ -27,7 +27,7 @@ ComputePressureAlchemy::ComputePressureAlchemy(LAMMPS *lmp, int narg, char **arg Compute(lmp, narg, arg), fix(nullptr) { if (narg != 4) error->all(FLERR, "Illegal compute pressure/alchemy command"); - if (igroup) error->all(FLERR, "Compute pressure/alchemy must use group all"); + if (igroup) error->all(FLERR, 1, "Compute pressure/alchemy must use group all"); scalar_flag = vector_flag = 1; size_vector = 6; @@ -38,7 +38,8 @@ ComputePressureAlchemy::ComputePressureAlchemy(LAMMPS *lmp, int narg, char **arg id_fix = arg[3]; if (!modify->get_fix_by_id(id_fix)) - error->all(FLERR, "Could not find compute pressure/alchemy fix ID {} for fix alchemy", id_fix); + error->all(FLERR, 3, "Could not find compute pressure/alchemy fix ID {} for fix alchemy", + id_fix); vector = new double[size_vector]; } @@ -57,11 +58,13 @@ void ComputePressureAlchemy::init() fix = modify->get_fix_by_id(id_fix); if (!fix) - error->all(FLERR, "Could not find compute pressure/alchemy fix ID {} for fix alchemy", id_fix); + error->all(FLERR, Error::NOLASTLINE, + "Could not find compute pressure/alchemy fix ID {} for fix alchemy", id_fix); int dim = 0; void *ptr = fix->extract("pressure", dim); - if (!ptr || (dim != 1)) error->all(FLERR, "Could not extract pressure from fix alchemy"); + if (!ptr || (dim != 1)) + error->all(FLERR, Error::NOLASTLINE, "Could not extract pressure from fix alchemy"); } /* ---------------------------------------------------------------------- @@ -72,7 +75,7 @@ double ComputePressureAlchemy::compute_scalar() { invoked_scalar = update->ntimestep; if (update->vflag_global != invoked_scalar) - error->all(FLERR, "Virial was not tallied on needed timestep"); + error->all(FLERR, Error::NOLASTLINE, "Virial was not tallied on needed timestep"); compute_vector(); @@ -92,11 +95,12 @@ void ComputePressureAlchemy::compute_vector() { invoked_vector = update->ntimestep; if (update->vflag_global != invoked_vector) - error->all(FLERR, "Virial was not tallied on needed timestep"); + error->all(FLERR, Error::NOLASTLINE, "Virial was not tallied on needed timestep"); int dim = 0; double *pressure = (double *) fix->extract("pressure", dim); - if (!pressure || (dim != 1)) error->all(FLERR, "Could not extract pressure from fix alchemy"); + if (!pressure || (dim != 1)) + error->all(FLERR, Error::NOLASTLINE, "Could not extract pressure from fix alchemy"); for (int i = 0; i < 6; i++) vector[i] = pressure[i]; } diff --git a/src/angle_write.cpp b/src/angle_write.cpp index 863183995b..1c1601d002 100644 --- a/src/angle_write.cpp +++ b/src/angle_write.cpp @@ -26,6 +26,7 @@ #include "force.h" #include "input.h" #include "math_const.h" +#include "safe_pointers.h" #include "update.h" #include @@ -79,13 +80,12 @@ void AngleWrite::command(int narg, char **arg) // otherwise make certain that units are consistent // print header in format used by angle_style table - FILE *fp = nullptr; + SafeFilePtr fp; std::string coeffs_file = table_file + ".tmp.coeffs"; if (comm->me == 0) { - fp = fopen(coeffs_file.c_str(), "w"); - force->angle->write_data(fp); - fclose(fp); + SafeFilePtr coeffs = fopen(coeffs_file.c_str(), "w"); + force->angle->write_data(coeffs); // units sanity check: // - if this is the first time we write to this potential file, @@ -145,16 +145,14 @@ void AngleWrite::command(int narg, char **arg) writer->input->one("pair_coeff * *"); writer->input->one("mass * 1.0"); writer->input->one(fmt::format("angle_style {}", force->angle_style)); - FILE *coeffs; char line[MAXLINE] = {'\0'}; - coeffs = fopen(coeffs_file.c_str(), "r"); + SafeFilePtr coeffs = fopen(coeffs_file.c_str(), "r"); if (!coeffs) error->one(FLERR, "Unable to open temporary file {}: {}", coeffs_file, utils::getsyserror()); for (int i = 0; i < atom->nangletypes; ++i) { utils::sfgets(FLERR, line, MAXLINE, coeffs, coeffs_file.c_str(), error); writer->input->one(fmt::format("angle_coeff {}", line)); } - fclose(coeffs); platform::unlink(coeffs_file); // initialize system @@ -221,7 +219,6 @@ void AngleWrite::command(int narg, char **arg) // clean up delete writer; - fclose(fp); } MPI_Comm_free(&singlecomm); } diff --git a/src/atom.cpp b/src/atom.cpp index 6faffd105c..bbc00dec75 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -767,7 +767,7 @@ void Atom::init() if (firstgroupname) { firstgroup = group->find(firstgroupname); if (firstgroup < 0) - error->all(FLERR,"Could not find atom_modify first group ID {}", firstgroupname); + error->all(FLERR, Error::NOLASTLINE, "Could not find atom_modify first group ID {}", firstgroupname); } else firstgroup = -1; // init AtomVec @@ -830,21 +830,23 @@ void Atom::modify_params(int narg, char **arg) if (narg == 0) utils::missing_cmd_args(FLERR, "atom_modify", error); int iarg = 0; + int idx; while (iarg < narg) { + idx = iarg ? iarg : Error::ARGZERO; if (strcmp(arg[iarg],"id") == 0) { if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "atom_modify id", error); if (domain->box_exist) - error->all(FLERR,"Atom_modify id command after simulation box is defined"); + error->all(FLERR, idx, "Atom_modify id command after simulation box is defined"); tag_enable = utils::logical(FLERR,arg[iarg+1],false,lmp); iarg += 2; } else if (strcmp(arg[iarg],"map") == 0) { if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "atom_modify map", error); if (domain->box_exist) - error->all(FLERR,"Atom_modify map command after simulation box is defined"); + error->all(FLERR, idx, "Atom_modify map command after simulation box is defined"); if (strcmp(arg[iarg+1],"array") == 0) map_user = MAP_ARRAY; else if (strcmp(arg[iarg+1],"hash") == 0) map_user = MAP_HASH; else if (strcmp(arg[iarg+1],"yes") == 0) map_user = MAP_YES; - else error->all(FLERR,"Illegal atom_modify map command argument {}", arg[iarg+1]); + else error->all(FLERR, iarg + 1, "Illegal atom_modify map command argument {}", arg[iarg+1]); map_style = map_user; iarg += 2; } else if (strcmp(arg[iarg],"first") == 0) { @@ -861,12 +863,12 @@ void Atom::modify_params(int narg, char **arg) if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "atom_modify sort", error); sortfreq = utils::inumeric(FLERR,arg[iarg+1],false,lmp); userbinsize = utils::numeric(FLERR,arg[iarg+2],false,lmp); - if (sortfreq < 0) error->all(FLERR,"Illegal atom_modify sort frequency {}", sortfreq); - if (userbinsize < 0.0) error->all(FLERR,"Illegal atom_modify sort bin size {}", userbinsize); + if (sortfreq < 0) error->all(FLERR, iarg + 1, "Illegal atom_modify sort frequency {}", sortfreq); + if (userbinsize < 0.0) error->all(FLERR, iarg + 2, "Illegal atom_modify sort bin size {}", userbinsize); if ((sortfreq >= 0) && firstgroupname) - error->all(FLERR,"Atom_modify sort and first options cannot be used together"); + error->all(FLERR, idx, "Atom_modify sort and first options cannot be used together"); iarg += 3; - } else error->all(FLERR,"Illegal atom_modify command argument: {}", arg[iarg]); + } else error->all(FLERR, idx, "Illegal atom_modify command argument: {}", arg[iarg]); } } diff --git a/src/bond.cpp b/src/bond.cpp index f5af30062e..d42dd6fd24 100644 --- a/src/bond.cpp +++ b/src/bond.cpp @@ -20,6 +20,7 @@ #include "force.h" #include "memory.h" #include "neighbor.h" +#include "safe_pointers.h" #include "suffix.h" #include "update.h" @@ -365,7 +366,7 @@ void Bond::write_file(int narg, char **arg) // add line with DATE: and UNITS: tag when creating new file // print header in format used by bond_style table - FILE *fp = nullptr; + SafeFilePtr fp; if (comm->me == 0) { std::string table_file = arg[4]; @@ -419,7 +420,6 @@ void Bond::write_file(int narg, char **arg) e = single(btype, r * r, itype, jtype, f); fprintf(fp, "%8d %- 22.15g %- 22.15g %- 22.15g\n", i + 1, r, e, f * r); } - fclose(fp); } } diff --git a/src/compute.cpp b/src/compute.cpp index 06f58e817b..578667d76c 100644 --- a/src/compute.cpp +++ b/src/compute.cpp @@ -41,7 +41,7 @@ Compute::Compute(LAMMPS *lmp, int narg, char **arg) : { instance_me = instance_total++; - if (narg < 3) error->all(FLERR,"Illegal compute command"); + if (narg < 3) utils::missing_cmd_args(FLERR,"compute", error); // compute ID, group, and style // ID must be all alphanumeric chars or underscores diff --git a/src/compute_msd_chunk.cpp b/src/compute_msd_chunk.cpp index d738b835fa..98d08f1fcc 100644 --- a/src/compute_msd_chunk.cpp +++ b/src/compute_msd_chunk.cpp @@ -21,6 +21,7 @@ #include "group.h" #include "memory.h" #include "modify.h" +#include "update.h" using namespace LAMMPS_NS; @@ -30,7 +31,7 @@ ComputeMSDChunk::ComputeMSDChunk(LAMMPS *lmp, int narg, char **arg) : ComputeChunk(lmp, narg, arg), id_fix(nullptr), fix(nullptr), massproc(nullptr), masstotal(nullptr), com(nullptr), comall(nullptr), msd(nullptr) { - if (narg != 4) error->all(FLERR, "Illegal compute msd/chunk command"); + if (narg != 4) error->all(FLERR, "Incorrect number of arguments for compute msd/chunk"); msdnchunk = 0; array_flag = 1; @@ -114,6 +115,8 @@ void ComputeMSDChunk::setup() void ComputeMSDChunk::compute_array() { + invoked_array = update->ntimestep; + int index; double massone; double unwrap[3]; @@ -127,7 +130,7 @@ void ComputeMSDChunk::compute_array() if (firstflag) msdnchunk = nchunk; else if (msdnchunk != nchunk) - error->all(FLERR, "Compute msd/chunk nchunk is not static"); + error->all(FLERR, Error::NOLASTLINE, "Compute msd/chunk nchunk is not static"); // zero local per-chunk values diff --git a/src/compute_pe.cpp b/src/compute_pe.cpp index f4207408f9..8b80f909d2 100644 --- a/src/compute_pe.cpp +++ b/src/compute_pe.cpp @@ -35,8 +35,8 @@ using namespace LAMMPS_NS; ComputePE::ComputePE(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg) { - if (narg < 3) error->all(FLERR, "Illegal compute pe command"); - if (igroup) error->all(FLERR, "Compute pe must use group all"); + if (narg < 3) utils::missing_cmd_args(FLERR, "compute pe", error); + if (igroup) error->all(FLERR, 1, "Compute pe must use group all"); scalar_flag = 1; extscalar = 1; @@ -70,7 +70,7 @@ ComputePE::ComputePE(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg else if (strcmp(arg[iarg], "fix") == 0) fixflag = 1; else - error->all(FLERR, "Illegal compute pe command"); + error->all(FLERR, iarg, "Unknown compute pe keyword {}", arg[iarg]); iarg++; } } @@ -85,7 +85,7 @@ double ComputePE::compute_scalar() { invoked_scalar = update->ntimestep; if (update->eflag_global != invoked_scalar) - error->all(FLERR, "Energy was not tallied on needed timestep"); + error->all(FLERR, Error::NOLASTLINE, "Energy was not tallied on needed timestep"); double one = 0.0; if (pairflag && force->pair) one += force->pair->eng_vdwl + force->pair->eng_coul; diff --git a/src/compute_pressure.cpp b/src/compute_pressure.cpp index 65cb612390..55c2fdb1be 100644 --- a/src/compute_pressure.cpp +++ b/src/compute_pressure.cpp @@ -40,7 +40,7 @@ ComputePressure::ComputePressure(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), vptr(nullptr), id_temp(nullptr), pstyle(nullptr) { if (narg < 4) utils::missing_cmd_args(FLERR,"compute pressure", error); - if (igroup) error->all(FLERR,"Compute pressure must use group all"); + if (igroup) error->all(FLERR, 1, "Compute pressure must use group all"); scalar_flag = vector_flag = 1; size_vector = 6; @@ -58,9 +58,9 @@ ComputePressure::ComputePressure(LAMMPS *lmp, int narg, char **arg) : id_temp = utils::strdup(arg[3]); auto icompute = modify->get_compute_by_id(id_temp); if (!icompute) - error->all(FLERR,"Could not find compute pressure temperature ID {}", id_temp); + error->all(FLERR, 3, "Could not find compute pressure temperature ID {}", id_temp); if (!icompute->tempflag) - error->all(FLERR,"Compute pressure temperature ID {} does not compute temperature", id_temp); + error->all(FLERR, 3, "Compute pressure temperature ID {} does not compute temperature", id_temp); } // process optional args diff --git a/src/compute_vacf.cpp b/src/compute_vacf.cpp index 813a28dff6..067ac605b0 100644 --- a/src/compute_vacf.cpp +++ b/src/compute_vacf.cpp @@ -27,7 +27,7 @@ using namespace LAMMPS_NS; ComputeVACF::ComputeVACF(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), id_fix(nullptr) { - if (narg < 3) error->all(FLERR, "Illegal compute vacf command"); + if (narg > 3) error->all(FLERR, 3, "Compute vacf does not accept any arguments"); vector_flag = 1; size_vector = 4; diff --git a/src/compute_vacf_chunk.cpp b/src/compute_vacf_chunk.cpp new file mode 100644 index 0000000000..7e058b4e85 --- /dev/null +++ b/src/compute_vacf_chunk.cpp @@ -0,0 +1,225 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + LAMMPS development team: developers@lammps.org + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#include "compute_vacf_chunk.h" + +#include "atom.h" +#include "compute_chunk_atom.h" +#include "error.h" +#include "fix_store_global.h" +#include "group.h" +#include "memory.h" +#include "modify.h" +#include "update.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +ComputeVACFChunk::ComputeVACFChunk(LAMMPS *lmp, int narg, char **arg) : + ComputeChunk(lmp, narg, arg), id_fix(nullptr), fix(nullptr), massproc(nullptr), + masstotal(nullptr), vcm(nullptr), vcmall(nullptr), vacf(nullptr) +{ + if (narg != 4) error->all(FLERR, "Incorrect number of arguments for compute vacf/chunk"); + + vacfnchunk = 0; + array_flag = 1; + size_array_cols = 4; + size_array_rows = 0; + size_array_rows_variable = 1; + extarray = 0; + + ComputeVACFChunk::init(); + + // create a new fix STORE style for reference velocities + // id = compute-ID + COMPUTE_STORE, fix group = compute group + // do not know size of array at this point, just allocate 1x1 array + // fix creation must be done now so that a restart run can + // potentially re-populate the fix array (and change it to correct size) + // otherwise size reset and init will be done in setup() + + id_fix = utils::strdup(std::string(id) + "_COMPUTE_STORE"); + fix = dynamic_cast( + modify->add_fix(fmt::format("{} {} STORE/GLOBAL 1 1", id_fix, group->names[igroup]))); +} + +/* ---------------------------------------------------------------------- */ + +ComputeVACFChunk::~ComputeVACFChunk() +{ + // check nfix in case all fixes have already been deleted + + if (modify->nfix) modify->delete_fix(id_fix); + + delete[] id_fix; + memory->destroy(massproc); + memory->destroy(masstotal); + memory->destroy(vcm); + memory->destroy(vcmall); + memory->destroy(vacf); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeVACFChunk::init() +{ + ComputeChunk::init(); + + // set fix which stores reference atom coords + // if firstflag, will be created in setup() + + if (!firstflag) { + fix = dynamic_cast(modify->get_fix_by_id(id_fix)); + if (!fix) error->all(FLERR, "Could not find compute vacf/chunk fix with ID {}", id_fix); + } +} + +/* ---------------------------------------------------------------------- + compute initial VCM for each chunk + only once on timestep compute is defined, when firstflag = 1 +------------------------------------------------------------------------- */ + +void ComputeVACFChunk::setup() +{ + if (!firstflag) return; + compute_array(); + firstflag = 0; + + // if fix->astore is already correct size, restart file set it up + // otherwise reset its size now and initialize to current VCM + + if (fix->nrow == nchunk && fix->ncol == 3) return; + fix->reset_global(nchunk, 3); + + double **vcminit = fix->astore; + for (int i = 0; i < nchunk; i++) { + vcminit[i][0] = vcmall[i][0]; + vcminit[i][1] = vcmall[i][1]; + vcminit[i][2] = vcmall[i][2]; + vacf[i][0] = vacf[i][1] = vacf[i][2] = vacf[i][3] = 1.0; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeVACFChunk::compute_array() +{ + invoked_array = update->ntimestep; + + int index; + double massone; + + ComputeChunk::compute_array(); + int *ichunk = cchunk->ichunk; + + // first time call, allocate per-chunk arrays + // thereafter, require nchunk remain the same + + if (firstflag) + vacfnchunk = nchunk; + else if (vacfnchunk != nchunk) + error->all(FLERR, Error::NOLASTLINE, "Compute vacf/chunk nchunk is not static"); + + // zero local per-chunk values + + for (int i = 0; i < nchunk; i++) { + massproc[i] = 0.0; + vcm[i][0] = vcm[i][1] = vcm[i][2] = 0.0; + } + + // compute current VCM for each chunk + + double **v = atom->v; + int *mask = atom->mask; + int *type = atom->type; + double *mass = atom->mass; + double *rmass = atom->rmass; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) { + index = ichunk[i] - 1; + if (index < 0) continue; + if (rmass) + massone = rmass[i]; + else + massone = mass[type[i]]; + massproc[index] += massone; + vcm[index][0] += v[i][0] * massone; + vcm[index][1] += v[i][1] * massone; + vcm[index][2] += v[i][2] * massone; + } + + MPI_Allreduce(massproc, masstotal, nchunk, MPI_DOUBLE, MPI_SUM, world); + MPI_Allreduce(&vcm[0][0], &vcmall[0][0], 3 * nchunk, MPI_DOUBLE, MPI_SUM, world); + + for (int i = 0; i < nchunk; i++) { + if (masstotal[i] > 0.0) { + vcmall[i][0] /= masstotal[i]; + vcmall[i][1] /= masstotal[i]; + vcmall[i][2] /= masstotal[i]; + } + } + + // VACF is dot product between current and initial VCM + // vcminit is initilialized by setup() when firstflag is set + + if (firstflag) return; + + double vxsq, vysq, vzsq; + double **vcminit = fix->astore; + + for (int i = 0; i < nchunk; i++) { + vxsq = vcmall[i][0] * vcminit[i][0]; + vysq = vcmall[i][1] * vcminit[i][1]; + vzsq = vcmall[i][2] * vcminit[i][2]; + vacf[i][0] = vxsq; + vacf[i][1] = vysq; + vacf[i][2] = vzsq; + vacf[i][3] = vxsq + vysq + vzsq; + } +} + +/* ---------------------------------------------------------------------- + one-time allocate of per-chunk arrays +------------------------------------------------------------------------- */ + +void ComputeVACFChunk::allocate() +{ + ComputeChunk::allocate(); + memory->destroy(massproc); + memory->destroy(masstotal); + memory->destroy(vcm); + memory->destroy(vcmall); + memory->destroy(vacf); + + memory->create(massproc, nchunk, "vacf/chunk:massproc"); + memory->create(masstotal, nchunk, "vacf/chunk:masstotal"); + memory->create(vcm, nchunk, 3, "vacf/chunk:vcm"); + memory->create(vcmall, nchunk, 3, "vacf/chunk:vcmall"); + memory->create(vacf, nchunk, 4, "vacf/chunk:vacf"); + array = vacf; +} + +/* ---------------------------------------------------------------------- + memory usage of local data +------------------------------------------------------------------------- */ + +double ComputeVACFChunk::memory_usage() +{ + double bytes = ComputeChunk::memory_usage(); + bytes += (bigint) nchunk * 2 * sizeof(double); + bytes += (double) nchunk * 2 * 3 * sizeof(double); + bytes += (double) nchunk * 4 * sizeof(double); + return bytes; +} diff --git a/src/compute_vacf_chunk.h b/src/compute_vacf_chunk.h new file mode 100644 index 0000000000..1501960422 --- /dev/null +++ b/src/compute_vacf_chunk.h @@ -0,0 +1,52 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + LAMMPS development team: developers@lammps.org + + 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. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS +// clang-format off +ComputeStyle(vacf/chunk,ComputeVACFChunk); +// clang-format on +#else + +#ifndef LMP_COMPUTE_VACF_CHUNK_H +#define LMP_COMPUTE_VACF_CHUNK_H + +#include "compute_chunk.h" + +namespace LAMMPS_NS { + +class ComputeVACFChunk : public ComputeChunk { + public: + ComputeVACFChunk(class LAMMPS *, int, char **); + ~ComputeVACFChunk() override; + void init() override; + void setup() override; + + void compute_array() override; + + double memory_usage() override; + + protected: + bigint vacfnchunk; + + char *id_fix; + class FixStoreGlobal *fix; + + double *massproc, *masstotal; + double **vcm, **vcmall; + double **vacf; + + void allocate() override; +}; +} // namespace LAMMPS_NS +#endif +#endif diff --git a/src/create_atoms.cpp b/src/create_atoms.cpp index 1a8318e315..dc00e2e1d1 100644 --- a/src/create_atoms.cpp +++ b/src/create_atoms.cpp @@ -34,6 +34,7 @@ #include "random_mars.h" #include "random_park.h" #include "region.h" +#include "safe_pointers.h" #include "special.h" #include "text_file_reader.h" #include "variable.h" @@ -1082,8 +1083,9 @@ void CreateAtoms::add_mesh(const char *filename) molid = maxmol + 1; } - FILE *fp = fopen(filename, "rb"); - if (fp == nullptr) error->one(FLERR, "Cannot open file {}: {}", filename, utils::getsyserror()); + SafeFilePtr fp = fopen(filename, "rb"); + if (fp == nullptr) + error->one(FLERR, "Cannot open STL mesh file {}: {}", filename, utils::getsyserror()); // first try reading the file in ASCII format @@ -1184,7 +1186,7 @@ void CreateAtoms::add_mesh(const char *filename) } } } else { - error->all(FLERR, "Error reading triangles from file {}: {}", filename, e.what()); + error->all(FLERR, "Error reading triangles from STL mesh file {}: {}", filename, e.what()); } } @@ -1195,7 +1197,6 @@ void CreateAtoms::add_mesh(const char *filename) utils::logmesg(lmp, " read {} triangles with {:.2f} atoms per triangle added in {} mode\n", ntriangle, ratio, mesh_name[mesh_style]); } - if (fp) fclose(fp); } /* ---------------------------------------------------------------------- diff --git a/src/fix_adapt.cpp b/src/fix_adapt.cpp index 9144ecde71..418e2e4a80 100644 --- a/src/fix_adapt.cpp +++ b/src/fix_adapt.cpp @@ -52,7 +52,7 @@ FixAdapt::FixAdapt(LAMMPS *lmp, int narg, char **arg) : { if (narg < 5) utils::missing_cmd_args(FLERR,"fix adapt", error); nevery = utils::inumeric(FLERR,arg[3],false,lmp); - if (nevery < 0) error->all(FLERR,"Illegal fix adapt every value {}", nevery); + if (nevery < 0) error->all(FLERR, 3, "Illegal fix adapt every value {}", nevery); dynamic_group_allow = 1; create_attribute = 1; @@ -86,7 +86,7 @@ FixAdapt::FixAdapt(LAMMPS *lmp, int narg, char **arg) : } else break; } - if (nadapt == 0) error->all(FLERR,"Nothing to adapt in fix adapt command"); + if (nadapt == 0) error->all(FLERR, 3, "Nothing to adapt in fix adapt command"); adapt = new Adapt[nadapt]; // parse keywords @@ -119,7 +119,7 @@ FixAdapt::FixAdapt(LAMMPS *lmp, int narg, char **arg) : if (utils::strmatch(arg[iarg+5],"^v_")) { adapt[nadapt].var = utils::strdup(arg[iarg+5]+2); - } else error->all(FLERR,"Argument #{} must be variable not {}", iarg+6, arg[iarg+5]); + } else error->all(FLERR, iarg+5, "Argument must be variable not {}", arg[iarg+5]); nadapt++; iarg += 6; @@ -132,7 +132,7 @@ FixAdapt::FixAdapt(LAMMPS *lmp, int narg, char **arg) : adapt[nadapt].ilo, adapt[nadapt].ihi, lmp, Atom::BOND); if (utils::strmatch(arg[iarg+4],"^v_")) { adapt[nadapt].var = utils::strdup(arg[iarg+4]+2); - } else error->all(FLERR,"Argument #{} must be variable not {}", iarg+5, arg[iarg+4]); + } else error->all(FLERR, iarg+4, "Argument must be variable not {}", arg[iarg+4]); nadapt++; iarg += 5; @@ -145,7 +145,7 @@ FixAdapt::FixAdapt(LAMMPS *lmp, int narg, char **arg) : adapt[nadapt].ilo, adapt[nadapt].ihi, lmp, Atom::ANGLE); if (utils::strmatch(arg[iarg+4],"^v_")) { adapt[nadapt].var = utils::strdup(arg[iarg+4]+2); - } else error->all(FLERR,"Argument #{} must be variable not {}", iarg+5, arg[iarg+4]); + } else error->all(FLERR,iarg+4, "Argument must be variable not {}", arg[iarg+4]); nadapt++; iarg += 5; @@ -153,7 +153,7 @@ FixAdapt::FixAdapt(LAMMPS *lmp, int narg, char **arg) : adapt[nadapt].which = KSPACE; if (utils::strmatch(arg[iarg+1],"^v_")) { adapt[nadapt].var = utils::strdup(arg[iarg+1]+2); - } else error->all(FLERR,"Argument #{} must be variable not {}", iarg+2, arg[iarg+1]); + } else error->all(FLERR, iarg+1, "Argument must be variable not {}", arg[iarg+1]); nadapt++; iarg += 2; @@ -168,10 +168,11 @@ FixAdapt::FixAdapt(LAMMPS *lmp, int narg, char **arg) : } else if (strcmp(arg[iarg+1],"charge") == 0) { adapt[nadapt].atomparam = CHARGE; chgflag = 1; - } else error->all(FLERR,"Unsupported per-atom property {} for fix adapt", arg[iarg+1]); + } else error->all(FLERR, iarg+1, "Unsupported per-atom property {} for fix adapt", + arg[iarg+1]); if (utils::strmatch(arg[iarg+2],"^v_")) { adapt[nadapt].var = utils::strdup(arg[iarg+2]+2); - } else error->all(FLERR,"Argument #{} must be variable not {}", iarg+3, arg[iarg+2]); + } else error->all(FLERR, iarg+2, "Argument must be variable not {}", arg[iarg+2]); nadapt++; iarg += 3; } else break; @@ -329,7 +330,8 @@ void FixAdapt::init() if (group->dynamic[igroup]) for (i = 0; i < nadapt; i++) if (adapt[i].which == ATOM) - error->all(FLERR,"Cannot use dynamic group {} with fix adapt atom", group->names[igroup]); + error->all(FLERR, Error::NOLASTLINE, + "Cannot use dynamic group {} with fix adapt atom", group->names[igroup]); // setup and error checks @@ -342,9 +344,11 @@ void FixAdapt::init() ad->ivar = input->variable->find(ad->var); if (ad->ivar < 0) - error->all(FLERR,"Variable name {} for fix adapt does not exist", ad->var); + error->all(FLERR, Error::NOLASTLINE, + "Variable name {} for fix adapt does not exist", ad->var); if (!input->variable->equalstyle(ad->ivar)) - error->all(FLERR,"Variable {} for fix adapt is invalid style", ad->var); + error->all(FLERR, Error::NOLASTLINE, + "Variable {} for fix adapt is invalid style", ad->var); if (ad->which == PAIR) { anypair = 1; @@ -369,17 +373,20 @@ void FixAdapt::init() ad->pair = force->pair_match(fmt::format("{}/{}",pstyle,lmp->suffix2),1,nsub); } if (ad->pair == nullptr) ad->pair = force->pair_match(pstyle,1,nsub); - if (ad->pair == nullptr) error->all(FLERR,"Fix adapt pair style {} not found", pstyle); + if (ad->pair == nullptr) + error->all(FLERR, Error::NOLASTLINE, "Fix adapt pair style {} not found", pstyle); void *ptr = ad->pair->extract(ad->pparam,ad->pdim); if (ptr == nullptr) - error->all(FLERR,"Fix adapt pair style {} param {} not supported", ad->pstyle, ad->pparam); + error->all(FLERR, Error::NOLASTLINE, + "Fix adapt pair style {} param {} not supported", ad->pstyle, ad->pparam); // for pair styles only parameters that are 2-d arrays in atom types or // scalars are supported if (ad->pdim != 2 && ad->pdim != 0) - error->all(FLERR,"Pair style parameter {} is not compatible with fix adapt", ad->pparam); + error->all(FLERR, Error::NOLASTLINE, + "Pair style parameter {} is not compatible with fix adapt", ad->pparam); if (ad->pdim == 2) ad->array = (double **) ptr; if (ad->pdim == 0) ad->scalar = (double *) ptr; @@ -392,7 +399,7 @@ void FixAdapt::init() for (i = ad->ilo; i <= ad->ihi; i++) { for (j = MAX(ad->jlo,i); j <= ad->jhi; j++) { if (!pair->check_ijtype(i,j,pstyle)) - error->all(FLERR,"Fix adapt type pair range is not valid " + error->all(FLERR, Error::NOLASTLINE, "Fix adapt type pair range is not valid " "for pair hybrid sub-style {}", pstyle); } } @@ -411,12 +418,13 @@ void FixAdapt::init() if (ad->bond == nullptr) ad->bond = force->bond_match(bstyle); if (ad->bond == nullptr ) - error->all(FLERR,"Fix adapt bond style {} does not exist", bstyle); + error->all(FLERR, Error::NOLASTLINE,"Fix adapt bond style {} does not exist", bstyle); void *ptr = ad->bond->extract(ad->bparam,ad->bdim); if (ptr == nullptr) - error->all(FLERR,"Fix adapt bond style parameter {} not supported", ad->bparam); + error->all(FLERR, Error::NOLASTLINE, + "Fix adapt bond style parameter {} not supported", ad->bparam); // for bond styles, use a vector @@ -427,8 +435,8 @@ void FixAdapt::init() if (bond) { for (i = ad->ilo; i <= ad->ihi; i++) { if (!bond->check_itype(i,bstyle)) - error->all(FLERR,"Fix adapt type bond range is not valid " - "for pair hybrid sub-style {}", bstyle); + error->all(FLERR, Error::NOLASTLINE, "Fix adapt type bond range is not valid " + "for bond hybrid sub-style {}", bstyle); } } } @@ -445,12 +453,13 @@ void FixAdapt::init() if (ad->angle == nullptr) ad->angle = force->angle_match(astyle); if (ad->angle == nullptr ) - error->all(FLERR,"Fix adapt angle style {} does not exist", astyle); + error->all(FLERR, Error::NOLASTLINE, "Fix adapt angle style {} does not exist", astyle); void *ptr = ad->angle->extract(ad->aparam,ad->adim); if (ptr == nullptr) - error->all(FLERR,"Fix adapt angle style parameter {} not supported", ad->aparam); + error->all(FLERR, Error::NOLASTLINE, + "Fix adapt angle style parameter {} not supported", ad->aparam); // for angle styles, use a vector @@ -461,8 +470,8 @@ void FixAdapt::init() if (angle) { for (i = ad->ilo; i <= ad->ihi; i++) { if (!angle->check_itype(i,astyle)) - error->all(FLERR,"Fix adapt type angle range is not valid " - "for pair hybrid sub-style {}", astyle); + error->all(FLERR, Error::NOLASTLINE, "Fix adapt type angle range is not valid " + "for angle hybrid sub-style {}", astyle); } } } @@ -471,22 +480,23 @@ void FixAdapt::init() } else if (ad->which == KSPACE) { if (force->kspace == nullptr) - error->all(FLERR,"Fix adapt expected a kspace style but none was defined"); + error->all(FLERR, Error::NOLASTLINE, + "Fix adapt expected a kspace style but none was defined"); kspace_scale = (double *) force->kspace->extract("scale"); } else if (ad->which == ATOM) { if (ad->atomparam == DIAMETER) { if (!atom->radius_flag) - error->all(FLERR,"Fix adapt requires atom attribute diameter"); + error->all(FLERR, Error::NOLASTLINE, "Fix adapt requires atom attribute diameter"); if (!atom->rmass_flag) - error->all(FLERR,"Fix adapt requires atom attribute mass"); + error->all(FLERR, Error::NOLASTLINE, "Fix adapt requires atom attribute mass"); if (discflag && domain->dimension != 2) - error->all(FLERR,"Fix adapt requires 2d simulation"); + error->all(FLERR, Error::NOLASTLINE, "Fix adapt requires 2d simulation"); if (!restart_reset) previous_diam_scale = 1.0; } if (ad->atomparam == CHARGE) { if (!atom->q_flag) - error->all(FLERR,"Fix adapt requires atom attribute charge"); + error->all(FLERR, Error::NOLASTLINE, "Fix adapt requires atom attribute charge"); if (!restart_reset) previous_chg_scale = 1.0; } } @@ -520,11 +530,15 @@ void FixAdapt::init() if (id_fix_diam) { fix_diam = dynamic_cast(modify->get_fix_by_id(id_fix_diam)); - if (!fix_diam) error->all(FLERR,"Could not find fix adapt storage fix ID {}", id_fix_diam); + if (!fix_diam) + error->all(FLERR, Error::NOLASTLINE, + "Could not find fix adapt storage fix ID {}", id_fix_diam); } if (id_fix_chg) { fix_chg = dynamic_cast(modify->get_fix_by_id(id_fix_chg)); - if (!fix_chg) error->all(FLERR,"Could not find fix adapt storage fix ID {}", id_fix_chg); + if (!fix_chg) + error->all(FLERR, Error::NOLASTLINE, + "Could not find fix adapt storage fix ID {}", id_fix_chg); } if (utils::strmatch(update->integrate_style,"^respa")) diff --git a/src/fix_nve.cpp b/src/fix_nve.cpp index 58a5677b92..c96454fe92 100644 --- a/src/fix_nve.cpp +++ b/src/fix_nve.cpp @@ -33,7 +33,7 @@ FixNVE::FixNVE(LAMMPS *lmp, int narg, char **arg) : auto plain_style = utils::strip_style_suffix(style, lmp); if (utils::strmatch(plain_style, "^nve$") && narg > 3) - error->all(FLERR, "Unsupported additional arguments for fix {}", style); + error->all(FLERR, 3, "Unsupported additional arguments for fix {}", style); dynamic_group_allow = 1; time_integrate = 1; diff --git a/src/modify.cpp b/src/modify.cpp index 89cc1d0643..9908b96d79 100644 --- a/src/modify.cpp +++ b/src/modify.cpp @@ -262,11 +262,13 @@ void Modify::init() for (i = 0; i < nfix; i++) if (!fix[i]->dynamic_group_allow && group->dynamic[fix[i]->igroup]) - error->all(FLERR, "Fix {} does not allow use with a dynamic group", fix[i]->style); + error->all(FLERR, Error::NOLASTLINE, "Fix {} does not allow use with a dynamic group", + fix[i]->style); for (i = 0; i < ncompute; i++) if (!compute[i]->dynamic_group_allow && group->dynamic[compute[i]->igroup]) - error->all(FLERR, "Compute {} does not allow use with a dynamic group", compute[i]->style); + error->all(FLERR, Error::NOLASTLINE, "Compute {} does not allow use with a dynamic group", + compute[i]->style); // warn if any particle is time integrated more than once @@ -834,13 +836,13 @@ Fix *Modify::add_fix(int narg, char **arg, int trysuffix) for (m = 0; exceptions[m] != nullptr; m++) if (strcmp(arg[2], exceptions[m]) == 0) break; if (exceptions[m] == nullptr) - error->all(FLERR, "Fix {} command before simulation box is defined", arg[2]); + error->all(FLERR, 2, "Fix {} command before simulation box is defined", arg[2]); } // check group ID int igroup = group->find(arg[1]); - if (igroup == -1) error->all(FLERR, "Could not find fix group ID {}", arg[1]); + if (igroup == -1) error->all(FLERR, 1, "Could not find fix group ID {}", arg[1]); // if fix ID exists: // set newflag = 0 so create new fix in same location in fix list @@ -874,7 +876,7 @@ Fix *Modify::add_fix(int narg, char **arg, int trysuffix) if (estyle == fix[ifix]->style) match = 1; } } - if (!match) error->all(FLERR, "Replacing a fix, but new style != old style"); + if (!match) error->all(FLERR, 2, "Replacing a fix, but new style != old style"); if (fix[ifix]->igroup != igroup && comm->me == 0) error->warning(FLERR, "Replacing a fix, but new group != old group"); @@ -921,7 +923,8 @@ Fix *Modify::add_fix(int narg, char **arg, int trysuffix) fix[ifix] = fix_creator(lmp, narg, arg); } - if (fix[ifix] == nullptr) error->all(FLERR, utils::check_packages_for_style("fix", arg[2], lmp)); + if (fix[ifix] == nullptr) + error->all(FLERR, 2, utils::check_packages_for_style("fix", arg[2], lmp)); // increment nfix and update fix_list vector (if new) @@ -1244,7 +1247,8 @@ Compute *Modify::add_compute(int narg, char **arg, int trysuffix) // error check - if (get_compute_by_id(arg[0])) error->all(FLERR, "Reuse of compute ID '{}'", arg[0]); + if (get_compute_by_id(arg[0])) + error->all(FLERR, Error::ARGZERO, "Reuse of compute ID '{}'", arg[0]); // extend Compute list if necessary diff --git a/src/neighbor.cpp b/src/neighbor.cpp index e12713094e..c90eaa752c 100644 --- a/src/neighbor.cpp +++ b/src/neighbor.cpp @@ -392,6 +392,13 @@ void Neighbor::init() } cutneighmaxsq = cutneighmax * cutneighmax; + // update cutneighmin based on individual neighbor list requests + + for (i = 0; i < nrequest; ++i) { + if (requests[i]->cut) cutneighmin = MIN(cutneighmin, requests[i]->cutoff + + (requests[i]->occasional ? 0.0 : skin)); + } + // Define cutoffs for multi if (style == Neighbor::MULTI) { int icollection, jcollection; diff --git a/src/region.cpp b/src/region.cpp index 2d2c6513c9..1615ad5952 100644 --- a/src/region.cpp +++ b/src/region.cpp @@ -65,27 +65,39 @@ void Region::init() { if (xstr) { xvar = input->variable->find(xstr); - if (xvar < 0) error->all(FLERR, "Variable {} for region does not exist", xstr); + if (xvar < 0) + error->all(FLERR, Error::NOLASTLINE, "Variable {} for region {} {} does not exist", xstr, + style, id); if (!input->variable->equalstyle(xvar)) - error->all(FLERR, "Variable {} for region is invalid style", xstr); + error->all(FLERR, Error::NOLASTLINE, "Variable {} for region {} {} is invalid style", xstr, + style, id); } if (ystr) { yvar = input->variable->find(ystr); - if (yvar < 0) error->all(FLERR, "Variable {} for region does not exist", ystr); + if (yvar < 0) + error->all(FLERR, Error::NOLASTLINE, "Variable {} for region {} {} does not exist", ystr, + style, id); if (!input->variable->equalstyle(yvar)) - error->all(FLERR, "Variable {} for region is not equal style", ystr); + error->all(FLERR, Error::NOLASTLINE, "Variable {} for region {} {} is not equal style", ystr, + style, id); } if (zstr) { zvar = input->variable->find(zstr); - if (zvar < 0) error->all(FLERR, "Variable {} for region does not exist", zstr); + if (zvar < 0) + error->all(FLERR, Error::NOLASTLINE, "Variable {} for region {} {} does not exist", zstr, + style, id); if (!input->variable->equalstyle(zvar)) - error->all(FLERR, "Variable {} for region is not equal style", zstr); + error->all(FLERR, Error::NOLASTLINE, "Variable {} for region {} {} is not equal style", zstr, + style, id); } if (tstr) { tvar = input->variable->find(tstr); - if (tvar < 0) error->all(FLERR, "Variable {} for region does not exist", tstr); + if (tvar < 0) + error->all(FLERR, Error::NOLASTLINE, "Variable {} for region {} {} does not exist", tstr, + style, id); if (!input->variable->equalstyle(tvar)) - error->all(FLERR, "Variable {} for region is not equal style", tstr); + error->all(FLERR, Error::NOLASTLINE, "Variable {} for region {} {} is not equal style", tstr, + style, id); } vel_timestep = -1; } @@ -303,6 +315,16 @@ void Region::options(int narg, char **arg) { if (narg < 0) utils::missing_cmd_args(FLERR, "region", error); + int offset = -20; + if (input && input->arg && arg) { + for (int i = 0; i < input->narg; ++i) { + if (arg[0] == input->arg[i]) { + offset = i; + break; + } + } + } + // option defaults interior = 1; @@ -321,7 +343,7 @@ void Region::options(int narg, char **arg) else if (strcmp(arg[iarg + 1], "lattice") == 0) scaleflag = 1; else - error->all(FLERR, "Illegal region units: {}", arg[iarg + 1]); + error->all(FLERR, iarg + 1 + offset, "Unknown region units: {}", arg[iarg + 1]); iarg += 2; } else if (strcmp(arg[iarg], "side") == 0) { if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "region side", error); @@ -330,24 +352,27 @@ void Region::options(int narg, char **arg) else if (strcmp(arg[iarg + 1], "out") == 0) interior = 0; else - error->all(FLERR, "Illegal region side: {}", arg[iarg + 1]); + error->all(FLERR, iarg + 1 + offset, "Unknown region side setting: {}", arg[iarg + 1]); iarg += 2; } else if (strcmp(arg[iarg], "move") == 0) { if (iarg + 4 > narg) utils::missing_cmd_args(FLERR, "region move", error); if (strcmp(arg[iarg + 1], "NULL") != 0) { if (strstr(arg[iarg + 1], "v_") != arg[iarg + 1]) - error->all(FLERR, "Illegal region move x displacement variable: {}", arg[iarg + 1]); + error->all(FLERR, iarg + 1 + offset, "Illegal region move x displacement variable: {}", + arg[iarg + 1]); xstr = utils::strdup(&arg[iarg + 1][2]); } if (strcmp(arg[iarg + 2], "NULL") != 0) { if (strstr(arg[iarg + 2], "v_") != arg[iarg + 2]) - error->all(FLERR, "Illegal region move y displacement variable: {}", arg[iarg + 2]); + error->all(FLERR, iarg + 2 + offset, "Illegal region move y displacement variable: {}", + arg[iarg + 2]); ystr = utils::strdup(&arg[iarg + 2][2]); } if (strcmp(arg[iarg + 3], "NULL") != 0) { if (strstr(arg[iarg + 3], "v_") != arg[iarg + 3]) - error->all(FLERR, "Illegal region move z displacement variable: {}", arg[iarg + 3]); + error->all(FLERR, iarg + 3 + offset, "Illegal region move z displacement variable: {}", + arg[iarg + 3]); zstr = utils::strdup(&arg[iarg + 3][2]); } moveflag = 1; @@ -369,19 +394,20 @@ void Region::options(int narg, char **arg) } else if (strcmp(arg[iarg], "open") == 0) { if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "region open", error); int iface = utils::inumeric(FLERR, arg[iarg + 1], false, lmp); - if (iface < 1 || iface > 6) error->all(FLERR, "Illegal region open face index: {}", iface); + if (iface < 1 || iface > 6) + error->all(FLERR, iarg + 1 + offset, "Illegal region open face index: {}", iface); // additional checks on valid face index are done by region classes open_faces[iface - 1] = 1; openflag = 1; iarg += 2; } else - error->all(FLERR, iarg, "Unknown region command argument: {}", arg[iarg]); + error->all(FLERR, iarg + offset, "Unknown region command argument: {}", arg[iarg]); } // error check if ((moveflag || rotateflag) && (strcmp(style, "union") == 0 || strcmp(style, "intersect") == 0)) - error->all(FLERR, "Region union or intersect cannot be dynamic"); + error->all(FLERR, 1, "Region union or intersect cannot be dynamic"); // setup scaling @@ -402,7 +428,7 @@ void Region::options(int narg, char **arg) if (rotateflag) { double len = sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]); - if (len == 0.0) error->all(FLERR, "Region cannot have 0 length rotation vector"); + if (len == 0.0) error->all(FLERR, Error::NOPOINTER, "Region cannot have 0 length rotation vector"); runit[0] = axis[0] / len; runit[1] = axis[1] / len; runit[2] = axis[2] / len; diff --git a/src/region.h b/src/region.h index 19fdec31c7..8a51f404a2 100644 --- a/src/region.h +++ b/src/region.h @@ -47,7 +47,7 @@ class Region : protected Pointers { double delx, dely, delz; // vector from surface pt to particle double radius; // curvature of region at contact point int iwall; // unique id of wall for storing shear history - int varflag; // 1 if wall can be variable-controlled + int varflag = 0; // 1 if wall can be variable-controlled }; Contact *contact; // list of contacts int cmax; // max # of contacts possible with region diff --git a/src/region_cone.cpp b/src/region_cone.cpp index 401ed53735..30f29e3934 100644 --- a/src/region_cone.cpp +++ b/src/region_cone.cpp @@ -41,10 +41,11 @@ RegCone::RegCone(LAMMPS *lmp, int narg, char **arg) : if (openflag) for (int i = 3; i < 6; i++) - if (open_faces[i]) error->all(FLERR, "Illegal region cone open face: {}", i + 1); + if (open_faces[i]) + error->all(FLERR, Error::NOPOINTER, "Illegal region cone open face: {}", i + 1); if (strcmp(arg[2], "x") != 0 && strcmp(arg[2], "y") != 0 && strcmp(arg[2], "z") != 0) - error->all(FLERR, "Illegal region cone axis: {}", arg[2]); + error->all(FLERR, 2, "Illegal region cone axis: {}", arg[2]); axis = arg[2][0]; if (axis == 'x') { @@ -256,8 +257,8 @@ RegCone::RegCone(LAMMPS *lmp, int narg, char **arg) : // error check - if (radiuslo < 0.0) error->all(FLERR, "Illegal radius in region cone command"); - if (radiushi < 0.0) error->all(FLERR, "Illegal radius in region cone command"); + if (radiuslo < 0.0) error->all(FLERR, 5, "Illegal lower radius in region cone command"); + if (radiushi < 0.0) error->all(FLERR, 6, "Illegal upper radius in region cone command"); if (radiuslo == 0.0 && radiushi == 0.0) error->all(FLERR, "Illegal radius in region cone command"); if (hi <= lo) error->all(FLERR, "Illegal cone length in region cone command"); diff --git a/src/region_plane.h b/src/region_plane.h index 790564e176..0988fda812 100644 --- a/src/region_plane.h +++ b/src/region_plane.h @@ -25,6 +25,8 @@ RegionStyle(plane,RegPlane); namespace LAMMPS_NS { class RegPlane : public Region { + friend class Region2VMD; + public: RegPlane(class LAMMPS *, int, char **); ~RegPlane() override; diff --git a/src/safe_pointers.h b/src/safe_pointers.h new file mode 100644 index 0000000000..6925d58646 --- /dev/null +++ b/src/safe_pointers.h @@ -0,0 +1,60 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + LAMMPS development team: developers@lammps.org + + 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_SAFE_POINTERS_H +#define LMP_SAFE_POINTERS_H + +// collection of smart pointers for specific purposes + +#include + +namespace LAMMPS_NS { + +/** Class to automatically close a FILE pointer when a class instance goes out of scope. + +\verbatim embed:rst + +Drop in replacement for ``FILE *``. Use as ``SafeFilePtr fp;`` instead of +``FILE *fp = nullptr;`` and there is no more need to explicitly call +``fclose(fp)``. + +\endverbatim +*/ +class SafeFilePtr { + public: + SafeFilePtr() : fp(nullptr) {}; + SafeFilePtr(FILE *_fp) : fp(_fp) {}; + + SafeFilePtr(const SafeFilePtr &) = delete; + SafeFilePtr(SafeFilePtr &&o) noexcept : fp(o.fp) { o.fp = nullptr; } + SafeFilePtr &operator=(const SafeFilePtr &) = delete; + + ~SafeFilePtr() + { + if (fp) fclose(fp); + } + + SafeFilePtr &operator=(FILE *_fp) + { + if (fp && (fp != _fp)) fclose(fp); + fp = _fp; + return *this; + } + operator FILE *() const { return fp; } + + private: + FILE *fp; +}; +} // namespace LAMMPS_NS + +#endif diff --git a/src/text_file_reader.h b/src/text_file_reader.h index cc62471f66..f22885963c 100644 --- a/src/text_file_reader.h +++ b/src/text_file_reader.h @@ -26,6 +26,7 @@ namespace LAMMPS_NS { class TextFileReader { + private: std::string filetype; bool closefp; int bufsize; diff --git a/src/thermo.cpp b/src/thermo.cpp index c7e53f8c85..b211007125 100644 --- a/src/thermo.cpp +++ b/src/thermo.cpp @@ -88,7 +88,7 @@ static constexpr char YAML[] = "step temp ke pe ebond eangle edihed eimp evdwl e #define FORMAT_INT_YAML_DEFAULT "%d" static constexpr char FORMAT_MULTI_HEADER[] = - "------------ Step {:14} ----- CPU = {:12.7g} (sec) -------------"; + "------------ Step {:14} ----- CPU = {:12.7g} (sec) -------------"; enum { SCALAR, VECTOR, ARRAY }; @@ -136,7 +136,7 @@ Thermo::Thermo(LAMMPS *_lmp, int narg, char **arg) : lineflag = YAMLLINE; } else if (strcmp(style, "custom") == 0) { - if (narg == 1) error->all(FLERR, "Illegal thermo style custom command"); + if (narg == 1) error->all(FLERR, Error::ARGZERO, "Illegal thermo style custom command"); // expand args if any have wildcard character "*" @@ -159,7 +159,7 @@ Thermo::Thermo(LAMMPS *_lmp, int narg, char **arg) : } } else - error->all(FLERR, "Illegal thermo style command"); + error->all(FLERR, Error::ARGZERO, "Illegal thermo style {}", style); index_temp = index_press_scalar = index_press_vector = index_pe = -1; @@ -297,7 +297,9 @@ void Thermo::init() for (int i = 0; i < ncompute; i++) { computes[i] = modify->get_compute_by_id(id_compute[i]); - if (!computes[i]) error->all(FLERR, "Could not find thermo compute with ID {}", id_compute[i]); + if (!computes[i]) + error->all(FLERR, Error::NOLASTLINE, "Could not find thermo compute with ID {}", + id_compute[i]); } // find current ptr for each Fix ID @@ -305,17 +307,20 @@ void Thermo::init() for (int i = 0; i < nfix; i++) { fixes[i] = modify->get_fix_by_id(id_fix[i]); - if (!fixes[i]) error->all(FLERR, "Could not find thermo fix ID {}", id_fix[i]); + if (!fixes[i]) + error->all(FLERR, Error::NOLASTLINE, "Could not find thermo fix ID {}", id_fix[i]); if (output->thermo_every % fixes[i]->global_freq) - error->all(FLERR, "Thermo and fix {} not computed at compatible times", id_fix[i]); + error->all(FLERR, Error::NOLASTLINE, "Thermo and fix {} not computed at compatible times", + id_fix[i]); } // find current ptr for each Variable ID for (int i = 0; i < nvariable; i++) { variables[i] = input->variable->find(id_variable[i]); - if (variables[i] < 0) error->all(FLERR, "Could not find thermo variable {}", id_variable[i]); + if (variables[i] < 0) + error->all(FLERR, Error::NOLASTLINE, "Could not find thermo variable {}", id_variable[i]); } // set ptrs to keyword-specific Compute objects @@ -486,7 +491,7 @@ bigint Thermo::lost_check() nlocal[0] = atom->nlocal; nlocal[1] = error->get_numwarn(); MPI_Allreduce(nlocal, ntotal, 2, MPI_LMP_BIGINT, MPI_SUM, world); - if (ntotal[0] < 0) error->all(FLERR, "Too many total atoms"); + if (ntotal[0] < 0) error->all(FLERR, Error::NOLASTLINE, "Too many total atoms"); // print notification, if future warnings will be ignored bigint maxwarn = error->get_maxwarn(); @@ -494,7 +499,8 @@ bigint Thermo::lost_check() warnbefore = 1; if (comm->me == 0) error->message(FLERR, - "WARNING: Too many warnings: {} vs {}. All future warnings will be suppressed", + "WARNING: Too many warnings: {} vs {}. " + "All future warnings will be suppressed", ntotal[1], maxwarn); } error->set_allwarn(MIN(MAXSMALLINT, ntotal[1])); @@ -509,7 +515,8 @@ bigint Thermo::lost_check() // error message if (lostflag == Thermo::ERROR) - error->all(FLERR, "Lost atoms: original {} current {}", atom->natoms, ntotal[0]); + error->all(FLERR, Error::NOLASTLINE, "Lost atoms: original {} current {}", atom->natoms, + ntotal[0]); // warning message @@ -537,16 +544,18 @@ void Thermo::modify_params(int narg, char **arg) while (iarg < narg) { if (strcmp(arg[iarg], "temp") == 0) { if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "thermo_modify temp", error); - if (index_temp < 0) error->all(FLERR, "Thermo style does not use temp"); + if (index_temp < 0) error->all(FLERR, iarg + 1, "Thermo style does not use temp"); delete[] id_compute[index_temp]; id_compute[index_temp] = utils::strdup(arg[iarg + 1]); temperature = modify->get_compute_by_id(arg[iarg + 1]); if (!temperature) - error->all(FLERR, "Could not find thermo_modify temperature compute {}", arg[iarg + 1]); + error->all(FLERR, iarg + 1, "Could not find thermo_modify temperature compute {}", + arg[iarg + 1]); if (temperature->tempflag == 0) - error->all(FLERR, "Thermo_modify compute {} does not compute temperature", arg[iarg + 1]); + error->all(FLERR, iarg + 1, "Thermo_modify compute {} does not compute temperature", + arg[iarg + 1]); if (temperature->igroup != 0 && comm->me == 0) error->warning(FLERR, "Temperature for thermo pressure is not for group all"); @@ -557,12 +566,16 @@ void Thermo::modify_params(int narg, char **arg) if (index_press_scalar >= 0) { pcompute = modify->get_compute_by_id(id_compute[index_press_scalar]); if (!pcompute) - error->all(FLERR, "Pressure compute {} for thermo output does not exist", + error->all(FLERR, Error::NOPOINTER, + "Pressure compute {} for thermo output does " + "not exist", id_compute[index_press_scalar]); } else if (index_press_vector >= 0) { pcompute = modify->get_compute_by_id(id_compute[index_press_vector]); if (!pcompute) - error->all(FLERR, "Pressure compute {} for thermo output does not exist", + error->all(FLERR, Error::NOPOINTER, + "Pressure compute {} for thermo output does " + "not exist", id_compute[index_press_vector]); } else pcompute = modify->get_compute_by_id("thermo_press"); @@ -594,10 +607,10 @@ void Thermo::modify_params(int narg, char **arg) iarg += 2; } else if (strcmp(arg[iarg], "triclinic/general") == 0) { - if (iarg + 2 > narg) error->all(FLERR, "Illegal thermo_modify command"); + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "thermo_modify tricinic/general", error); triclinic_general = utils::logical(FLERR, arg[iarg + 1], false, lmp); if (triclinic_general && !domain->triclinic_general) - error->all(FLERR, + error->all(FLERR, iarg, "Thermo_modify triclinic/general cannot be used " "if simulation box is not general triclinic"); iarg += 2; @@ -611,7 +624,7 @@ void Thermo::modify_params(int narg, char **arg) else if (strcmp(arg[iarg + 1], "error") == 0) lostflag = Thermo::ERROR; else - error->all(FLERR, "Unknown thermo_modify lost argument: {}", arg[iarg + 1]); + error->all(FLERR, iarg + 1, "Unknown thermo_modify lost argument: {}", arg[iarg + 1]); iarg += 2; } else if (strcmp(arg[iarg], "lost/bond") == 0) { @@ -623,7 +636,7 @@ void Thermo::modify_params(int narg, char **arg) else if (strcmp(arg[iarg + 1], "error") == 0) lostbond = Thermo::ERROR; else - error->all(FLERR, "Unknown thermo_modify lost/bond argument: {}", arg[iarg + 1]); + error->all(FLERR, iarg + 1, "Unknown thermo_modify lost/bond argument: {}", arg[iarg + 1]); iarg += 2; } else if (strcmp(arg[iarg], "warn") == 0) { @@ -663,7 +676,7 @@ void Thermo::modify_params(int narg, char **arg) else if (strcmp(arg[iarg + 1], "yaml") == 0) lineflag = YAMLLINE; else - error->all(FLERR, "Unknown thermo_modify line argument: {}", arg[iarg + 1]); + error->all(FLERR, iarg + 1, "Unknown thermo_modify line argument: {}", arg[iarg + 1]); iarg += 2; } else if (strcmp(arg[iarg], "colname") == 0) { @@ -686,7 +699,7 @@ void Thermo::modify_params(int narg, char **arg) } } if ((icol < 0) || (icol >= nfield_initial)) - error->all(FLERR, "Invalid thermo_modify colname argument: {}", arg[iarg + 1]); + error->all(FLERR, iarg + 1, "Invalid thermo_modify colname argument: {}", arg[iarg + 1]); keyword_user[icol] = arg[iarg + 2]; iarg += 3; } @@ -713,7 +726,8 @@ void Thermo::modify_params(int narg, char **arg) auto found = format_int_user.find('%'); found = format_int_user.find('d', found); if (found == std::string::npos) - error->all(FLERR, "Thermo_modify int format does not contain a d conversion character"); + error->all(FLERR, iarg + 2, + "Thermo_modify int format does not contain a d conversion character"); format_bigint_user = format_int_user.replace(found, 1, std::string(BIGINT_FORMAT).substr(1)); } else if (strcmp(arg[iarg + 1], "float") == 0) { @@ -729,7 +743,7 @@ void Thermo::modify_params(int narg, char **arg) else icol = i; if (icol < 0 || (icol >= nfield_initial)) - error->all(FLERR, "Invalid thermo_modify format argument: {}", arg[iarg + 1]); + error->all(FLERR, iarg + 1, "Invalid thermo_modify format argument: {}", arg[iarg + 1]); format_column_user[icol] = arg[iarg + 2]; } } else { @@ -746,13 +760,13 @@ void Thermo::modify_params(int narg, char **arg) } } if ((icol < 0) || (icol >= nfield_initial)) - error->all(FLERR, "Invalid thermo_modify format argument: {}", arg[iarg + 1]); + error->all(FLERR, iarg + 1, "Invalid thermo_modify format argument: {}", arg[iarg + 1]); format_column_user[icol] = arg[iarg + 2]; } iarg += 3; } else - error->all(FLERR, "Unknown thermo_modify keyword: {}", arg[iarg]); + error->all(FLERR, iarg, "Unknown thermo_modify keyword: {}", arg[iarg]); } } diff --git a/src/utils.cpp b/src/utils.cpp index 940faa3eed..310669c241 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -234,9 +234,9 @@ std::string utils::point_to_error(Input *input, int failed) // construct and append error indicator line cmdline += '\n'; cmdline += std::string(indicator, ' '); - cmdline += std::string(strlen(input->arg[failed]) + quoted, '^'); + cmdline += std::string(strlen((failed < 0) ? input->command : input->arg[failed]) + + quoted, '^'); cmdline += '\n'; - } else { cmdline += lastline; cmdline += '\n'; diff --git a/src/version.h b/src/version.h index d24e7ed8f1..d28810b466 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1,2 @@ #define LAMMPS_VERSION "4 Feb 2025" +#define LAMMPS_UPDATE "Development" diff --git a/tools/lammps-gui/CMakeLists.txt b/tools/lammps-gui/CMakeLists.txt index aee806c81a..b09c6c26d9 100644 --- a/tools/lammps-gui/CMakeLists.txt +++ b/tools/lammps-gui/CMakeLists.txt @@ -279,7 +279,7 @@ if(APPLE) MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} MACOSX_BUNDLE_ICON_FILE lammps.icns - MACOSX_BUNDLE_COPYRIGHT "(c) 2003 - 2024, The LAMMPS Developers" + MACOSX_BUNDLE_COPYRIGHT "(c) 2003 - 2025, The LAMMPS Developers" MACOSX_BUNDLE TRUE ) # additional targets to populate the bundle tree and create the .dmg image file diff --git a/tools/singularity/README.md b/tools/singularity/README.md index 4700dac6ec..8f0508b9f0 100644 --- a/tools/singularity/README.md +++ b/tools/singularity/README.md @@ -1,6 +1,6 @@ # Apptainer (aka Singularity) container definitions for compiling/testing LAMMPS -The *.def files in this folder can be used to build container images +The \*.def files in this folder can be used to build container images for [Apptainer](https://apptainer.org) (previously called [Singularity](https://sylabs.io)), suitable for compiling and testing LAMMPS on a variety of OS variants with support for most standard diff --git a/tools/singularity/fedora41_musl_mingw.def b/tools/singularity/fedora41_musl_mingw.def new file mode 100644 index 0000000000..7e15f6590b --- /dev/null +++ b/tools/singularity/fedora41_musl_mingw.def @@ -0,0 +1,109 @@ +BootStrap: docker +From: fedora:41 + +%setup + curl -L -o musl-gcc-f37.tar.gz https://download.lammps.org/static/musl-gcc-f37.tar.gz + cp musl-gcc-f37.tar.gz ${APPTAINER_ROOTFS} + +%post + dnf -y update + dnf -y install vim-enhanced git file make cmake patch which file \ + ninja-build libomp-devel diffutils dos2unix findutils rsync \ + ccache gcc-c++ gcc-gfortran gdb valgrind python3-pyyaml \ + enchant enchant2 python3-enchant python3-virtualenv doxygen latexmk \ + texlive-latex-fonts texlive-pslatex texlive-collection-latexrecommended \ + texlive-latex texlive-latexconfig doxygen-latex texlive-collection-latex \ + texlive-latex-bin texlive-lualatex-math texlive-fncychap texlive-tabulary \ + texlive-framed texlive-wrapfig texlive-upquote texlive-capt-of texlive-pict2e \ + texlive-needspace texlive-titlesec texlive-anysize texlive-dvipng texlive-xindy \ + texlive-fontawesome texlive-ellipse texlive-tex-gyre \ + mingw-filesystem-base mingw32-nsis mingw-binutils-generic \ + mingw64-filesystem mingw64-pkg-config \ + mingw64-crt mingw64-headers mingw64-binutils \ + mingw64-cpp mingw64-gcc mingw64-gcc-gfortran mingw64-gcc-c++ \ + mingw64-curl \ + mingw64-libgomp \ + mingw64-winpthreads \ + mingw64-eigen3 \ + mingw64-fftw \ + mingw64-libjpeg-turbo \ + mingw64-libpng \ + mingw64-python3 \ + mingw64-python3-numpy \ + mingw64-python3-pyyaml \ + mingw64-python3-setuptools \ + mingw64-readline \ + mingw64-termcap \ + mingw64-tcl \ + mingw64-tk \ + mingw64-zlib \ + mingw64-zstd \ + mingw64-qt5-qtdeclarative \ + mingw64-qt5-qmldevtools \ + mingw64-qt5-qmldevtools-devel \ + mingw64-qt5-qttools-tools \ + mingw64-qt5-qtcharts \ + mingw64-qt5-qttools \ + mingw64-qt5-qmake \ + mingw64-qt5-qtbase \ + mingw64-qt5-qtbase-devel \ + mingw64-qt5-qtbase-static \ + + dnf clean all + + # install musl-libc Linux-2-Linux cross-compiler + tar -C /usr/ -xvf /musl-gcc-f37.tar.gz + rm -f /musl-gcc-f37.tar.gz + + # install NSIS EnVar plugin + curl -L -o EnVar_plugin.zip https://nsis.sourceforge.io/mediawiki/images/7/7f/EnVar_plugin.zip + unzip -d /usr/share/nsis EnVar_plugin.zip + rm EnVar_plugin.zip + + # create missing termcap pkgconfig file + cat > /usr/x86_64-w64-mingw32/sys-root/mingw/lib/pkgconfig/termcap.pc <$CUSTOM_PROMPT_ENV <