From 6ba94d1619aeadb5798d282bddf51d16447222d3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 23 Sep 2023 12:55:10 -0400 Subject: [PATCH 01/93] flag as maintenance branch again --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index e7f36633bf..87d76feb9d 100644 --- a/src/version.h +++ b/src/version.h @@ -1,2 +1,2 @@ #define LAMMPS_VERSION "2 Aug 2023" -#define LAMMPS_UPDATE "Update 1" +#define LAMMPS_UPDATE "Maintenance" From b21db641d96a4b089bc0dc8a937c1a4a16cf7611 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 25 Sep 2023 08:07:36 -0400 Subject: [PATCH 02/93] check for compatible LAMMPS version when creating LAMMPS instance This check must be done at runtime, since the LAMMPS shared library may have been loaded dynamically and thus required library functions may not be present or missing features with too only a LAMMPS version. --- tools/lammps-gui/lammpsgui.cpp | 8 ++++++++ tools/lammps-gui/lammpswrapper.cpp | 13 +++++++++++++ tools/lammps-gui/lammpswrapper.h | 1 + 3 files changed, 22 insertions(+) diff --git a/tools/lammps-gui/lammpsgui.cpp b/tools/lammps-gui/lammpsgui.cpp index 68b29d4830..68b76186d2 100644 --- a/tools/lammps-gui/lammpsgui.cpp +++ b/tools/lammps-gui/lammpsgui.cpp @@ -1170,6 +1170,14 @@ void LammpsGui::start_lammps() lammps.open(narg, args); lammpsstatus->show(); + // must have at least 2 August 2023 version of LAMMPS + if (lammps.version() < 20230802) { + QMessageBox::critical(this, "Incompatible LAMMPS Version", + "LAMMPS-GUI version " LAMMPS_GUI_VERSION " requires\n" + "LAMMPS version 2 August 2023 or later"); + exit(1); + } + // delete additional arguments again (3 were there initially while (lammps_args.size() > initial_narg) { delete lammps_args.back(); diff --git a/tools/lammps-gui/lammpswrapper.cpp b/tools/lammps-gui/lammpswrapper.cpp index bb46d7c425..ac6bbb1cbc 100644 --- a/tools/lammps-gui/lammpswrapper.cpp +++ b/tools/lammps-gui/lammpswrapper.cpp @@ -32,6 +32,19 @@ void LammpsWrapper::open(int narg, char **args) #endif } +int LammpsWrapper::version() +{ + int val = 0; + if (lammps_handle) { +#if defined(LAMMPS_GUI_USE_PLUGIN) + val = ((liblammpsplugin_t *)plugin_handle)->version(lammps_handle); +#else + val = lammps_version(lammps_handle); +#endif + } + return val; +} + int LammpsWrapper::extract_setting(const char *keyword) { int val = 0; diff --git a/tools/lammps-gui/lammpswrapper.h b/tools/lammps-gui/lammpswrapper.h index 555307960c..7723326145 100644 --- a/tools/lammps-gui/lammpswrapper.h +++ b/tools/lammps-gui/lammpswrapper.h @@ -28,6 +28,7 @@ public: void force_timeout(); + int version(); int extract_setting(const char *keyword); void *extract_global(const char *keyword); void *extract_atom(const char *keyword); From f634b25e312e3fff32cbddb2c3855f2287871385 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 25 Sep 2023 08:11:55 -0400 Subject: [PATCH 03/93] apply clang-format --- tools/lammps-gui/lammpsgui.cpp | 4 ++-- tools/lammps-gui/periodic_table.h | 6 ++++-- tools/lammps-gui/preferences.cpp | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/lammps-gui/lammpsgui.cpp b/tools/lammps-gui/lammpsgui.cpp index 68b76186d2..d8d916910e 100644 --- a/tools/lammps-gui/lammpsgui.cpp +++ b/tools/lammps-gui/lammpsgui.cpp @@ -1084,8 +1084,8 @@ void LammpsGui::preferences() QSettings settings; int oldthreads = settings.value("nthreads", 1).toInt(); int oldaccel = settings.value("accelerator", AcceleratorTab::None).toInt(); - bool oldecho = settings.value("echo", 0).toBool(); - bool oldcite = settings.value("cite", 0).toBool(); + bool oldecho = settings.value("echo", 0).toBool(); + bool oldcite = settings.value("cite", 0).toBool(); Preferences prefs(&lammps); if (prefs.exec() == QDialog::Accepted) { diff --git a/tools/lammps-gui/periodic_table.h b/tools/lammps-gui/periodic_table.h index 22138c19ad..1193341ada 100644 --- a/tools/lammps-gui/periodic_table.h +++ b/tools/lammps-gui/periodic_table.h @@ -13,11 +13,13 @@ * all tables and functions are declared static, so that it * can be safely included by all plugins that may need it. * - * 2002-2009 akohlmey@cmm.chem.upenn.edu, vmd@ks.uiuc.edu + * 2002-2009,2023 akohlmey@gmail.com, vmd@ks.uiuc.edu */ -#include #include +#include + +// clang-format off /* periodic table of elements for translation of ordinal to atom type */ static const char *pte_label[] = { diff --git a/tools/lammps-gui/preferences.cpp b/tools/lammps-gui/preferences.cpp index 7ce80261a9..bdb7d39dbf 100644 --- a/tools/lammps-gui/preferences.cpp +++ b/tools/lammps-gui/preferences.cpp @@ -397,7 +397,7 @@ SnapshotTab::SnapshotTab(QSettings *_settings, QWidget *parent) : auto *ssao = new QLabel("HQ Image mode:"); auto *bbox = new QLabel("Show Box:"); auto *axes = new QLabel("Show Axes:"); - auto *vdw = new QLabel("VDW Style:"); + auto *vdw = new QLabel("VDW Style:"); auto *cback = new QLabel("Background Color:"); auto *cbox = new QLabel("Box Color:"); settings->beginGroup("snapshot"); From b5480e4e1b05f03a6ee0d0b4574740a12cb42f5a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 25 Sep 2023 08:54:56 -0400 Subject: [PATCH 04/93] must also update CWD when *saving* a file, not only when loading --- tools/lammps-gui/lammpsgui.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/lammps-gui/lammpsgui.cpp b/tools/lammps-gui/lammpsgui.cpp index d8d916910e..0e22adca30 100644 --- a/tools/lammps-gui/lammpsgui.cpp +++ b/tools/lammps-gui/lammpsgui.cpp @@ -530,6 +530,8 @@ void LammpsGui::open_file(const QString &fileName) update_variables(); } +// write file and update CWD to its folder + void LammpsGui::write_file(const QString &fileName) { QFileInfo path(fileName); @@ -542,6 +544,7 @@ void LammpsGui::write_file(const QString &fileName) return; } setWindowTitle(QString("LAMMPS-GUI - " + current_file)); + QDir::setCurrent(current_dir); update_recents(path.absoluteFilePath()); From f3beb206c919f6ab623a023ef7ce69cf3eb1ab9e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 27 Sep 2023 00:06:15 -0400 Subject: [PATCH 05/93] support old ReaxFF force field files without ovcorr entry in bonds section --- src/REAXFF/reaxff_ffield.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/REAXFF/reaxff_ffield.cpp b/src/REAXFF/reaxff_ffield.cpp index d79d63b87b..12fbc781db 100644 --- a/src/REAXFF/reaxff_ffield.cpp +++ b/src/REAXFF/reaxff_ffield.cpp @@ -336,7 +336,7 @@ namespace ReaxFF { values = reader.next_values(0); ++lineno; - if (values.count() < 8) + if (values.count() < 7) THROW_ERROR("Invalid force field file format"); if ((j < ntypes) && (k < ntypes)) { @@ -346,7 +346,11 @@ namespace ReaxFF { values.skip(); tbp[j][k].p_bo1 = tbp[k][j].p_bo1 = values.next_double(); tbp[j][k].p_bo2 = tbp[k][j].p_bo2 = values.next_double(); - tbp[j][k].ovc = tbp[k][j].ovc = values.next_double(); + // if the 8th value is missing use 0.0 + if (values.has_next()) + tbp[j][k].ovc = tbp[k][j].ovc = values.next_double(); + else + tbp[j][k].ovc = tbp[k][j].ovc = 0.0; } } From f8493ed80560e558799a4a4e585cb73234707439 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 27 Sep 2023 18:00:19 -0400 Subject: [PATCH 06/93] Recognize Windows 11 23H2 --- src/platform.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/platform.cpp b/src/platform.cpp index 861e3d7722..b06090094b 100644 --- a/src/platform.cpp +++ b/src/platform.cpp @@ -239,6 +239,8 @@ std::string platform::os_info() buf = "Windows 11 21H2"; } else if (build == "22621") { buf = "Windows 11 22H2"; + } else if (build == "22631") { + buf = "Windows 11 23H2"; } else { const char *entry = "ProductName"; RegGetValue(HKEY_LOCAL_MACHINE, subkey, entry, RRF_RT_REG_SZ, nullptr, &value, From ed9bfb433fc754d2e68ac64b2e3a4d9183aa458e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 3 Oct 2023 14:35:48 -0400 Subject: [PATCH 07/93] avoid segfaults when accessing lammps_last_thermo() --- src/library.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/library.cpp b/src/library.cpp index a88498a5e9..f36d75a40a 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -822,14 +822,17 @@ void *lammps_last_thermo(void *handle, const char *what, int index) { auto lmp = (LAMMPS *) handle; void *val = nullptr; + + if (!lmp->output) return val; Thermo *th = lmp->output->thermo; - if (!th) return nullptr; + if (!th) return val; const int nfield = *th->get_nfield(); BEGIN_CAPTURE { if (strcmp(what, "setup") == 0) { - val = (void *) &lmp->update->setupflag; + if (lmp->update) + val = (void *) &lmp->update->setupflag; } else if (strcmp(what, "step") == 0) { val = (void *) th->get_timestep(); From d567fdae97fd1720d34b50a09c205655b1bf44d4 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 4 Oct 2023 08:37:53 -0400 Subject: [PATCH 08/93] fix delete / delete[] mismatch --- tools/lammps-gui/lammpsgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lammps-gui/lammpsgui.cpp b/tools/lammps-gui/lammpsgui.cpp index 0e22adca30..f101006f61 100644 --- a/tools/lammps-gui/lammpsgui.cpp +++ b/tools/lammps-gui/lammpsgui.cpp @@ -1183,7 +1183,7 @@ void LammpsGui::start_lammps() // delete additional arguments again (3 were there initially while (lammps_args.size() > initial_narg) { - delete lammps_args.back(); + delete[] lammps_args.back(); lammps_args.pop_back(); } From 894699519922ff87b4b6c64d7670ca2f0680865b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 4 Oct 2023 08:39:58 -0400 Subject: [PATCH 09/93] enforce threads are reset properly for /omp styles --- src/OPENMP/thr_omp.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/OPENMP/thr_omp.cpp b/src/OPENMP/thr_omp.cpp index c27a99028d..88344a900d 100644 --- a/src/OPENMP/thr_omp.cpp +++ b/src/OPENMP/thr_omp.cpp @@ -34,6 +34,10 @@ #include +#if defined(_OPENMP) +#include +#endif + using namespace LAMMPS_NS; using MathConst::THIRD; @@ -44,6 +48,9 @@ ThrOMP::ThrOMP(LAMMPS *ptr, int style) : lmp(ptr), fix(nullptr), thr_style(style // register fix omp with this class fix = static_cast(lmp->modify->get_fix_by_id("package_omp")); if (!fix) lmp->error->all(FLERR, "The 'package omp' command is required for /omp styles"); +#if defined(_OPENMP) + omp_set_num_threads(lmp->comm->nthreads); +#endif } // clang-format off From ddbdaaafdcc7866240164102504b36c6e66b49d9 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 4 Oct 2023 08:44:36 -0400 Subject: [PATCH 10/93] make threads handling consistent. address issue that threads could not be increased --- tools/lammps-gui/lammpsgui.cpp | 8 ++++++-- tools/lammps-gui/preferences.cpp | 14 ++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/tools/lammps-gui/lammpsgui.cpp b/tools/lammps-gui/lammpsgui.cpp index f101006f61..50f9a0b735 100644 --- a/tools/lammps-gui/lammpsgui.cpp +++ b/tools/lammps-gui/lammpsgui.cpp @@ -1095,9 +1095,9 @@ void LammpsGui::preferences() // must delete LAMMPS instance after preferences have changed that require // using different command line flags when creating the LAMMPS instance like // suffixes or package commands + int newthreads = settings.value("nthreads", 1).toInt(); if ((oldaccel != settings.value("accelerator", AcceleratorTab::None).toInt()) || - (oldthreads != settings.value("nthreads", 1).toInt()) || - (oldecho != settings.value("echo", 0).toBool()) || + (oldthreads != newthreads) || (oldecho != settings.value("echo", 0).toBool()) || (oldcite != settings.value("cite", 0).toBool())) { if (lammps.is_running()) { stop_run(); @@ -1106,6 +1106,10 @@ void LammpsGui::preferences() } lammps.close(); lammpsstatus->hide(); +#if defined(_OPENMP) + qputenv("OMP_NUM_THREADS", std::to_string(newthreads).c_str()); + omp_set_num_threads(newthreads); +#endif } if (imagewindow) imagewindow->createImage(); } diff --git a/tools/lammps-gui/preferences.cpp b/tools/lammps-gui/preferences.cpp index bdb7d39dbf..91d8026e3f 100644 --- a/tools/lammps-gui/preferences.cpp +++ b/tools/lammps-gui/preferences.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #if defined(_OPENMP) #include @@ -115,8 +116,13 @@ void Preferences::accept() // store number of threads QLineEdit *field = tabWidget->findChild("nthreads"); - if (field) - if (field->hasAcceptableInput()) settings->setValue("nthreads", field->text()); + if (field) { + int accel = settings->value("accelerator", AcceleratorTab::None).toInt(); + if ((accel == AcceleratorTab::None) || (accel == AcceleratorTab::Opt)) + settings->setValue("nthreads", 1); + else if (field->hasAcceptableInput()) + settings->setValue("nthreads", field->text()); + } // store image width, height, zoom, and rendering settings @@ -366,11 +372,11 @@ AcceleratorTab::AcceleratorTab(QSettings *_settings, LammpsWrapper *_lammps, QWi int maxthreads = 1; #if defined(_OPENMP) - maxthreads = omp_get_max_threads(); + maxthreads = QThread::idealThreadCount(); #endif auto *choices = new QFrame; auto *choiceLayout = new QVBoxLayout; - auto *ntlabel = new QLabel("Number of threads:"); + auto *ntlabel = new QLabel(QString("Number of threads (max %1):").arg(maxthreads)); auto *ntchoice = new QLineEdit(settings->value("nthreads", maxthreads).toString()); auto *intval = new QIntValidator(1, maxthreads, this); ntchoice->setValidator(intval); From 2f71bc7886666507efae8e37c8275279e8844b9e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 4 Oct 2023 08:55:07 -0400 Subject: [PATCH 11/93] step LAMMPS GUI patch level number to indicate included bugfixes --- tools/lammps-gui/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lammps-gui/CMakeLists.txt b/tools/lammps-gui/CMakeLists.txt index 67e8807b1e..de8e2aa7dc 100644 --- a/tools/lammps-gui/CMakeLists.txt +++ b/tools/lammps-gui/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(lammps-gui VERSION 1.2.4 LANGUAGES CXX) +project(lammps-gui VERSION 1.2.5 LANGUAGES CXX) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) From 75d0d9be1d06a8b95d2138422e4614f42086a624 Mon Sep 17 00:00:00 2001 From: Evangelos Voyiatzis Date: Wed, 4 Oct 2023 10:04:45 +0300 Subject: [PATCH 12/93] Fixes #3925 in region_ellipsoid.cpp --- src/region_ellipsoid.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/region_ellipsoid.cpp b/src/region_ellipsoid.cpp index 3520b55813..0296178648 100644 --- a/src/region_ellipsoid.cpp +++ b/src/region_ellipsoid.cpp @@ -190,8 +190,8 @@ int RegEllipsoid::surface_interior(double *x, double cutoff) double b_r = b - cutoff; double c_r = c - cutoff; double delx_r = b_r * c_r * (x[0] - xc); - double dely_r = a_r * c_r * (x[1] - xc); - double delz_r = a_r * b_r * (x[2] - xc); + double dely_r = a_r * c_r * (x[1] - yc); + double delz_r = a_r * b_r * (x[2] - zc); double r_r = delx_r * delx_r + dely_r * dely_r + delz_r * delz_r; double rc_r = a_r * a_r * b_r * b_r * c_r * c_r; @@ -217,9 +217,9 @@ int RegEllipsoid::surface_interior(double *x, double cutoff) contact[0].r = DistancePointEllipsoid( axes[sorting[2]], axes[sorting[1]], axes[sorting[0]], coords[sorting[2]], coords[sorting[1]], coords[sorting[0]], x0[sorting[2]], x0[sorting[1]], x0[sorting[0]]); - contact[0].delx = x[0] - (copysign(x0[sorting[2]], x[0] - xc) + xc); - contact[0].dely = x[1] - (copysign(x0[sorting[1]], x[1] - yc) + yc); - contact[0].delz = x[2] - (copysign(x0[sorting[0]], x[2] - zc) + zc); + contact[0].delx = x[0] - (copysign(x0[0], x[0] - xc) + xc); + contact[0].dely = x[1] - (copysign(x0[1], x[1] - yc) + yc); + contact[0].delz = x[2] - (copysign(x0[2], x[2] - zc) + zc); // contact[0].radius = -radius; contact[0].iwall = 0; contact[0].varflag = 1; @@ -236,7 +236,7 @@ int RegEllipsoid::surface_interior(double *x, double cutoff) double a_r = a - cutoff; double b_r = b - cutoff; double delx_r = b_r * (x[0] - xc); - double dely_r = a_r * (x[1] - xc); + double dely_r = a_r * (x[1] - yc); double r_r = delx_r * delx_r + dely_r * dely_r; double rc_r = a_r * a_r * b_r * b_r; @@ -281,8 +281,8 @@ int RegEllipsoid::surface_exterior(double *x, double cutoff) double b_r = b + cutoff; double c_r = c + cutoff; double delx_r = b_r * c_r * (x[0] - xc); - double dely_r = a_r * c_r * (x[1] - xc); - double delz_r = a_r * b_r * (x[2] - xc); + double dely_r = a_r * c_r * (x[1] - yc); + double delz_r = a_r * b_r * (x[2] - zc); double r_r = delx_r * delx_r + dely_r * dely_r + delz_r * delz_r; double rc_r = a_r * a_r * b_r * b_r * c_r * c_r; @@ -308,9 +308,9 @@ int RegEllipsoid::surface_exterior(double *x, double cutoff) contact[0].r = DistancePointEllipsoid( axes[sorting[2]], axes[sorting[1]], axes[sorting[0]], coords[sorting[2]], coords[sorting[1]], coords[sorting[0]], x0[sorting[2]], x0[sorting[1]], x0[sorting[0]]); - contact[0].delx = x[0] - (copysign(x0[sorting[2]], x[0] - xc) + xc); - contact[0].dely = x[1] - (copysign(x0[sorting[1]], x[1] - yc) + yc); - contact[0].delz = x[2] - (copysign(x0[sorting[0]], x[2] - zc) + zc); + contact[0].delx = x[0] - (copysign(x0[0], x[0] - xc) + xc); + contact[0].dely = x[1] - (copysign(x0[1], x[1] - yc) + yc); + contact[0].delz = x[2] - (copysign(x0[2], x[2] - zc) + zc); // contact[0].radius = radius; contact[0].iwall = 0; contact[0].varflag = 1; @@ -327,7 +327,7 @@ int RegEllipsoid::surface_exterior(double *x, double cutoff) double a_r = a + cutoff; double b_r = b + cutoff; double delx_r = b_r * (x[0] - xc); - double dely_r = a_r * (x[1] - xc); + double dely_r = a_r * (x[1] - yc); double r_r = delx_r * delx_r + dely_r * dely_r; double rc_r = a_r * a_r * b_r * b_r; From 308207d5f9413e6c0a28a3149e5dd49920875a67 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 5 Oct 2023 13:16:03 -0400 Subject: [PATCH 13/93] fix cut-n-paste error --- src/update.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/update.cpp b/src/update.cpp index e6b97e5731..f990893658 100644 --- a/src/update.cpp +++ b/src/update.cpp @@ -396,7 +396,7 @@ void Update::new_integrate(char *style, int narg, char **arg, int trysuffix, int void Update::create_minimize(int narg, char **arg, int trysuffix) { - if (narg < 1) error->all(FLERR, "Illegal run_style command"); + if (narg < 1) error->all(FLERR, "Illegal minimize_style command"); delete[] minimize_style; delete minimize; From a939e93a083dc4ddcd5d79aa26e4d0012e1599f2 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 11 Oct 2023 02:05:23 -0400 Subject: [PATCH 14/93] must re-initialized threads also for neigbor lists --- src/OPENMP/npair_omp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OPENMP/npair_omp.h b/src/OPENMP/npair_omp.h index 318fddfd54..7249c59406 100644 --- a/src/OPENMP/npair_omp.h +++ b/src/OPENMP/npair_omp.h @@ -32,6 +32,7 @@ namespace LAMMPS_NS { // get access to number of threads and per-thread data structures via FixOMP #define NPAIR_OMP_INIT \ const int nthreads = comm->nthreads; \ + omp_set_num_threads(nthreads); \ const int ifix = modify->find_fix("package_omp") // get thread id and then assign each thread a fixed chunk of atoms From 9def610c086b60669952892f0cfdfcee77493b0c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Oct 2023 16:31:09 -0400 Subject: [PATCH 15/93] update PACE library --- cmake/Modules/Packages/ML-PACE.cmake | 4 ++-- lib/pace/Install.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/Modules/Packages/ML-PACE.cmake b/cmake/Modules/Packages/ML-PACE.cmake index 6cdb751617..ce8f02f5f4 100644 --- a/cmake/Modules/Packages/ML-PACE.cmake +++ b/cmake/Modules/Packages/ML-PACE.cmake @@ -1,6 +1,6 @@ -set(PACELIB_URL "https://github.com/ICAMS/lammps-user-pace/archive/refs/tags/v.2023.01.3.fix.tar.gz" CACHE STRING "URL for PACE evaluator library sources") +set(PACELIB_URL "https://github.com/ICAMS/lammps-user-pace/archive/refs/tags/v.2023.10.04.tar.gz" CACHE STRING "URL for PACE evaluator library sources") -set(PACELIB_MD5 "4f0b3b5b14456fe9a73b447de3765caa" CACHE STRING "MD5 checksum of PACE evaluator library tarball") +set(PACELIB_MD5 "70ff79f4e59af175e55d24f3243ad1ff" CACHE STRING "MD5 checksum of PACE evaluator library tarball") mark_as_advanced(PACELIB_URL) mark_as_advanced(PACELIB_MD5) GetFallbackURL(PACELIB_URL PACELIB_FALLBACK) diff --git a/lib/pace/Install.py b/lib/pace/Install.py index 4f3cf299ac..8d31852e44 100644 --- a/lib/pace/Install.py +++ b/lib/pace/Install.py @@ -18,11 +18,11 @@ from install_helpers import fullpath, geturl, checkmd5sum, getfallback # settings thisdir = fullpath('.') -version ='v.2023.01.3.fix' +version ='v.2023.10.04' # known checksums for different PACE versions. used to validate the download. checksums = { \ - 'v.2023.01.3.fix': '4f0b3b5b14456fe9a73b447de3765caa' + 'v.2023.10.04': '70ff79f4e59af175e55d24f3243ad1ff' } parser = ArgumentParser(prog='Install.py', description="LAMMPS library build wrapper script") From 78adc1727a702a000aec9136820d1e2d11447734 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Oct 2023 16:32:36 -0400 Subject: [PATCH 16/93] backport KOKKOS package fixes from PR #3930 by @stanmoore1 --- src/KOKKOS/atom_kokkos.cpp | 43 ++++++- src/KOKKOS/atom_kokkos.h | 4 + src/KOKKOS/atom_vec_dpd_kokkos.cpp | 8 -- src/KOKKOS/atom_vec_kokkos.h | 2 + src/KOKKOS/fix_dt_reset_kokkos.cpp | 2 +- src/KOKKOS/fix_property_atom_kokkos.cpp | 120 ++++++++++++++++-- src/KOKKOS/fix_property_atom_kokkos.h | 11 +- src/KOKKOS/kokkos.cpp | 18 ++- src/KOKKOS/kokkos_base.h | 8 +- src/KOKKOS/modify_kokkos.cpp | 11 ++ src/KOKKOS/neigh_bond_kokkos.cpp | 5 +- src/KOKKOS/pair_buck_coul_cut_kokkos.h | 13 +- src/KOKKOS/pair_buck_coul_long_kokkos.h | 46 ++++--- src/KOKKOS/pair_buck_kokkos.h | 15 ++- src/KOKKOS/pair_coul_cut_kokkos.h | 13 +- src/KOKKOS/pair_coul_debye_kokkos.h | 13 +- src/KOKKOS/pair_coul_long_kokkos.h | 46 ++++--- src/KOKKOS/pair_eam_alloy_kokkos.cpp | 4 +- src/KOKKOS/pair_eam_fs_kokkos.cpp | 4 +- src/KOKKOS/pair_eam_kokkos.cpp | 4 +- src/KOKKOS/pair_kokkos.h | 81 +++++++----- ...ir_lj_charmm_coul_charmm_implicit_kokkos.h | 46 ++++--- .../pair_lj_charmm_coul_charmm_kokkos.h | 46 ++++--- src/KOKKOS/pair_lj_charmm_coul_long_kokkos.h | 46 ++++--- src/KOKKOS/pair_lj_class2_coul_cut_kokkos.h | 13 +- src/KOKKOS/pair_lj_class2_coul_long_kokkos.h | 46 ++++--- src/KOKKOS/pair_lj_class2_kokkos.h | 15 ++- src/KOKKOS/pair_lj_cut_coul_cut_kokkos.h | 13 +- src/KOKKOS/pair_lj_cut_coul_debye_kokkos.h | 13 +- src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.h | 13 +- src/KOKKOS/pair_lj_cut_coul_long_kokkos.h | 46 ++++--- src/KOKKOS/pair_lj_cut_kokkos.h | 15 ++- src/KOKKOS/pair_lj_expand_coul_long_kokkos.h | 46 ++++--- src/KOKKOS/pair_lj_expand_kokkos.h | 15 ++- .../pair_lj_gromacs_coul_gromacs_kokkos.h | 46 ++++--- src/KOKKOS/pair_lj_gromacs_kokkos.h | 46 ++++--- src/KOKKOS/pair_lj_spica_kokkos.h | 15 ++- src/KOKKOS/pair_morse_kokkos.h | 15 ++- src/KOKKOS/pair_pace_kokkos.cpp | 3 + src/KOKKOS/pair_table_kokkos.cpp | 12 +- src/KOKKOS/pair_table_kokkos.h | 51 ++++---- src/KOKKOS/pair_yukawa_kokkos.h | 19 ++- src/KOKKOS/pair_zbl_kokkos.h | 15 ++- src/fix_property_atom.cpp | 14 +- src/fix_property_atom.h | 1 + 45 files changed, 681 insertions(+), 400 deletions(-) diff --git a/src/KOKKOS/atom_kokkos.cpp b/src/KOKKOS/atom_kokkos.cpp index 03537e7b88..bc393b29d8 100644 --- a/src/KOKKOS/atom_kokkos.cpp +++ b/src/KOKKOS/atom_kokkos.cpp @@ -44,6 +44,9 @@ AtomKokkos::AtomKokkos(LAMMPS *lmp) : Atom(lmp) h_tag_min = Kokkos::subview(h_tag_min_max,0); h_tag_max = Kokkos::subview(h_tag_min_max,1); + + nprop_atom = 0; + fix_prop_atom = nullptr; } /* ---------------------------------------------------------------------- */ @@ -112,6 +115,7 @@ AtomKokkos::~AtomKokkos() memoryKK->destroy_kokkos(k_dvector, dvector); dvector = nullptr; + delete [] fix_prop_atom; } /* ---------------------------------------------------------------------- */ @@ -125,11 +129,37 @@ void AtomKokkos::init() /* ---------------------------------------------------------------------- */ +void AtomKokkos::update_property_atom() +{ + nprop_atom = 0; + std::vector prop_atom_fixes; + for (auto &ifix : modify->get_fix_by_style("^property/atom")) { + if (!ifix->kokkosable) + error->all(FLERR, "KOKKOS package requires a Kokkos-enabled version of fix property/atom"); + + ++nprop_atom; + prop_atom_fixes.push_back(ifix); + } + + delete[] fix_prop_atom; + fix_prop_atom = new FixPropertyAtomKokkos *[nprop_atom]; + + int n = 0; + for (auto &ifix : prop_atom_fixes) + fix_prop_atom[n++] = dynamic_cast(ifix); +} + +/* ---------------------------------------------------------------------- */ + void AtomKokkos::sync(const ExecutionSpace space, unsigned int mask) { - if (space == Device && lmp->kokkos->auto_sync) avecKK->modified(Host, mask); + if (space == Device && lmp->kokkos->auto_sync) { + avecKK->modified(Host, mask); + for (int n = 0; n < nprop_atom; n++) fix_prop_atom[n]->modified(Host, mask); + } avecKK->sync(space, mask); + for (int n = 0; n < nprop_atom; n++) fix_prop_atom[n]->sync(space, mask); } /* ---------------------------------------------------------------------- */ @@ -137,13 +167,20 @@ void AtomKokkos::sync(const ExecutionSpace space, unsigned int mask) void AtomKokkos::modified(const ExecutionSpace space, unsigned int mask) { avecKK->modified(space, mask); + for (int n = 0; n < nprop_atom; n++) fix_prop_atom[n]->modified(space, mask); - if (space == Device && lmp->kokkos->auto_sync) avecKK->sync(Host, mask); + if (space == Device && lmp->kokkos->auto_sync) { + avecKK->sync(Host, mask); + for (int n = 0; n < nprop_atom; n++) fix_prop_atom[n]->sync(Host, mask); + } } +/* ---------------------------------------------------------------------- */ + void AtomKokkos::sync_overlapping_device(const ExecutionSpace space, unsigned int mask) { avecKK->sync_overlapping_device(space, mask); + for (int n = 0; n < nprop_atom; n++) fix_prop_atom[n]->sync_overlapping_device(space, mask); } /* ---------------------------------------------------------------------- */ @@ -375,7 +412,7 @@ AtomVec *AtomKokkos::new_avec(const std::string &style, int trysuffix, int &sfla int hybrid_substyle_flag = (avec != nullptr); AtomVec *avec = Atom::new_avec(style, trysuffix, sflag); - if (!avec->kokkosable) error->all(FLERR, "KOKKOS package requires a kokkos enabled atom_style"); + if (!avec->kokkosable) error->all(FLERR, "KOKKOS package requires a Kokkos-enabled atom_style"); if (!hybrid_substyle_flag) avecKK = dynamic_cast(avec); diff --git a/src/KOKKOS/atom_kokkos.h b/src/KOKKOS/atom_kokkos.h index 23566cff03..e077a4033e 100644 --- a/src/KOKKOS/atom_kokkos.h +++ b/src/KOKKOS/atom_kokkos.h @@ -14,6 +14,7 @@ #include "atom.h" // IWYU pragma: export #include "kokkos_type.h" +#include "fix_property_atom_kokkos.h" #include @@ -25,6 +26,8 @@ namespace LAMMPS_NS { class AtomKokkos : public Atom { public: bool sort_classic; + int nprop_atom; + FixPropertyAtomKokkos** fix_prop_atom; DAT::tdual_tagint_1d k_tag; DAT::tdual_int_1d k_type, k_mask; @@ -144,6 +147,7 @@ class AtomKokkos : public Atom { } void init() override; + void update_property_atom(); void allocate_type_arrays() override; void sync(const ExecutionSpace space, unsigned int mask); void modified(const ExecutionSpace space, unsigned int mask); diff --git a/src/KOKKOS/atom_vec_dpd_kokkos.cpp b/src/KOKKOS/atom_vec_dpd_kokkos.cpp index a8ce29f666..c3430b9f6e 100644 --- a/src/KOKKOS/atom_vec_dpd_kokkos.cpp +++ b/src/KOKKOS/atom_vec_dpd_kokkos.cpp @@ -963,7 +963,6 @@ void AtomVecDPDKokkos::sync(ExecutionSpace space, unsigned int mask) if (mask & UCG_MASK) atomKK->k_uCG.sync(); if (mask & UCGNEW_MASK) atomKK->k_uCGnew.sync(); if (mask & DUCHEM_MASK) atomKK->k_duChem.sync(); - if (mask & DVECTOR_MASK) atomKK->k_dvector.sync(); } else { if (mask & X_MASK) atomKK->k_x.sync(); if (mask & V_MASK) atomKK->k_v.sync(); @@ -980,7 +979,6 @@ void AtomVecDPDKokkos::sync(ExecutionSpace space, unsigned int mask) if (mask & UCG_MASK) atomKK->k_uCG.sync(); if (mask & UCGNEW_MASK) atomKK->k_uCGnew.sync(); if (mask & DUCHEM_MASK) atomKK->k_duChem.sync(); - if (mask & DVECTOR_MASK) atomKK->k_dvector.sync(); } } @@ -1019,8 +1017,6 @@ void AtomVecDPDKokkos::sync_overlapping_device(ExecutionSpace space, unsigned in perform_async_copy(atomKK->k_uCGnew,space); if ((mask & DUCHEM_MASK) && atomKK->k_duChem.need_sync()) perform_async_copy(atomKK->k_duChem,space); - if ((mask & DVECTOR_MASK) && atomKK->k_dvector.need_sync()) - perform_async_copy(atomKK->k_dvector,space); } else { if ((mask & X_MASK) && atomKK->k_x.need_sync()) perform_async_copy(atomKK->k_x,space); @@ -1052,8 +1048,6 @@ void AtomVecDPDKokkos::sync_overlapping_device(ExecutionSpace space, unsigned in perform_async_copy(atomKK->k_uCGnew,space); if ((mask & DUCHEM_MASK) && atomKK->k_duChem.need_sync()) perform_async_copy(atomKK->k_duChem,space); - if ((mask & DVECTOR_MASK) && atomKK->k_dvector.need_sync()) - perform_async_copy(atomKK->k_dvector,space); } } @@ -1077,7 +1071,6 @@ void AtomVecDPDKokkos::modified(ExecutionSpace space, unsigned int mask) if (mask & UCG_MASK) atomKK->k_uCG.modify(); if (mask & UCGNEW_MASK) atomKK->k_uCGnew.modify(); if (mask & DUCHEM_MASK) atomKK->k_duChem.modify(); - if (mask & DVECTOR_MASK) atomKK->k_dvector.modify(); } else { if (mask & X_MASK) atomKK->k_x.modify(); if (mask & V_MASK) atomKK->k_v.modify(); @@ -1094,6 +1087,5 @@ void AtomVecDPDKokkos::modified(ExecutionSpace space, unsigned int mask) if (mask & UCG_MASK) atomKK->k_uCG.modify(); if (mask & UCGNEW_MASK) atomKK->k_uCGnew.modify(); if (mask & DUCHEM_MASK) atomKK->k_duChem.modify(); - if (mask & DVECTOR_MASK) atomKK->k_dvector.modify(); } } diff --git a/src/KOKKOS/atom_vec_kokkos.h b/src/KOKKOS/atom_vec_kokkos.h index 310f1f4d48..9d267176f1 100644 --- a/src/KOKKOS/atom_vec_kokkos.h +++ b/src/KOKKOS/atom_vec_kokkos.h @@ -139,6 +139,8 @@ class AtomVecKokkos : virtual public AtomVec { DAT::tdual_int_1d k_count; + public: + #ifdef LMP_KOKKOS_GPU template Kokkos::View::end_of_step() update->dt = dt; update->dt_default = 0; if (force->pair) force->pair->reset_dt(); - for (int i = 0; i < modify->nfix; i++) modify->fix[i]->reset_dt(); + for (auto &ifix : modify->get_fix_list()) ifix->reset_dt(); output->reset_dt(); } diff --git a/src/KOKKOS/fix_property_atom_kokkos.cpp b/src/KOKKOS/fix_property_atom_kokkos.cpp index 1de07b39dc..dcd943cac6 100644 --- a/src/KOKKOS/fix_property_atom_kokkos.cpp +++ b/src/KOKKOS/fix_property_atom_kokkos.cpp @@ -30,7 +30,46 @@ FixPropertyAtomKokkos::FixPropertyAtomKokkos(LAMMPS *lmp, int narg, char **arg) FixPropertyAtom(lmp, narg, arg) { atomKK = (AtomKokkos *) atom; - grow_arrays(atom->nmax); + kokkosable = 1; + + dvector_flag = 0; + for (int nv = 0; nv < nvalue; nv++) + if (styles[nv] == DVEC) dvector_flag = 1; +} + +/* ---------------------------------------------------------------------- */ + +void FixPropertyAtomKokkos::post_constructor() +{ + atomKK->update_property_atom(); + + FixPropertyAtom::post_constructor(); +} + +/* ---------------------------------------------------------------------- */ + +FixPropertyAtomKokkos::~FixPropertyAtomKokkos() +{ + // deallocate per-atom vectors in Atom class + // set ptrs to a null pointer, so they no longer exist for Atom class + + for (int nv = 0; nv < nvalue; nv++) { + if (styles[nv] == MOLECULE) { + atom->molecule_flag = 0; + memoryKK->destroy_kokkos(atomKK->k_molecule,atom->molecule); + atom->molecule = nullptr; + } else if (styles[nv] == CHARGE) { + atom->q_flag = 0; + memoryKK->destroy_kokkos(atomKK->k_q,atom->q); + atom->q = nullptr; + } else if (styles[nv] == RMASS) { + atom->rmass_flag = 0; + memoryKK->destroy_kokkos(atomKK->k_rmass,atom->rmass); + atom->rmass = nullptr; + } + } + + atomKK->update_property_atom(); } /* ---------------------------------------------------------------------- @@ -44,17 +83,17 @@ void FixPropertyAtomKokkos::grow_arrays(int nmax) { for (int nv = 0; nv < nvalue; nv++) { if (styles[nv] == MOLECULE) { - memory->grow(atom->molecule,nmax,"atom:molecule"); - size_t nbytes = (nmax-nmax_old) * sizeof(tagint); - memset(&atom->molecule[nmax_old],0,nbytes); + atomKK->sync(Device,MOLECULE_MASK); + memoryKK->grow_kokkos(atomKK->k_molecule,atom->molecule,nmax,"atom:molecule"); + atomKK->modified(Device,MOLECULE_MASK); } else if (styles[nv] == CHARGE) { - memory->grow(atom->q,nmax,"atom:q"); - size_t nbytes = (nmax-nmax_old) * sizeof(double); - memset(&atom->q[nmax_old],0,nbytes); + atomKK->sync(Device,Q_MASK); + memoryKK->grow_kokkos(atomKK->k_q,atom->q,nmax,"atom:q"); + atomKK->modified(Device,Q_MASK); } else if (styles[nv] == RMASS) { - memory->grow(atom->rmass,nmax,"atom:rmass"); - size_t nbytes = (nmax-nmax_old) * sizeof(double); - memset(&atom->rmass[nmax_old],0,nbytes); + atomKK->sync(Device,RMASS_MASK); + memoryKK->grow_kokkos(atomKK->k_rmass,atom->rmass,nmax,"atom:rmass"); + atomKK->modified(Device,RMASS_MASK); } else if (styles[nv] == TEMPERATURE) { memory->grow(atom->temperature, nmax, "atom:temperature"); size_t nbytes = (nmax - nmax_old) * sizeof(double); @@ -69,7 +108,7 @@ void FixPropertyAtomKokkos::grow_arrays(int nmax) memset(&atom->ivector[index[nv]][nmax_old],0,nbytes); } else if (styles[nv] == DVEC) { atomKK->sync(Device,DVECTOR_MASK); - memoryKK->grow_kokkos(atomKK->k_dvector,atomKK->dvector,atomKK->k_dvector.extent(0),nmax, + memoryKK->grow_kokkos(atomKK->k_dvector,atom->dvector,atomKK->k_dvector.extent(0),nmax, "atom:dvector"); atomKK->modified(Device,DVECTOR_MASK); } else if (styles[nv] == IARRAY) { @@ -84,3 +123,62 @@ void FixPropertyAtomKokkos::grow_arrays(int nmax) } nmax_old = nmax; } + +/* ---------------------------------------------------------------------- */ + +void FixPropertyAtomKokkos::sync(ExecutionSpace space, unsigned int mask) +{ + if (space == Device) { + if (molecule_flag && (mask & MOLECULE_MASK)) atomKK->k_molecule.sync(); + if (q_flag && (mask & Q_MASK)) atomKK->k_q.sync(); + if (rmass_flag && (mask & RMASS_MASK)) {atomKK->k_rmass.sync();} + if (dvector_flag && (mask & DVECTOR_MASK)) atomKK->k_dvector.sync(); + } else { + if (molecule_flag && (mask & MOLECULE_MASK)) atomKK->k_molecule.sync(); + if (q_flag && (mask & Q_MASK)) atomKK->k_q.sync(); + if (rmass_flag && (mask & RMASS_MASK)) atomKK->k_rmass.sync(); + if (dvector_flag && (mask & DVECTOR_MASK)) atomKK->k_dvector.sync(); + } +} + +/* ---------------------------------------------------------------------- */ + +void FixPropertyAtomKokkos::sync_overlapping_device(ExecutionSpace space, unsigned int mask) +{ + if (space == Device) { + if ((mask & MOLECULE_MASK) && atomKK->k_molecule.need_sync()) + atomKK->avecKK->perform_async_copy(atomKK->k_molecule,space); + if ((mask & Q_MASK) && atomKK->k_q.need_sync()) + atomKK->avecKK->perform_async_copy(atomKK->k_q,space); + if ((mask & RMASS_MASK) && atomKK->k_rmass.need_sync()) + atomKK->avecKK->perform_async_copy(atomKK->k_rmass,space); + if ((mask & DVECTOR_MASK) && atomKK->k_dvector.need_sync()) + atomKK->avecKK->perform_async_copy(atomKK->k_dvector,space); + } else { + if ((mask & MOLECULE_MASK) && atomKK->k_molecule.need_sync()) + atomKK->avecKK->perform_async_copy(atomKK->k_molecule,space); + if ((mask & Q_MASK) && atomKK->k_q.need_sync()) + atomKK->avecKK->perform_async_copy(atomKK->k_q,space); + if ((mask & RMASS_MASK) && atomKK->k_rmass.need_sync()) + atomKK->avecKK->perform_async_copy(atomKK->k_rmass,space); + if ((mask & DVECTOR_MASK) && atomKK->k_dvector.need_sync()) + atomKK->avecKK->perform_async_copy(atomKK->k_dvector,space); + } +} + +/* ---------------------------------------------------------------------- */ + +void FixPropertyAtomKokkos::modified(ExecutionSpace space, unsigned int mask) +{ + if (space == Device) { + if (molecule_flag && (mask & MOLECULE_MASK)) atomKK->k_molecule.modify(); + if (q_flag && (mask & Q_MASK)) atomKK->k_q.modify(); + if (rmass_flag && (mask & RMASS_MASK)) atomKK->k_rmass.modify(); + if (dvector_flag && (mask & DVECTOR_MASK)) atomKK->k_dvector.modify(); + } else { + if (molecule_flag && (mask & MOLECULE_MASK)) atomKK->k_molecule.modify(); + if (q_flag && (mask & Q_MASK)) atomKK->k_q.modify(); + if (rmass_flag && (mask & RMASS_MASK)) atomKK->k_rmass.modify(); + if (dvector_flag && (mask & DVECTOR_MASK)) atomKK->k_dvector.modify(); + } +} diff --git a/src/KOKKOS/fix_property_atom_kokkos.h b/src/KOKKOS/fix_property_atom_kokkos.h index 90eddc98e0..adbe6ab20b 100644 --- a/src/KOKKOS/fix_property_atom_kokkos.h +++ b/src/KOKKOS/fix_property_atom_kokkos.h @@ -22,14 +22,23 @@ FixStyle(property/atom/kk,FixPropertyAtomKokkos); #define LMP_FIX_PROPERTY_ATOM_KOKKOS_H #include "fix_property_atom.h" +#include "atom_vec_kokkos.h" namespace LAMMPS_NS { class FixPropertyAtomKokkos : public FixPropertyAtom { public: FixPropertyAtomKokkos(class LAMMPS *, int, char **); - + void post_constructor() override; + ~FixPropertyAtomKokkos() override; void grow_arrays(int) override; + + void sync(ExecutionSpace space, unsigned int mask); + void modified(ExecutionSpace space, unsigned int mask); + void sync_overlapping_device(ExecutionSpace space, unsigned int mask); + + private: + int dvector_flag; }; } diff --git a/src/KOKKOS/kokkos.cpp b/src/KOKKOS/kokkos.cpp index 91ea6d37ac..84a8f59dd0 100644 --- a/src/KOKKOS/kokkos.cpp +++ b/src/KOKKOS/kokkos.cpp @@ -137,13 +137,13 @@ KokkosLMP::KokkosLMP(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) int set_flag = 0; char *str; - if ((str = getenv("SLURM_LOCALID"))) { + if (str = getenv("SLURM_LOCALID")) { int local_rank = atoi(str); device = local_rank % ngpus; if (device >= skip_gpu) device++; set_flag = 1; } - if ((str = getenv("MPT_LRANK"))) { + if (str = getenv("FLUX_TASK_LOCAL_ID")) { if (ngpus > 0) { int local_rank = atoi(str); device = local_rank % ngpus; @@ -151,7 +151,7 @@ KokkosLMP::KokkosLMP(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) set_flag = 1; } } - if ((str = getenv("MV2_COMM_WORLD_LOCAL_RANK"))) { + if (str = getenv("MPT_LRANK")) { if (ngpus > 0) { int local_rank = atoi(str); device = local_rank % ngpus; @@ -159,7 +159,7 @@ KokkosLMP::KokkosLMP(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) set_flag = 1; } } - if ((str = getenv("OMPI_COMM_WORLD_LOCAL_RANK"))) { + if (str = getenv("MV2_COMM_WORLD_LOCAL_RANK")) { if (ngpus > 0) { int local_rank = atoi(str); device = local_rank % ngpus; @@ -167,7 +167,15 @@ KokkosLMP::KokkosLMP(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) set_flag = 1; } } - if ((str = getenv("PMI_LOCAL_RANK"))) { + if (str = getenv("OMPI_COMM_WORLD_LOCAL_RANK")) { + if (ngpus > 0) { + int local_rank = atoi(str); + device = local_rank % ngpus; + if (device >= skip_gpu) device++; + set_flag = 1; + } + } + if (str = getenv("PMI_LOCAL_RANK")) { if (ngpus > 0) { int local_rank = atoi(str); device = local_rank % ngpus; diff --git a/src/KOKKOS/kokkos_base.h b/src/KOKKOS/kokkos_base.h index 7d9ecb5d80..1e22a38657 100644 --- a/src/KOKKOS/kokkos_base.h +++ b/src/KOKKOS/kokkos_base.h @@ -41,11 +41,6 @@ class KokkosBase { int, int *) {return 0;}; virtual void unpack_forward_comm_fix_kokkos(int, int, DAT::tdual_xfloat_1d &) {} - - // Region - virtual void match_all_kokkos(int, DAT::tdual_int_1d) {} - - // Fix virtual int pack_exchange_kokkos(const int & /*nsend*/, DAT::tdual_xfloat_2d & /*k_buf*/, DAT::tdual_int_1d /*k_sendlist*/, DAT::tdual_int_1d /*k_copylist*/, @@ -54,6 +49,9 @@ class KokkosBase { DAT::tdual_int_1d & /*indices*/, int /*nrecv*/, ExecutionSpace /*space*/) {} + // Region + virtual void match_all_kokkos(int, DAT::tdual_int_1d) {} + using KeyViewType = DAT::t_x_array; using BinOp = BinOp3DLAMMPS; virtual void diff --git a/src/KOKKOS/modify_kokkos.cpp b/src/KOKKOS/modify_kokkos.cpp index 0b81a1cabb..8d8ffca671 100644 --- a/src/KOKKOS/modify_kokkos.cpp +++ b/src/KOKKOS/modify_kokkos.cpp @@ -362,6 +362,17 @@ void ModifyKokkos::pre_reverse(int eflag, int vflag) void ModifyKokkos::post_force(int vflag) { + for (int i = 0; i < n_post_force_group; i++) { + atomKK->sync(fix[list_post_force_group[i]]->execution_space, + fix[list_post_force_group[i]]->datamask_read); + int prev_auto_sync = lmp->kokkos->auto_sync; + if (!fix[list_post_force_group[i]]->kokkosable) lmp->kokkos->auto_sync = 1; + fix[list_post_force_group[i]]->post_force(vflag); + lmp->kokkos->auto_sync = prev_auto_sync; + atomKK->modified(fix[list_post_force_group[i]]->execution_space, + fix[list_post_force_group[i]]->datamask_modify); + } + for (int i = 0; i < n_post_force; i++) { atomKK->sync(fix[list_post_force[i]]->execution_space, fix[list_post_force[i]]->datamask_read); diff --git a/src/KOKKOS/neigh_bond_kokkos.cpp b/src/KOKKOS/neigh_bond_kokkos.cpp index 4cfe440b1f..b749590779 100644 --- a/src/KOKKOS/neigh_bond_kokkos.cpp +++ b/src/KOKKOS/neigh_bond_kokkos.cpp @@ -112,9 +112,8 @@ void NeighBondKokkos::init_topology_kk() { int i,m; int bond_off = 0; int angle_off = 0; - for (i = 0; i < modify->nfix; i++) - if ((strcmp(modify->fix[i]->style,"shake") == 0) - || (strcmp(modify->fix[i]->style,"rattle") == 0)) + for (const auto &ifix : modify->get_fix_list()) + if (utils::strmatch(ifix->style,"^shake") || utils::strmatch(ifix->style,"^rattle")) bond_off = angle_off = 1; if (force->bond && force->bond_match("quartic")) bond_off = 1; diff --git a/src/KOKKOS/pair_buck_coul_cut_kokkos.h b/src/KOKKOS/pair_buck_coul_cut_kokkos.h index b91348d557..9b6cc31898 100644 --- a/src/KOKKOS/pair_buck_coul_cut_kokkos.h +++ b/src/KOKKOS/pair_buck_coul_cut_kokkos.h @@ -112,15 +112,18 @@ class PairBuckCoulCutKokkos : public PairBuckCoulCut { void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairBuckCoulCutKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairBuckCoulCutKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairBuckCoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairBuckCoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairBuckCoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairBuckCoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairBuckCoulCutKokkos*,NeighListKokkos*); friend EV_FLOAT pair_compute(PairBuckCoulCutKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairBuckCoulCutKokkos*); diff --git a/src/KOKKOS/pair_buck_coul_long_kokkos.h b/src/KOKKOS/pair_buck_coul_long_kokkos.h index b776a84e3c..bed9b0d0f8 100644 --- a/src/KOKKOS/pair_buck_coul_long_kokkos.h +++ b/src/KOKKOS/pair_buck_coul_long_kokkos.h @@ -115,27 +115,33 @@ class PairBuckCoulLongKokkos : public PairBuckCoulLong { void allocate() override; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairBuckCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairBuckCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairBuckCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairBuckCoulLongKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairBuckCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairBuckCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairBuckCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairBuckCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairBuckCoulLongKokkos*, NeighListKokkos*); - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairBuckCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairBuckCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairBuckCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairBuckCoulLongKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairBuckCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairBuckCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairBuckCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairBuckCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairBuckCoulLongKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairBuckCoulLongKokkos*); diff --git a/src/KOKKOS/pair_buck_kokkos.h b/src/KOKKOS/pair_buck_kokkos.h index 364716453b..15325cd56a 100644 --- a/src/KOKKOS/pair_buck_kokkos.h +++ b/src/KOKKOS/pair_buck_kokkos.h @@ -91,16 +91,19 @@ class PairBuckKokkos : public PairBuck { int nlocal,nall,eflag,vflag; void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairBuckKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairBuckKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairBuckKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute(PairBuckKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairBuckKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairBuckKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairBuckKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairBuckKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute(PairBuckKokkos*,NeighListKokkos*); friend void pair_virial_fdotr_compute(PairBuckKokkos*); }; diff --git a/src/KOKKOS/pair_coul_cut_kokkos.h b/src/KOKKOS/pair_coul_cut_kokkos.h index 6626889660..3e0501edd9 100644 --- a/src/KOKKOS/pair_coul_cut_kokkos.h +++ b/src/KOKKOS/pair_coul_cut_kokkos.h @@ -112,15 +112,18 @@ class PairCoulCutKokkos : public PairCoulCut { double qqrd2e; void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairCoulCutKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairCoulCutKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairCoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairCoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairCoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairCoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairCoulCutKokkos*,NeighListKokkos*); friend EV_FLOAT pair_compute(PairCoulCutKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairCoulCutKokkos*); diff --git a/src/KOKKOS/pair_coul_debye_kokkos.h b/src/KOKKOS/pair_coul_debye_kokkos.h index b6bed9d557..d239291a25 100644 --- a/src/KOKKOS/pair_coul_debye_kokkos.h +++ b/src/KOKKOS/pair_coul_debye_kokkos.h @@ -112,15 +112,18 @@ class PairCoulDebyeKokkos : public PairCoulDebye { double qqrd2e; void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairCoulDebyeKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairCoulDebyeKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairCoulDebyeKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairCoulDebyeKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairCoulDebyeKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairCoulDebyeKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairCoulDebyeKokkos*,NeighListKokkos*); friend EV_FLOAT pair_compute(PairCoulDebyeKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairCoulDebyeKokkos*); diff --git a/src/KOKKOS/pair_coul_long_kokkos.h b/src/KOKKOS/pair_coul_long_kokkos.h index fcb1402028..232cdbb6df 100644 --- a/src/KOKKOS/pair_coul_long_kokkos.h +++ b/src/KOKKOS/pair_coul_long_kokkos.h @@ -114,27 +114,33 @@ class PairCoulLongKokkos : public PairCoulLong { void allocate() override; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairCoulLongKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairCoulLongKokkos*, NeighListKokkos*); - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairCoulLongKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairCoulLongKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairCoulLongKokkos*); diff --git a/src/KOKKOS/pair_eam_alloy_kokkos.cpp b/src/KOKKOS/pair_eam_alloy_kokkos.cpp index 2b81e21e2b..1e5279cb6f 100644 --- a/src/KOKKOS/pair_eam_alloy_kokkos.cpp +++ b/src/KOKKOS/pair_eam_alloy_kokkos.cpp @@ -1477,7 +1477,7 @@ void PairEAMAlloyKokkos::file2array_alloy() template template struct PairEAMAlloyKokkos::policyInstance { - KOKKOS_INLINE_FUNCTION + static auto get(int inum) { auto policy = Kokkos::RangePolicy(0,inum); return policy; @@ -1488,7 +1488,7 @@ struct PairEAMAlloyKokkos::policyInstance { template<> template struct PairEAMAlloyKokkos::policyInstance { - KOKKOS_INLINE_FUNCTION + static auto get(int inum) { static_assert(t_ffloat_2d_n7::static_extent(2) == 7, "Breaking assumption of spline dim for KernelAB and KernelC scratch caching"); diff --git a/src/KOKKOS/pair_eam_fs_kokkos.cpp b/src/KOKKOS/pair_eam_fs_kokkos.cpp index 4572d14e48..6753f43f6d 100644 --- a/src/KOKKOS/pair_eam_fs_kokkos.cpp +++ b/src/KOKKOS/pair_eam_fs_kokkos.cpp @@ -1487,7 +1487,7 @@ void PairEAMFSKokkos::file2array_fs() template template struct PairEAMFSKokkos::policyInstance { - KOKKOS_INLINE_FUNCTION + static auto get(int inum) { auto policy = Kokkos::RangePolicy(0,inum); return policy; @@ -1498,7 +1498,7 @@ struct PairEAMFSKokkos::policyInstance { template<> template struct PairEAMFSKokkos::policyInstance { - KOKKOS_INLINE_FUNCTION + static auto get(int inum) { static_assert(t_ffloat_2d_n7::static_extent(2) == 7, "Breaking assumption of spline dim for KernelAB and KernelC scratch caching"); diff --git a/src/KOKKOS/pair_eam_kokkos.cpp b/src/KOKKOS/pair_eam_kokkos.cpp index de6d3646bf..ec84ccb0c1 100644 --- a/src/KOKKOS/pair_eam_kokkos.cpp +++ b/src/KOKKOS/pair_eam_kokkos.cpp @@ -1162,7 +1162,7 @@ void PairEAMKokkos::ev_tally(EV_FLOAT &ev, const int &i, const int & template template struct PairEAMKokkos::policyInstance { - KOKKOS_INLINE_FUNCTION + static auto get(int inum) { auto policy = Kokkos::RangePolicy(0,inum); return policy; @@ -1173,7 +1173,7 @@ struct PairEAMKokkos::policyInstance { template<> template struct PairEAMKokkos::policyInstance { - KOKKOS_INLINE_FUNCTION + static auto get(int inum) { static_assert(t_ffloat_2d_n7::static_extent(2) == 7, "Breaking assumption of spline dim for KernelAB and KernelC scratch caching"); diff --git a/src/KOKKOS/pair_kokkos.h b/src/KOKKOS/pair_kokkos.h index f6925a376d..2b8c7ec1c9 100644 --- a/src/KOKKOS/pair_kokkos.h +++ b/src/KOKKOS/pair_kokkos.h @@ -50,7 +50,7 @@ struct DoCoul<1> { //Specialisation for Neighborlist types Half, HalfThread, Full -template +template struct PairComputeFunctor { typedef typename PairStyle::device_type device_type ; typedef ArrayTypes AT; @@ -137,7 +137,7 @@ struct PairComputeFunctor { F_FLOAT fytmp = 0.0; F_FLOAT fztmp = 0.0; - if (NEIGHFLAG == FULL) { + if (NEIGHFLAG == FULL && ZEROFLAG) { f(i,0) = 0.0; f(i,1) = 0.0; f(i,2) = 0.0; @@ -211,7 +211,7 @@ struct PairComputeFunctor { F_FLOAT fytmp = 0.0; F_FLOAT fztmp = 0.0; - if (NEIGHFLAG == FULL) { + if (NEIGHFLAG == FULL && ZEROFLAG) { f(i,0) = 0.0; f(i,1) = 0.0; f(i,2) = 0.0; @@ -292,11 +292,13 @@ struct PairComputeFunctor { const X_FLOAT ztmp = c.x(i,2); const int itype = c.type(i); - Kokkos::single(Kokkos::PerThread(team), [&] (){ - f(i,0) = 0.0; - f(i,1) = 0.0; - f(i,2) = 0.0; - }); + if (ZEROFLAG) { + Kokkos::single(Kokkos::PerThread(team), [&] (){ + f(i,0) = 0.0; + f(i,1) = 0.0; + f(i,2) = 0.0; + }); + } const AtomNeighborsConst neighbors_i = list.get_neighbors_const(i); const int jnum = list.d_numneigh[i]; @@ -355,11 +357,13 @@ struct PairComputeFunctor { const int itype = c.type(i); const F_FLOAT qtmp = c.q(i); - Kokkos::single(Kokkos::PerThread(team), [&] (){ - f(i,0) = 0.0; - f(i,1) = 0.0; - f(i,2) = 0.0; - }); + if (ZEROFLAG) { + Kokkos::single(Kokkos::PerThread(team), [&] (){ + f(i,0) = 0.0; + f(i,1) = 0.0; + f(i,2) = 0.0; + }); + } const AtomNeighborsConst neighbors_i = list.get_neighbors_const(i); const int jnum = list.d_numneigh[i]; @@ -423,11 +427,13 @@ struct PairComputeFunctor { const X_FLOAT ztmp = c.x(i,2); const int itype = c.type(i); - Kokkos::single(Kokkos::PerThread(team), [&] (){ - f(i,0) = 0.0; - f(i,1) = 0.0; - f(i,2) = 0.0; - }); + if (ZEROFLAG) { + Kokkos::single(Kokkos::PerThread(team), [&] (){ + f(i,0) = 0.0; + f(i,1) = 0.0; + f(i,2) = 0.0; + }); + } const AtomNeighborsConst neighbors_i = list.get_neighbors_const(i); const int jnum = list.d_numneigh[i]; @@ -525,11 +531,13 @@ struct PairComputeFunctor { const int itype = c.type(i); const F_FLOAT qtmp = c.q(i); - Kokkos::single(Kokkos::PerThread(team), [&] (){ - f(i,0) = 0.0; - f(i,1) = 0.0; - f(i,2) = 0.0; - }); + if (ZEROFLAG) { + Kokkos::single(Kokkos::PerThread(team), [&] (){ + f(i,0) = 0.0; + f(i,1) = 0.0; + f(i,2) = 0.0; + }); + } const AtomNeighborsConst neighbors_i = list.get_neighbors_const(i); const int jnum = list.d_numneigh[i]; @@ -740,7 +748,7 @@ struct PairComputeFunctor { // By having the enable_if with a ! and without it, exactly one of the functions // pair_compute_neighlist will match - either the dummy version // or the real one further below. -template +template EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename std::enable_if*>::type list) { EV_FLOAT ev; (void) fpair; @@ -770,7 +778,7 @@ int GetTeamSize(FunctorStyle& KOKKOS_GPU_ARG(functor), int KOKKOS_GPU_ARG(inum), } // Submit ParallelFor for NEIGHFLAG=HALF,HALFTHREAD,FULL -template +template EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename std::enable_if<(NEIGHFLAG&PairStyle::EnabledNeighFlags) != 0, NeighListKokkos*>::type list) { EV_FLOAT ev; @@ -784,13 +792,13 @@ EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename std::enable_if<(NEIG int atoms_per_team = 32; if (fpair->atom->ntypes > MAX_TYPES_STACKPARAMS) { - PairComputeFunctor ff(fpair,list); + PairComputeFunctor ff(fpair,list); atoms_per_team = GetTeamSize(ff, list->inum, (fpair->eflag || fpair->vflag), atoms_per_team, vector_length); Kokkos::TeamPolicy > policy(list->inum,atoms_per_team,vector_length); if (fpair->eflag || fpair->vflag) Kokkos::parallel_reduce(policy,ff,ev); else Kokkos::parallel_for(policy,ff); } else { - PairComputeFunctor ff(fpair,list); + PairComputeFunctor ff(fpair,list); atoms_per_team = GetTeamSize(ff, list->inum, (fpair->eflag || fpair->vflag), atoms_per_team, vector_length); Kokkos::TeamPolicy > policy(list->inum,atoms_per_team,vector_length); if (fpair->eflag || fpair->vflag) Kokkos::parallel_reduce(policy,ff,ev); @@ -798,12 +806,12 @@ EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename std::enable_if<(NEIG } } else { if (fpair->atom->ntypes > MAX_TYPES_STACKPARAMS) { - PairComputeFunctor ff(fpair,list); + PairComputeFunctor ff(fpair,list); if (fpair->eflag || fpair->vflag) Kokkos::parallel_reduce(list->inum,ff,ev); else Kokkos::parallel_for(list->inum,ff); ff.contribute(); } else { - PairComputeFunctor ff(fpair,list); + PairComputeFunctor ff(fpair,list); if (fpair->eflag || fpair->vflag) Kokkos::parallel_reduce(list->inum,ff,ev); else Kokkos::parallel_for(list->inum,ff); ff.contribute(); @@ -812,16 +820,21 @@ EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename std::enable_if<(NEIG return ev; } -template +template EV_FLOAT pair_compute (PairStyle* fpair, NeighListKokkos* list) { EV_FLOAT ev; if (fpair->neighflag == FULL) { - fpair->fuse_force_clear_flag = 1; - ev = pair_compute_neighlist (fpair,list); + if (utils::strmatch(fpair->lmp->force->pair_style,"^hybrid/overlay")) { + fpair->fuse_force_clear_flag = 0; + ev = pair_compute_neighlist (fpair,list); + } else { + fpair->fuse_force_clear_flag = 1; + ev = pair_compute_neighlist (fpair,list); + } } else if (fpair->neighflag == HALFTHREAD) { - ev = pair_compute_neighlist (fpair,list); + ev = pair_compute_neighlist (fpair,list); } else if (fpair->neighflag == HALF) { - ev = pair_compute_neighlist (fpair,list); + ev = pair_compute_neighlist (fpair,list); } return ev; } diff --git a/src/KOKKOS/pair_lj_charmm_coul_charmm_implicit_kokkos.h b/src/KOKKOS/pair_lj_charmm_coul_charmm_implicit_kokkos.h index ae27ee68ab..7e21676fd5 100644 --- a/src/KOKKOS/pair_lj_charmm_coul_charmm_implicit_kokkos.h +++ b/src/KOKKOS/pair_lj_charmm_coul_charmm_implicit_kokkos.h @@ -110,27 +110,33 @@ class PairLJCharmmCoulCharmmImplicitKokkos : public PairLJCharmmCoulCharmmImplic void allocate() override; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulCharmmImplicitKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulCharmmImplicitKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulCharmmImplicitKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJCharmmCoulCharmmImplicitKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmImplicitKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmImplicitKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmImplicitKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmImplicitKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJCharmmCoulCharmmImplicitKokkos*, NeighListKokkos*); - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulCharmmImplicitKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulCharmmImplicitKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulCharmmImplicitKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJCharmmCoulCharmmImplicitKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmImplicitKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmImplicitKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmImplicitKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmImplicitKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJCharmmCoulCharmmImplicitKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJCharmmCoulCharmmImplicitKokkos*); diff --git a/src/KOKKOS/pair_lj_charmm_coul_charmm_kokkos.h b/src/KOKKOS/pair_lj_charmm_coul_charmm_kokkos.h index 912ad573c6..1f26242ded 100644 --- a/src/KOKKOS/pair_lj_charmm_coul_charmm_kokkos.h +++ b/src/KOKKOS/pair_lj_charmm_coul_charmm_kokkos.h @@ -108,27 +108,33 @@ class PairLJCharmmCoulCharmmKokkos : public PairLJCharmmCoulCharmm { void allocate() override; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulCharmmKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulCharmmKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulCharmmKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJCharmmCoulCharmmKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJCharmmCoulCharmmKokkos*, NeighListKokkos*); - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulCharmmKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulCharmmKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulCharmmKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJCharmmCoulCharmmKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulCharmmKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJCharmmCoulCharmmKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJCharmmCoulCharmmKokkos*); diff --git a/src/KOKKOS/pair_lj_charmm_coul_long_kokkos.h b/src/KOKKOS/pair_lj_charmm_coul_long_kokkos.h index 4ae8a12944..c6c80e76dc 100644 --- a/src/KOKKOS/pair_lj_charmm_coul_long_kokkos.h +++ b/src/KOKKOS/pair_lj_charmm_coul_long_kokkos.h @@ -106,27 +106,33 @@ class PairLJCharmmCoulLongKokkos : public PairLJCharmmCoulLong { void allocate() override; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJCharmmCoulLongKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJCharmmCoulLongKokkos*, NeighListKokkos*); - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCharmmCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJCharmmCoulLongKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCharmmCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJCharmmCoulLongKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJCharmmCoulLongKokkos*); diff --git a/src/KOKKOS/pair_lj_class2_coul_cut_kokkos.h b/src/KOKKOS/pair_lj_class2_coul_cut_kokkos.h index 5ca276c28e..9399345458 100644 --- a/src/KOKKOS/pair_lj_class2_coul_cut_kokkos.h +++ b/src/KOKKOS/pair_lj_class2_coul_cut_kokkos.h @@ -104,15 +104,18 @@ class PairLJClass2CoulCutKokkos : public PairLJClass2CoulCut { double qqrd2e; void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairLJClass2CoulCutKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJClass2CoulCutKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJClass2CoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJClass2CoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJClass2CoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJClass2CoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJClass2CoulCutKokkos*,NeighListKokkos*); friend EV_FLOAT pair_compute(PairLJClass2CoulCutKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJClass2CoulCutKokkos*); diff --git a/src/KOKKOS/pair_lj_class2_coul_long_kokkos.h b/src/KOKKOS/pair_lj_class2_coul_long_kokkos.h index 599cc2a83c..1cf6590855 100644 --- a/src/KOKKOS/pair_lj_class2_coul_long_kokkos.h +++ b/src/KOKKOS/pair_lj_class2_coul_long_kokkos.h @@ -107,27 +107,33 @@ class PairLJClass2CoulLongKokkos : public PairLJClass2CoulLong { double qqrd2e; void allocate() override; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJClass2CoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJClass2CoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJClass2CoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJClass2CoulLongKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJClass2CoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJClass2CoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJClass2CoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJClass2CoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJClass2CoulLongKokkos*, NeighListKokkos*); - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJClass2CoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJClass2CoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJClass2CoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJClass2CoulLongKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJClass2CoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJClass2CoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJClass2CoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJClass2CoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJClass2CoulLongKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJClass2CoulLongKokkos*); diff --git a/src/KOKKOS/pair_lj_class2_kokkos.h b/src/KOKKOS/pair_lj_class2_kokkos.h index 0936399ca8..5594680929 100644 --- a/src/KOKKOS/pair_lj_class2_kokkos.h +++ b/src/KOKKOS/pair_lj_class2_kokkos.h @@ -96,16 +96,19 @@ class PairLJClass2Kokkos : public PairLJClass2 { int nlocal,nall,eflag,vflag; void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairLJClass2Kokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJClass2Kokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJClass2Kokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute(PairLJClass2Kokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJClass2Kokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJClass2Kokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJClass2Kokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJClass2Kokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute(PairLJClass2Kokkos*,NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJClass2Kokkos*); }; diff --git a/src/KOKKOS/pair_lj_cut_coul_cut_kokkos.h b/src/KOKKOS/pair_lj_cut_coul_cut_kokkos.h index 87464b37dc..affc67bf16 100644 --- a/src/KOKKOS/pair_lj_cut_coul_cut_kokkos.h +++ b/src/KOKKOS/pair_lj_cut_coul_cut_kokkos.h @@ -104,15 +104,18 @@ class PairLJCutCoulCutKokkos : public PairLJCutCoulCut { double qqrd2e; void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulCutKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulCutKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulCutKokkos*,NeighListKokkos*); friend EV_FLOAT pair_compute(PairLJCutCoulCutKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJCutCoulCutKokkos*); diff --git a/src/KOKKOS/pair_lj_cut_coul_debye_kokkos.h b/src/KOKKOS/pair_lj_cut_coul_debye_kokkos.h index ea0b401959..eeed483b76 100644 --- a/src/KOKKOS/pair_lj_cut_coul_debye_kokkos.h +++ b/src/KOKKOS/pair_lj_cut_coul_debye_kokkos.h @@ -104,15 +104,18 @@ class PairLJCutCoulDebyeKokkos : public PairLJCutCoulDebye { double qqrd2e; void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulDebyeKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulDebyeKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulDebyeKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulDebyeKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulDebyeKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulDebyeKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulDebyeKokkos*,NeighListKokkos*); friend EV_FLOAT pair_compute(PairLJCutCoulDebyeKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJCutCoulDebyeKokkos*); diff --git a/src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.h b/src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.h index e420bd22a9..d9e5fcfe49 100644 --- a/src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.h +++ b/src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.h @@ -101,15 +101,18 @@ class PairLJCutCoulDSFKokkos : public PairLJCutCoulDSF { double qqrd2e; void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulDSFKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulDSFKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulDSFKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulDSFKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulDSFKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulDSFKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutCoulDSFKokkos*,NeighListKokkos*); friend EV_FLOAT pair_compute(PairLJCutCoulDSFKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJCutCoulDSFKokkos*); diff --git a/src/KOKKOS/pair_lj_cut_coul_long_kokkos.h b/src/KOKKOS/pair_lj_cut_coul_long_kokkos.h index bcb97a59cd..ec6e2db176 100644 --- a/src/KOKKOS/pair_lj_cut_coul_long_kokkos.h +++ b/src/KOKKOS/pair_lj_cut_coul_long_kokkos.h @@ -107,27 +107,33 @@ class PairLJCutCoulLongKokkos : public PairLJCutCoulLong { double qqrd2e; void allocate() override; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJCutCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCutCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCutCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJCutCoulLongKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJCutCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCutCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCutCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCutCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJCutCoulLongKokkos*, NeighListKokkos*); - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJCutCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCutCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJCutCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJCutCoulLongKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJCutCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCutCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCutCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJCutCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJCutCoulLongKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJCutCoulLongKokkos*); diff --git a/src/KOKKOS/pair_lj_cut_kokkos.h b/src/KOKKOS/pair_lj_cut_kokkos.h index 106f1a9048..b44c1aa6fe 100644 --- a/src/KOKKOS/pair_lj_cut_kokkos.h +++ b/src/KOKKOS/pair_lj_cut_kokkos.h @@ -92,16 +92,19 @@ class PairLJCutKokkos : public PairLJCut { int nlocal,nall,eflag,vflag; void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairLJCutKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJCutKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJCutKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute(PairLJCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJCutKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute(PairLJCutKokkos*,NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJCutKokkos*); }; diff --git a/src/KOKKOS/pair_lj_expand_coul_long_kokkos.h b/src/KOKKOS/pair_lj_expand_coul_long_kokkos.h index 09a694a122..30e82b7dab 100644 --- a/src/KOKKOS/pair_lj_expand_coul_long_kokkos.h +++ b/src/KOKKOS/pair_lj_expand_coul_long_kokkos.h @@ -116,27 +116,33 @@ class PairLJExpandCoulLongKokkos : public PairLJExpandCoulLong { double qqrd2e; void allocate() override; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJExpandCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJExpandCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJExpandCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJExpandCoulLongKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJExpandCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJExpandCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJExpandCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJExpandCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJExpandCoulLongKokkos*, NeighListKokkos*); - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJExpandCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJExpandCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJExpandCoulLongKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJExpandCoulLongKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJExpandCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJExpandCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJExpandCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJExpandCoulLongKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJExpandCoulLongKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJExpandCoulLongKokkos*); }; diff --git a/src/KOKKOS/pair_lj_expand_kokkos.h b/src/KOKKOS/pair_lj_expand_kokkos.h index 0df0a6f8f8..64fe7d8b8e 100644 --- a/src/KOKKOS/pair_lj_expand_kokkos.h +++ b/src/KOKKOS/pair_lj_expand_kokkos.h @@ -97,16 +97,19 @@ class PairLJExpandKokkos : public PairLJExpand { int nlocal,nall,eflag,vflag; void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairLJExpandKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJExpandKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJExpandKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute(PairLJExpandKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJExpandKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJExpandKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJExpandKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJExpandKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute(PairLJExpandKokkos*,NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJExpandKokkos*); }; diff --git a/src/KOKKOS/pair_lj_gromacs_coul_gromacs_kokkos.h b/src/KOKKOS/pair_lj_gromacs_coul_gromacs_kokkos.h index 359c4a1229..020b621e33 100644 --- a/src/KOKKOS/pair_lj_gromacs_coul_gromacs_kokkos.h +++ b/src/KOKKOS/pair_lj_gromacs_coul_gromacs_kokkos.h @@ -115,27 +115,33 @@ class PairLJGromacsCoulGromacsKokkos : public PairLJGromacsCoulGromacs { void allocate() override; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJGromacsCoulGromacsKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJGromacsCoulGromacsKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJGromacsCoulGromacsKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJGromacsCoulGromacsKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsCoulGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsCoulGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsCoulGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsCoulGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJGromacsCoulGromacsKokkos*, NeighListKokkos*); - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJGromacsCoulGromacsKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJGromacsCoulGromacsKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJGromacsCoulGromacsKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJGromacsCoulGromacsKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsCoulGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsCoulGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsCoulGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsCoulGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJGromacsCoulGromacsKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJGromacsCoulGromacsKokkos*); diff --git a/src/KOKKOS/pair_lj_gromacs_kokkos.h b/src/KOKKOS/pair_lj_gromacs_kokkos.h index 95c600a415..ad41ca5120 100644 --- a/src/KOKKOS/pair_lj_gromacs_kokkos.h +++ b/src/KOKKOS/pair_lj_gromacs_kokkos.h @@ -115,27 +115,33 @@ class PairLJGromacsKokkos : public PairLJGromacs { void allocate() override; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJGromacsKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJGromacsKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJGromacsKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJGromacsKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJGromacsKokkos*, NeighListKokkos*); - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend EV_FLOAT pair_compute_neighlist >(PairLJGromacsKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJGromacsKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist >(PairLJGromacsKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute >(PairLJGromacsKokkos*, + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend struct PairComputeFunctor>; + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist>(PairLJGromacsKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute>(PairLJGromacsKokkos*, NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJGromacsKokkos*); diff --git a/src/KOKKOS/pair_lj_spica_kokkos.h b/src/KOKKOS/pair_lj_spica_kokkos.h index b330af4bfd..06c70ebd3e 100644 --- a/src/KOKKOS/pair_lj_spica_kokkos.h +++ b/src/KOKKOS/pair_lj_spica_kokkos.h @@ -97,16 +97,19 @@ class PairLJSPICAKokkos : public PairLJSPICA { int nlocal,nall,eflag,vflag; void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairLJSPICAKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJSPICAKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairLJSPICAKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute(PairLJSPICAKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJSPICAKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJSPICAKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJSPICAKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairLJSPICAKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute(PairLJSPICAKokkos*,NeighListKokkos*); friend void pair_virial_fdotr_compute(PairLJSPICAKokkos*); }; diff --git a/src/KOKKOS/pair_morse_kokkos.h b/src/KOKKOS/pair_morse_kokkos.h index d06cf2deb1..ccf27b018b 100644 --- a/src/KOKKOS/pair_morse_kokkos.h +++ b/src/KOKKOS/pair_morse_kokkos.h @@ -92,16 +92,19 @@ class PairMorseKokkos : public PairMorse { int nlocal,nall,eflag,vflag; void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairMorseKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairMorseKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairMorseKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute(PairMorseKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairMorseKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairMorseKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairMorseKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairMorseKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute(PairMorseKokkos*,NeighListKokkos*); friend void pair_virial_fdotr_compute(PairMorseKokkos*); }; diff --git a/src/KOKKOS/pair_pace_kokkos.cpp b/src/KOKKOS/pair_pace_kokkos.cpp index 55d0081110..58fd83317d 100644 --- a/src/KOKKOS/pair_pace_kokkos.cpp +++ b/src/KOKKOS/pair_pace_kokkos.cpp @@ -237,6 +237,9 @@ void PairPACEKokkos::copy_splines() ACERadialFunctions* radial_functions = dynamic_cast(basis_set->radial_functions); + if (radial_functions == nullptr) + error->all(FLERR,"Chosen radial basis style not supported by pair style pace/kk"); + for (int i = 0; i < nelements; i++) { for (int j = 0; j < nelements; j++) { k_splines_gk.h_view(i, j) = radial_functions->splines_gk(i, j); diff --git a/src/KOKKOS/pair_table_kokkos.cpp b/src/KOKKOS/pair_table_kokkos.cpp index b1514c8c6f..437679e412 100644 --- a/src/KOKKOS/pair_table_kokkos.cpp +++ b/src/KOKKOS/pair_table_kokkos.cpp @@ -133,19 +133,19 @@ void PairTableKokkos::compute_style(int eflag_in, int vflag_in) EV_FLOAT ev; if (atom->ntypes > MAX_TYPES_STACKPARAMS) { if (neighflag == FULL) { - PairComputeFunctor,FULL,false,S_TableCompute > + PairComputeFunctor,FULL,false,0,S_TableCompute > ff(this,(NeighListKokkos*) list); if (eflag || vflag) Kokkos::parallel_reduce(list->inum,ff,ev); else Kokkos::parallel_for(list->inum,ff); ff.contribute(); } else if (neighflag == HALFTHREAD) { - PairComputeFunctor,HALFTHREAD,false,S_TableCompute > + PairComputeFunctor,HALFTHREAD,false,0,S_TableCompute > ff(this,(NeighListKokkos*) list); if (eflag || vflag) Kokkos::parallel_reduce(list->inum,ff,ev); else Kokkos::parallel_for(list->inum,ff); ff.contribute(); } else if (neighflag == HALF) { - PairComputeFunctor,HALF,false,S_TableCompute > + PairComputeFunctor,HALF,false,0,S_TableCompute > f(this,(NeighListKokkos*) list); if (eflag || vflag) Kokkos::parallel_reduce(list->inum,f,ev); else Kokkos::parallel_for(list->inum,f); @@ -153,19 +153,19 @@ void PairTableKokkos::compute_style(int eflag_in, int vflag_in) } } else { if (neighflag == FULL) { - PairComputeFunctor,FULL,true,S_TableCompute > + PairComputeFunctor,FULL,true,0,S_TableCompute > f(this,(NeighListKokkos*) list); if (eflag || vflag) Kokkos::parallel_reduce(list->inum,f,ev); else Kokkos::parallel_for(list->inum,f); f.contribute(); } else if (neighflag == HALFTHREAD) { - PairComputeFunctor,HALFTHREAD,true,S_TableCompute > + PairComputeFunctor,HALFTHREAD,true,0,S_TableCompute > f(this,(NeighListKokkos*) list); if (eflag || vflag) Kokkos::parallel_reduce(list->inum,f,ev); else Kokkos::parallel_for(list->inum,f); f.contribute(); } else if (neighflag == HALF) { - PairComputeFunctor,HALF,true,S_TableCompute > + PairComputeFunctor,HALF,true,0,S_TableCompute > f(this,(NeighListKokkos*) list); if (eflag || vflag) Kokkos::parallel_reduce(list->inum,f,ev); else Kokkos::parallel_for(list->inum,f); diff --git a/src/KOKKOS/pair_table_kokkos.h b/src/KOKKOS/pair_table_kokkos.h index 80226d3770..18112e4c18 100644 --- a/src/KOKKOS/pair_table_kokkos.h +++ b/src/KOKKOS/pair_table_kokkos.h @@ -35,9 +35,6 @@ struct S_TableCompute { static constexpr int TabStyle = TABSTYLE; }; -template -struct PairTableComputeFunctor; - template class PairTableKokkos : public PairTable { public: @@ -135,33 +132,33 @@ class PairTableKokkos : public PairTable { F_FLOAT compute_ecoul(const F_FLOAT& /*rsq*/, const int& /*i*/, const int& /*j*/, const int& /*itype*/, const int& /*jtype*/) const { return 0; } - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; - friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; + friend struct PairComputeFunctor >; friend void pair_virial_fdotr_compute(PairTableKokkos*); }; diff --git a/src/KOKKOS/pair_yukawa_kokkos.h b/src/KOKKOS/pair_yukawa_kokkos.h index e04f65264b..dc93e83aea 100644 --- a/src/KOKKOS/pair_yukawa_kokkos.h +++ b/src/KOKKOS/pair_yukawa_kokkos.h @@ -95,20 +95,19 @@ class PairYukawaKokkos : public PairYukawa { int nlocal,nall,eflag,vflag; void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist( - PairYukawaKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist( - PairYukawaKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist( - PairYukawaKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute( - PairYukawaKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairYukawaKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairYukawaKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairYukawaKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairYukawaKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute(PairYukawaKokkos*,NeighListKokkos*); friend void pair_virial_fdotr_compute(PairYukawaKokkos*); }; diff --git a/src/KOKKOS/pair_zbl_kokkos.h b/src/KOKKOS/pair_zbl_kokkos.h index bd33cdb5e0..b7638a25e0 100644 --- a/src/KOKKOS/pair_zbl_kokkos.h +++ b/src/KOKKOS/pair_zbl_kokkos.h @@ -89,16 +89,19 @@ class PairZBLKokkos : public PairZBL { void allocate() override; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend struct PairComputeFunctor; + friend struct PairComputeFunctor; + friend struct PairComputeFunctor; friend struct PairComputeFunctor; friend struct PairComputeFunctor; - friend EV_FLOAT pair_compute_neighlist(PairZBLKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairZBLKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute_neighlist(PairZBLKokkos*,NeighListKokkos*); - friend EV_FLOAT pair_compute(PairZBLKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairZBLKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairZBLKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairZBLKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute_neighlist(PairZBLKokkos*,NeighListKokkos*); + friend EV_FLOAT pair_compute(PairZBLKokkos*,NeighListKokkos*); friend void pair_virial_fdotr_compute(PairZBLKokkos*); }; diff --git a/src/fix_property_atom.cpp b/src/fix_property_atom.cpp index 994b4f0f19..3a53110839 100644 --- a/src/fix_property_atom.cpp +++ b/src/fix_property_atom.cpp @@ -198,16 +198,24 @@ FixPropertyAtom::FixPropertyAtom(LAMMPS *lmp, int narg, char **arg) : astyle = utils::strdup(atom->atom_style); - // perform initial allocation of atom-based array // register with Atom class - nmax_old = 0; - if (!lmp->kokkos) FixPropertyAtom::grow_arrays(atom->nmax); atom->add_callback(Atom::GROW); atom->add_callback(Atom::RESTART); if (border) atom->add_callback(Atom::BORDER); } + +/* ---------------------------------------------------------------------- */ + +void FixPropertyAtom::post_constructor() +{ + // perform initial allocation of atom-based array + + nmax_old = 0; + grow_arrays(atom->nmax); +} + /* ---------------------------------------------------------------------- */ FixPropertyAtom::~FixPropertyAtom() diff --git a/src/fix_property_atom.h b/src/fix_property_atom.h index 92497d6188..c50b6049dc 100644 --- a/src/fix_property_atom.h +++ b/src/fix_property_atom.h @@ -27,6 +27,7 @@ namespace LAMMPS_NS { class FixPropertyAtom : public Fix { public: FixPropertyAtom(class LAMMPS *, int, char **); + void post_constructor() override; ~FixPropertyAtom() override; int setmask() override; void init() override; From 23691d4336a432bcce46a971f0d75e555c21c9c4 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 15 Oct 2023 23:43:44 -0400 Subject: [PATCH 17/93] avoid issue with neighbor list trimming when used as a hybrid substyle --- src/MANYBODY/pair_extep.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MANYBODY/pair_extep.cpp b/src/MANYBODY/pair_extep.cpp index 755b4d0132..1f7dab3614 100644 --- a/src/MANYBODY/pair_extep.cpp +++ b/src/MANYBODY/pair_extep.cpp @@ -51,6 +51,7 @@ PairExTeP::PairExTeP(LAMMPS *lmp) : Pair(lmp) manybody_flag = 1; centroidstressflag = CENTROID_NOTAVAIL; ghostneigh = 1; + trim_flag = 0; // workaround params = nullptr; From 2ba7059c005cd93ca3b0ea648b8c443a1e7a1e29 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 10 Sep 2023 10:25:03 -0400 Subject: [PATCH 18/93] disable neighbor list trimming by default for REBO pair styles for now --- src/MANYBODY/pair_airebo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index 129b9d2218..e34283f71c 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -59,6 +59,7 @@ PairAIREBO::PairAIREBO(LAMMPS *lmp) nextra = 3; pvector = new double[nextra]; + trim_flag = 0; // workaround maxlocal = 0; REBO_numneigh = nullptr; REBO_firstneigh = nullptr; From aa1c901f94b3f2eee9a302b53920bd32c58922e6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 16 Oct 2023 00:00:12 -0400 Subject: [PATCH 19/93] disable neighbor list trimming for all other pair styles requesting neighbors of ghosts --- src/GPU/pair_sw_gpu.cpp | 1 + src/GPU/pair_tersoff_gpu.cpp | 1 + src/GPU/pair_tersoff_mod_gpu.cpp | 1 + src/GPU/pair_tersoff_zbl_gpu.cpp | 1 + src/GPU/pair_vashishta_gpu.cpp | 1 + src/INTERLAYER/pair_drip.cpp | 1 + src/INTERLAYER/pair_ilp_graphene_hbn.cpp | 1 + src/INTERLAYER/pair_kolmogorov_crespi_full.cpp | 1 + src/MANYBODY/pair_bop.cpp | 1 + src/MANYBODY/pair_comb3.cpp | 1 + src/MANYBODY/pair_lcbop.cpp | 1 + src/ML-IAP/pair_mliap.cpp | 1 + 12 files changed, 12 insertions(+) diff --git a/src/GPU/pair_sw_gpu.cpp b/src/GPU/pair_sw_gpu.cpp index 7645218a85..3cb243d212 100644 --- a/src/GPU/pair_sw_gpu.cpp +++ b/src/GPU/pair_sw_gpu.cpp @@ -60,6 +60,7 @@ PairSWGPU::PairSWGPU(LAMMPS *lmp) : PairSW(lmp), gpu_mode(GPU_FORCE) reinitflag = 0; suffix_flag |= Suffix::GPU; GPU_EXTRA::gpu_ready(lmp->modify, lmp->error); + trim_flag = 0; // workaround cutghost = nullptr; ghostneigh = 1; diff --git a/src/GPU/pair_tersoff_gpu.cpp b/src/GPU/pair_tersoff_gpu.cpp index 8610a3880c..948aa594ba 100644 --- a/src/GPU/pair_tersoff_gpu.cpp +++ b/src/GPU/pair_tersoff_gpu.cpp @@ -64,6 +64,7 @@ PairTersoffGPU::PairTersoffGPU(LAMMPS *lmp) : PairTersoff(lmp), gpu_mode(GPU_FOR cpu_time = 0.0; suffix_flag |= Suffix::GPU; GPU_EXTRA::gpu_ready(lmp->modify, lmp->error); + trim_flag = 0; // workaround cutghost = nullptr; ghostneigh = 1; diff --git a/src/GPU/pair_tersoff_mod_gpu.cpp b/src/GPU/pair_tersoff_mod_gpu.cpp index 1bb09c1403..5124486474 100644 --- a/src/GPU/pair_tersoff_mod_gpu.cpp +++ b/src/GPU/pair_tersoff_mod_gpu.cpp @@ -63,6 +63,7 @@ PairTersoffMODGPU::PairTersoffMODGPU(LAMMPS *lmp) : PairTersoffMOD(lmp), gpu_mod cpu_time = 0.0; suffix_flag |= Suffix::GPU; GPU_EXTRA::gpu_ready(lmp->modify, lmp->error); + trim_flag = 0; // workaround cutghost = nullptr; ghostneigh = 1; diff --git a/src/GPU/pair_tersoff_zbl_gpu.cpp b/src/GPU/pair_tersoff_zbl_gpu.cpp index 8d5e05ce4c..e936db246d 100644 --- a/src/GPU/pair_tersoff_zbl_gpu.cpp +++ b/src/GPU/pair_tersoff_zbl_gpu.cpp @@ -67,6 +67,7 @@ PairTersoffZBLGPU::PairTersoffZBLGPU(LAMMPS *lmp) : PairTersoffZBL(lmp), gpu_mod cpu_time = 0.0; suffix_flag |= Suffix::GPU; GPU_EXTRA::gpu_ready(lmp->modify, lmp->error); + trim_flag = 0; // workaround cutghost = nullptr; ghostneigh = 1; diff --git a/src/GPU/pair_vashishta_gpu.cpp b/src/GPU/pair_vashishta_gpu.cpp index 38ad2b3c57..5840187627 100644 --- a/src/GPU/pair_vashishta_gpu.cpp +++ b/src/GPU/pair_vashishta_gpu.cpp @@ -62,6 +62,7 @@ PairVashishtaGPU::PairVashishtaGPU(LAMMPS *lmp) : PairVashishta(lmp), gpu_mode(G gpu_allocated = false; suffix_flag |= Suffix::GPU; GPU_EXTRA::gpu_ready(lmp->modify, lmp->error); + trim_flag = 0; // workaround cutghost = nullptr; ghostneigh = 1; diff --git a/src/INTERLAYER/pair_drip.cpp b/src/INTERLAYER/pair_drip.cpp index 90773b4034..5712c107bb 100644 --- a/src/INTERLAYER/pair_drip.cpp +++ b/src/INTERLAYER/pair_drip.cpp @@ -61,6 +61,7 @@ PairDRIP::PairDRIP(LAMMPS *lmp) : Pair(lmp) manybody_flag = 1; centroidstressflag = CENTROID_NOTAVAIL; unit_convert_flag = utils::get_supported_conversions(utils::ENERGY); + trim_flag = 0; // workaround params = nullptr; nearest3neigh = nullptr; diff --git a/src/INTERLAYER/pair_ilp_graphene_hbn.cpp b/src/INTERLAYER/pair_ilp_graphene_hbn.cpp index 69896d7c0b..890707a67b 100644 --- a/src/INTERLAYER/pair_ilp_graphene_hbn.cpp +++ b/src/INTERLAYER/pair_ilp_graphene_hbn.cpp @@ -69,6 +69,7 @@ PairILPGrapheneHBN::PairILPGrapheneHBN(LAMMPS *lmp) : Pair(lmp), variant(ILP_Grh manybody_flag = 1; centroidstressflag = CENTROID_NOTAVAIL; unit_convert_flag = utils::get_supported_conversions(utils::ENERGY); + trim_flag = 0; // workaround if (lmp->citeme) lmp->citeme->add(cite_ilp); diff --git a/src/INTERLAYER/pair_kolmogorov_crespi_full.cpp b/src/INTERLAYER/pair_kolmogorov_crespi_full.cpp index b497ae3568..0f13ecf6ae 100644 --- a/src/INTERLAYER/pair_kolmogorov_crespi_full.cpp +++ b/src/INTERLAYER/pair_kolmogorov_crespi_full.cpp @@ -64,6 +64,7 @@ PairKolmogorovCrespiFull::PairKolmogorovCrespiFull(LAMMPS *lmp) : Pair(lmp) manybody_flag = 1; centroidstressflag = CENTROID_NOTAVAIL; unit_convert_flag = utils::get_supported_conversions(utils::ENERGY); + trim_flag = 0; // workaround if (lmp->citeme) lmp->citeme->add(cite_kc); diff --git a/src/MANYBODY/pair_bop.cpp b/src/MANYBODY/pair_bop.cpp index 518a6dad79..c69a36d1a0 100644 --- a/src/MANYBODY/pair_bop.cpp +++ b/src/MANYBODY/pair_bop.cpp @@ -90,6 +90,7 @@ PairBOP::PairBOP(LAMMPS *lmp) : Pair(lmp) manybody_flag = 1; ghostneigh = 1; allocated = 0; + trim_flag = 0; // workaround pairParameters = nullptr; tripletParameters = nullptr; diff --git a/src/MANYBODY/pair_comb3.cpp b/src/MANYBODY/pair_comb3.cpp index a6a6ed37fd..e05fc36572 100644 --- a/src/MANYBODY/pair_comb3.cpp +++ b/src/MANYBODY/pair_comb3.cpp @@ -57,6 +57,7 @@ PairComb3::PairComb3(LAMMPS *lmp) : Pair(lmp) manybody_flag = 1; centroidstressflag = CENTROID_NOTAVAIL; ghostneigh = 1; + trim_flag = 0; // workaround nmax = 0; NCo = nullptr; diff --git a/src/MANYBODY/pair_lcbop.cpp b/src/MANYBODY/pair_lcbop.cpp index ed085c4b98..57e37b60d9 100644 --- a/src/MANYBODY/pair_lcbop.cpp +++ b/src/MANYBODY/pair_lcbop.cpp @@ -47,6 +47,7 @@ PairLCBOP::PairLCBOP(LAMMPS *lmp) : Pair(lmp) manybody_flag = 1; centroidstressflag = CENTROID_NOTAVAIL; ghostneigh = 1; + trim_flag = 0; // workaround maxlocal = 0; SR_numneigh = nullptr; diff --git a/src/ML-IAP/pair_mliap.cpp b/src/ML-IAP/pair_mliap.cpp index 66e8b848cd..d21a3ff059 100644 --- a/src/ML-IAP/pair_mliap.cpp +++ b/src/ML-IAP/pair_mliap.cpp @@ -50,6 +50,7 @@ PairMLIAP::PairMLIAP(LAMMPS *lmp) : one_coeff = 1; manybody_flag = 1; is_child = false; + trim_flag = 0; // workaround centroidstressflag = CENTROID_NOTAVAIL; model=nullptr; descriptor=nullptr; From d326327bd737357b3842cceb6866d172d4402be5 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 16 Oct 2023 13:55:48 -0400 Subject: [PATCH 20/93] Revert "disable neighbor list trimming for all other pair styles requesting neighbors of ghosts" This reverts commit aa1c901f94b3f2eee9a302b53920bd32c58922e6. --- src/GPU/pair_sw_gpu.cpp | 1 - src/GPU/pair_tersoff_gpu.cpp | 1 - src/GPU/pair_tersoff_mod_gpu.cpp | 1 - src/GPU/pair_tersoff_zbl_gpu.cpp | 1 - src/GPU/pair_vashishta_gpu.cpp | 1 - src/INTERLAYER/pair_drip.cpp | 1 - src/INTERLAYER/pair_ilp_graphene_hbn.cpp | 1 - src/INTERLAYER/pair_kolmogorov_crespi_full.cpp | 1 - src/MANYBODY/pair_bop.cpp | 1 - src/MANYBODY/pair_comb3.cpp | 1 - src/MANYBODY/pair_lcbop.cpp | 1 - src/ML-IAP/pair_mliap.cpp | 1 - 12 files changed, 12 deletions(-) diff --git a/src/GPU/pair_sw_gpu.cpp b/src/GPU/pair_sw_gpu.cpp index 3cb243d212..7645218a85 100644 --- a/src/GPU/pair_sw_gpu.cpp +++ b/src/GPU/pair_sw_gpu.cpp @@ -60,7 +60,6 @@ PairSWGPU::PairSWGPU(LAMMPS *lmp) : PairSW(lmp), gpu_mode(GPU_FORCE) reinitflag = 0; suffix_flag |= Suffix::GPU; GPU_EXTRA::gpu_ready(lmp->modify, lmp->error); - trim_flag = 0; // workaround cutghost = nullptr; ghostneigh = 1; diff --git a/src/GPU/pair_tersoff_gpu.cpp b/src/GPU/pair_tersoff_gpu.cpp index 948aa594ba..8610a3880c 100644 --- a/src/GPU/pair_tersoff_gpu.cpp +++ b/src/GPU/pair_tersoff_gpu.cpp @@ -64,7 +64,6 @@ PairTersoffGPU::PairTersoffGPU(LAMMPS *lmp) : PairTersoff(lmp), gpu_mode(GPU_FOR cpu_time = 0.0; suffix_flag |= Suffix::GPU; GPU_EXTRA::gpu_ready(lmp->modify, lmp->error); - trim_flag = 0; // workaround cutghost = nullptr; ghostneigh = 1; diff --git a/src/GPU/pair_tersoff_mod_gpu.cpp b/src/GPU/pair_tersoff_mod_gpu.cpp index 5124486474..1bb09c1403 100644 --- a/src/GPU/pair_tersoff_mod_gpu.cpp +++ b/src/GPU/pair_tersoff_mod_gpu.cpp @@ -63,7 +63,6 @@ PairTersoffMODGPU::PairTersoffMODGPU(LAMMPS *lmp) : PairTersoffMOD(lmp), gpu_mod cpu_time = 0.0; suffix_flag |= Suffix::GPU; GPU_EXTRA::gpu_ready(lmp->modify, lmp->error); - trim_flag = 0; // workaround cutghost = nullptr; ghostneigh = 1; diff --git a/src/GPU/pair_tersoff_zbl_gpu.cpp b/src/GPU/pair_tersoff_zbl_gpu.cpp index e936db246d..8d5e05ce4c 100644 --- a/src/GPU/pair_tersoff_zbl_gpu.cpp +++ b/src/GPU/pair_tersoff_zbl_gpu.cpp @@ -67,7 +67,6 @@ PairTersoffZBLGPU::PairTersoffZBLGPU(LAMMPS *lmp) : PairTersoffZBL(lmp), gpu_mod cpu_time = 0.0; suffix_flag |= Suffix::GPU; GPU_EXTRA::gpu_ready(lmp->modify, lmp->error); - trim_flag = 0; // workaround cutghost = nullptr; ghostneigh = 1; diff --git a/src/GPU/pair_vashishta_gpu.cpp b/src/GPU/pair_vashishta_gpu.cpp index 5840187627..38ad2b3c57 100644 --- a/src/GPU/pair_vashishta_gpu.cpp +++ b/src/GPU/pair_vashishta_gpu.cpp @@ -62,7 +62,6 @@ PairVashishtaGPU::PairVashishtaGPU(LAMMPS *lmp) : PairVashishta(lmp), gpu_mode(G gpu_allocated = false; suffix_flag |= Suffix::GPU; GPU_EXTRA::gpu_ready(lmp->modify, lmp->error); - trim_flag = 0; // workaround cutghost = nullptr; ghostneigh = 1; diff --git a/src/INTERLAYER/pair_drip.cpp b/src/INTERLAYER/pair_drip.cpp index 5712c107bb..90773b4034 100644 --- a/src/INTERLAYER/pair_drip.cpp +++ b/src/INTERLAYER/pair_drip.cpp @@ -61,7 +61,6 @@ PairDRIP::PairDRIP(LAMMPS *lmp) : Pair(lmp) manybody_flag = 1; centroidstressflag = CENTROID_NOTAVAIL; unit_convert_flag = utils::get_supported_conversions(utils::ENERGY); - trim_flag = 0; // workaround params = nullptr; nearest3neigh = nullptr; diff --git a/src/INTERLAYER/pair_ilp_graphene_hbn.cpp b/src/INTERLAYER/pair_ilp_graphene_hbn.cpp index 890707a67b..69896d7c0b 100644 --- a/src/INTERLAYER/pair_ilp_graphene_hbn.cpp +++ b/src/INTERLAYER/pair_ilp_graphene_hbn.cpp @@ -69,7 +69,6 @@ PairILPGrapheneHBN::PairILPGrapheneHBN(LAMMPS *lmp) : Pair(lmp), variant(ILP_Grh manybody_flag = 1; centroidstressflag = CENTROID_NOTAVAIL; unit_convert_flag = utils::get_supported_conversions(utils::ENERGY); - trim_flag = 0; // workaround if (lmp->citeme) lmp->citeme->add(cite_ilp); diff --git a/src/INTERLAYER/pair_kolmogorov_crespi_full.cpp b/src/INTERLAYER/pair_kolmogorov_crespi_full.cpp index 0f13ecf6ae..b497ae3568 100644 --- a/src/INTERLAYER/pair_kolmogorov_crespi_full.cpp +++ b/src/INTERLAYER/pair_kolmogorov_crespi_full.cpp @@ -64,7 +64,6 @@ PairKolmogorovCrespiFull::PairKolmogorovCrespiFull(LAMMPS *lmp) : Pair(lmp) manybody_flag = 1; centroidstressflag = CENTROID_NOTAVAIL; unit_convert_flag = utils::get_supported_conversions(utils::ENERGY); - trim_flag = 0; // workaround if (lmp->citeme) lmp->citeme->add(cite_kc); diff --git a/src/MANYBODY/pair_bop.cpp b/src/MANYBODY/pair_bop.cpp index c69a36d1a0..518a6dad79 100644 --- a/src/MANYBODY/pair_bop.cpp +++ b/src/MANYBODY/pair_bop.cpp @@ -90,7 +90,6 @@ PairBOP::PairBOP(LAMMPS *lmp) : Pair(lmp) manybody_flag = 1; ghostneigh = 1; allocated = 0; - trim_flag = 0; // workaround pairParameters = nullptr; tripletParameters = nullptr; diff --git a/src/MANYBODY/pair_comb3.cpp b/src/MANYBODY/pair_comb3.cpp index e05fc36572..a6a6ed37fd 100644 --- a/src/MANYBODY/pair_comb3.cpp +++ b/src/MANYBODY/pair_comb3.cpp @@ -57,7 +57,6 @@ PairComb3::PairComb3(LAMMPS *lmp) : Pair(lmp) manybody_flag = 1; centroidstressflag = CENTROID_NOTAVAIL; ghostneigh = 1; - trim_flag = 0; // workaround nmax = 0; NCo = nullptr; diff --git a/src/MANYBODY/pair_lcbop.cpp b/src/MANYBODY/pair_lcbop.cpp index 57e37b60d9..ed085c4b98 100644 --- a/src/MANYBODY/pair_lcbop.cpp +++ b/src/MANYBODY/pair_lcbop.cpp @@ -47,7 +47,6 @@ PairLCBOP::PairLCBOP(LAMMPS *lmp) : Pair(lmp) manybody_flag = 1; centroidstressflag = CENTROID_NOTAVAIL; ghostneigh = 1; - trim_flag = 0; // workaround maxlocal = 0; SR_numneigh = nullptr; diff --git a/src/ML-IAP/pair_mliap.cpp b/src/ML-IAP/pair_mliap.cpp index d21a3ff059..66e8b848cd 100644 --- a/src/ML-IAP/pair_mliap.cpp +++ b/src/ML-IAP/pair_mliap.cpp @@ -50,7 +50,6 @@ PairMLIAP::PairMLIAP(LAMMPS *lmp) : one_coeff = 1; manybody_flag = 1; is_child = false; - trim_flag = 0; // workaround centroidstressflag = CENTROID_NOTAVAIL; model=nullptr; descriptor=nullptr; From e65ed32ecd0631f427f8885a96bc0602afb1fd95 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 16 Oct 2023 13:55:52 -0400 Subject: [PATCH 21/93] Revert "disable neighbor list trimming by default for REBO pair styles for now" This reverts commit 2ba7059c005cd93ca3b0ea648b8c443a1e7a1e29. --- src/MANYBODY/pair_airebo.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index e34283f71c..129b9d2218 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -59,7 +59,6 @@ PairAIREBO::PairAIREBO(LAMMPS *lmp) nextra = 3; pvector = new double[nextra]; - trim_flag = 0; // workaround maxlocal = 0; REBO_numneigh = nullptr; REBO_firstneigh = nullptr; From a5374997d2d4d22613202d51e70a59d022258165 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 16 Oct 2023 13:55:53 -0400 Subject: [PATCH 22/93] Revert "avoid issue with neighbor list trimming when used as a hybrid substyle" This reverts commit 23691d4336a432bcce46a971f0d75e555c21c9c4. --- src/MANYBODY/pair_extep.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/MANYBODY/pair_extep.cpp b/src/MANYBODY/pair_extep.cpp index 1f7dab3614..755b4d0132 100644 --- a/src/MANYBODY/pair_extep.cpp +++ b/src/MANYBODY/pair_extep.cpp @@ -51,7 +51,6 @@ PairExTeP::PairExTeP(LAMMPS *lmp) : Pair(lmp) manybody_flag = 1; centroidstressflag = CENTROID_NOTAVAIL; ghostneigh = 1; - trim_flag = 0; // workaround params = nullptr; From 810e3e5fa58512f3892e868bbcf5256381f2186a Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 16 Oct 2023 11:20:06 -0600 Subject: [PATCH 23/93] Fix issues with trim lists --- src/KOKKOS/neighbor_kokkos.cpp | 3 ++- src/KOKKOS/npair_trim_kokkos.cpp | 12 ++++++------ src/npair_trim.cpp | 8 ++++++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/KOKKOS/neighbor_kokkos.cpp b/src/KOKKOS/neighbor_kokkos.cpp index 0b40bce841..efb1247560 100644 --- a/src/KOKKOS/neighbor_kokkos.cpp +++ b/src/KOKKOS/neighbor_kokkos.cpp @@ -308,7 +308,8 @@ void NeighborKokkos::build_kokkos(int topoflag) for (i = 0; i < npair_perpetual; i++) { m = plist[i]; if (!lists[m]->kokkos) atomKK->sync(Host,ALL_MASK); - if (!lists[m]->copy) lists[m]->grow(nlocal,nall); + if (!lists[m]->copy || lists[m]->trim || lists[m]->kk2cpu) + lists[m]->grow(nlocal,nall); neigh_pair[m]->build_setup(); neigh_pair[m]->build(lists[m]); } diff --git a/src/KOKKOS/npair_trim_kokkos.cpp b/src/KOKKOS/npair_trim_kokkos.cpp index 97931bf250..d04d8676d7 100644 --- a/src/KOKKOS/npair_trim_kokkos.cpp +++ b/src/KOKKOS/npair_trim_kokkos.cpp @@ -62,8 +62,8 @@ void NPairTrimKokkos::trim_to_kokkos(NeighList *list) d_ilist_copy = k_list_copy->d_ilist; d_numneigh_copy = k_list_copy->d_numneigh; d_neighbors_copy = k_list_copy->d_neighbors; - int inum_copy = list->listcopy->inum; - if (list->ghost) inum_copy += list->listcopy->gnum; + int inum_trim = list->listcopy->inum; + if (list->ghost) inum_trim += list->listcopy->gnum; NeighListKokkos* k_list = static_cast*>(list); k_list->maxneighs = k_list_copy->maxneighs; // simple, but could be made more memory efficient @@ -75,7 +75,7 @@ void NPairTrimKokkos::trim_to_kokkos(NeighList *list) // loop over parent list and trim copymode = 1; - Kokkos::parallel_for(Kokkos::RangePolicy(0,inum_copy),*this); + Kokkos::parallel_for(Kokkos::RangePolicy(0,inum_trim),*this); copymode = 0; list->inum = k_list_copy->inum; @@ -132,8 +132,8 @@ void NPairTrimKokkos::trim_to_cpu(NeighList *list) int inum = listcopy->inum; int gnum = listcopy->gnum; - int inum_all = inum; - if (list->ghost) inum_all += gnum; + int inum_trim = inum; + if (list->ghost) inum_trim += gnum; auto h_ilist = listcopy_kk->k_ilist.h_view; auto h_numneigh = Kokkos::create_mirror_view_and_copy(LMPHostType(),listcopy_kk->d_numneigh); auto h_neighbors = Kokkos::create_mirror_view_and_copy(LMPHostType(),listcopy_kk->d_neighbors); @@ -151,7 +151,7 @@ void NPairTrimKokkos::trim_to_cpu(NeighList *list) MyPage *ipage = list->ipage; ipage->reset(); - for (int ii = 0; ii < inum_all; ii++) { + for (int ii = 0; ii < inum_trim; ii++) { int n = 0; neighptr = ipage->vget(); diff --git a/src/npair_trim.cpp b/src/npair_trim.cpp index 14974d72ab..a4b6c1c6a1 100644 --- a/src/npair_trim.cpp +++ b/src/npair_trim.cpp @@ -50,11 +50,15 @@ void NPairTrim::build(NeighList *list) int *numneigh_copy = listcopy->numneigh; int **firstneigh_copy = listcopy->firstneigh; int inum = listcopy->inum; + int gnum = listcopy->gnum; list->inum = inum; - list->gnum = listcopy->gnum; + list->gnum = gnum; - for (ii = 0; ii < inum; ii++) { + int inum_trim = inum; + if (list->ghost) inum_trim += gnum; + + for (ii = 0; ii < inum_trim; ii++) { n = 0; neighptr = ipage->vget(); From 6c2e469f5d784aeafa8fcab190e0f38e5f1e0cbf Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Oct 2023 19:39:31 -0400 Subject: [PATCH 24/93] copy-and-paste bugfix from @stanmoore1 --- src/balance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/balance.cpp b/src/balance.cpp index 3bd083e2b9..6f28081f13 100644 --- a/src/balance.cpp +++ b/src/balance.cpp @@ -473,7 +473,7 @@ void Balance::options(int iarg, int narg, char **arg, int sortflag_default) } iarg += 2+nopt; - } else if (strcmp(arg[iarg+1],"sort") == 0) { + } else if (strcmp(arg[iarg],"sort") == 0) { if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "balance sort", error); sortflag = utils::logical(FLERR,arg[iarg+1],false,lmp); iarg += 2; From 058f87e019cdf28be8a50b4dab0ebaa30896e93f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Oct 2023 07:51:25 -0400 Subject: [PATCH 25/93] make sure itag is initialized --- src/OPENMP/npair_half_size_multi_old_newton_tri_omp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OPENMP/npair_half_size_multi_old_newton_tri_omp.cpp b/src/OPENMP/npair_half_size_multi_old_newton_tri_omp.cpp index caa993ed38..5dd88f8cbb 100644 --- a/src/OPENMP/npair_half_size_multi_old_newton_tri_omp.cpp +++ b/src/OPENMP/npair_half_size_multi_old_newton_tri_omp.cpp @@ -86,6 +86,7 @@ void NPairHalfSizeMultiOldNewtonTriOmp::build(NeighList *list) n = 0; neighptr = ipage.vget(); + itag = tag[i]; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; From b9ce258935bbd69ad7249da8eaa018ab5d3291d0 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Oct 2023 09:32:44 -0400 Subject: [PATCH 26/93] Revert "make sure itag is initialized" This reverts commit 058f87e019cdf28be8a50b4dab0ebaa30896e93f. --- src/OPENMP/npair_half_size_multi_old_newton_tri_omp.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/OPENMP/npair_half_size_multi_old_newton_tri_omp.cpp b/src/OPENMP/npair_half_size_multi_old_newton_tri_omp.cpp index 5dd88f8cbb..caa993ed38 100644 --- a/src/OPENMP/npair_half_size_multi_old_newton_tri_omp.cpp +++ b/src/OPENMP/npair_half_size_multi_old_newton_tri_omp.cpp @@ -86,7 +86,6 @@ void NPairHalfSizeMultiOldNewtonTriOmp::build(NeighList *list) n = 0; neighptr = ipage.vget(); - itag = tag[i]; itype = type[i]; xtmp = x[i][0]; ytmp = x[i][1]; From 0f948e98f26492f57c9c3e6a8c197b9a46c330d0 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 19 Oct 2023 10:01:10 -0400 Subject: [PATCH 27/93] quote strings with special characters in keyword lists --- src/EXTRA-DUMP/dump_yaml.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/EXTRA-DUMP/dump_yaml.cpp b/src/EXTRA-DUMP/dump_yaml.cpp index 3ca5c59edf..6c21c24f77 100644 --- a/src/EXTRA-DUMP/dump_yaml.cpp +++ b/src/EXTRA-DUMP/dump_yaml.cpp @@ -24,6 +24,8 @@ using namespace LAMMPS_NS; +static constexpr char special_chars[] = "{}[],&:*#?|-<>=!%@\\"; + /* ---------------------------------------------------------------------- */ DumpYAML::DumpYAML(class LAMMPS *_lmp, int narg, char **args) : DumpCustom(_lmp, narg, args), thermo(false) @@ -67,7 +69,12 @@ void DumpYAML::write_header(bigint ndump) const auto &fields = th->get_fields(); thermo_data += "thermo:\n - keywords: [ "; - for (int i = 0; i < nfield; ++i) thermo_data += fmt::format("{}, ", keywords[i]); + for (int i = 0; i < nfield; ++i) { + if (keywords[i].find_first_of(special_chars) == std::string::npos) + thermo_data += fmt::format("{}, ", keywords[i]); + else + thermo_data += fmt::format("'{}', ", keywords[i]); + } thermo_data += "]\n - data: [ "; for (int i = 0; i < nfield; ++i) { @@ -107,7 +114,12 @@ void DumpYAML::write_header(bigint ndump) if (domain->triclinic) fmt::print(fp, " - [ {}, {}, {} ]\n", boxxy, boxxz, boxyz); fmt::print(fp, "keywords: [ "); - for (const auto &item : utils::split_words(columns)) fmt::print(fp, "{}, ", item); + for (const auto &item : utils::split_words(columns)) { + if (item.find_first_of(special_chars) == std::string::npos) + fmt::print(fp, "{}, ", item); + else + fmt::print(fp, "'{}', ", item); + } fputs(" ]\ndata:\n", fp); } else // reset so that the remainder of the output is not multi-proc filewriter = 0; From 8bfec75568270c33f14dc5f2d791674cbf1451d8 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Thu, 19 Oct 2023 08:02:11 -0600 Subject: [PATCH 28/93] Add more error checks to Kokkos minimize --- src/KOKKOS/min_kokkos.cpp | 3 +++ src/min.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/KOKKOS/min_kokkos.cpp b/src/KOKKOS/min_kokkos.cpp index 4e1c3967ff..bbb9a0bd6e 100644 --- a/src/KOKKOS/min_kokkos.cpp +++ b/src/KOKKOS/min_kokkos.cpp @@ -59,6 +59,9 @@ void MinKokkos::init() { Min::init(); + if (!fix_minimize->kokkosable) + error->all(FLERR,"KOKKOS package requires fix minimize/kk"); + fix_minimize_kk = (FixMinimizeKokkos*) fix_minimize; } diff --git a/src/min.cpp b/src/min.cpp index 5a469a788b..acc7d17654 100644 --- a/src/min.cpp +++ b/src/min.cpp @@ -215,6 +215,9 @@ void Min::setup(int flag) } update->setupflag = 1; + if (lmp->kokkos) + error->all(FLERR,"KOKKOS package requires Kokkos-enabled min_style"); + // setup extra global dof due to fixes // cannot be done in init() b/c update init() is before modify init() From 9e45df19c128daf3169f63596efaec5d245a701c Mon Sep 17 00:00:00 2001 From: Maria-Lesniewski Date: Wed, 18 Oct 2023 13:13:37 -0400 Subject: [PATCH 29/93] Barostat fix - see lammps PR 879 and 942 --- src/BOCS/fix_bocs.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/BOCS/fix_bocs.cpp b/src/BOCS/fix_bocs.cpp index d17884855a..52ca948657 100644 --- a/src/BOCS/fix_bocs.cpp +++ b/src/BOCS/fix_bocs.cpp @@ -1024,7 +1024,10 @@ void FixBocs::final_integrate() if (pstat_flag) { if (pstyle == ISO) pressure->compute_scalar(); - else pressure->compute_vector(); + else { + temperature->compute_vector(); + pressure->compute_vector(); + } couple(); pressure->addstep(update->ntimestep+1); } @@ -1961,7 +1964,7 @@ void FixBocs::nhc_press_integrate() int ich,i,pdof; double expfac,factor_etap,kecurrent; double kt = boltz * t_target; - + double lkt_press; // Update masses, to preserve initial freq, if flag set if (omega_mass_flag) { @@ -2006,7 +2009,8 @@ void FixBocs::nhc_press_integrate() } } - double lkt_press = pdof * kt; + if (pstyle == ISO) lkt_press = kt; + else lkt_press = pdof * kt; etap_dotdot[0] = (kecurrent - lkt_press)/etap_mass[0]; double ncfac = 1.0/nc_pchain; From fc7119982b9e8c697adc88f317b6595428d52d72 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Thu, 19 Oct 2023 07:44:44 -0600 Subject: [PATCH 30/93] whitespace --- src/BOCS/fix_bocs.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/BOCS/fix_bocs.cpp b/src/BOCS/fix_bocs.cpp index 52ca948657..17bb1af002 100644 --- a/src/BOCS/fix_bocs.cpp +++ b/src/BOCS/fix_bocs.cpp @@ -1025,8 +1025,8 @@ void FixBocs::final_integrate() if (pstat_flag) { if (pstyle == ISO) pressure->compute_scalar(); else { - temperature->compute_vector(); - pressure->compute_vector(); + temperature->compute_vector(); + pressure->compute_vector(); } couple(); pressure->addstep(update->ntimestep+1); @@ -1965,6 +1965,7 @@ void FixBocs::nhc_press_integrate() double expfac,factor_etap,kecurrent; double kt = boltz * t_target; double lkt_press; + // Update masses, to preserve initial freq, if flag set if (omega_mass_flag) { From b54545d1a46ca25bdfebf5d521b8e6d11ae72673 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Thu, 19 Oct 2023 12:15:01 -0700 Subject: [PATCH 31/93] Fix bug in Kokkos SNAP on GPUs --- src/KOKKOS/pair_snap_kokkos_impl.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/KOKKOS/pair_snap_kokkos_impl.h b/src/KOKKOS/pair_snap_kokkos_impl.h index 45bacb4c97..9ed25de0cd 100644 --- a/src/KOKKOS/pair_snap_kokkos_impl.h +++ b/src/KOKKOS/pair_snap_kokkos_impl.h @@ -63,10 +63,6 @@ PairSNAPKokkos::PairSNAPKokkos(LAMMPS *lmp datamask_read = EMPTY_MASK; datamask_modify = EMPTY_MASK; - k_cutsq = tdual_fparams("PairSNAPKokkos::cutsq",atom->ntypes+1,atom->ntypes+1); - auto d_cutsq = k_cutsq.template view(); - rnd_cutsq = d_cutsq; - host_flag = (execution_space == Host); } @@ -101,6 +97,8 @@ void PairSNAPKokkos::init_style() if (force->newton_pair == 0) error->all(FLERR,"Pair style SNAP requires newton pair on"); + + // neighbor list request for KOKKOS neighflag = lmp->kokkos->neighflag; @@ -546,6 +544,9 @@ void PairSNAPKokkos::allocate() int n = atom->ntypes; MemKK::realloc_kokkos(d_map,"PairSNAPKokkos::map",n+1); + + MemKK::realloc_kokkos(k_cutsq,"PairSNAPKokkos::cutsq",n+1,n+1); + rnd_cutsq = k_cutsq.template view(); } From e944140ff221801a7da05c2fa302e45bcf27e6b8 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Thu, 19 Oct 2023 12:16:26 -0700 Subject: [PATCH 32/93] whitespace --- src/KOKKOS/pair_snap_kokkos_impl.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/KOKKOS/pair_snap_kokkos_impl.h b/src/KOKKOS/pair_snap_kokkos_impl.h index 9ed25de0cd..1791e1875d 100644 --- a/src/KOKKOS/pair_snap_kokkos_impl.h +++ b/src/KOKKOS/pair_snap_kokkos_impl.h @@ -97,8 +97,6 @@ void PairSNAPKokkos::init_style() if (force->newton_pair == 0) error->all(FLERR,"Pair style SNAP requires newton pair on"); - - // neighbor list request for KOKKOS neighflag = lmp->kokkos->neighflag; From 71c7d143b7d494d9c590797c22471ca77a70664d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 20 Oct 2023 07:01:48 -0400 Subject: [PATCH 33/93] fix logic bug --- src/region_cone.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/region_cone.cpp b/src/region_cone.cpp index 76bedf4c92..5fe7b4b5db 100644 --- a/src/region_cone.cpp +++ b/src/region_cone.cpp @@ -131,7 +131,7 @@ RegCone::RegCone(LAMMPS *lmp, int narg, char **arg) : Region(lmp, narg, arg), lo if (radiushi < 0.0) error->all(FLERR, "Illegal 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"); + if (hi <= lo) error->all(FLERR, "Illegal cone length in region cone command"); // extent of cone From 4ed5243d9b42f2ad6161ae08cf77c21704374771 Mon Sep 17 00:00:00 2001 From: Yifan Li Date: Fri, 20 Oct 2023 23:41:06 -0400 Subject: [PATCH 34/93] add the missing dividing by np in compute t_prim --- src/REPLICA/fix_pimd_langevin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/REPLICA/fix_pimd_langevin.cpp b/src/REPLICA/fix_pimd_langevin.cpp index 7ba502d2e6..553da625c7 100644 --- a/src/REPLICA/fix_pimd_langevin.cpp +++ b/src/REPLICA/fix_pimd_langevin.cpp @@ -1353,7 +1353,7 @@ void FixPIMDLangevin::compute_tote() void FixPIMDLangevin::compute_t_prim() { - t_prim = 1.5 * atom->natoms * np * force->boltz * temp - total_spring_energy; + t_prim = 1.5 * atom->natoms * np * force->boltz * temp - total_spring_energy * inverse_np; } /* ---------------------------------------------------------------------- */ From c90f874a0d5e591ec9cd0c3d974cd9f0e5ea0d80 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 22 Oct 2023 20:00:33 -0400 Subject: [PATCH 35/93] avoid invalid escape warnings for regexp expressions with python 3.12 --- doc/utils/sphinx-config/LAMMPSLexer.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/utils/sphinx-config/LAMMPSLexer.py b/doc/utils/sphinx-config/LAMMPSLexer.py index a7ba5d92a8..ee548dc602 100644 --- a/doc/utils/sphinx-config/LAMMPSLexer.py +++ b/doc/utils/sphinx-config/LAMMPSLexer.py @@ -76,12 +76,12 @@ class LAMMPSLexer(RegexLexer): include('conditionals'), include('keywords'), (r'#.*?\n', Comment), - ('"', String, 'string'), - ('\'', String, 'single_quote_string'), + (r'"', String, 'string'), + (r'\'', String, 'single_quote_string'), (r'[0-9]+:[0-9]+(:[0-9]+)?', Number), (r'[0-9]+(\.[0-9]+)?([eE]\-?[0-9]+)?', Number), - ('\$?\(', Name.Variable, 'expression'), - ('\$\{', Name.Variable, 'variable'), + (r'\$?\(', Name.Variable, 'expression'), + (r'\$\{', Name.Variable, 'variable'), (r'[\w_\.\[\]]+', Name), (r'\$[\w_]+', Name.Variable), (r'\s+', Whitespace), @@ -97,21 +97,21 @@ class LAMMPSLexer(RegexLexer): ] , 'variable' : [ - ('[^\}]+', Name.Variable), - ('\}', Name.Variable, '#pop'), + (r'[^\}]+', Name.Variable), + (r'\}', Name.Variable, '#pop'), ], 'string' : [ - ('[^"]+', String), - ('"', String, '#pop'), + (r'[^"]+', String), + (r'"', String, '#pop'), ], 'single_quote_string' : [ - ('[^\']+', String), - ('\'', String, '#pop'), + (r'[^\']+', String), + (r'\'', String, '#pop'), ], 'expression' : [ - ('[^\(\)]+', Name.Variable), - ('\(', Name.Variable, 'expression'), - ('\)', Name.Variable, '#pop'), + (r'[^\(\)]+', Name.Variable), + (r'\(', Name.Variable, 'expression'), + (r'\)', Name.Variable, '#pop'), ], 'modify_cmd' : [ (r'[\w_\-\.\[\]]+', Name.Variable.Identifier), From 723dc17d80e79f0b2489add28121172d3eab1c1e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 21 Oct 2023 06:28:14 -0400 Subject: [PATCH 36/93] must initialize deleted pointers to null since the following commands may fail --- src/force.cpp | 10 ++++++++++ src/update.cpp | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/src/force.cpp b/src/force.cpp index 347b3087cf..a64865cf58 100644 --- a/src/force.cpp +++ b/src/force.cpp @@ -332,6 +332,8 @@ void Force::create_bond(const std::string &style, int trysuffix) { delete[] bond_style; if (bond) delete bond; + bond_style = nullptr; + bond = nullptr; int sflag; bond = new_bond(style, trysuffix, sflag); @@ -400,6 +402,8 @@ void Force::create_angle(const std::string &style, int trysuffix) { delete[] angle_style; if (angle) delete angle; + angle_style = nullptr; + angle = nullptr; int sflag; angle = new_angle(style, trysuffix, sflag); @@ -468,6 +472,8 @@ void Force::create_dihedral(const std::string &style, int trysuffix) { delete[] dihedral_style; if (dihedral) delete dihedral; + dihedral_style = nullptr; + dihedral = nullptr; int sflag; dihedral = new_dihedral(style, trysuffix, sflag); @@ -536,6 +542,8 @@ void Force::create_improper(const std::string &style, int trysuffix) { delete[] improper_style; if (improper) delete improper; + improper_style = nullptr; + improper = nullptr; int sflag; improper = new_improper(style, trysuffix, sflag); @@ -604,6 +612,8 @@ void Force::create_kspace(const std::string &style, int trysuffix) { delete[] kspace_style; if (kspace) delete kspace; + kspace_style = nullptr; + kspace = nullptr; int sflag; kspace = new_kspace(style, trysuffix, sflag); diff --git a/src/update.cpp b/src/update.cpp index f990893658..093dd375d5 100644 --- a/src/update.cpp +++ b/src/update.cpp @@ -332,6 +332,8 @@ void Update::create_integrate(int narg, char **arg, int trysuffix) delete[] integrate_style; delete integrate; + integrate_style = nullptr; + integrate = nullptr; int sflag; @@ -400,6 +402,8 @@ void Update::create_minimize(int narg, char **arg, int trysuffix) delete[] minimize_style; delete minimize; + minimize_style = nullptr; + minimize = nullptr; // temporarily assign the style name without suffix (for error messages during creation) minimize_style = arg[0]; From c9aedf9df88cbecdf1ecd604e8d493f30ee692b7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 23 Oct 2023 14:57:27 -0400 Subject: [PATCH 37/93] make sure liblinalg is built before linking phana --- tools/phonon/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/phonon/CMakeLists.txt b/tools/phonon/CMakeLists.txt index f3c3b8386c..697c7870b9 100644 --- a/tools/phonon/CMakeLists.txt +++ b/tools/phonon/CMakeLists.txt @@ -119,5 +119,9 @@ if(USE_SPGLIB) target_link_libraries(phana PRIVATE SPGLIB::SYMSPG) endif() +# add dependency when using local linear algebra lib +if(NOT LAPACK_FOUND OR NOT BLAS_FOUND OR USE_INTERNAL_LINALG) + add_dependencies(phana linalg) +endif() target_link_libraries(phana PRIVATE tricubic ${LAPACK_LIBRARIES}) install(TARGETS phana EXPORT LAMMPS_Targets DESTINATION ${CMAKE_INSTALL_BINDIR}) From 97c4875a087b76c39aa7ab85415f5ccc47e06f5a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 24 Oct 2023 10:39:19 -0400 Subject: [PATCH 38/93] add sanity check on path to LAMMPS python package folder --- python/install.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/install.py b/python/install.py index 853479e9f6..c3944bab3a 100644 --- a/python/install.py +++ b/python/install.py @@ -39,6 +39,12 @@ if args.package: sys.exit(1) else: args.package = os.path.abspath(args.package) + if ((os.path.basename(args.package) != "lammps") + and ((os.path.basename(os.path.dirname(args.package)) != "python"))): + print("\nERROR: LAMMPS package folder path %s does not end in %s\n" + % (args.package, os.path.join("python", "lammps"))) + parser.print_help() + sys.exit(1) if args.lib: if not os.path.exists(args.lib): From cff21ce808eb7e2f65b981b55f5946cb30d3c958 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 24 Oct 2023 10:39:49 -0400 Subject: [PATCH 39/93] improve help and error messages --- python/install.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python/install.py b/python/install.py index c3944bab3a..fd9f95f1bf 100644 --- a/python/install.py +++ b/python/install.py @@ -18,7 +18,7 @@ parser = ArgumentParser(prog='install.py', description='LAMMPS python package installer script') parser.add_argument("-p", "--package", required=True, - help="path to the LAMMPS Python package") + help="path to the LAMMPS Python package folder") parser.add_argument("-l", "--lib", required=True, help="path to the compiled LAMMPS shared library") parser.add_argument("-n", "--noinstall", action="store_true", default=False, @@ -34,7 +34,7 @@ args = parser.parse_args() if args.package: if not os.path.exists(args.package): - print("ERROR: LAMMPS package folder %s does not exist" % args.package) + print("\nERROR: LAMMPS package folder %s does not exist\n" % args.package) parser.print_help() sys.exit(1) else: @@ -48,7 +48,7 @@ if args.package: if args.lib: if not os.path.exists(args.lib): - print("ERROR: LAMMPS shared library %s does not exist" % args.lib) + print("\nERROR: LAMMPS shared library %s does not exist\n" % args.lib) parser.print_help() sys.exit(1) else: @@ -56,7 +56,7 @@ if args.lib: if args.wheeldir: if not os.path.exists(args.wheeldir): - print("ERROR: directory %s to store the wheel does not exist" % args.wheeldir) + print("\nERROR: directory %s to store the wheel does not exist\n" % args.wheeldir) parser.print_help() sys.exit(1) else: @@ -64,7 +64,7 @@ if args.wheeldir: if args.versionfile: if not os.path.exists(args.versionfile): - print("ERROR: LAMMPS version file at %s does not exist" % args.versionfile) + print("\nERROR: LAMMPS version file at %s does not exist\n" % args.versionfile) parser.print_help() sys.exit(1) else: From e8e2c5f9866eb6cdb395878bc7a8fda54e7a0d95 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Tue, 24 Oct 2023 10:33:55 -0600 Subject: [PATCH 40/93] Fix harmless compiler warnings --- src/KOKKOS/kokkos.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/KOKKOS/kokkos.cpp b/src/KOKKOS/kokkos.cpp index 84a8f59dd0..be8823d8e2 100644 --- a/src/KOKKOS/kokkos.cpp +++ b/src/KOKKOS/kokkos.cpp @@ -137,13 +137,13 @@ KokkosLMP::KokkosLMP(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) int set_flag = 0; char *str; - if (str = getenv("SLURM_LOCALID")) { + if ((str = getenv("SLURM_LOCALID"))) { int local_rank = atoi(str); device = local_rank % ngpus; if (device >= skip_gpu) device++; set_flag = 1; } - if (str = getenv("FLUX_TASK_LOCAL_ID")) { + if ((str = getenv("FLUX_TASK_LOCAL_ID"))) { if (ngpus > 0) { int local_rank = atoi(str); device = local_rank % ngpus; @@ -151,7 +151,7 @@ KokkosLMP::KokkosLMP(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) set_flag = 1; } } - if (str = getenv("MPT_LRANK")) { + if ((str = getenv("MPT_LRANK"))) { if (ngpus > 0) { int local_rank = atoi(str); device = local_rank % ngpus; @@ -159,7 +159,7 @@ KokkosLMP::KokkosLMP(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) set_flag = 1; } } - if (str = getenv("MV2_COMM_WORLD_LOCAL_RANK")) { + if ((str = getenv("MV2_COMM_WORLD_LOCAL_RANK"))) { if (ngpus > 0) { int local_rank = atoi(str); device = local_rank % ngpus; @@ -167,7 +167,7 @@ KokkosLMP::KokkosLMP(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) set_flag = 1; } } - if (str = getenv("OMPI_COMM_WORLD_LOCAL_RANK")) { + if ((str = getenv("OMPI_COMM_WORLD_LOCAL_RANK"))) { if (ngpus > 0) { int local_rank = atoi(str); device = local_rank % ngpus; @@ -175,7 +175,7 @@ KokkosLMP::KokkosLMP(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) set_flag = 1; } } - if (str = getenv("PMI_LOCAL_RANK")) { + if ((str = getenv("PMI_LOCAL_RANK"))) { if (ngpus > 0) { int local_rank = atoi(str); device = local_rank % ngpus; From 854c6d93e299b35694cd8079f0e0d1b6f7640fd5 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 26 Oct 2023 05:07:45 -0400 Subject: [PATCH 41/93] more checks for misformatted ReST roles --- doc/Makefile | 4 ++++ doc/src/Howto_lammps_gui.rst | 4 ++-- doc/src/fix_ave_chunk.rst | 8 ++++---- doc/src/improper_amoeba.rst | 4 ++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index 2a4edc70f3..b652c515e1 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -63,6 +63,7 @@ help: @echo " anchor_check scan for duplicate anchor labels" @echo " style_check check for complete and consistent style lists" @echo " package_check check for complete and consistent package lists" + @echo " role_check check for misformatted role keywords" @echo " spelling spell-check the manual" # ------------------------------------------ @@ -98,6 +99,7 @@ html: xmlgen $(VENV) $(SPHINXCONFIG)/conf.py $(ANCHORCHECK) $(MATHJAX) env LC_ALL=C grep -n '[^ -~]' $(RSTDIR)/*.rst ;\ env LC_ALL=C grep -n ' :[a-z]\+`' $(RSTDIR)/*.rst ;\ env LC_ALL=C grep -n ' `[^`]\+<[a-z][^`]\+`[^_]' $(RSTDIR)/*.rst ;\ + env LC_ALL=C grep -n ':\(ref\|doc\):[^`]' $(RSTDIR)/*.rst ;\ $(PYTHON) $(BUILDDIR)/utils/check-styles.py -s ../src -d src ;\ echo "############################################" ;\ deactivate ;\ @@ -179,6 +181,7 @@ pdf: xmlgen $(VENV) $(SPHINXCONFIG)/conf.py $(ANCHORCHECK) env LC_ALL=C grep -n '[^ -~]' $(RSTDIR)/*.rst ;\ env LC_ALL=C grep -n ' :[a-z]\+`' $(RSTDIR)/*.rst ;\ env LC_ALL=C grep -n ' `[^`]\+<[a-z][^`]\+`[^_]' $(RSTDIR)/*.rst ;\ + env LC_ALL=C grep -n ':\(ref\|doc\):[^`]' $(RSTDIR)/*.rst ;\ $(PYTHON) utils/check-styles.py -s ../src -d src ;\ echo "############################################" ;\ deactivate ;\ @@ -227,6 +230,7 @@ char_check : role_check : @( env LC_ALL=C grep -n ' :[a-z]\+`' $(RSTDIR)/*.rst && exit 1 || : ) @( env LC_ALL=C grep -n ' `[^`]\+<[a-z][^`]\+`[^_]' $(RSTDIR)/*.rst && exit 1 || : ) + @( env LC_ALL=C grep -n ':\(ref\|doc\):[^`]' $(RSTDIR)/*.rst && exit 1 || : ) link_check : $(VENV) html @(\ diff --git a/doc/src/Howto_lammps_gui.rst b/doc/src/Howto_lammps_gui.rst index f7d4cffe13..471424e98b 100644 --- a/doc/src/Howto_lammps_gui.rst +++ b/doc/src/Howto_lammps_gui.rst @@ -90,8 +90,8 @@ The run can be stopped cleanly by using either the ``Stop LAMMPS`` entry in the ``Run`` menu, the hotkey `Ctrl-/` (`Command-/` on macOS), or clicking on the red button in the status bar. This will cause that the running LAMMPS process will complete the current iteration and then -stop. This is equivalent to the command `timer timeout 0 ` and -implemented by calling the :cpp:func:`lammps_force_timeout()` function +stop. This is equivalent to the command :doc:`timer timeout 0 ` +and implemented by calling the :cpp:func:`lammps_force_timeout()` function of the LAMMPS C-library interface. diff --git a/doc/src/fix_ave_chunk.rst b/doc/src/fix_ave_chunk.rst index 3c358c9aa5..adbfb43d72 100644 --- a/doc/src/fix_ave_chunk.rst +++ b/doc/src/fix_ave_chunk.rst @@ -541,10 +541,10 @@ Restrictions Related commands """""""""""""""" -:doc:`compute `, :doc:`fix ave/atom `, `fix -:doc:ave/histo `, :doc:`fix ave/time `, -:doc:`variable `, :doc:`fix ave/correlate -:doc:`, `fix ave/atogrid ` +:doc:`compute `, :doc:`fix ave/atom `, +:doc:`fix ave/histo `, :doc:`fix ave/time `, +:doc:`variable `, :doc:`fix ave/correlate `, +:doc:`fix ave/grid ` Default diff --git a/doc/src/improper_amoeba.rst b/doc/src/improper_amoeba.rst index 18c7f11080..1a93b0d32a 100644 --- a/doc/src/improper_amoeba.rst +++ b/doc/src/improper_amoeba.rst @@ -68,8 +68,8 @@ for more info. Related commands """""""""""""""" -:doc:`improper_coeff `, `improper_harmonic -:doc:` +:doc:`improper_coeff `, +:doc:`improper_harmonic ` Default """"""" From 50fbe616164143df9bc6f9e3182ed89a31fcfb81 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 26 Oct 2023 20:38:53 -0400 Subject: [PATCH 42/93] Backport of PR #3954 to stable release --- src/KOKKOS/mliap_data_kokkos.cpp | 1 + src/KOKKOS/mliap_data_kokkos.h | 4 +- .../mliap_model_python_couple_kokkos.pyx | 7 ++-- src/KOKKOS/mliap_unified_couple_kokkos.pyx | 37 +++++++++++-------- src/KOKKOS/mliap_unified_kokkos.cpp | 16 ++++---- src/KOKKOS/pair_mliap_kokkos.cpp | 6 ++- src/ML-IAP/mliap_data.cpp | 1 + src/ML-IAP/mliap_data.h | 1 + src/ML-IAP/mliap_model_python_couple.pyx | 1 + src/ML-IAP/mliap_unified.cpp | 7 ++-- src/ML-IAP/mliap_unified_couple.pyx | 37 +++++++++++-------- 11 files changed, 70 insertions(+), 48 deletions(-) diff --git a/src/KOKKOS/mliap_data_kokkos.cpp b/src/KOKKOS/mliap_data_kokkos.cpp index a2a8743c66..18637543f8 100644 --- a/src/KOKKOS/mliap_data_kokkos.cpp +++ b/src/KOKKOS/mliap_data_kokkos.cpp @@ -85,6 +85,7 @@ void MLIAPDataKokkos::generate_neighdata(class NeighList *list_in, i // clear gradforce and elems arrays int nall = atom->nlocal + atom->nghost; + nlocal = atom->nlocal; ntotal = nall; if (gradgradflag > -1){ auto d_gradforce = k_gradforce.template view(); diff --git a/src/KOKKOS/mliap_data_kokkos.h b/src/KOKKOS/mliap_data_kokkos.h index f641085c6a..7d95793aa2 100644 --- a/src/KOKKOS/mliap_data_kokkos.h +++ b/src/KOKKOS/mliap_data_kokkos.h @@ -118,6 +118,7 @@ public: egradient(nullptr), ntotal(base.ntotal), nlistatoms(base.nlistatoms), + nlocal(base.nlocal), natomneigh(base.natomneigh), numneighs(base.numneighs), iatoms(base.k_iatoms.d_view.data()), @@ -171,6 +172,7 @@ public: // Neighborlist stuff const int ntotal; const int nlistatoms; + const int nlocal; const int natomneigh; int *numneighs; int *iatoms; @@ -191,7 +193,7 @@ public: int dev; #ifdef LMP_KOKKOS_GPU - MLIAPDataKokkosDevice(MLIAPDataKokkos &base) : ndescriptors(-1),nparams(-1),nelements(-1),ntotal(-1),nlistatoms(-1),natomneigh(-1), + MLIAPDataKokkosDevice(MLIAPDataKokkos &base) : ndescriptors(-1),nparams(-1),nelements(-1),ntotal(-1),nlistatoms(-1),nlocal(-1),natomneigh(-1), nneigh_max(-1),npairs(-1) { // It cannot get here, but needed for compilation diff --git a/src/KOKKOS/mliap_model_python_couple_kokkos.pyx b/src/KOKKOS/mliap_model_python_couple_kokkos.pyx index 6dec8cdbfe..24a0e0897f 100644 --- a/src/KOKKOS/mliap_model_python_couple_kokkos.pyx +++ b/src/KOKKOS/mliap_model_python_couple_kokkos.pyx @@ -25,6 +25,7 @@ cdef extern from "mliap_data_kokkos.h" namespace "LAMMPS_NS": cdef cppclass MLIAPDataKokkosDevice: # Array shapes int nlistatoms + int nlocal int ndescriptors # Input data @@ -130,14 +131,14 @@ cdef create_array(device, void *pointer, shape,is_int): return numpy.asarray(pointer) else: return numpy.asarray(pointer) - + cdef public void MLIAPPYKokkos_compute_gradients(MLIAPModelPythonKokkosDevice * c_model, MLIAPDataKokkosDevice * data) with gil: dev=data.dev torch.cuda.nvtx.range_push("set data fields") - model = retrieve(c_model) + model = retrieve(c_model) n_d = data.ndescriptors n_a = data.nlistatoms @@ -148,7 +149,7 @@ cdef public void MLIAPPYKokkos_compute_gradients(MLIAPModelPythonKokkosDevice * beta_cp = create_array(dev, data.betas, (n_a, n_d), False) desc_cp = create_array(dev, data.descriptors, (n_a, n_d), False) torch.cuda.nvtx.range_pop() - + # Invoke python model on numpy arrays. torch.cuda.nvtx.range_push("call model") model(elem_cp,desc_cp,beta_cp,en_cp,dev==1) diff --git a/src/KOKKOS/mliap_unified_couple_kokkos.pyx b/src/KOKKOS/mliap_unified_couple_kokkos.pyx index bd94b79eb4..97d807ac33 100644 --- a/src/KOKKOS/mliap_unified_couple_kokkos.pyx +++ b/src/KOKKOS/mliap_unified_couple_kokkos.pyx @@ -59,6 +59,7 @@ cdef extern from "mliap_data_kokkos.h" namespace "LAMMPS_NS": int ntotal # total number of owned and ghost atoms on this proc int nlistatoms # current number of atoms in local atom lists + int nlocal int natomneigh # current number of atoms and ghosts in atom neighbor arrays int * numneighs # neighbors count for each atom int * iatoms # index of each atom @@ -133,14 +134,14 @@ cdef create_array(device, void *pointer, shape,is_int): return np.asarray(pointer) else: return np.asarray(pointer) - + # Cython implementation of MLIAPData # Automatically converts between C arrays and numpy when needed cdef class MLIAPDataPy: cdef MLIAPDataKokkosDevice * data - + def __cinit__(self): self.data = NULL @@ -157,7 +158,7 @@ cdef class MLIAPDataPy: ptr = eij.data.ptr except: ptr = eij.data_ptr() - update_pair_energy(self.data, ptr) + update_pair_energy(self.data, ptr) def update_pair_energy(self, eij): if self.data.dev==0: self.update_pair_energy_cpu(eij) @@ -177,7 +178,7 @@ cdef class MLIAPDataPy: ptr = fij.data.ptr except: ptr = fij.data_ptr() - update_pair_forces(self.data, ptr) + update_pair_forces(self.data, ptr) def update_pair_forces(self, fij): if self.data.dev==0: self.update_pair_forces_cpu(fij) @@ -189,11 +190,11 @@ cdef class MLIAPDataPy: return None return create_array(self.data.dev, self.data.f, [self.ntotal, 3],False) - + @property def size_gradforce(self): return self.data.size_gradforce - + @write_only_property def gradforce(self, value): if self.data.gradforce is NULL: @@ -202,7 +203,7 @@ cdef class MLIAPDataPy: cdef double[:, :] value_view = value gradforce_view[:] = value_view print("This code has not been tested or optimized for the GPU, if you are getting this warning optimize gradforce") - + @write_only_property def betas(self, value): if self.data.betas is NULL: @@ -280,7 +281,7 @@ cdef class MLIAPDataPy: @property def ntotal(self): return self.data.ntotal - + @property def elems(self): if self.data.elems is NULL: @@ -290,7 +291,11 @@ cdef class MLIAPDataPy: @property def nlistatoms(self): return self.data.nlistatoms - + + @property + def nlocal(self): + return self.data.nlocal + @property def natomneigh(self): return self.data.natomneigh @@ -306,7 +311,7 @@ cdef class MLIAPDataPy: if self.data.iatoms is NULL: return None return create_array(self.data.dev, self.data.iatoms, [self.natomneigh],True) - + @property def ielems(self): if self.data.ielems is NULL: @@ -322,7 +327,7 @@ cdef class MLIAPDataPy: if self.data.pair_i is NULL: return None return create_array(self.data.dev, self.data.pair_i, [self.npairs],True) - + @property def pair_j(self): return self.jatoms @@ -332,7 +337,7 @@ cdef class MLIAPDataPy: if self.data.jatoms is NULL: return None return create_array(self.data.dev, self.data.jatoms, [self.npairs],True) - + @property def jelems(self): if self.data.jelems is NULL: @@ -383,13 +388,13 @@ cdef class MLIAPUnifiedInterfaceKokkos: self.model = NULL self.descriptor = NULL self.unified_impl = unified_impl - + def compute_gradients(self, data): self.unified_impl.compute_gradients(data) - + def compute_descriptors(self, data): self.unified_impl.compute_descriptors(data) - + def compute_forces(self, data): self.unified_impl.compute_forces(data) @@ -443,7 +448,7 @@ cdef public object mliap_unified_connect_kokkos(char *fname, MLIAPDummyModel * m if unified.element_types is None: raise ValueError("no element type set") - + cdef int nelements = len(unified.element_types) cdef char **elements = malloc(nelements * sizeof(char*)) diff --git a/src/KOKKOS/mliap_unified_kokkos.cpp b/src/KOKKOS/mliap_unified_kokkos.cpp index deb9cbc346..4c38e4f1d6 100644 --- a/src/KOKKOS/mliap_unified_kokkos.cpp +++ b/src/KOKKOS/mliap_unified_kokkos.cpp @@ -271,8 +271,8 @@ void LAMMPS_NS::update_pair_energy(MLIAPDataKokkosDevice *data, double *eij) { auto d_eatoms = data->eatoms; auto d_pair_i= data->pair_i; - const auto nlistatoms = data->nlistatoms; - Kokkos::parallel_for(nlistatoms, KOKKOS_LAMBDA(int ii){ + const auto nlocal = data->nlocal; + Kokkos::parallel_for(nlocal, KOKKOS_LAMBDA(int ii){ d_eatoms[ii] = 0; }); @@ -281,7 +281,7 @@ void LAMMPS_NS::update_pair_energy(MLIAPDataKokkosDevice *data, double *eij) double e = 0.5 * eij[ii]; // must not count any contribution where i is not a local atom - if (i < nlistatoms) { + if (i < nlocal) { Kokkos::atomic_add(&d_eatoms[i], e); local_sum += e; } @@ -294,7 +294,7 @@ void LAMMPS_NS::update_pair_energy(MLIAPDataKokkosDevice *data, double *eij) void LAMMPS_NS::update_pair_forces(MLIAPDataKokkosDevice *data, double *fij) { - const auto nlistatoms = data->nlistatoms; + const auto nlocal = data->nlocal; auto *f = data->f; auto pair_i = data->pair_i; auto j_atoms = data->jatoms; @@ -315,7 +315,7 @@ void LAMMPS_NS::update_pair_forces(MLIAPDataKokkosDevice *data, double *fij) int i = pair_i[ii]; int j = j_atoms[ii]; // must not count any contribution where i is not a local atom - if (i < nlistatoms) { + if (i < nlocal) { Kokkos::atomic_add(&f[i*3+0], fij[ii3+0]); Kokkos::atomic_add(&f[i*3+1], fij[ii3+1]); Kokkos::atomic_add(&f[i*3+2], fij[ii3+2]); @@ -378,12 +378,12 @@ void LAMMPS_NS::update_pair_forces(MLIAPDataKokkosDevice *data, double *fij) void LAMMPS_NS::update_atom_energy(MLIAPDataKokkosDevice *data, double *ei) { auto d_eatoms = data->eatoms; - const auto nlistatoms = data->nlistatoms; + const auto nlocal = data->nlocal; - Kokkos::parallel_reduce(nlistatoms, KOKKOS_LAMBDA(int i, double &local_sum){ + Kokkos::parallel_reduce(nlocal, KOKKOS_LAMBDA(int i, double &local_sum){ double e = ei[i]; // must not count any contribution where i is not a local atom - if (i < nlistatoms) { + if (i < nlocal) { d_eatoms[i] = e; local_sum += e; } diff --git a/src/KOKKOS/pair_mliap_kokkos.cpp b/src/KOKKOS/pair_mliap_kokkos.cpp index d19d81e314..59f15b8c96 100644 --- a/src/KOKKOS/pair_mliap_kokkos.cpp +++ b/src/KOKKOS/pair_mliap_kokkos.cpp @@ -138,6 +138,7 @@ template void PairMLIAPKokkos::allocate() { int n = atom->ntypes; + memoryKK->destroy_kokkos(k_map, map); memoryKK->destroy_kokkos(k_cutsq, cutsq); memoryKK->destroy_kokkos(k_setflag, setflag); @@ -275,7 +276,10 @@ void PairMLIAPKokkos::coeff(int narg, char **arg) { auto h_cutsq=k_cutsq.template view(); for (int itype=1; itype <= atom->ntypes; ++itype) for (int jtype=1; jtype <= atom->ntypes; ++jtype) - h_cutsq(itype,jtype) = descriptor->cutsq[map[itype]][map[jtype]]; + // do not set cuts for NULL atoms + if (map[itype] >= 0 && map[jtype] >= 0) { + h_cutsq(itype,jtype) = descriptor->cutsq[map[itype]][map[jtype]]; + } k_cutsq.modify(); k_cutsq.sync(); constexpr int gradgradflag = -1; diff --git a/src/ML-IAP/mliap_data.cpp b/src/ML-IAP/mliap_data.cpp index 1c817bd3bd..b40fefd3ba 100644 --- a/src/ML-IAP/mliap_data.cpp +++ b/src/ML-IAP/mliap_data.cpp @@ -115,6 +115,7 @@ void MLIAPData::generate_neighdata(NeighList *list_in, int eflag_in, int vflag_i int **firstneigh = list->firstneigh; int nall = atom->nlocal + atom->nghost; + nlocal = atom->nlocal; ntotal = nall; // grow nmax gradforce, elems arrays if necessary diff --git a/src/ML-IAP/mliap_data.h b/src/ML-IAP/mliap_data.h index dc468b99cb..adb0dc4bd0 100644 --- a/src/ML-IAP/mliap_data.h +++ b/src/ML-IAP/mliap_data.h @@ -61,6 +61,7 @@ class MLIAPData : protected Pointers { int ntotal; // total number of owned and ghost atoms on this proc int nlistatoms; // current number of atoms in local atom lists int nlistatoms_max; // allocated size of descriptor array + int nlocal; int natomneigh; // current number of atoms and ghosts in atom neighbor arrays int natomneigh_max; // allocated size of atom neighbor arrays int *numneighs; // neighbors count for each atom diff --git a/src/ML-IAP/mliap_model_python_couple.pyx b/src/ML-IAP/mliap_model_python_couple.pyx index 1f5b739092..3beffc77bb 100644 --- a/src/ML-IAP/mliap_model_python_couple.pyx +++ b/src/ML-IAP/mliap_model_python_couple.pyx @@ -18,6 +18,7 @@ cdef extern from "mliap_data.h" namespace "LAMMPS_NS": cdef cppclass MLIAPData: # Array shapes int nlistatoms + int nlocal int ndescriptors # Input data diff --git a/src/ML-IAP/mliap_unified.cpp b/src/ML-IAP/mliap_unified.cpp index a3727976de..4de1709468 100644 --- a/src/ML-IAP/mliap_unified.cpp +++ b/src/ML-IAP/mliap_unified.cpp @@ -246,6 +246,7 @@ void LAMMPS_NS::update_pair_energy(MLIAPData *data, double *eij) { double e_total = 0.0; const auto nlistatoms = data->nlistatoms; + const auto nlocal = data->nlocal; for (int ii = 0; ii < nlistatoms; ii++) data->eatoms[ii] = 0; for (int ii = 0; ii < data->npairs; ii++) { @@ -253,7 +254,7 @@ void LAMMPS_NS::update_pair_energy(MLIAPData *data, double *eij) double e = 0.5 * eij[ii]; // must not count any contribution where i is not a local atom - if (i < nlistatoms) { + if (i < nlocal) { data->eatoms[i] += e; e_total += e; } @@ -267,7 +268,7 @@ void LAMMPS_NS::update_pair_energy(MLIAPData *data, double *eij) void LAMMPS_NS::update_pair_forces(MLIAPData *data, double *fij) { - const auto nlistatoms = data->nlistatoms; + const auto nlocal = data->nlocal; double **f = data->f; for (int ii = 0; ii < data->npairs; ii++) { int ii3 = ii * 3; @@ -275,7 +276,7 @@ void LAMMPS_NS::update_pair_forces(MLIAPData *data, double *fij) int j = data->jatoms[ii]; // must not count any contribution where i is not a local atom - if (i < nlistatoms) { + if (i < nlocal) { f[i][0] += fij[ii3]; f[i][1] += fij[ii3 + 1]; f[i][2] += fij[ii3 + 2]; diff --git a/src/ML-IAP/mliap_unified_couple.pyx b/src/ML-IAP/mliap_unified_couple.pyx index 25852a1c5f..3148b96b51 100644 --- a/src/ML-IAP/mliap_unified_couple.pyx +++ b/src/ML-IAP/mliap_unified_couple.pyx @@ -53,7 +53,8 @@ cdef extern from "mliap_data.h" namespace "LAMMPS_NS": # only neighbors strictly inside descriptor cutoff int ntotal # total number of owned and ghost atoms on this proc - int nlistatoms # current number of atoms in local atom lists + int nlistatoms # current number of non-NULL atoms in local atom lists + int nlocal # current number of NULL and normal atoms in local atom lists int natomneigh # current number of atoms and ghosts in atom neighbor arrays int * numneighs # neighbors count for each atom int * iatoms # index of each atom @@ -113,11 +114,11 @@ cdef class MLIAPDataPy: def __cinit__(self): self.data = NULL - + def update_pair_energy(self, eij): cdef double[:] eij_arr = eij update_pair_energy(self.data, &eij_arr[0]) - + def update_pair_forces(self, fij): cdef double[:, ::1] fij_arr = fij update_pair_forces(self.data, &fij_arr[0][0]) @@ -127,11 +128,11 @@ cdef class MLIAPDataPy: if self.data.f is NULL: return None return np.asarray( &self.data.f[0][0]) - + @property def size_gradforce(self): return self.data.size_gradforce - + @write_only_property def gradforce(self, value): if self.data.gradforce is NULL: @@ -139,7 +140,7 @@ cdef class MLIAPDataPy: cdef double[:, :] gradforce_view = &self.data.gradforce[0][0] cdef double[:, :] value_view = value gradforce_view[:] = value_view - + @write_only_property def betas(self, value): if self.data.betas is NULL: @@ -216,7 +217,7 @@ cdef class MLIAPDataPy: @property def ntotal(self): return self.data.ntotal - + @property def elems(self): if self.data.elems is NULL: @@ -226,7 +227,11 @@ cdef class MLIAPDataPy: @property def nlistatoms(self): return self.data.nlistatoms - + + @property + def nlocal(self): + return self.data.nlocal + @property def natomneigh(self): return self.data.natomneigh @@ -242,13 +247,13 @@ cdef class MLIAPDataPy: if self.data.iatoms is NULL: return None return np.asarray( &self.data.iatoms[0]) - + @property def ielems(self): if self.data.ielems is NULL: return None return np.asarray( &self.data.ielems[0]) - + @property def npairs(self): return self.data.npairs @@ -258,7 +263,7 @@ cdef class MLIAPDataPy: if self.data.pair_i is NULL: return None return np.asarray( &self.data.pair_i[0]) - + @property def pair_j(self): return self.jatoms @@ -268,7 +273,7 @@ cdef class MLIAPDataPy: if self.data.jatoms is NULL: return None return np.asarray( &self.data.jatoms[0]) - + @property def jelems(self): if self.data.jelems is NULL: @@ -318,13 +323,13 @@ cdef class MLIAPUnifiedInterface: self.model = NULL self.descriptor = NULL self.unified_impl = unified_impl - + def compute_gradients(self, data): self.unified_impl.compute_gradients(data) - + def compute_descriptors(self, data): self.unified_impl.compute_descriptors(data) - + def compute_forces(self, data): self.unified_impl.compute_forces(data) @@ -379,7 +384,7 @@ cdef public object mliap_unified_connect(char *fname, MLIAPDummyModel * model, if unified.element_types is None: raise ValueError("no element type set") - + cdef int nelements = len(unified.element_types) cdef char **elements = malloc(nelements * sizeof(char*)) From 00ef4ca3f662b6213752d844dc5e328e8d66d083 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 27 Oct 2023 11:08:02 -0400 Subject: [PATCH 43/93] fix bug in not listing all not compiled-in styles --- src/lammps.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lammps.cpp b/src/lammps.cpp index 9ac4c98bc3..56322ab78f 100644 --- a/src/lammps.cpp +++ b/src/lammps.cpp @@ -16,6 +16,7 @@ #include "style_angle.h" // IWYU pragma: keep #include "style_atom.h" // IWYU pragma: keep +#include "style_body.h" // IWYU pragma: keep #include "style_bond.h" // IWYU pragma: keep #include "style_command.h" // IWYU pragma: keep #include "style_compute.h" // IWYU pragma: keep @@ -27,6 +28,7 @@ #include "style_kspace.h" // IWYU pragma: keep #include "style_minimize.h" // IWYU pragma: keep #include "style_pair.h" // IWYU pragma: keep +#include "style_reader.h" // IWYU pragma: keep #include "style_region.h" // IWYU pragma: keep #include "accelerator_kokkos.h" @@ -1152,9 +1154,9 @@ const char *LAMMPS::match_style(const char *style, const char *name) check_for_match(bond,style,name); check_for_match(command,style,name); check_for_match(compute,style,name); + check_for_match(dihedral,style,name); check_for_match(dump,style,name); check_for_match(fix,style,name); - check_for_match(compute,style,name); check_for_match(improper,style,name); check_for_match(integrate,style,name); check_for_match(kspace,style,name); @@ -1165,6 +1167,8 @@ const char *LAMMPS::match_style(const char *style, const char *name) return nullptr; } +#undef check_for_match + /** \brief Return suffix for non-pair styles depending on pair_only_flag * * \return suffix or null pointer From 0f8af20d0b6db2008cc5ca8d9c2eeaef52d38bcc Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 27 Oct 2023 19:10:55 -0400 Subject: [PATCH 44/93] limit the maximum number of iterations so the LAMMPS simulation will not stall --- src/compute_cluster_atom.cpp | 9 +++++++-- src/compute_fragment_atom.cpp | 10 ++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/compute_cluster_atom.cpp b/src/compute_cluster_atom.cpp index ae44fbcd37..0d60b8b993 100644 --- a/src/compute_cluster_atom.cpp +++ b/src/compute_cluster_atom.cpp @@ -29,6 +29,7 @@ using namespace LAMMPS_NS; +static constexpr int MAXLOOP = 100; /* ---------------------------------------------------------------------- */ ComputeClusterAtom::ComputeClusterAtom(LAMMPS *lmp, int narg, char **arg) : @@ -136,9 +137,11 @@ void ComputeClusterAtom::compute_peratom() int change, done, anychange; - while (true) { + int counter = 0; + // stop after MAXLOOP iterations + while (counter < MAXLOOP) { comm->forward_comm(this); - + ++counter; change = 0; while (true) { done = 1; @@ -177,6 +180,8 @@ void ComputeClusterAtom::compute_peratom() MPI_Allreduce(&change, &anychange, 1, MPI_INT, MPI_MAX, world); if (!anychange) break; } + if ((comm->me == 0) && (counter >= MAXLOOP)) + error->warning(FLERR, "Compute cluster/atom did not converge after {} iterations", MAXLOOP); } /* ---------------------------------------------------------------------- */ diff --git a/src/compute_fragment_atom.cpp b/src/compute_fragment_atom.cpp index 035f554c8d..7e3f3437b6 100644 --- a/src/compute_fragment_atom.cpp +++ b/src/compute_fragment_atom.cpp @@ -31,7 +31,8 @@ using namespace LAMMPS_NS; -#define BIG 1.0e20 +static constexpr double BIG = 1.0e20; +static constexpr int MAXLOOP = 100; /* ---------------------------------------------------------------------- */ @@ -145,8 +146,11 @@ void ComputeFragmentAtom::compute_peratom() commflag = 1; - while (true) { + int counter = 0; + // stop after MAXLOOP iterations + while (counter < MAXLOOP) { comm->forward_comm(this); + ++counter; done = 1; // set markflag = 0 for all owned atoms, for new iteration @@ -223,6 +227,8 @@ void ComputeFragmentAtom::compute_peratom() MPI_Allreduce(&done,&alldone,1,MPI_INT,MPI_MIN,world); if (alldone) break; } + if ((comm->me == 0) && (counter >= MAXLOOP)) + error->warning(FLERR, "Compute fragment/atom did not converge after {} iterations", MAXLOOP); } /* ---------------------------------------------------------------------- */ From dd498fcbf80b20166f50f442044018c3d25deeda Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Tue, 31 Oct 2023 16:02:49 -0600 Subject: [PATCH 45/93] add comm of ghost atom coords to compute cluster/atom and aggregate/atom --- src/compute_aggregate_atom.cpp | 5 +++++ src/compute_cluster_atom.cpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/compute_aggregate_atom.cpp b/src/compute_aggregate_atom.cpp index e68062b73e..54da23c302 100644 --- a/src/compute_aggregate_atom.cpp +++ b/src/compute_aggregate_atom.cpp @@ -110,6 +110,11 @@ void ComputeAggregateAtom::compute_peratom() vector_atom = aggregateID; } + // communicate coords for ghost atoms if box can change, e.g. fix deform + // this ensures ghost atom coords are current + + comm->forward_comm(); + // invoke full neighbor list (will copy or build if necessary) // on the first step of a run, set preflag to one in neighbor->build_one(...) diff --git a/src/compute_cluster_atom.cpp b/src/compute_cluster_atom.cpp index 0d60b8b993..ba0f263747 100644 --- a/src/compute_cluster_atom.cpp +++ b/src/compute_cluster_atom.cpp @@ -100,6 +100,11 @@ void ComputeClusterAtom::compute_peratom() vector_atom = clusterID; } + // communicate coords for ghost atoms if box can change, e.g. fix deform + // this ensures ghost atom coords are current + + comm->forward_comm(); + // invoke full neighbor list (will copy or build if necessary) // on the first step of a run, set preflag to one in neighbor->build_one(...) From 28803ee78df694195c9d1d31d9c4d5f8f7c70111 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 1 Nov 2023 05:11:43 -0400 Subject: [PATCH 46/93] add code to avoid deadlock --- src/compute_aggregate_atom.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/compute_aggregate_atom.cpp b/src/compute_aggregate_atom.cpp index 54da23c302..5a489092b7 100644 --- a/src/compute_aggregate_atom.cpp +++ b/src/compute_aggregate_atom.cpp @@ -35,6 +35,7 @@ using namespace LAMMPS_NS; +static constexpr int MAXLOOP = 100; /* ---------------------------------------------------------------------- */ ComputeAggregateAtom::ComputeAggregateAtom(LAMMPS *lmp, int narg, char **arg) : @@ -163,8 +164,11 @@ void ComputeAggregateAtom::compute_peratom() int change, done, anychange; - while (true) { + int counter = 0; + // stop after MAXLOOP iterations + while (counter < MAXLOOP) { comm->forward_comm(this); + ++counter; // reverse communication when bonds are not stored on every processor @@ -223,6 +227,8 @@ void ComputeAggregateAtom::compute_peratom() MPI_Allreduce(&change, &anychange, 1, MPI_INT, MPI_MAX, world); if (!anychange) break; } + if ((comm->me == 0) && (counter >= MAXLOOP)) + error->warning(FLERR, "Compute aggregate/atom did not converge after {} iterations", MAXLOOP); } /* ---------------------------------------------------------------------- */ From acaae8a36f5810bf529e3bf90c5dccde7cb159e7 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Thu, 2 Nov 2023 13:05:18 -0600 Subject: [PATCH 47/93] Fix bug in fix_dt_reset_kokkos --- src/KOKKOS/fix_dt_reset_kokkos.cpp | 83 +++++++++++++----------------- 1 file changed, 36 insertions(+), 47 deletions(-) diff --git a/src/KOKKOS/fix_dt_reset_kokkos.cpp b/src/KOKKOS/fix_dt_reset_kokkos.cpp index 4c7545cee0..0e8d0d985c 100644 --- a/src/KOKKOS/fix_dt_reset_kokkos.cpp +++ b/src/KOKKOS/fix_dt_reset_kokkos.cpp @@ -52,14 +52,6 @@ void FixDtResetKokkos::init() { FixDtReset::init(); - k_emax = Kokkos::DualView("FixDtResetKokkos:gamma", 1); - - k_emax.h_view(0) = emax; - - - k_emax.template modify(); - k_emax.template sync(); - if (utils::strmatch(update->integrate_style,"^respa")) error->all(FLERR,"Cannot (yet) use respa with Kokkos"); } @@ -95,41 +87,38 @@ void FixDtResetKokkos::end_of_step() atomKK->modified(execution_space, F_MASK); - if (minbound) dt = MAX(dt, tmin); - if (maxbound) dt = MIN(dt, tmax); + if (minbound) dt = MAX(dt, tmin); + if (maxbound) dt = MIN(dt, tmax); - // if timestep didn't change, just return - // else reset update->dt and other classes that depend on it - // rRESPA, pair style, fixes + // if timestep didn't change, just return + // else reset update->dt and other classes that depend on it + // rRESPA, pair style, fixes - if (dt == update->dt) return; + if (dt == update->dt) return; - laststep = update->ntimestep; + laststep = update->ntimestep; - // calls to other classes that need to know timestep size changed - // similar logic is in Input::timestep() - - update->update_time(); - update->dt = dt; - update->dt_default = 0; - if (force->pair) force->pair->reset_dt(); - for (auto &ifix : modify->get_fix_list()) ifix->reset_dt(); - output->reset_dt(); + // calls to other classes that need to know timestep size changed + // similar logic is in Input::timestep() + update->update_time(); + update->dt = dt; + update->dt_default = 0; + if (force->pair) force->pair->reset_dt(); + for (auto &ifix : modify->get_fix_list()) ifix->reset_dt(); + output->reset_dt(); } /* ---------------------------------------------------------------------- */ template KOKKOS_INLINE_FUNCTION -void FixDtResetKokkos::operator()(TagFixDtResetMass, const int &i, double &k_dt) const { +void FixDtResetKokkos::operator()(TagFixDtResetMass, const int &i, double &dt_min) const { - double dtv, dtf, dte, dtsq; + double dt, dtv, dtf, dte, dtsq; double vsq, fsq, massinv; double delx, dely, delz, delr; - double emax = k_emax.d_view(0); - if (mask[i] & groupbit) { massinv = 1.0 / mass[type[i]]; @@ -138,32 +127,31 @@ void FixDtResetKokkos::operator()(TagFixDtResetMass, const int &i, d dtv = dtf = dte = BIG; if (vsq > 0.0) dtv = xmax / sqrt(vsq); if (fsq > 0.0) dtf = sqrt(2.0 * xmax / (ftm2v * sqrt(fsq) * massinv)); - k_dt = MIN(dtv, dtf); + dt = MIN(dtv, dtf); if ((emax > 0.0) && (fsq * vsq > 0.0)) { dte = emax / sqrt(fsq * vsq) / sqrt(ftm2v * mvv2e); - k_dt = MIN(dt, dte); + dt = MIN(dt, dte); } - dtsq = k_dt * k_dt; - delx = k_dt * v(i,0) + 0.5 * dtsq * massinv * f(i,0) * ftm2v; - dely = k_dt * v(i,1) + 0.5 * dtsq * massinv * f(i,1) * ftm2v; - delz = k_dt * v(i,2) + 0.5 * dtsq * massinv * f(i,2) * ftm2v; + dtsq = dt * dt; + delx = dt * v(i,0) + 0.5 * dtsq * massinv * f(i,0) * ftm2v; + dely = dt * v(i,1) + 0.5 * dtsq * massinv * f(i,1) * ftm2v; + delz = dt * v(i,2) + 0.5 * dtsq * massinv * f(i,2) * ftm2v; delr = sqrt(delx * delx + dely * dely + delz * delz); - if (delr > xmax) k_dt *= xmax / delr; + if (delr > xmax) dt *= xmax / delr; + dt_min = MIN(dt_min,dt); } - } +} /* ---------------------------------------------------------------------- */ template KOKKOS_INLINE_FUNCTION -void FixDtResetKokkos::operator()(TagFixDtResetRMass, const int &i, double &k_dt) const { +void FixDtResetKokkos::operator()(TagFixDtResetRMass, const int &i, double &dt_min) const { - double dtv, dtf, dte, dtsq; + double dt, dtv, dtf, dte, dtsq; double vsq, fsq, massinv; double delx, dely, delz, delr; - double emax = k_emax.d_view(0); - if (mask[i] & groupbit) { massinv = 1.0 / rmass[i]; @@ -172,17 +160,18 @@ void FixDtResetKokkos::operator()(TagFixDtResetRMass, const int &i, dtv = dtf = dte = BIG; if (vsq > 0.0) dtv = xmax / sqrt(vsq); if (fsq > 0.0) dtf = sqrt(2.0 * xmax / (ftm2v * sqrt(fsq) * massinv)); - k_dt = MIN(dtv, dtf); + dt = MIN(dtv, dtf); if ((emax > 0.0) && (fsq * vsq > 0.0)) { dte = emax / sqrt(fsq * vsq) / sqrt(ftm2v * mvv2e); - k_dt = MIN(dt, dte); + dt = MIN(dt, dte); } - dtsq = k_dt * k_dt; - delx = k_dt * v(i,0) + 0.5 * dtsq * massinv * f(i,0) * ftm2v; - dely = k_dt * v(i,1) + 0.5 * dtsq * massinv * f(i,1) * ftm2v; - delz = k_dt * v(i,2) + 0.5 * dtsq * massinv * f(i,2) * ftm2v; + dtsq = dt * dt; + delx = dt * v(i,0) + 0.5 * dtsq * massinv * f(i,0) * ftm2v; + dely = dt * v(i,1) + 0.5 * dtsq * massinv * f(i,1) * ftm2v; + delz = dt * v(i,2) + 0.5 * dtsq * massinv * f(i,2) * ftm2v; delr = sqrt(delx * delx + dely * dely + delz * delz); - if (delr > xmax) k_dt *= xmax / delr; + if (delr > xmax) dt *= xmax / delr; + dt_min = MIN(dt_min,dt); } } From 917606e40e5c2c965fd950a10a8cbc7218c971f1 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Thu, 2 Nov 2023 13:10:27 -0600 Subject: [PATCH 48/93] Forces are not modified --- src/KOKKOS/fix_dt_reset_kokkos.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/KOKKOS/fix_dt_reset_kokkos.cpp b/src/KOKKOS/fix_dt_reset_kokkos.cpp index 0e8d0d985c..6e7709ace1 100644 --- a/src/KOKKOS/fix_dt_reset_kokkos.cpp +++ b/src/KOKKOS/fix_dt_reset_kokkos.cpp @@ -85,8 +85,6 @@ void FixDtResetKokkos::end_of_step() MPI_Allreduce(MPI_IN_PLACE, &dt, 1, MPI_DOUBLE, MPI_MIN, world); - atomKK->modified(execution_space, F_MASK); - if (minbound) dt = MAX(dt, tmin); if (maxbound) dt = MIN(dt, tmax); From 4526dccaca836d6d64f7c87eea189d028a3f6ba4 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Mon, 6 Nov 2023 23:18:42 -0700 Subject: [PATCH 49/93] Correctly build argv with nullptr at the end --- src/angle_write.cpp | 8 +- src/dihedral_write.cpp | 8 +- src/lammps.cpp | 23 +++++ src/lammps.h | 6 ++ unittest/c-library/test_library_commands.cpp | 5 +- unittest/c-library/test_library_config.cpp | 5 +- unittest/c-library/test_library_external.cpp | 8 +- unittest/c-library/test_library_mpi.cpp | 20 ++-- unittest/c-library/test_library_open.cpp | 20 ++-- .../c-library/test_library_properties.cpp | 13 +-- .../c-library/test_library_scatter_gather.cpp | 5 +- unittest/commands/test_mpi_load_balancing.cpp | 6 +- unittest/cplusplus/test_input_class.cpp | 15 ++- unittest/cplusplus/test_lammps_class.cpp | 52 +++++------ unittest/force-styles/test_angle_style.cpp | 44 +++------ unittest/force-styles/test_bond_style.cpp | 44 +++------ unittest/force-styles/test_dihedral_style.cpp | 32 +++---- unittest/force-styles/test_fix_timestep.cpp | 30 +++--- unittest/force-styles/test_improper_style.cpp | 30 +++--- unittest/force-styles/test_pair_style.cpp | 92 +++++++------------ unittest/fortran/wrap_extract_variable.cpp | 4 +- unittest/testing/core.h | 20 +--- 22 files changed, 207 insertions(+), 283 deletions(-) diff --git a/src/angle_write.cpp b/src/angle_write.cpp index e64c2f23c8..fb0e65ccf5 100644 --- a/src/angle_write.cpp +++ b/src/angle_write.cpp @@ -123,11 +123,9 @@ void AngleWrite::command(int narg, char **arg) if (comm->me == 0) { // set up new LAMMPS instance with dummy system to evaluate angle potential - const char *args[] = {"AngleWrite", "-nocite", "-echo", "none", - "-log", "none", "-screen", "none"}; - char **argv = (char **) args; - int argc = sizeof(args) / sizeof(char *); - LAMMPS *writer = new LAMMPS(argc, argv, singlecomm); + LAMMPS::argv args = {"AngleWrite", "-nocite", "-echo", "none", + "-log", "none", "-screen", "none"}; + LAMMPS *writer = new LAMMPS(args, singlecomm); // create dummy system replicating angle style settings writer->input->one(fmt::format("units {}", update->unit_style)); diff --git a/src/dihedral_write.cpp b/src/dihedral_write.cpp index 285d9cf931..3d87591bcc 100644 --- a/src/dihedral_write.cpp +++ b/src/dihedral_write.cpp @@ -124,12 +124,8 @@ void DihedralWrite::command(int narg, char **arg) if (comm->me == 0) { // set up new LAMMPS instance with dummy system to evaluate dihedral potential - // const char *args[] = {"DihedralWrite", "-nocite", "-echo", "none", - // "-log", "none", "-screen", "none"}; - const char *args[] = {"DihedralWrite", "-nocite", "-echo", "screen", "-log", "none"}; - char **argv = (char **) args; - int argc = sizeof(args) / sizeof(char *); - LAMMPS *writer = new LAMMPS(argc, argv, singlecomm); + LAMMPS::argv args = {"DihedralWrite", "-nocite", "-echo", "screen", "-log", "none"}; + LAMMPS *writer = new LAMMPS(args, singlecomm); // create dummy system replicating dihedral style settings writer->input->one(fmt::format("units {}", update->unit_style)); diff --git a/src/lammps.cpp b/src/lammps.cpp index 56322ab78f..35824a6efb 100644 --- a/src/lammps.cpp +++ b/src/lammps.cpp @@ -109,6 +109,15 @@ using namespace LAMMPS_NS; * The specifics of setting up and running a simulation are handled by the * individual component class instances. */ +/** Create a LAMMPS simulation instance + * + * \param args list of arguments + * \param communicator MPI communicator used by this LAMMPS instance + */ +LAMMPS::LAMMPS(argv & args, MPI_Comm communicator) : + LAMMPS(args.size(), argv_pointers(args).data(), communicator) { +} + /** Create a LAMMPS simulation instance * * The LAMMPS constructor starts up a simulation by allocating all @@ -1471,3 +1480,17 @@ void LAMMPS::print_config(FILE *fp) } fputs("\n\n",fp); } + +/** Create vector of argv string pointers including terminating nullptr element + * + * \param args list of arguments + */ +std::vector LAMMPS::argv_pointers(argv & args){ + std::vector r; + r.reserve(args.size()+1); + for(auto & a : args) { + r.push_back((char*)a.data()); + } + r.push_back(nullptr); + return r; +} diff --git a/src/lammps.h b/src/lammps.h index 03b019ed43..0d6d62fc60 100644 --- a/src/lammps.h +++ b/src/lammps.h @@ -16,6 +16,8 @@ #include #include +#include +#include namespace LAMMPS_NS { @@ -84,6 +86,10 @@ class LAMMPS { static const char *git_branch(); static const char *git_descriptor(); + using argv = std::vector; + static std::vector argv_pointers(argv & args); + + LAMMPS(argv & args, MPI_Comm); LAMMPS(int, char **, MPI_Comm); ~LAMMPS(); void create(); diff --git a/unittest/c-library/test_library_commands.cpp b/unittest/c-library/test_library_commands.cpp index d4e326cd36..31f8268a8f 100644 --- a/unittest/c-library/test_library_commands.cpp +++ b/unittest/c-library/test_library_commands.cpp @@ -26,10 +26,11 @@ protected: void SetUp() override { const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite", - "-var", "x", "2", "-var", "zpos", "1.5"}; + "-var", "x", "2", "-var", "zpos", "1.5", + nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; ::testing::internal::CaptureStdout(); lmp = lammps_open_no_mpi(argc, argv, nullptr); diff --git a/unittest/c-library/test_library_config.cpp b/unittest/c-library/test_library_config.cpp index f402ffc2e9..a1f9cf0006 100644 --- a/unittest/c-library/test_library_config.cpp +++ b/unittest/c-library/test_library_config.cpp @@ -29,10 +29,11 @@ protected: { const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite", - "-var", "input_dir", STRINGIFY(TEST_INPUT_FOLDER)}; + "-var", "input_dir", STRINGIFY(TEST_INPUT_FOLDER), + nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; ::testing::internal::CaptureStdout(); lmp = lammps_open_no_mpi(argc, argv, nullptr); diff --git a/unittest/c-library/test_library_external.cpp b/unittest/c-library/test_library_external.cpp index 57d3bef080..9011ac19a8 100644 --- a/unittest/c-library/test_library_external.cpp +++ b/unittest/c-library/test_library_external.cpp @@ -64,9 +64,9 @@ static void callback(void *handle, step_t timestep, int nlocal, tag_t *, double TEST(lammps_external, callback) { - const char *args[] = {"liblammps", "-log", "none", "-nocite"}; + const char *args[] = {"liblammps", "-log", "none", "-nocite", nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; ::testing::internal::CaptureStdout(); void *handle = lammps_open_no_mpi(argc, argv, nullptr); @@ -131,9 +131,9 @@ TEST(lammps_external, callback) TEST(lammps_external, array) { - const char *args[] = {"liblammps", "-log", "none", "-nocite"}; + const char *args[] = {"liblammps", "-log", "none", "-nocite", nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; ::testing::internal::CaptureStdout(); void *handle = lammps_open_no_mpi(argc, argv, nullptr); diff --git a/unittest/c-library/test_library_mpi.cpp b/unittest/c-library/test_library_mpi.cpp index 1609107ae0..f60105a229 100644 --- a/unittest/c-library/test_library_mpi.cpp +++ b/unittest/c-library/test_library_mpi.cpp @@ -34,9 +34,9 @@ TEST(MPI, global_box) int boxflag; ::testing::internal::CaptureStdout(); - const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite"}; + const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite", nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; void *lmp = lammps_open(argc, argv, MPI_COMM_WORLD, nullptr); lammps_command(lmp, "units lj"); lammps_command(lmp, "atom_style atomic"); @@ -77,9 +77,9 @@ TEST(MPI, sub_box) int boxflag; ::testing::internal::CaptureStdout(); - const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite"}; + const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite", nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; void *lmp = lammps_open(argc, argv, MPI_COMM_WORLD, nullptr); lammps_command(lmp, "units lj"); lammps_command(lmp, "atom_style atomic"); @@ -143,9 +143,9 @@ TEST(MPI, split_comm) MPI_Comm_split(MPI_COMM_WORLD, color, key, &newcomm); - const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite"}; + const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite", nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; void *lmp = lammps_open(argc, argv, newcomm, nullptr); lammps_command(lmp, "units lj"); lammps_command(lmp, "atom_style atomic"); @@ -173,9 +173,9 @@ TEST(MPI, multi_partition) MPI_Comm_rank(MPI_COMM_WORLD, &me); const char *args[] = {"LAMMPS_test", "-log", "none", "-partition", "4x1", - "-echo", "screen", "-nocite", "-in", "none"}; + "-echo", "screen", "-nocite", "-in", "none", nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; void *lmp = lammps_open(argc, argv, MPI_COMM_WORLD, nullptr); lammps_command(lmp, "units lj"); @@ -205,9 +205,9 @@ protected: void SetUp() override { - const char *args[] = {testbinary, "-log", "none", "-echo", "screen", "-nocite"}; + const char *args[] = {testbinary, "-log", "none", "-echo", "screen", "-nocite", nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; if (!verbose) ::testing::internal::CaptureStdout(); lmp = lammps_open(argc, argv, MPI_COMM_WORLD, nullptr); InitSystem(); diff --git a/unittest/c-library/test_library_open.cpp b/unittest/c-library/test_library_open.cpp index 1cd65d843d..267f8e0978 100644 --- a/unittest/c-library/test_library_open.cpp +++ b/unittest/c-library/test_library_open.cpp @@ -39,9 +39,9 @@ TEST(lammps_open, null_args) TEST(lammps_open, with_args) { - const char *args[] = {"liblammps", "-log", "none", "-nocite"}; + const char *args[] = {"liblammps", "-log", "none", "-nocite", nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; // MPI is already initialized MPI_Comm mycomm; @@ -78,9 +78,9 @@ TEST(lammps_open, with_args) TEST(lammps_open, with_kokkos) { if (!LAMMPS_NS::LAMMPS::is_installed_pkg("KOKKOS")) GTEST_SKIP(); - const char *args[] = {"liblammps", "-k", "on", "t", "2", "-sf", "kk", "-log", "none"}; + const char *args[] = {"liblammps", "-k", "on", "t", "2", "-sf", "kk", "-log", "none", nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; ::testing::internal::CaptureStdout(); void *alt_ptr; @@ -108,9 +108,9 @@ TEST(lammps_open, with_kokkos) TEST(lammps_open_no_mpi, no_screen) { - const char *args[] = {"liblammps", "-log", "none", "-screen", "none", "-nocite"}; + const char *args[] = {"liblammps", "-log", "none", "-screen", "none", "-nocite", nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; ::testing::internal::CaptureStdout(); void *alt_ptr; @@ -139,9 +139,9 @@ TEST(lammps_open_no_mpi, with_omp) { if (!LAMMPS_NS::LAMMPS::is_installed_pkg("OPENMP")) GTEST_SKIP(); const char *args[] = {"liblammps", "-pk", "omp", "2", "neigh", "no", - "-sf", "omp", "-log", "none", "-nocite"}; + "-sf", "omp", "-log", "none", "-nocite", nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; ::testing::internal::CaptureStdout(); void *alt_ptr; @@ -201,9 +201,9 @@ TEST(lammps_open_fortran, no_args) TEST(lammps_open_no_mpi, lammps_error) { - const char *args[] = {"liblammps", "-log", "none", "-nocite"}; + const char *args[] = {"liblammps", "-log", "none", "-nocite", nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; ::testing::internal::CaptureStdout(); void *alt_ptr; diff --git a/unittest/c-library/test_library_properties.cpp b/unittest/c-library/test_library_properties.cpp index 14eab06213..1eace87f77 100644 --- a/unittest/c-library/test_library_properties.cpp +++ b/unittest/c-library/test_library_properties.cpp @@ -33,10 +33,11 @@ protected: { const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite", - "-var", "input_dir", STRINGIFY(TEST_INPUT_FOLDER)}; + "-var", "input_dir", STRINGIFY(TEST_INPUT_FOLDER), + nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; ::testing::internal::CaptureStdout(); lmp = lammps_open_no_mpi(argc, argv, nullptr); @@ -554,10 +555,10 @@ protected: void SetUp() override { - const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite"}; + const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite", nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; ::testing::internal::CaptureStdout(); lmp = lammps_open_no_mpi(argc, argv, nullptr); @@ -635,10 +636,10 @@ TEST(SystemSettings, kokkos) // clang-format off const char *args[] = {"SystemSettings", "-log", "none", "-echo", "screen", "-nocite", - "-k", "on", "t", "4", "-sf", "kk"}; + "-k", "on", "t", "4", "-sf", "kk", nullptr}; // clang-format on char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; ::testing::internal::CaptureStdout(); void *lmp = lammps_open_no_mpi(argc, argv, nullptr); diff --git a/unittest/c-library/test_library_scatter_gather.cpp b/unittest/c-library/test_library_scatter_gather.cpp index ee672c9b86..0303a47337 100644 --- a/unittest/c-library/test_library_scatter_gather.cpp +++ b/unittest/c-library/test_library_scatter_gather.cpp @@ -32,10 +32,11 @@ protected: { const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite", - "-var", "input_dir", STRINGIFY(TEST_INPUT_FOLDER)}; + "-var", "input_dir", STRINGIFY(TEST_INPUT_FOLDER), + nullptr}; char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + int argc = (sizeof(args) / sizeof(char *)) - 1; ::testing::internal::CaptureStdout(); lmp = lammps_open_no_mpi(argc, argv, nullptr); diff --git a/unittest/commands/test_mpi_load_balancing.cpp b/unittest/commands/test_mpi_load_balancing.cpp index bc5f07beb1..efdee8c4eb 100644 --- a/unittest/commands/test_mpi_load_balancing.cpp +++ b/unittest/commands/test_mpi_load_balancing.cpp @@ -33,11 +33,9 @@ protected: void SetUp() override { - const char *args[] = {testbinary, "-log", "none", "-echo", "screen", "-nocite"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {testbinary, "-log", "none", "-echo", "screen", "-nocite"}; if (!verbose) ::testing::internal::CaptureStdout(); - lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); + lmp = new LAMMPS(args, MPI_COMM_WORLD); InitSystem(); if (!verbose) ::testing::internal::GetCapturedStdout(); } diff --git a/unittest/cplusplus/test_input_class.cpp b/unittest/cplusplus/test_input_class.cpp index 6595c24695..708d3f7cae 100644 --- a/unittest/cplusplus/test_input_class.cpp +++ b/unittest/cplusplus/test_input_class.cpp @@ -8,6 +8,7 @@ #include #include +#include "../testing/utils.h" #include "gtest/gtest.h" const char *demo_input[] = {"region box block 0 $x 0 2 0 2", "create_box 1 box", @@ -21,9 +22,9 @@ protected: LAMMPS *lmp; Input_commands() { - const char *args[] = {"LAMMPS_test"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + const char * args[] = {"LAMMPS_test", nullptr}; + char ** argv = (char**)args; + int argc = 1; int flag; MPI_Initialized(&flag); @@ -33,13 +34,11 @@ protected: void SetUp() override { - const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite", - "-var", "zpos", "1.5", "-var", "x", "2"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"LAMMPS_test", "-log", "none", "-echo", "screen", "-nocite", + "-var", "zpos", "1.5", "-var", "x", "2"}; ::testing::internal::CaptureStdout(); - lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); + lmp = new LAMMPS(args, MPI_COMM_WORLD); std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_STREQ(output.substr(0, 8).c_str(), "LAMMPS ("); } diff --git a/unittest/cplusplus/test_lammps_class.cpp b/unittest/cplusplus/test_lammps_class.cpp index 64ce1eefb1..6f279fc96c 100644 --- a/unittest/cplusplus/test_lammps_class.cpp +++ b/unittest/cplusplus/test_lammps_class.cpp @@ -21,9 +21,9 @@ protected: LAMMPS *lmp; LAMMPS_plain() : lmp(nullptr) { - const char *args[] = {"LAMMPS_test"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + const char * args[] = {"LAMMPS_test", nullptr}; + char ** argv = (char**)args; + int argc = 1; int flag; MPI_Initialized(&flag); @@ -34,12 +34,10 @@ protected: void SetUp() override { - const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "both", "-nocite"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"LAMMPS_test", "-log", "none", "-echo", "both", "-nocite"}; ::testing::internal::CaptureStdout(); - lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); + lmp = new LAMMPS(args, MPI_COMM_WORLD); std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_THAT(output, StartsWith("LAMMPS (")); } @@ -159,9 +157,9 @@ protected: LAMMPS *lmp; LAMMPS_omp() : lmp(nullptr) { - const char *args[] = {"LAMMPS_test"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + const char * args[] = {"LAMMPS_test", nullptr}; + char ** argv = (char**)args; + int argc = 1; int flag; MPI_Initialized(&flag); @@ -172,15 +170,13 @@ protected: void SetUp() override { - const char *args[] = {"LAMMPS_test", "-log", "none", "-screen", "none", "-echo", "screen", - "-pk", "omp", "2", "neigh", "yes", "-sf", "omp"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"LAMMPS_test", "-log", "none", "-screen", "none", "-echo", "screen", + "-pk", "omp", "2", "neigh", "yes", "-sf", "omp"}; // only run this test fixture with omp suffix if OPENMP package is installed if (LAMMPS::is_installed_pkg("OPENMP")) - lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); + lmp = new LAMMPS(args, MPI_COMM_WORLD); else GTEST_SKIP(); } @@ -242,9 +238,9 @@ protected: LAMMPS *lmp; LAMMPS_kokkos() : lmp(nullptr) { - const char *args[] = {"LAMMPS_test"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + const char * args[] = {"LAMMPS_test", nullptr}; + char ** argv = (char**)args; + int argc = 1; int flag; MPI_Initialized(&flag); @@ -255,15 +251,13 @@ protected: void SetUp() override { - const char *args[] = {"LAMMPS_test", "-log", "none", "-echo", "none", "-screen", "none", - "-k", "on", "t", "1", "-sf", "kk"}; + LAMMPS::argv args = {"LAMMPS_test", "-log", "none", "-echo", "none", "-screen", "none", + "-k", "on", "t", "1", "-sf", "kk"}; if (Info::has_accelerator_feature("KOKKOS", "api", "openmp")) args[10] = "2"; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); if (LAMMPS::is_installed_pkg("KOKKOS")) { ::testing::internal::CaptureStdout(); - lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); + lmp = new LAMMPS(args, MPI_COMM_WORLD); ::testing::internal::GetCapturedStdout(); } else GTEST_SKIP(); @@ -333,12 +327,10 @@ TEST(LAMMPS_init, OpenMP) fputs("\n", fp); fclose(fp); - const char *args[] = {"LAMMPS_init", "-in", "in.lammps_empty", "-log", "none", "-nocite"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"LAMMPS_init", "-in", "in.lammps_empty", "-log", "none", "-nocite"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); + LAMMPS *lmp = new LAMMPS(args, MPI_COMM_WORLD); std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_THAT(output, ContainsRegex(".*using 2 OpenMP thread.*per MPI task.*")); @@ -366,12 +358,10 @@ TEST(LAMMPS_init, NoOpenMP) fclose(fp); platform::unsetenv("OMP_NUM_THREADS"); - const char *args[] = {"LAMMPS_init", "-in", "in.lammps_class_noomp", "-log", "none", "-nocite"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"LAMMPS_init", "-in", "in.lammps_class_noomp", "-log", "none", "-nocite"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); + LAMMPS *lmp = new LAMMPS(args, MPI_COMM_WORLD); std::string output = ::testing::internal::GetCapturedStdout(); EXPECT_THAT(output, ContainsRegex( ".*OMP_NUM_THREADS environment is not set.*Defaulting to 1 thread.*")); diff --git a/unittest/force-styles/test_angle_style.cpp b/unittest/force-styles/test_angle_style.cpp index e9f4a3f7fc..bd0e3d8859 100644 --- a/unittest/force-styles/test_angle_style.cpp +++ b/unittest/force-styles/test_angle_style.cpp @@ -59,11 +59,11 @@ void cleanup_lammps(LAMMPS *lmp, const TestConfig &cfg) delete lmp; } -LAMMPS *init_lammps(int argc, char **argv, const TestConfig &cfg, const bool newton = true) +LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newton = true) { LAMMPS *lmp; - lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); + lmp = new LAMMPS(args, MPI_COMM_WORLD); // check if prerequisite styles are available Info *info = new Info(lmp); @@ -211,11 +211,9 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) void generate_yaml_file(const char *outfile, const TestConfig &config) { // initialize system geometry - const char *args[] = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite"}; + LAMMPS::argv args = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); - LAMMPS *lmp = init_lammps(argc, argv, config); + LAMMPS *lmp = init_lammps(args, config); if (!lmp) { std::cerr << "One or more prerequisite styles are not available " "in this LAMMPS configuration:\n"; @@ -303,13 +301,10 @@ TEST(AngleStyle, plain) { if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -358,7 +353,7 @@ TEST(AngleStyle, plain) if (!verbose) ::testing::internal::CaptureStdout(); cleanup_lammps(lmp, test_config); - lmp = init_lammps(argc, argv, test_config, false); + lmp = init_lammps(args, test_config, false); if (!verbose) ::testing::internal::GetCapturedStdout(); // skip over these tests if newton bond is forced to be on @@ -422,14 +417,11 @@ TEST(AngleStyle, omp) if (!LAMMPS::is_installed_pkg("OPENMP")) GTEST_SKIP(); if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite", - "-pk", "omp", "4", "-sf", "omp"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite", + "-pk", "omp", "4", "-sf", "omp"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -482,7 +474,7 @@ TEST(AngleStyle, omp) if (!verbose) ::testing::internal::CaptureStdout(); cleanup_lammps(lmp, test_config); - lmp = init_lammps(argc, argv, test_config, false); + lmp = init_lammps(args, test_config, false); if (!verbose) ::testing::internal::GetCapturedStdout(); // skip over these tests if newton bond is forced to be on @@ -525,14 +517,11 @@ TEST(AngleStyle, single) { if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite"}; // create a LAMMPS instance with standard settings to detect the number of atom types if (!verbose) ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config); + LAMMPS *lmp = init_lammps(args, test_config); if (!verbose) ::testing::internal::GetCapturedStdout(); if (!lmp) { @@ -672,13 +661,10 @@ TEST(AngleStyle, extract) { if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"AngleStyle", "-log", "none", "-echo", "screen", "-nocite"}; if (!verbose) ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); if (!verbose) ::testing::internal::GetCapturedStdout(); if (!lmp) { diff --git a/unittest/force-styles/test_bond_style.cpp b/unittest/force-styles/test_bond_style.cpp index c723541366..aa99f41f8d 100644 --- a/unittest/force-styles/test_bond_style.cpp +++ b/unittest/force-styles/test_bond_style.cpp @@ -59,11 +59,11 @@ void cleanup_lammps(LAMMPS *lmp, const TestConfig &cfg) delete lmp; } -LAMMPS *init_lammps(int argc, char **argv, const TestConfig &cfg, const bool newton = true) +LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newton = true) { LAMMPS *lmp; - lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); + lmp = new LAMMPS(args, MPI_COMM_WORLD); // check if prerequisite styles are available Info *info = new Info(lmp); @@ -211,11 +211,9 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) void generate_yaml_file(const char *outfile, const TestConfig &config) { // initialize system geometry - const char *args[] = {"BondStyle", "-log", "none", "-echo", "screen", "-nocite"}; + LAMMPS::argv args = {"BondStyle", "-log", "none", "-echo", "screen", "-nocite"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); - LAMMPS *lmp = init_lammps(argc, argv, config); + LAMMPS *lmp = init_lammps(args, config); if (!lmp) { std::cerr << "One or more prerequisite styles are not available " "in this LAMMPS configuration:\n"; @@ -303,13 +301,10 @@ TEST(BondStyle, plain) { if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"BondStyle", "-log", "none", "-echo", "screen", "-nocite"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"BondStyle", "-log", "none", "-echo", "screen", "-nocite"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -358,7 +353,7 @@ TEST(BondStyle, plain) if (!verbose) ::testing::internal::CaptureStdout(); cleanup_lammps(lmp, test_config); - lmp = init_lammps(argc, argv, test_config, false); + lmp = init_lammps(args, test_config, false); if (!verbose) ::testing::internal::GetCapturedStdout(); // skip over these tests if newton bond is forced to be on @@ -424,14 +419,11 @@ TEST(BondStyle, omp) if (!LAMMPS::is_installed_pkg("OPENMP")) GTEST_SKIP(); if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"BondStyle", "-log", "none", "-echo", "screen", "-nocite", - "-pk", "omp", "4", "-sf", "omp"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"BondStyle", "-log", "none", "-echo", "screen", "-nocite", + "-pk", "omp", "4", "-sf", "omp"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -484,7 +476,7 @@ TEST(BondStyle, omp) if (!verbose) ::testing::internal::CaptureStdout(); cleanup_lammps(lmp, test_config); - lmp = init_lammps(argc, argv, test_config, false); + lmp = init_lammps(args, test_config, false); if (!verbose) ::testing::internal::GetCapturedStdout(); // skip over these tests if newton bond is forced to be on @@ -527,14 +519,11 @@ TEST(BondStyle, single) { if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"BondStyle", "-log", "none", "-echo", "screen", "-nocite"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"BondStyle", "-log", "none", "-echo", "screen", "-nocite"}; // create a LAMMPS instance with standard settings to detect the number of atom types if (!verbose) ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config); + LAMMPS *lmp = init_lammps(args, test_config); if (!verbose) ::testing::internal::GetCapturedStdout(); if (!lmp) { @@ -785,13 +774,10 @@ TEST(BondStyle, extract) { if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"BondStyle", "-log", "none", "-echo", "screen", "-nocite"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"BondStyle", "-log", "none", "-echo", "screen", "-nocite"}; if (!verbose) ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); if (!verbose) ::testing::internal::GetCapturedStdout(); if (!lmp) { diff --git a/unittest/force-styles/test_dihedral_style.cpp b/unittest/force-styles/test_dihedral_style.cpp index 2039155644..25690fc33d 100644 --- a/unittest/force-styles/test_dihedral_style.cpp +++ b/unittest/force-styles/test_dihedral_style.cpp @@ -59,11 +59,9 @@ void cleanup_lammps(LAMMPS *lmp, const TestConfig &cfg) delete lmp; } -LAMMPS *init_lammps(int argc, char **argv, const TestConfig &cfg, const bool newton = true) +LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newton = true) { - LAMMPS *lmp; - - lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); + LAMMPS *lmp = new LAMMPS(args, MPI_COMM_WORLD); // check if prerequisite styles are available Info *info = new Info(lmp); @@ -220,11 +218,9 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) void generate_yaml_file(const char *outfile, const TestConfig &config) { // initialize system geometry - const char *args[] = {"DihedralStyle", "-log", "none", "-echo", "screen", "-nocite"}; + LAMMPS::argv args = {"DihedralStyle", "-log", "none", "-echo", "screen", "-nocite"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); - LAMMPS *lmp = init_lammps(argc, argv, config); + LAMMPS *lmp = init_lammps(args, config); if (!lmp) { std::cerr << "One or more prerequisite styles are not available " "in this LAMMPS configuration:\n"; @@ -306,13 +302,10 @@ TEST(DihedralStyle, plain) { if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"DihedralStyle", "-log", "none", "-echo", "screen", "-nocite"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"DihedralStyle", "-log", "none", "-echo", "screen", "-nocite"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -361,7 +354,7 @@ TEST(DihedralStyle, plain) if (!verbose) ::testing::internal::CaptureStdout(); cleanup_lammps(lmp, test_config); - lmp = init_lammps(argc, argv, test_config, false); + lmp = init_lammps(args, test_config, false); if (!verbose) ::testing::internal::GetCapturedStdout(); // skip over these tests if newton bond is forced to be on @@ -427,14 +420,11 @@ TEST(DihedralStyle, omp) if (!LAMMPS::is_installed_pkg("OPENMP")) GTEST_SKIP(); if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"DihedralStyle", "-log", "none", "-echo", "screen", "-nocite", - "-pk", "omp", "4", "-sf", "omp"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"DihedralStyle", "-log", "none", "-echo", "screen", "-nocite", + "-pk", "omp", "4", "-sf", "omp"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -488,7 +478,7 @@ TEST(DihedralStyle, omp) if (!verbose) ::testing::internal::CaptureStdout(); cleanup_lammps(lmp, test_config); - lmp = init_lammps(argc, argv, test_config, false); + lmp = init_lammps(args, test_config, false); if (!verbose) ::testing::internal::GetCapturedStdout(); // skip over these tests if newton bond is forced to be on diff --git a/unittest/force-styles/test_fix_timestep.cpp b/unittest/force-styles/test_fix_timestep.cpp index b65eab2049..2d2c2fa0b8 100644 --- a/unittest/force-styles/test_fix_timestep.cpp +++ b/unittest/force-styles/test_fix_timestep.cpp @@ -61,11 +61,11 @@ void cleanup_lammps(LAMMPS *lmp, const TestConfig &cfg) delete lmp; } -LAMMPS *init_lammps(int argc, char **argv, const TestConfig &cfg, const bool use_respa = false) +LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool use_respa = false) { LAMMPS *lmp; - lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); + lmp = new LAMMPS(args, MPI_COMM_WORLD); // check if prerequisite styles are available Info *info = new Info(lmp); @@ -169,11 +169,8 @@ void restart_lammps(LAMMPS *lmp, const TestConfig &cfg, bool use_rmass, bool use void generate_yaml_file(const char *outfile, const TestConfig &config) { // initialize system geometry - const char *args[] = {"FixIntegrate", "-log", "none", "-echo", "screen", "-nocite"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); - LAMMPS *lmp = init_lammps(argc, argv, config); + LAMMPS::argv args = {"FixIntegrate", "-log", "none", "-echo", "screen", "-nocite"}; + LAMMPS *lmp = init_lammps(args, config); if (!lmp) { std::cerr << "One or more prerequisite styles are not available " "in this LAMMPS configuration:\n"; @@ -252,13 +249,10 @@ TEST(FixTimestep, plain) if (test_config.skip_tests.count("static")) GTEST_SKIP(); #endif - const char *args[] = {"FixTimestep", "-log", "none", "-echo", "screen", "-nocite"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"FixTimestep", "-log", "none", "-echo", "screen", "-nocite"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config); + LAMMPS *lmp = init_lammps(args, test_config); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -420,7 +414,7 @@ TEST(FixTimestep, plain) if (!verbose) ::testing::internal::GetCapturedStdout(); ::testing::internal::CaptureStdout(); - lmp = init_lammps(argc, argv, test_config, true); + lmp = init_lammps(args, test_config, true); output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -554,14 +548,12 @@ TEST(FixTimestep, omp) if (test_config.skip_tests.count("static")) GTEST_SKIP(); #endif - const char *args[] = {"FixTimestep", "-log", "none", "-echo", "screen", "-nocite", - "-pk", "omp", "4", "-sf", "omp"}; + LAMMPS::argv args = {"FixTimestep", "-log", "none", "-echo", "screen", "-nocite", + "-pk", "omp", "4", "-sf", "omp"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config); + LAMMPS *lmp = init_lammps(args, test_config); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -723,7 +715,7 @@ TEST(FixTimestep, omp) if (!verbose) ::testing::internal::GetCapturedStdout(); ::testing::internal::CaptureStdout(); - lmp = init_lammps(argc, argv, test_config, true); + lmp = init_lammps(args, test_config, true); output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; diff --git a/unittest/force-styles/test_improper_style.cpp b/unittest/force-styles/test_improper_style.cpp index 259bd9008d..b4096df868 100644 --- a/unittest/force-styles/test_improper_style.cpp +++ b/unittest/force-styles/test_improper_style.cpp @@ -59,11 +59,11 @@ void cleanup_lammps(LAMMPS *lmp, const TestConfig &cfg) delete lmp; } -LAMMPS *init_lammps(int argc, char **argv, const TestConfig &cfg, const bool newton = true) +LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newton = true) { LAMMPS *lmp; - lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); + lmp = new LAMMPS(args, MPI_COMM_WORLD); // check if prerequisite styles are available Info *info = new Info(lmp); @@ -211,11 +211,9 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) void generate_yaml_file(const char *outfile, const TestConfig &config) { // initialize system geometry - const char *args[] = {"ImproperStyle", "-log", "none", "-echo", "screen", "-nocite"}; + LAMMPS::argv args = {"ImproperStyle", "-log", "none", "-echo", "screen", "-nocite"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); - LAMMPS *lmp = init_lammps(argc, argv, config); + LAMMPS *lmp = init_lammps(args, config); if (!lmp) { std::cerr << "One or more prerequisite styles are not available " "in this LAMMPS configuration:\n"; @@ -297,13 +295,10 @@ TEST(ImproperStyle, plain) { if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"ImproperStyle", "-log", "none", "-echo", "screen", "-nocite"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"ImproperStyle", "-log", "none", "-echo", "screen", "-nocite"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -352,7 +347,7 @@ TEST(ImproperStyle, plain) if (!verbose) ::testing::internal::CaptureStdout(); cleanup_lammps(lmp, test_config); - lmp = init_lammps(argc, argv, test_config, false); + lmp = init_lammps(args, test_config, false); if (!verbose) ::testing::internal::GetCapturedStdout(); // skip over these tests if newton bond is forced to be on @@ -418,14 +413,11 @@ TEST(ImproperStyle, omp) if (!LAMMPS::is_installed_pkg("OPENMP")) GTEST_SKIP(); if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"ImproperStyle", "-log", "none", "-echo", "screen", "-nocite", - "-pk", "omp", "4", "-sf", "omp"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"ImproperStyle", "-log", "none", "-echo", "screen", "-nocite", + "-pk", "omp", "4", "-sf", "omp"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -479,7 +471,7 @@ TEST(ImproperStyle, omp) if (!verbose) ::testing::internal::CaptureStdout(); cleanup_lammps(lmp, test_config); - lmp = init_lammps(argc, argv, test_config, false); + lmp = init_lammps(args, test_config, false); if (!verbose) ::testing::internal::GetCapturedStdout(); // skip over these tests if newton bond is forced to be on diff --git a/unittest/force-styles/test_pair_style.cpp b/unittest/force-styles/test_pair_style.cpp index f44a6e61d3..8ad2ce9aaa 100644 --- a/unittest/force-styles/test_pair_style.cpp +++ b/unittest/force-styles/test_pair_style.cpp @@ -61,11 +61,11 @@ void cleanup_lammps(LAMMPS *lmp, const TestConfig &cfg) delete lmp; } -LAMMPS *init_lammps(int argc, char **argv, const TestConfig &cfg, const bool newton = true) +LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newton = true) { LAMMPS *lmp; - lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); + lmp = new LAMMPS(args, MPI_COMM_WORLD); // check if prerequisite styles are available Info *info = new Info(lmp); @@ -225,11 +225,9 @@ void data_lammps(LAMMPS *lmp, const TestConfig &cfg) void generate_yaml_file(const char *outfile, const TestConfig &config) { // initialize system geometry - const char *args[] = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite"}; + LAMMPS::argv args = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite"}; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); - LAMMPS *lmp = init_lammps(argc, argv, config); + LAMMPS *lmp = init_lammps(args, config); if (!lmp) { std::cerr << "One or more prerequisite styles are not available " "in this LAMMPS configuration:\n"; @@ -323,13 +321,10 @@ TEST(PairStyle, plain) { if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -388,7 +383,7 @@ TEST(PairStyle, plain) if (!verbose) ::testing::internal::CaptureStdout(); cleanup_lammps(lmp, test_config); - lmp = init_lammps(argc, argv, test_config, false); + lmp = init_lammps(args, test_config, false); if (!verbose) ::testing::internal::GetCapturedStdout(); // skip over these tests if newton pair is forced to be on @@ -469,7 +464,7 @@ TEST(PairStyle, plain) if (pair->respa_enable) { if (!verbose) ::testing::internal::CaptureStdout(); cleanup_lammps(lmp, test_config); - lmp = init_lammps(argc, argv, test_config, false); + lmp = init_lammps(args, test_config, false); lmp->input->one("run_style respa 2 1 inner 1 4.8 5.5 outer 2"); run_lammps(lmp); if (!verbose) ::testing::internal::GetCapturedStdout(); @@ -501,17 +496,14 @@ TEST(PairStyle, omp) if (!LAMMPS::is_installed_pkg("OPENMP")) GTEST_SKIP(); if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite", - "-pk", "omp", "4", "-sf", "omp"}; + LAMMPS::argv args = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite", + "-pk", "omp", "4", "-sf", "omp"}; // cannot run dpd styles with more than 1 thread due to using multiple pRNGs if (utils::strmatch(test_config.pair_style, "^dpd")) args[8] = "1"; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); - ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -570,7 +562,7 @@ TEST(PairStyle, omp) if (!verbose) ::testing::internal::CaptureStdout(); cleanup_lammps(lmp, test_config); - lmp = init_lammps(argc, argv, test_config, false); + lmp = init_lammps(args, test_config, false); if (!verbose) ::testing::internal::GetCapturedStdout(); pair = lmp->force->pair; @@ -626,8 +618,8 @@ TEST(PairStyle, kokkos_omp) if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); if (!Info::has_accelerator_feature("KOKKOS", "api", "openmp")) GTEST_SKIP(); - const char *args[] = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite", - "-k", "on", "t", "4", "-sf", "kk"}; + LAMMPS::argv args = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite", + "-k", "on", "t", "4", "-sf", "kk"}; // cannot run dpd styles in plain or hybrid with more than 1 thread due to using multiple pRNGs if (utils::strmatch(test_config.pair_style, "^dpd") || @@ -642,11 +634,8 @@ TEST(PairStyle, kokkos_omp) utils::strmatch(test_config.pair_style, " pace")) args[9] = "1"; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); - ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -704,7 +693,7 @@ TEST(PairStyle, kokkos_omp) if (lmp->force->newton_pair == 0) { if (!verbose) ::testing::internal::CaptureStdout(); cleanup_lammps(lmp, test_config); - lmp = init_lammps(argc, argv, test_config, false); + lmp = init_lammps(args, test_config, false); if (!verbose) ::testing::internal::GetCapturedStdout(); pair = lmp->force->pair; @@ -767,22 +756,19 @@ TEST(PairStyle, gpu) (!Info::has_fft_single_support())) GTEST_SKIP(); - const char *args_neigh[] = {"PairStyle", "-log", "none", "-echo", - "screen", "-nocite", "-sf", "gpu"}; - const char *args_noneigh[] = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite", "-sf", - "gpu", "-pk", "gpu", "0", "neigh", "no"}; - - char **argv = (char **)args_neigh; - int argc = sizeof(args_neigh) / sizeof(char *); + LAMMPS::argv args_neigh = {"PairStyle", "-log", "none", "-echo", + "screen", "-nocite", "-sf", "gpu"}; + LAMMPS::argv args_noneigh = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite", "-sf", + "gpu", "-pk", "gpu", "0", "neigh", "no"}; + LAMMPS::argv args = args_neigh; // cannot use GPU neighbor list with hybrid pair style (yet) if (test_config.pair_style.substr(0, 6) == "hybrid") { - argv = (char **)args_noneigh; - argc = sizeof(args_noneigh) / sizeof(char *); + args = args_noneigh; } ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, false); + LAMMPS *lmp = init_lammps(args, test_config, false); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -854,18 +840,15 @@ TEST(PairStyle, intel) if (!LAMMPS::is_installed_pkg("INTEL")) GTEST_SKIP(); if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite", - "-pk", "intel", "0", "mode", "double", "omp", - "4", "lrt", "no", "-sf", "intel"}; + LAMMPS::argv args = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite", + "-pk", "intel", "0", "mode", "double", "omp", + "4", "lrt", "no", "-sf", "intel"}; // cannot use more than 1 thread for dpd styles due to pRNG if (utils::strmatch(test_config.pair_style, "^dpd")) args[12] = "1"; - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); - ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -942,13 +925,10 @@ TEST(PairStyle, opt) if (!LAMMPS::is_installed_pkg("OPT")) GTEST_SKIP(); if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite", "-sf", "opt"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite", "-sf", "opt"}; ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config); + LAMMPS *lmp = init_lammps(args, test_config); std::string output = ::testing::internal::GetCapturedStdout(); if (verbose) std::cout << output; @@ -1025,17 +1005,14 @@ TEST(PairStyle, single) { if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite"}; // need to add this dependency test_config.prerequisites.emplace_back("atom", "full"); // create a LAMMPS instance with standard settings to detect the number of atom types if (!verbose) ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config); + LAMMPS *lmp = init_lammps(args, test_config); if (!verbose) ::testing::internal::GetCapturedStdout(); if (!lmp) { @@ -1276,13 +1253,10 @@ TEST(PairStyle, extract) { if (test_config.skip_tests.count(test_info_->name())) GTEST_SKIP(); - const char *args[] = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite"}; - - char **argv = (char **)args; - int argc = sizeof(args) / sizeof(char *); + LAMMPS::argv args = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite"}; if (!verbose) ::testing::internal::CaptureStdout(); - LAMMPS *lmp = init_lammps(argc, argv, test_config, true); + LAMMPS *lmp = init_lammps(args, test_config, true); if (!verbose) ::testing::internal::GetCapturedStdout(); if (!lmp) { diff --git a/unittest/fortran/wrap_extract_variable.cpp b/unittest/fortran/wrap_extract_variable.cpp index 1082a381bb..8c81897c0a 100644 --- a/unittest/fortran/wrap_extract_variable.cpp +++ b/unittest/fortran/wrap_extract_variable.cpp @@ -71,10 +71,10 @@ protected: // clang-format off const char *args[] = { "LAMMPS_Fortran_test", "-l", "none", "-echo", "screen", "-nocite", - "-var", "input_dir", input_dir, "-var", "zpos", "1.5", "-var", "x", "2" }; + "-var", "input_dir", input_dir, "-var", "zpos", "1.5", "-var", "x", "2", nullptr }; // clang-format on char **argv = (char **)args; - int argc = sizeof(args) / sizeof(const char *); + int argc = (sizeof(args) / sizeof(const char *)) - 1; ::testing::internal::CaptureStdout(); lmp = (LAMMPS_NS::LAMMPS *)f_lammps_with_c_args(argc, argv); diff --git a/unittest/testing/core.h b/unittest/testing/core.h index 272d1d21c5..6e7feb4409 100644 --- a/unittest/testing/core.h +++ b/unittest/testing/core.h @@ -115,31 +115,21 @@ public: } protected: - std::string testbinary = "LAMMPSTest"; - std::vector args = {"-log", "none", "-echo", "screen", "-nocite"}; + std::string testbinary = "LAMMPSTest"; + LAMMPS::argv args = {"-log", "none", "-echo", "screen", "-nocite"}; LAMMPS *lmp; Info *info; void SetUp() override { - int argc = args.size() + 1; - char **argv = new char *[argc]; - argv[0] = LAMMPS_NS::utils::strdup(testbinary); - for (int i = 1; i < argc; i++) { - argv[i] = LAMMPS_NS::utils::strdup(args[i - 1]); - } + LAMMPS::argv full_args = {testbinary}; + full_args.insert(full_args.end(), args.begin(), args.end()); HIDE_OUTPUT([&] { - lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD); + lmp = new LAMMPS(full_args, MPI_COMM_WORLD); info = new Info(lmp); }); InitSystem(); - - for (int i = 0; i < argc; i++) { - delete[] argv[i]; - argv[i] = nullptr; - } - delete[] argv; } virtual void InitSystem() {} From 4e94e697ec2c25a40337897f2ca06bf9a156012a Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Tue, 7 Nov 2023 17:55:32 -0700 Subject: [PATCH 50/93] bugfix: make copy of exename --- src/lammps.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lammps.cpp b/src/lammps.cpp index 35824a6efb..ab20aedea7 100644 --- a/src/lammps.cpp +++ b/src/lammps.cpp @@ -221,7 +221,7 @@ LAMMPS::LAMMPS(int narg, char **arg, MPI_Comm communicator) : suffix = suffix2 = nullptr; suffix_enable = 0; pair_only_flag = 0; - if (arg) exename = arg[0]; + if (arg) exename = utils::strdup(arg[0]); else exename = nullptr; packargs = nullptr; num_package = 0; @@ -813,6 +813,7 @@ LAMMPS::~LAMMPS() delete memory; delete pkg_lists; + delete[] exename; } /* ---------------------------------------------------------------------- From 990c07a133808a086e6eac7f91c00942633374f5 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Thu, 9 Nov 2023 20:29:14 -0700 Subject: [PATCH 51/93] bugfix: correctly build argv when using Python interface --- python/lammps/core.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/python/lammps/core.py b/python/lammps/core.py index 84a80e77a3..1ff123760b 100644 --- a/python/lammps/core.py +++ b/python/lammps/core.py @@ -379,8 +379,9 @@ class lammps(object): for i in range(narg): if type(cmdargs[i]) is str: cmdargs[i] = cmdargs[i].encode() - cargs = (c_char_p*narg)(*cmdargs) - self.lib.lammps_open.argtypes = [c_int, c_char_p*narg, MPI_Comm, c_void_p] + cargs = (c_char_p*(narg+1))(*cmdargs) + cargs[narg] = None + self.lib.lammps_open.argtypes = [c_int, c_char_p*(narg+1), MPI_Comm, c_void_p] else: self.lib.lammps_open.argtypes = [c_int, c_char_p, MPI_Comm, c_void_p] @@ -399,8 +400,9 @@ class lammps(object): for i in range(narg): if type(cmdargs[i]) is str: cmdargs[i] = cmdargs[i].encode() - cargs = (c_char_p*narg)(*cmdargs) - self.lib.lammps_open_no_mpi.argtypes = [c_int, c_char_p*narg, c_void_p] + cargs = (c_char_p*(narg+1))(*cmdargs) + cargs[narg] = None + self.lib.lammps_open_no_mpi.argtypes = [c_int, c_char_p*(narg+1), c_void_p] self.lmp = c_void_p(self.lib.lammps_open_no_mpi(narg,cargs,None)) else: self.lib.lammps_open_no_mpi.argtypes = [c_int, c_char_p, c_void_p] From b6c031fd035f1d702cfb04f8b5dac6ecb3c17c7a Mon Sep 17 00:00:00 2001 From: yury-lysogorskiy Date: Tue, 7 Nov 2023 16:46:47 +0100 Subject: [PATCH 52/93] Update pair_pace_extrapolation.cpp BUGFIX: pair_pace_extrapolation: setup flag aceimpl->ace->compute_projections = true before computing extrapolation grade --- src/ML-PACE/pair_pace_extrapolation.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ML-PACE/pair_pace_extrapolation.cpp b/src/ML-PACE/pair_pace_extrapolation.cpp index 8a0116526a..dc0fb1848b 100644 --- a/src/ML-PACE/pair_pace_extrapolation.cpp +++ b/src/ML-PACE/pair_pace_extrapolation.cpp @@ -202,8 +202,10 @@ void PairPACEExtrapolation::compute(int eflag, int vflag) // jnum(0) = 50 // jlist(neigh ind of 0-atom) = [1,2,10,7,99,25, .. 50 element in total] try { - if (flag_compute_extrapolation_grade) + if (flag_compute_extrapolation_grade) { + aceimpl->ace->compute_projections = true; aceimpl->ace->compute_atom(i, x, type, jnum, jlist); + } else aceimpl->rec_ace->compute_atom(i, x, type, jnum, jlist); } catch (std::exception &e) { From 08eae40f9a4cf7bfa59df4cca48ef95050d849a9 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 15 Nov 2023 07:10:55 -0500 Subject: [PATCH 53/93] backport enforce2d with fix rigid bugfix --- src/KOKKOS/fix_enforce2d_kokkos.cpp | 20 +- src/OPENMP/fix_rigid_nh_omp.cpp | 77 ++- src/OPENMP/fix_rigid_nh_omp.h | 8 +- src/OPENMP/fix_rigid_omp.cpp | 121 +++-- src/OPENMP/fix_rigid_omp.h | 6 +- src/OPENMP/fix_rigid_small_omp.cpp | 106 ++-- src/OPENMP/fix_rigid_small_omp.h | 6 +- src/RIGID/fix_rigid.cpp | 797 +++++++++++++++------------- src/RIGID/fix_rigid.h | 6 +- src/RIGID/fix_rigid_nh.cpp | 186 +++---- src/RIGID/fix_rigid_nh.h | 7 +- src/RIGID/fix_rigid_nh_small.cpp | 209 +++----- src/RIGID/fix_rigid_nh_small.h | 6 +- src/RIGID/fix_rigid_small.cpp | 518 +++++++++--------- src/RIGID/fix_rigid_small.h | 5 +- src/fix.cpp | 1 - src/fix.h | 2 - src/fix_enforce2d.cpp | 36 +- src/fix_enforce2d.h | 4 - 19 files changed, 1067 insertions(+), 1054 deletions(-) diff --git a/src/KOKKOS/fix_enforce2d_kokkos.cpp b/src/KOKKOS/fix_enforce2d_kokkos.cpp index 11402e4568..24cf307827 100644 --- a/src/KOKKOS/fix_enforce2d_kokkos.cpp +++ b/src/KOKKOS/fix_enforce2d_kokkos.cpp @@ -17,15 +17,14 @@ ------------------------------------------------------------------------- */ #include "fix_enforce2d_kokkos.h" + #include "atom_masks.h" #include "atom_kokkos.h" #include "comm.h" #include "error.h" - using namespace LAMMPS_NS; - template FixEnforce2DKokkos::FixEnforce2DKokkos(LAMMPS *lmp, int narg, char **arg) : FixEnforce2D(lmp, narg, arg) @@ -34,21 +33,16 @@ FixEnforce2DKokkos::FixEnforce2DKokkos(LAMMPS *lmp, int narg, char * atomKK = (AtomKokkos *) atom; execution_space = ExecutionSpaceFromDevice::space; - datamask_read = V_MASK | F_MASK | OMEGA_MASK | MASK_MASK - | TORQUE_MASK | ANGMOM_MASK; - - datamask_modify = V_MASK | F_MASK | OMEGA_MASK - | TORQUE_MASK | ANGMOM_MASK; + datamask_read = V_MASK | F_MASK | OMEGA_MASK | MASK_MASK | TORQUE_MASK | ANGMOM_MASK; + datamask_modify = V_MASK | F_MASK | OMEGA_MASK | TORQUE_MASK | ANGMOM_MASK; } - template void FixEnforce2DKokkos::setup(int vflag) { post_force(vflag); } - template void FixEnforce2DKokkos::post_force(int /*vflag*/) { @@ -66,7 +60,6 @@ void FixEnforce2DKokkos::post_force(int /*vflag*/) if (atomKK->torque_flag) torque = atomKK->k_torque.view(); - mask = atomKK->k_mask.view(); int nlocal = atomKK->nlocal; @@ -125,13 +118,6 @@ void FixEnforce2DKokkos::post_force(int /*vflag*/) copymode = 0; atomKK->modified(execution_space,datamask_modify); - - for (int m = 0; m < nfixlist; m++) { - atomKK->sync(flist[m]->execution_space,flist[m]->datamask_read); - flist[m]->enforce2d(); - atomKK->modified(flist[m]->execution_space,flist[m]->datamask_modify); - } - } diff --git a/src/OPENMP/fix_rigid_nh_omp.cpp b/src/OPENMP/fix_rigid_nh_omp.cpp index 2f1b81fd5b..19e5d4f240 100644 --- a/src/OPENMP/fix_rigid_nh_omp.cpp +++ b/src/OPENMP/fix_rigid_nh_omp.cpp @@ -211,16 +211,31 @@ void FixRigidNHOMP::initial_integrate(int vflag) // set coords/orient and velocity/rotation of atoms in rigid bodies // from quarternion and omega - if (triclinic) - if (evflag) - set_xv_thr<1,1>(); - else - set_xv_thr<1,0>(); - else - if (evflag) - set_xv_thr<0,1>(); - else - set_xv_thr<0,0>(); + if (domain->dimension == 2) { + if (triclinic) { + if (evflag) + set_xv_thr<1,1,2>(); + else + set_xv_thr<1,0,2>(); + } else { + if (evflag) + set_xv_thr<0,1,2>(); + else + set_xv_thr<0,0,2>(); + } + } else { + if (triclinic) { + if (evflag) + set_xv_thr<1,1,3>(); + else + set_xv_thr<1,0,3>(); + } else { + if (evflag) + set_xv_thr<0,1,3>(); + else + set_xv_thr<0,0,3>(); + } + } // remap simulation box by full step // redo KSpace coeffs since volume has changed @@ -323,11 +338,13 @@ void FixRigidNHOMP::compute_forces_and_torques() // a few atoms each. so we loop over all atoms for all threads // and then each thread only processes some bodies. - const int nthreads=comm->nthreads; memset(&sum[0][0],0,6*nbody*sizeof(double)); #if defined(_OPENMP) + const int nthreads=comm->nthreads; #pragma omp parallel LMP_DEFAULT_NONE +#else + const int nthreads=1; #endif { #if defined(_OPENMP) @@ -503,13 +520,23 @@ void FixRigidNHOMP::final_integrate() // virial is already setup from initial_integrate // triclinic only matters for virial calculation. - if (evflag) - if (triclinic) - set_v_thr<1,1>(); + if (domain->dimension == 2) { + if (evflag) + if (triclinic) + set_v_thr<1,1,2>(); + else + set_v_thr<0,1,2>(); else - set_v_thr<0,1>(); - else - set_v_thr<0,0>(); + set_v_thr<0,0,2>(); + } else { + if (evflag) + if (triclinic) + set_v_thr<1,1,3>(); + else + set_v_thr<0,1,3>(); + else + set_v_thr<0,0,3>(); + } // compute current temperature if (tcomputeflag) t_current = temperature->compute_scalar(); @@ -558,9 +585,7 @@ void FixRigidNHOMP::remap() domain->x2lamda(x[i],x[i]); } - if (nrigid) - for (int i = 0; i < nrigidfix; i++) - modify->fix[rfix[i]]->deform(0); + for (auto &ifix : rfix) ifix->deform(0); // reset global and local box to new size/shape @@ -590,9 +615,7 @@ void FixRigidNHOMP::remap() domain->lamda2x(x[i],x[i]); } - if (nrigid) - for (int i = 0; i< nrigidfix; i++) - modify->fix[rfix[i]]->deform(1); + for (auto &ifix : rfix) ifix->deform(1); } /* ---------------------------------------------------------------------- @@ -603,7 +626,7 @@ void FixRigidNHOMP::remap() NOTE: this needs to be kept in sync with FixRigidOMP ------------------------------------------------------------------------- */ -template +template void FixRigidNHOMP::set_xv_thr() { auto * _noalias const x = (dbl3_t *) atom->x[0]; @@ -665,6 +688,8 @@ void FixRigidNHOMP::set_xv_thr() v[i].y = omegai.z*x[i].x - omegai.x*x[i].z + vcmi.y; v[i].z = omegai.x*x[i].y - omegai.y*x[i].x + vcmi.z; + if (DIMENSION == 2) x[i].z = v[i].z = 0.0; + // add center of mass to displacement // map back into periodic box via xbox,ybox,zbox // for triclinic, add in box tilt factors as well @@ -803,7 +828,7 @@ void FixRigidNHOMP::set_xv_thr() NOTE: this needs to be kept in sync with FixRigidOMP ------------------------------------------------------------------------- */ -template +template void FixRigidNHOMP::set_v_thr() { auto * _noalias const x = (dbl3_t *) atom->x[0]; @@ -852,6 +877,8 @@ void FixRigidNHOMP::set_v_thr() v[i].y = omegai.z*delta[0] - omegai.x*delta[2] + vcmi.y; v[i].z = omegai.x*delta[1] - omegai.y*delta[0] + vcmi.z; + if (DIMENSION == 2) v[i].z = 0.0; + // virial = unwrapped coords dotted into body constraint force // body constraint force = implied force due to v change minus f external // assume f does not include forces internal to body diff --git a/src/OPENMP/fix_rigid_nh_omp.h b/src/OPENMP/fix_rigid_nh_omp.h index 6b70841058..169bef706f 100644 --- a/src/OPENMP/fix_rigid_nh_omp.h +++ b/src/OPENMP/fix_rigid_nh_omp.h @@ -24,14 +24,14 @@ class FixRigidNHOMP : public FixRigidNH { void initial_integrate(int) override; void final_integrate() override; - virtual void remap(); + void remap() override; protected: - virtual void compute_forces_and_torques(); + void compute_forces_and_torques() override; private: // copied from FixRigidOMP - template void set_xv_thr(); - template void set_v_thr(); + template void set_xv_thr(); + template void set_v_thr(); }; } // namespace LAMMPS_NS diff --git a/src/OPENMP/fix_rigid_omp.cpp b/src/OPENMP/fix_rigid_omp.cpp index de381415a0..75794b3419 100644 --- a/src/OPENMP/fix_rigid_omp.cpp +++ b/src/OPENMP/fix_rigid_omp.cpp @@ -16,33 +16,35 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ -#include "omp_compat.h" #include "fix_rigid_omp.h" -#include -#include #include "atom.h" #include "atom_vec_ellipsoid.h" #include "atom_vec_line.h" #include "atom_vec_tri.h" #include "comm.h" -#include "error.h" #include "domain.h" +#include "error.h" +#include "math_const.h" +#include "math_extra.h" +#include "rigid_const.h" + +#include +#include #if defined(_OPENMP) #include #endif - -#include "math_extra.h" -#include "math_const.h" -#include "rigid_const.h" +#include "omp_compat.h" using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; using namespace RigidConst; -typedef struct { double x,y,z; } dbl3_t; +typedef struct { + double x, y, z; +} dbl3_t; /* ---------------------------------------------------------------------- */ @@ -77,13 +79,11 @@ void FixRigidOMP::initial_integrate(int vflag) // returns new normalized quaternion, also updated omega at 1/2 step // update ex,ey,ez to reflect new quaternion - MathExtra::angmom_to_omega(angmom[ibody],ex_space[ibody],ey_space[ibody], - ez_space[ibody],inertia[ibody],omega[ibody]); - MathExtra::richardson(quat[ibody],angmom[ibody],omega[ibody], - inertia[ibody],dtq); - MathExtra::q_to_exyz(quat[ibody], - ex_space[ibody],ey_space[ibody],ez_space[ibody]); - } // end of omp parallel for + MathExtra::angmom_to_omega(angmom[ibody], ex_space[ibody], ey_space[ibody], ez_space[ibody], + inertia[ibody], omega[ibody]); + MathExtra::richardson(quat[ibody], angmom[ibody], omega[ibody], inertia[ibody], dtq); + MathExtra::q_to_exyz(quat[ibody], ex_space[ibody], ey_space[ibody], ez_space[ibody]); + } // end of omp parallel for // virial setup before call to set_xv @@ -92,16 +92,32 @@ void FixRigidOMP::initial_integrate(int vflag) // set coords/orient and velocity/rotation of atoms in rigid bodies // from quarternion and omega - if (triclinic) - if (evflag) - set_xv_thr<1,1>(); - else - set_xv_thr<1,0>(); - else - if (evflag) - set_xv_thr<0,1>(); - else - set_xv_thr<0,0>(); + if (domain->dimension == 2) { + if (triclinic) { + if (evflag) + set_xv_thr<1,1,2>(); + else + set_xv_thr<1,0,2>(); + } else { + if (evflag) + set_xv_thr<0,1,2>(); + else + set_xv_thr<0,0,2>(); + } + } else { + + if (triclinic) { + if (evflag) + set_xv_thr<1,1,3>(); + else + set_xv_thr<1,0,3>(); + } else { + if (evflag) + set_xv_thr<0,1,3>(); + else + set_xv_thr<0,0,3>(); + } + } } /* ---------------------------------------------------------------------- */ @@ -152,7 +168,7 @@ void FixRigidOMP::compute_forces_and_torques() } else if (rstyle == GROUP) { - // we likely have only a rather number of groups so we loops + // we likely have a rather small number of groups so we loop // over bodies and thread over all atoms for each of them. for (int ib = 0; ib < nbody; ++ib) { @@ -196,11 +212,13 @@ void FixRigidOMP::compute_forces_and_torques() // a few atoms each. so we loop over all atoms for all threads // and then each thread only processes some bodies. - const int nthreads=comm->nthreads; memset(&sum[0][0],0,6*nbody*sizeof(double)); #if defined(_OPENMP) + const int nthreads=comm->nthreads; #pragma omp parallel LMP_DEFAULT_NONE +#else + const int nthreads=1; #endif { #if defined(_OPENMP) @@ -250,12 +268,12 @@ void FixRigidOMP::compute_forces_and_torques() #pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int ibody = 0; ibody < nbody; ibody++) { - fcm[ibody][0] = all[ibody][0] + langextra[ibody][0]; - fcm[ibody][1] = all[ibody][1] + langextra[ibody][1]; - fcm[ibody][2] = all[ibody][2] + langextra[ibody][2]; - torque[ibody][0] = all[ibody][3] + langextra[ibody][3]; - torque[ibody][1] = all[ibody][4] + langextra[ibody][4]; - torque[ibody][2] = all[ibody][5] + langextra[ibody][5]; + fcm[ibody][0] = all[ibody][0] + fflag[ibody][0]*langextra[ibody][0]; + fcm[ibody][1] = all[ibody][1] + fflag[ibody][1]*langextra[ibody][1]; + fcm[ibody][2] = all[ibody][2] + fflag[ibody][2]*langextra[ibody][2]; + torque[ibody][0] = all[ibody][3] + tflag[ibody][0]*langextra[ibody][3]; + torque[ibody][1] = all[ibody][4] + tflag[ibody][1]*langextra[ibody][4]; + torque[ibody][2] = all[ibody][5] + tflag[ibody][2]*langextra[ibody][5]; } // add gravity force to COM of each body @@ -277,6 +295,7 @@ void FixRigidOMP::compute_forces_and_torques() void FixRigidOMP::final_integrate() { if (!earlyflag) compute_forces_and_torques(); + if (domain->dimension == 2) enforce2d(); // update vcm and angmom @@ -306,13 +325,27 @@ void FixRigidOMP::final_integrate() // virial is already setup from initial_integrate // triclinic only matters for virial calculation. - if (evflag) - if (triclinic) - set_v_thr<1,1>(); +#if defined(_OPENMP) + if (domain->dimension == 2) { + if (evflag) + if (triclinic) + set_v_thr<1,1,2>(); + else + set_v_thr<0,1,2>(); else - set_v_thr<0,1>(); - else - set_v_thr<0,0>(); + set_v_thr<0,0,2>(); + } else { + if (evflag) + if (triclinic) + set_v_thr<1,1,3>(); + else + set_v_thr<0,1,3>(); + else + set_v_thr<0,0,3>(); + } +#else + set_v(); +#endif } /* ---------------------------------------------------------------------- @@ -323,7 +356,7 @@ void FixRigidOMP::final_integrate() NOTE: this needs to be kept in sync with FixRigidNHOMP ------------------------------------------------------------------------- */ -template +template void FixRigidOMP::set_xv_thr() { auto * _noalias const x = (dbl3_t *) atom->x[0]; @@ -385,6 +418,8 @@ void FixRigidOMP::set_xv_thr() v[i].y = omegai.z*x[i].x - omegai.x*x[i].z + vcmi.y; v[i].z = omegai.x*x[i].y - omegai.y*x[i].x + vcmi.z; + if (DIMENSION == 2) x[i].z = v[i].z = 0.0; + // add center of mass to displacement // map back into periodic box via xbox,ybox,zbox // for triclinic, add in box tilt factors as well @@ -523,7 +558,7 @@ void FixRigidOMP::set_xv_thr() NOTE: this needs to be kept in sync with FixRigidNHOMP ------------------------------------------------------------------------- */ -template +template void FixRigidOMP::set_v_thr() { auto * _noalias const x = (dbl3_t *) atom->x[0]; @@ -572,6 +607,8 @@ void FixRigidOMP::set_v_thr() v[i].y = omegai.z*delta[0] - omegai.x*delta[2] + vcmi.y; v[i].z = omegai.x*delta[1] - omegai.y*delta[0] + vcmi.z; + if (DIMENSION == 2) v[i].z = 0.0; + // virial = unwrapped coords dotted into body constraint force // body constraint force = implied force due to v change minus f external // assume f does not include forces internal to body diff --git a/src/OPENMP/fix_rigid_omp.h b/src/OPENMP/fix_rigid_omp.h index 679dff7508..b74b808544 100644 --- a/src/OPENMP/fix_rigid_omp.h +++ b/src/OPENMP/fix_rigid_omp.h @@ -32,11 +32,11 @@ class FixRigidOMP : public FixRigid { void final_integrate() override; protected: - virtual void compute_forces_and_torques(); + void compute_forces_and_torques() override; private: - template void set_xv_thr(); - template void set_v_thr(); + template void set_xv_thr(); + template void set_v_thr(); }; } // namespace LAMMPS_NS diff --git a/src/OPENMP/fix_rigid_small_omp.cpp b/src/OPENMP/fix_rigid_small_omp.cpp index e11b98b7e1..59fd274f95 100644 --- a/src/OPENMP/fix_rigid_small_omp.cpp +++ b/src/OPENMP/fix_rigid_small_omp.cpp @@ -1,4 +1,3 @@ -// clang-format off /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories @@ -16,31 +15,36 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ -#include "omp_compat.h" #include "fix_rigid_small_omp.h" -#include + #include "atom.h" #include "atom_vec_ellipsoid.h" #include "atom_vec_line.h" #include "atom_vec_tri.h" #include "comm.h" #include "domain.h" +#include "math_const.h" +#include "math_extra.h" +#include "rigid_const.h" + +#include + +#include "omp_compat.h" #if defined(_OPENMP) #include #endif -#include "math_extra.h" -#include "math_const.h" -#include "rigid_const.h" - using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; using namespace RigidConst; -typedef struct { double x,y,z; } dbl3_t; +typedef struct { + double x, y, z; +} dbl3_t; +// clang-format off /* ---------------------------------------------------------------------- */ void FixRigidSmallOMP::initial_integrate(int vflag) @@ -94,16 +98,36 @@ void FixRigidSmallOMP::initial_integrate(int vflag) // set coords/orient and velocity/rotation of atoms in rigid bodies - if (triclinic) - if (evflag) - set_xv_thr<1,1>(); - else - set_xv_thr<1,0>(); - else - if (evflag) - set_xv_thr<0,1>(); - else - set_xv_thr<0,0>(); +#if defined(_OPENMP) + if (domain->dimension == 2) { + if (triclinic) { + if (evflag) + set_xv_thr<1,1,2>(); + else + set_xv_thr<1,0,2>(); + } else { + + if (evflag) + set_xv_thr<0,1,2>(); + else + set_xv_thr<0,0,2>(); + } + } else { + if (triclinic) { + if (evflag) + set_xv_thr<1,1,3>(); + else + set_xv_thr<1,0,3>(); + } else { + if (evflag) + set_xv_thr<0,1,3>(); + else + set_xv_thr<0,0,3>(); + } + } +#else + set_xv(); +#endif } /* ---------------------------------------------------------------------- */ @@ -114,7 +138,6 @@ void FixRigidSmallOMP::compute_forces_and_torques() const auto * _noalias const f = (dbl3_t *) atom->f[0]; const double * const * const torque_one = atom->torque; const int nlocal = atom->nlocal; - const int nthreads=comm->nthreads; #if defined(_OPENMP) #pragma omp parallel for LMP_DEFAULT_NONE schedule(static) @@ -132,7 +155,10 @@ void FixRigidSmallOMP::compute_forces_and_torques() // and then each thread only processes some bodies. #if defined(_OPENMP) + const int nthreads=comm->nthreads; #pragma omp parallel LMP_DEFAULT_NONE +#else + const int nthreads=1; #endif { #if defined(_OPENMP) @@ -218,6 +244,7 @@ void FixRigidSmallOMP::compute_forces_and_torques() void FixRigidSmallOMP::final_integrate() { if (!earlyflag) compute_forces_and_torques(); + if (domain->dimension == 2) enforce2d(); // update vcm and angmom, recompute omega @@ -253,24 +280,34 @@ void FixRigidSmallOMP::final_integrate() // virial is already setup from initial_integrate // triclinic only matters for virial calculation. - if (evflag) - if (triclinic) - set_v_thr<1,1>(); + if (domain->dimension == 2) { + if (evflag) { + if (triclinic) + set_v_thr<1,1,2>(); + else + set_v_thr<0,1,2>(); + } else { + set_v_thr<0,0,2>(); + } + } else { + if (evflag) + if (triclinic) + set_v_thr<1,1,3>(); + else + set_v_thr<0,1,3>(); else - set_v_thr<0,1>(); - else - set_v_thr<0,0>(); + set_v_thr<0,0,3>(); + } } - /* ---------------------------------------------------------------------- set space-frame coords and velocity of each atom in each rigid body set orientation and rotation of extended particles x = Q displace + Xcm, mapped back to periodic box v = Vcm + (W cross (x - Xcm)) -------------------------------------------------------------------------- */ + ------------------------------------------------------------------------- */ -template +template void FixRigidSmallOMP::set_xv_thr() { auto * _noalias const x = (dbl3_t *) atom->x[0]; @@ -329,6 +366,8 @@ void FixRigidSmallOMP::set_xv_thr() v[i].y = b.omega[2]*x[i].x - b.omega[0]*x[i].z + b.vcm[1]; v[i].z = b.omega[0]*x[i].y - b.omega[1]*x[i].x + b.vcm[2]; + if (DIMENSION == 2) x[i].z = v[i].z = 0.0; + // add center of mass to displacement // map back into periodic box via xbox,ybox,zbox // for triclinic, add in box tilt factors as well @@ -463,9 +502,9 @@ void FixRigidSmallOMP::set_xv_thr() set space-frame velocity of each atom in a rigid body set omega and angmom of extended particles v = Vcm + (W cross (x - Xcm)) -------------------------------------------------------------------------- */ + ------------------------------------------------------------------------- */ -template +template void FixRigidSmallOMP::set_v_thr() { auto * _noalias const x = (dbl3_t *) atom->x[0]; @@ -512,6 +551,8 @@ void FixRigidSmallOMP::set_v_thr() v[i].y = b.omega[2]*delta[0] - b.omega[0]*delta[2] + b.vcm[1]; v[i].z = b.omega[0]*delta[1] - b.omega[1]*delta[0] + b.vcm[2]; + if (DIMENSION == 2) v[i].z = 0.0; + // virial = unwrapped coords dotted into body constraint force // body constraint force = implied force due to v change minus f external // assume f does not include forces internal to body @@ -564,8 +605,8 @@ void FixRigidSmallOMP::set_v_thr() } } // end of parallel for - // second part of thread safe virial accumulation - // add global virial component after it was reduced across all threads + // second part of thread safe virial accumulation + // add global virial component after it was reduced across all threads if (EVFLAG) { if (vflag_global) { virial[0] += v0; @@ -624,4 +665,3 @@ void FixRigidSmallOMP::set_v_thr() } } } - diff --git a/src/OPENMP/fix_rigid_small_omp.h b/src/OPENMP/fix_rigid_small_omp.h index 3d8bca1a6d..d3a7bd6349 100644 --- a/src/OPENMP/fix_rigid_small_omp.h +++ b/src/OPENMP/fix_rigid_small_omp.h @@ -36,11 +36,11 @@ class FixRigidSmallOMP : public FixRigidSmall { void final_integrate() override; protected: - virtual void compute_forces_and_torques(); + void compute_forces_and_torques() override; private: - template void set_xv_thr(); - template void set_v_thr(); + template void set_xv_thr(); + template void set_v_thr(); }; } // namespace LAMMPS_NS diff --git a/src/RIGID/fix_rigid.cpp b/src/RIGID/fix_rigid.cpp index 44427d2914..628abb240e 100644 --- a/src/RIGID/fix_rigid.cpp +++ b/src/RIGID/fix_rigid.cpp @@ -1,4 +1,3 @@ -// clang-format off /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories @@ -47,18 +46,16 @@ using namespace RigidConst; /* ---------------------------------------------------------------------- */ FixRigid::FixRigid(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), step_respa(nullptr), - inpfile(nullptr), nrigid(nullptr), mol2body(nullptr), body2mol(nullptr), - body(nullptr), displace(nullptr), masstotal(nullptr), xcm(nullptr), - vcm(nullptr), fcm(nullptr), inertia(nullptr), ex_space(nullptr), - ey_space(nullptr), ez_space(nullptr), angmom(nullptr), omega(nullptr), - torque(nullptr), quat(nullptr), imagebody(nullptr), fflag(nullptr), - tflag(nullptr), langextra(nullptr), sum(nullptr), all(nullptr), - remapflag(nullptr), xcmimage(nullptr), eflags(nullptr), orient(nullptr), - dorient(nullptr), id_dilate(nullptr), id_gravity(nullptr), random(nullptr), - avec_ellipsoid(nullptr), avec_line(nullptr), avec_tri(nullptr) + Fix(lmp, narg, arg), step_respa(nullptr), inpfile(nullptr), nrigid(nullptr), mol2body(nullptr), + body2mol(nullptr), body(nullptr), displace(nullptr), masstotal(nullptr), xcm(nullptr), + vcm(nullptr), fcm(nullptr), inertia(nullptr), ex_space(nullptr), ey_space(nullptr), + ez_space(nullptr), angmom(nullptr), omega(nullptr), torque(nullptr), quat(nullptr), + imagebody(nullptr), fflag(nullptr), tflag(nullptr), langextra(nullptr), sum(nullptr), + all(nullptr), remapflag(nullptr), xcmimage(nullptr), eflags(nullptr), orient(nullptr), + dorient(nullptr), id_dilate(nullptr), id_gravity(nullptr), random(nullptr), + avec_ellipsoid(nullptr), avec_line(nullptr), avec_tri(nullptr) { - int i,ibody; + int i, ibody; scalar_flag = 1; extscalar = 0; @@ -68,12 +65,8 @@ FixRigid::FixRigid(LAMMPS *lmp, int narg, char **arg) : thermo_virial = 1; create_attribute = 1; dof_flag = 1; - enforce2d_flag = 1; centroidstressflag = CENTROID_NOTAVAIL; - MPI_Comm_rank(world,&me); - MPI_Comm_size(world,&nprocs); - // perform initial allocation of atom-based arrays // register with Atom class @@ -90,7 +83,7 @@ FixRigid::FixRigid(LAMMPS *lmp, int narg, char **arg) : // parse args for rigid body specification // set nbody and body[i] for each atom - if (narg < 4) error->all(FLERR,"Illegal fix rigid command"); + if (narg < 4) utils::missing_cmd_args(FLERR, std::string("fix ") + style, error); int iarg; mol2body = nullptr; @@ -100,7 +93,7 @@ FixRigid::FixRigid(LAMMPS *lmp, int narg, char **arg) : // nbody = 1 // all atoms in fix group are part of body - if (strcmp(arg[3],"single") == 0) { + if (strcmp(arg[3], "single") == 0) { rstyle = SINGLE; iarg = 4; nbody = 1; @@ -113,67 +106,68 @@ FixRigid::FixRigid(LAMMPS *lmp, int narg, char **arg) : if (mask[i] & groupbit) body[i] = 0; } - // each molecule in fix group is a rigid body - // maxmol = largest molecule ID - // ncount = # of atoms in each molecule (have to sum across procs) - // nbody = # of non-zero ncount values - // use nall as incremented ptr to set body[] values for each atom + // each molecule in fix group is a rigid body + // maxmol = largest molecule ID + // ncount = # of atoms in each molecule (have to sum across procs) + // nbody = # of non-zero ncount values + // use nall as incremented ptr to set body[] values for each atom - } else if (strcmp(arg[3],"molecule") == 0 || strcmp(arg[3],"custom") == 0) { + } else if ((strcmp(arg[3], "molecule") == 0) || (strcmp(arg[3], "custom") == 0)) { rstyle = MOLECULE; tagint *molecule; int *mask = atom->mask; int nlocal = atom->nlocal; - int custom_flag = strcmp(arg[3],"custom") == 0; + int custom_flag = strcmp(arg[3], "custom") == 0; if (custom_flag) { - if (narg < 5) error->all(FLERR,"Illegal fix rigid command"); + if (narg < 5) utils::missing_cmd_args(FLERR, fmt::format("fix {} custom"), error); // determine whether atom-style variable or atom property is used - if (utils::strmatch(arg[4],"^i_")) { - int is_double,cols; - int custom_index = atom->find_custom(arg[4]+2,is_double,cols); + if (utils::strmatch(arg[4], "^i_")) { + int is_double, cols; + int custom_index = atom->find_custom(arg[4] + 2, is_double, cols); if (custom_index == -1) - error->all(FLERR,"Fix rigid custom requires previously defined property/atom"); + error->all(FLERR, "Fix {} custom requires previously defined property/atom", style); else if (is_double) - error->all(FLERR,"Fix rigid custom requires integer-valued property/atom vector"); + error->all(FLERR, "Fix {} custom requires integer-valued property/atom vector", style); int minval = INT_MAX; int *value = atom->ivector[custom_index]; for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit) minval = MIN(minval,value[i]); + if (mask[i] & groupbit) minval = MIN(minval, value[i]); int vmin = minval; - MPI_Allreduce(&vmin,&minval,1,MPI_INT,MPI_MIN,world); + MPI_Allreduce(&vmin, &minval, 1, MPI_INT, MPI_MIN, world); molecule = new tagint[nlocal]; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) - molecule[i] = (tagint)(value[i] - minval + 1); + molecule[i] = (tagint) (value[i] - minval + 1); else molecule[i] = 0; - } else if (utils::strmatch(arg[4],"^v_")) { - int ivariable = input->variable->find(arg[4]+2); + } else if (utils::strmatch(arg[4], "^v_")) { + int ivariable = input->variable->find(arg[4] + 2); if (ivariable < 0) - error->all(FLERR,"Variable {} for fix rigid/small custom does not exist", arg[4]+2); + error->all(FLERR, "Variable {} for fix {} custom does not exist", arg[4] + 2, style); if (input->variable->atomstyle(ivariable) == 0) - error->all(FLERR,"Fix rigid custom variable {} is not atom-style variable", arg[4]+2); + error->all(FLERR, "Fix {} custom variable {} is not atom-style variable", style, + arg[4] + 2); auto value = new double[nlocal]; - input->variable->compute_atom(ivariable,0,value,1,0); + input->variable->compute_atom(ivariable, 0, value, 1, 0); int minval = INT_MAX; for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit) minval = MIN(minval,(int)value[i]); + if (mask[i] & groupbit) minval = MIN(minval, (int) value[i]); int vmin = minval; - MPI_Allreduce(&vmin,&minval,1,MPI_INT,MPI_MIN,world); + MPI_Allreduce(&vmin, &minval, 1, MPI_INT, MPI_MIN, world); molecule = new tagint[nlocal]; for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit) - molecule[i] = (tagint)((tagint)value[i] - minval + 1); + if (mask[i] & groupbit) molecule[i] = (tagint) ((tagint) value[i] - minval + 1); delete[] value; - } else error->all(FLERR,"Unsupported fix rigid custom property"); + } else + error->all(FLERR, "Unsupported fix {} custom property: {}", style, arg[4]); } else { if (atom->molecule_flag == 0) - error->all(FLERR,"Fix rigid molecule requires atom attribute molecule"); + error->all(FLERR, "Fix {} molecule requires atom attribute molecule", style); molecule = atom->molecule; } @@ -181,30 +175,31 @@ FixRigid::FixRigid(LAMMPS *lmp, int narg, char **arg) : tagint maxmol_tag = -1; for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit) maxmol_tag = MAX(maxmol_tag,molecule[i]); + if (mask[i] & groupbit) maxmol_tag = MAX(maxmol_tag, molecule[i]); tagint itmp; - MPI_Allreduce(&maxmol_tag,&itmp,1,MPI_LMP_TAGINT,MPI_MAX,world); - if (itmp+1 > MAXSMALLINT) - error->all(FLERR,"Too many molecules for fix rigid"); + MPI_Allreduce(&maxmol_tag, &itmp, 1, MPI_LMP_TAGINT, MPI_MAX, world); + if (itmp + 1 > MAXSMALLINT) error->all(FLERR, "Too many molecules for fix {}", style); maxmol = (int) itmp; int *ncount; - memory->create(ncount,maxmol+1,"rigid:ncount"); + memory->create(ncount, maxmol + 1, "rigid:ncount"); for (i = 0; i <= maxmol; i++) ncount[i] = 0; for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) ncount[molecule[i]]++; - memory->create(mol2body,maxmol+1,"rigid:mol2body"); - MPI_Allreduce(ncount,mol2body,maxmol+1,MPI_INT,MPI_SUM,world); + memory->create(mol2body, maxmol + 1, "rigid:mol2body"); + MPI_Allreduce(ncount, mol2body, maxmol + 1, MPI_INT, MPI_SUM, world); nbody = 0; for (i = 0; i <= maxmol; i++) - if (mol2body[i]) mol2body[i] = nbody++; - else mol2body[i] = -1; + if (mol2body[i]) + mol2body[i] = nbody++; + else + mol2body[i] = -1; - memory->create(body2mol,nbody,"rigid:body2mol"); + memory->create(body2mol, nbody, "rigid:body2mol"); nbody = 0; for (i = 0; i <= maxmol; i++) @@ -218,24 +213,24 @@ FixRigid::FixRigid(LAMMPS *lmp, int narg, char **arg) : memory->destroy(ncount); if (custom_flag) delete[] molecule; - // each listed group is a rigid body - // check if all listed groups exist - // an atom must belong to fix group and listed group to be in rigid body - // error if atom belongs to more than 1 rigid body + // each listed group is a rigid body + // check if all listed groups exist + // an atom must belong to fix group and listed group to be in rigid body + // error if atom belongs to more than 1 rigid body - } else if (strcmp(arg[3],"group") == 0) { - if (narg < 5) error->all(FLERR,"Illegal fix rigid command"); + } else if (strcmp(arg[3], "group") == 0) { + if (narg < 5) utils::missing_cmd_args(FLERR, fmt::format("fix {} group"), error); rstyle = GROUP; - nbody = utils::inumeric(FLERR,arg[4],false,lmp); - if (nbody <= 0) error->all(FLERR,"Illegal fix rigid command"); - if (narg < 5+nbody) error->all(FLERR,"Illegal fix rigid command"); - iarg = 5+nbody; + nbody = utils::inumeric(FLERR, arg[4], false, lmp); + if (nbody <= 0) error->all(FLERR, "Illegal fix {} number of groups {}", style, nbody); + if (narg < 5 + nbody) utils::missing_cmd_args(FLERR, fmt::format("fix {} group"), error); + iarg = 5 + nbody; int *igroups = new int[nbody]; for (ibody = 0; ibody < nbody; ibody++) { - igroups[ibody] = group->find(arg[5+ibody]); + igroups[ibody] = group->find(arg[5 + ibody]); if (igroups[ibody] == -1) - error->all(FLERR,"Could not find fix rigid group ID"); + error->all(FLERR, "Could not find fix {} group ID {}", style, arg[5 + ibody]); } int *mask = atom->mask; @@ -253,41 +248,41 @@ FixRigid::FixRigid(LAMMPS *lmp, int narg, char **arg) : } int flagall; - MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); - if (flagall) - error->all(FLERR,"One or more atoms belong to multiple rigid bodies"); + MPI_Allreduce(&flag, &flagall, 1, MPI_INT, MPI_SUM, world); + if (flagall) error->all(FLERR, "One or more atoms belong to multiple rigid bodies"); delete[] igroups; - } else error->all(FLERR,"Illegal fix rigid command"); + } else + error->all(FLERR, "Unknown fix {} mode {}", style, arg[3]); // error check on nbody - if (nbody == 0) error->all(FLERR,"No rigid bodies defined"); + if (nbody == 0) error->all(FLERR, "No rigid bodies defined"); // create all nbody-length arrays - memory->create(nrigid,nbody,"rigid:nrigid"); - memory->create(masstotal,nbody,"rigid:masstotal"); - memory->create(xcm,nbody,3,"rigid:xcm"); - memory->create(vcm,nbody,3,"rigid:vcm"); - memory->create(fcm,nbody,3,"rigid:fcm"); - memory->create(inertia,nbody,3,"rigid:inertia"); - memory->create(ex_space,nbody,3,"rigid:ex_space"); - memory->create(ey_space,nbody,3,"rigid:ey_space"); - memory->create(ez_space,nbody,3,"rigid:ez_space"); - memory->create(angmom,nbody,3,"rigid:angmom"); - memory->create(omega,nbody,3,"rigid:omega"); - memory->create(torque,nbody,3,"rigid:torque"); - memory->create(quat,nbody,4,"rigid:quat"); - memory->create(imagebody,nbody,"rigid:imagebody"); - memory->create(fflag,nbody,3,"rigid:fflag"); - memory->create(tflag,nbody,3,"rigid:tflag"); - memory->create(langextra,nbody,6,"rigid:langextra"); + memory->create(nrigid, nbody, "rigid:nrigid"); + memory->create(masstotal, nbody, "rigid:masstotal"); + memory->create(xcm, nbody, 3, "rigid:xcm"); + memory->create(vcm, nbody, 3, "rigid:vcm"); + memory->create(fcm, nbody, 3, "rigid:fcm"); + memory->create(inertia, nbody, 3, "rigid:inertia"); + memory->create(ex_space, nbody, 3, "rigid:ex_space"); + memory->create(ey_space, nbody, 3, "rigid:ey_space"); + memory->create(ez_space, nbody, 3, "rigid:ez_space"); + memory->create(angmom, nbody, 3, "rigid:angmom"); + memory->create(omega, nbody, 3, "rigid:omega"); + memory->create(torque, nbody, 3, "rigid:torque"); + memory->create(quat, nbody, 4, "rigid:quat"); + memory->create(imagebody, nbody, "rigid:imagebody"); + memory->create(fflag, nbody, 3, "rigid:fflag"); + memory->create(tflag, nbody, 3, "rigid:tflag"); + memory->create(langextra, nbody, 6, "rigid:langextra"); - memory->create(sum,nbody,6,"rigid:sum"); - memory->create(all,nbody,6,"rigid:all"); - memory->create(remapflag,nbody,4,"rigid:remapflag"); + memory->create(sum, nbody, 6, "rigid:sum"); + memory->create(all, nbody, 6, "rigid:all"); + memory->create(remapflag, nbody, 4, "rigid:remapflag"); // initialize force/torque flags to default = 1.0 // for 2d: fz, tx, ty = 0.0 @@ -328,7 +323,6 @@ FixRigid::FixRigid(LAMMPS *lmp, int narg, char **arg) : pcouple = NONE; pstyle = ANISO; - dimension = domain->dimension; for (i = 0; i < 3; i++) { p_start[i] = p_stop[i] = p_period[i] = 0.0; @@ -336,229 +330,254 @@ FixRigid::FixRigid(LAMMPS *lmp, int narg, char **arg) : } while (iarg < narg) { - if (strcmp(arg[iarg],"force") == 0) { - if (iarg+5 > narg) error->all(FLERR,"Illegal fix rigid command"); + if (strcmp(arg[iarg], "force") == 0) { + if (iarg + 5 > narg) + utils::missing_cmd_args(FLERR, fmt::format("fix {} force", style), error); - int mlo,mhi; - utils::bounds(FLERR,arg[iarg+1],1,nbody,mlo,mhi,error); + int mlo, mhi; + utils::bounds(FLERR, arg[iarg + 1], 1, nbody, mlo, mhi, error); - double xflag,yflag,zflag; - if (strcmp(arg[iarg+2],"off") == 0) xflag = 0.0; - else if (strcmp(arg[iarg+2],"on") == 0) xflag = 1.0; - else error->all(FLERR,"Illegal fix rigid command"); - if (strcmp(arg[iarg+3],"off") == 0) yflag = 0.0; - else if (strcmp(arg[iarg+3],"on") == 0) yflag = 1.0; - else error->all(FLERR,"Illegal fix rigid command"); - if (strcmp(arg[iarg+4],"off") == 0) zflag = 0.0; - else if (strcmp(arg[iarg+4],"on") == 0) zflag = 1.0; - else error->all(FLERR,"Illegal fix rigid command"); + double xflag, yflag, zflag; + if (strcmp(arg[iarg + 2], "off") == 0) + xflag = 0.0; + else if (strcmp(arg[iarg + 2], "on") == 0) + xflag = 1.0; + else + error->all(FLERR, "Illegal fix {} command", style); + if (strcmp(arg[iarg + 3], "off") == 0) + yflag = 0.0; + else if (strcmp(arg[iarg + 3], "on") == 0) + yflag = 1.0; + else + error->all(FLERR, "Illegal fix {} command", style); + if (strcmp(arg[iarg + 4], "off") == 0) + zflag = 0.0; + else if (strcmp(arg[iarg + 4], "on") == 0) + zflag = 1.0; + else + error->all(FLERR, "Illegal fix {} command", style); - if (domain->dimension == 2 && zflag == 1.0) - error->all(FLERR,"Fix rigid z force cannot be on for 2d simulation"); + if ((domain->dimension == 2) && (zflag == 1.0)) + error->all(FLERR, "Fix rigid z force cannot be on for 2d simulation"); int count = 0; for (int m = mlo; m <= mhi; m++) { - fflag[m-1][0] = xflag; - fflag[m-1][1] = yflag; - fflag[m-1][2] = zflag; + fflag[m - 1][0] = xflag; + fflag[m - 1][1] = yflag; + fflag[m - 1][2] = zflag; count++; } - if (count == 0) error->all(FLERR,"Illegal fix rigid command"); + if (count == 0) error->all(FLERR, "Illegal fix {} command", style); iarg += 5; - } else if (strcmp(arg[iarg],"torque") == 0) { - if (iarg+5 > narg) error->all(FLERR,"Illegal fix rigid command"); + } else if (strcmp(arg[iarg], "torque") == 0) { + if (iarg + 5 > narg) error->all(FLERR, "Illegal fix {} command", style); - int mlo,mhi; - utils::bounds(FLERR,arg[iarg+1],1,nbody,mlo,mhi,error); + int mlo, mhi; + utils::bounds(FLERR, arg[iarg + 1], 1, nbody, mlo, mhi, error); - double xflag,yflag,zflag; - if (strcmp(arg[iarg+2],"off") == 0) xflag = 0.0; - else if (strcmp(arg[iarg+2],"on") == 0) xflag = 1.0; - else error->all(FLERR,"Illegal fix rigid command"); - if (strcmp(arg[iarg+3],"off") == 0) yflag = 0.0; - else if (strcmp(arg[iarg+3],"on") == 0) yflag = 1.0; - else error->all(FLERR,"Illegal fix rigid command"); - if (strcmp(arg[iarg+4],"off") == 0) zflag = 0.0; - else if (strcmp(arg[iarg+4],"on") == 0) zflag = 1.0; - else error->all(FLERR,"Illegal fix rigid command"); + double xflag, yflag, zflag; + if (strcmp(arg[iarg + 2], "off") == 0) + xflag = 0.0; + else if (strcmp(arg[iarg + 2], "on") == 0) + xflag = 1.0; + else + error->all(FLERR, "Illegal fix {} command", style); + if (strcmp(arg[iarg + 3], "off") == 0) + yflag = 0.0; + else if (strcmp(arg[iarg + 3], "on") == 0) + yflag = 1.0; + else + error->all(FLERR, "Illegal fix {} command", style); + if (strcmp(arg[iarg + 4], "off") == 0) + zflag = 0.0; + else if (strcmp(arg[iarg + 4], "on") == 0) + zflag = 1.0; + else + error->all(FLERR, "Illegal fix {} command", style); if (domain->dimension == 2 && (xflag == 1.0 || yflag == 1.0)) - error->all(FLERR,"Fix rigid xy torque cannot be on for 2d simulation"); + error->all(FLERR, "Fix rigid xy torque cannot be on for 2d simulation"); int count = 0; for (int m = mlo; m <= mhi; m++) { - tflag[m-1][0] = xflag; - tflag[m-1][1] = yflag; - tflag[m-1][2] = zflag; + tflag[m - 1][0] = xflag; + tflag[m - 1][1] = yflag; + tflag[m - 1][2] = zflag; count++; } - if (count == 0) error->all(FLERR,"Illegal fix rigid command"); + if (count == 0) error->all(FLERR, "Illegal fix {} command", style); iarg += 5; - } else if (strcmp(arg[iarg],"langevin") == 0) { - if (iarg+5 > narg) error->all(FLERR,"Illegal fix rigid command"); - if (strcmp(style,"rigid") != 0 && strcmp(style,"rigid/nve") != 0 && - strcmp(style,"rigid/omp") != 0 && strcmp(style,"rigid/nve/omp") != 0) - error->all(FLERR,"Illegal fix rigid command"); + } else if (strcmp(arg[iarg], "langevin") == 0) { + if (iarg + 5 > narg) error->all(FLERR, "Illegal fix {} command", style); + if (strcmp(style, "rigid") != 0 && strcmp(style, "rigid/nve") != 0 && + strcmp(style, "rigid/omp") != 0 && strcmp(style, "rigid/nve/omp") != 0) + error->all(FLERR, "Illegal fix {} command", style); langflag = 1; - t_start = utils::numeric(FLERR,arg[iarg+1],false,lmp); - t_stop = utils::numeric(FLERR,arg[iarg+2],false,lmp); - t_period = utils::numeric(FLERR,arg[iarg+3],false,lmp); - seed = utils::inumeric(FLERR,arg[iarg+4],false,lmp); - if (t_period <= 0.0) - error->all(FLERR,"Fix rigid langevin period must be > 0.0"); - if (seed <= 0) error->all(FLERR,"Illegal fix rigid command"); + t_start = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + t_stop = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + t_period = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + seed = utils::inumeric(FLERR, arg[iarg + 4], false, lmp); + if (t_period <= 0.0) error->all(FLERR, "Fix rigid langevin period must be > 0.0"); + if (seed <= 0) error->all(FLERR, "Illegal fix {} command", style); iarg += 5; - } else if (strcmp(arg[iarg],"temp") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid command"); - if (!utils::strmatch(style,"^rigid/n.t")) - error->all(FLERR,"Illegal fix rigid command"); + } else if (strcmp(arg[iarg], "temp") == 0) { + if (iarg + 4 > narg) error->all(FLERR, "Illegal fix {} command", style); + if (!utils::strmatch(style, "^rigid/n.t")) error->all(FLERR, "Illegal fix {} command", style); tstat_flag = 1; - t_start = utils::numeric(FLERR,arg[iarg+1],false,lmp); - t_stop = utils::numeric(FLERR,arg[iarg+2],false,lmp); - t_period = utils::numeric(FLERR,arg[iarg+3],false,lmp); + t_start = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + t_stop = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + t_period = utils::numeric(FLERR, arg[iarg + 3], false, lmp); iarg += 4; - } else if (strcmp(arg[iarg],"iso") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid command"); - if (!utils::strmatch(style,"^rigid/np.")) - error->all(FLERR,"Illegal fix rigid command"); + } else if (strcmp(arg[iarg], "iso") == 0) { + if (iarg + 4 > narg) error->all(FLERR, "Illegal fix {} command", style); + if (!utils::strmatch(style, "^rigid/np.")) error->all(FLERR, "Illegal fix {} command", style); pcouple = XYZ; - p_start[0] = p_start[1] = p_start[2] = utils::numeric(FLERR,arg[iarg+1],false,lmp); - p_stop[0] = p_stop[1] = p_stop[2] = utils::numeric(FLERR,arg[iarg+2],false,lmp); - p_period[0] = p_period[1] = p_period[2] = - utils::numeric(FLERR,arg[iarg+3],false,lmp); + p_start[0] = p_start[1] = p_start[2] = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + p_stop[0] = p_stop[1] = p_stop[2] = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + p_period[0] = p_period[1] = p_period[2] = utils::numeric(FLERR, arg[iarg + 3], false, lmp); p_flag[0] = p_flag[1] = p_flag[2] = 1; - if (dimension == 2) { - p_start[2] = p_stop[2] = p_period[2] = 0.0; + if (domain->dimension == 2) { + p_start[2] = p_stop[2] = p_period[2] = 0.0; p_flag[2] = 0; } iarg += 4; - } else if (strcmp(arg[iarg],"aniso") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid command"); - if (!utils::strmatch(style,"^rigid/np.")) - error->all(FLERR,"Illegal fix rigid command"); - p_start[0] = p_start[1] = p_start[2] = utils::numeric(FLERR,arg[iarg+1],false,lmp); - p_stop[0] = p_stop[1] = p_stop[2] = utils::numeric(FLERR,arg[iarg+2],false,lmp); - p_period[0] = p_period[1] = p_period[2] = - utils::numeric(FLERR,arg[iarg+3],false,lmp); + } else if (strcmp(arg[iarg], "aniso") == 0) { + if (iarg + 4 > narg) error->all(FLERR, "Illegal fix {} command", style); + if (!utils::strmatch(style, "^rigid/np.")) error->all(FLERR, "Illegal fix {} command", style); + p_start[0] = p_start[1] = p_start[2] = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + p_stop[0] = p_stop[1] = p_stop[2] = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + p_period[0] = p_period[1] = p_period[2] = utils::numeric(FLERR, arg[iarg + 3], false, lmp); p_flag[0] = p_flag[1] = p_flag[2] = 1; - if (dimension == 2) { + if (domain->dimension == 2) { p_start[2] = p_stop[2] = p_period[2] = 0.0; - p_flag[2] = 0; + p_flag[2] = 0; } iarg += 4; - } else if (strcmp(arg[iarg],"x") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid command"); - if (!utils::strmatch(style,"^rigid/np.")) - error->all(FLERR,"Illegal fix rigid command"); - p_start[0] = utils::numeric(FLERR,arg[iarg+1],false,lmp); - p_stop[0] = utils::numeric(FLERR,arg[iarg+2],false,lmp); - p_period[0] = utils::numeric(FLERR,arg[iarg+3],false,lmp); + } else if (strcmp(arg[iarg], "x") == 0) { + if (iarg + 4 > narg) error->all(FLERR, "Illegal fix {} command", style); + if (!utils::strmatch(style, "^rigid/np.")) error->all(FLERR, "Illegal fix {} command", style); + p_start[0] = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + p_stop[0] = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + p_period[0] = utils::numeric(FLERR, arg[iarg + 3], false, lmp); p_flag[0] = 1; iarg += 4; - } else if (strcmp(arg[iarg],"y") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid command"); - if (!utils::strmatch(style,"^rigid/np.")) - error->all(FLERR,"Illegal fix rigid command"); - p_start[1] = utils::numeric(FLERR,arg[iarg+1],false,lmp); - p_stop[1] = utils::numeric(FLERR,arg[iarg+2],false,lmp); - p_period[1] = utils::numeric(FLERR,arg[iarg+3],false,lmp); + } else if (strcmp(arg[iarg], "y") == 0) { + if (iarg + 4 > narg) error->all(FLERR, "Illegal fix {} command", style); + if (!utils::strmatch(style, "^rigid/np.")) error->all(FLERR, "Illegal fix {} command", style); + p_start[1] = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + p_stop[1] = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + p_period[1] = utils::numeric(FLERR, arg[iarg + 3], false, lmp); p_flag[1] = 1; iarg += 4; - } else if (strcmp(arg[iarg],"z") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid command"); - if (!utils::strmatch(style,"^rigid/np.")) - error->all(FLERR,"Illegal fix rigid command"); - p_start[2] = utils::numeric(FLERR,arg[iarg+1],false,lmp); - p_stop[2] = utils::numeric(FLERR,arg[iarg+2],false,lmp); - p_period[2] = utils::numeric(FLERR,arg[iarg+3],false,lmp); + } else if (strcmp(arg[iarg], "z") == 0) { + if (iarg + 4 > narg) error->all(FLERR, "Illegal fix {} command", style); + if (!utils::strmatch(style, "^rigid/np.")) error->all(FLERR, "Illegal fix {} command", style); + p_start[2] = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + p_stop[2] = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + p_period[2] = utils::numeric(FLERR, arg[iarg + 3], false, lmp); p_flag[2] = 1; iarg += 4; - } else if (strcmp(arg[iarg],"couple") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid command"); - if (strcmp(arg[iarg+1],"xyz") == 0) pcouple = XYZ; - else if (strcmp(arg[iarg+1],"xy") == 0) pcouple = XY; - else if (strcmp(arg[iarg+1],"yz") == 0) pcouple = YZ; - else if (strcmp(arg[iarg+1],"xz") == 0) pcouple = XZ; - else if (strcmp(arg[iarg+1],"none") == 0) pcouple = NONE; - else error->all(FLERR,"Illegal fix rigid command"); + } else if (strcmp(arg[iarg], "couple") == 0) { + if (iarg + 2 > narg) + utils::missing_cmd_args(FLERR, fmt::format("fix {} couple", style), error); + if (strcmp(arg[iarg + 1], "xyz") == 0) + pcouple = XYZ; + else if (strcmp(arg[iarg + 1], "xy") == 0) + pcouple = XY; + else if (strcmp(arg[iarg + 1], "yz") == 0) + pcouple = YZ; + else if (strcmp(arg[iarg + 1], "xz") == 0) + pcouple = XZ; + else if (strcmp(arg[iarg + 1], "none") == 0) + pcouple = NONE; + else + error->all(FLERR, "Unknown fix {} couple option ", style, arg[iarg + 1]); iarg += 2; - } else if (strcmp(arg[iarg],"dilate") == 0) { - if (iarg+2 > narg) - error->all(FLERR,"Illegal fix rigid npt/nph command"); - if (strcmp(arg[iarg+1],"all") == 0) allremap = 1; + } else if (strcmp(arg[iarg], "dilate") == 0) { + if (iarg + 2 > narg) + utils::missing_cmd_args(FLERR, fmt::format("fix {} dilate", style), error); + if (strcmp(arg[iarg + 1], "all") == 0) + allremap = 1; else { allremap = 0; delete[] id_dilate; - id_dilate = utils::strdup(arg[iarg+1]); + id_dilate = utils::strdup(arg[iarg + 1]); int idilate = group->find(id_dilate); if (idilate == -1) - error->all(FLERR, - "Fix rigid npt/nph dilate group ID does not exist"); + error->all(FLERR, "Fix {} dilate group ID {} does not exist", style, id_dilate); } iarg += 2; - } else if (strcmp(arg[iarg],"tparam") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid command"); - if (!utils::strmatch(style,"^rigid/n.t")) - error->all(FLERR,"Illegal fix rigid command"); - t_chain = utils::inumeric(FLERR,arg[iarg+1],false,lmp); - t_iter = utils::inumeric(FLERR,arg[iarg+2],false,lmp); - t_order = utils::inumeric(FLERR,arg[iarg+3],false,lmp); + } else if (strcmp(arg[iarg], "tparam") == 0) { + if (iarg + 4 > narg) + utils::missing_cmd_args(FLERR, fmt::format("fix {} tparam", style), error); + if (!utils::strmatch(style, "^rigid/n.t")) + error->all(FLERR, "Illegal fix {} command option tparam", style); + t_chain = utils::inumeric(FLERR, arg[iarg + 1], false, lmp); + t_iter = utils::inumeric(FLERR, arg[iarg + 2], false, lmp); + t_order = utils::inumeric(FLERR, arg[iarg + 3], false, lmp); iarg += 4; - } else if (strcmp(arg[iarg],"pchain") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid command"); - if (!utils::strmatch(style,"^rigid/np.")) - error->all(FLERR,"Illegal fix rigid command"); - p_chain = utils::inumeric(FLERR,arg[iarg+1],false,lmp); + } else if (strcmp(arg[iarg], "pchain") == 0) { + if (iarg + 2 > narg) + utils::missing_cmd_args(FLERR, fmt::format("fix {} pchain", style), error); + if (!utils::strmatch(style, "^rigid/np.")) + error->all(FLERR, "Illegal fix {} command option pchain", style); + p_chain = utils::inumeric(FLERR, arg[iarg + 1], false, lmp); iarg += 2; - } else if (strcmp(arg[iarg],"infile") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid command"); + } else if (strcmp(arg[iarg], "infile") == 0) { + if (iarg + 2 > narg) + utils::missing_cmd_args(FLERR, fmt::format("fix {} infile", style), error); delete[] inpfile; - inpfile = utils::strdup(arg[iarg+1]); + inpfile = utils::strdup(arg[iarg + 1]); restart_file = 1; reinitflag = 0; iarg += 2; - } else if (strcmp(arg[iarg],"reinit") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid command"); - reinitflag = utils::logical(FLERR,arg[iarg+1],false,lmp); + } else if (strcmp(arg[iarg], "reinit") == 0) { + if (iarg + 2 > narg) + utils::missing_cmd_args(FLERR, fmt::format("fix {} reinit", style), error); + reinitflag = utils::logical(FLERR, arg[iarg + 1], false, lmp); iarg += 2; - } else if (strcmp(arg[iarg],"gravity") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid command"); + } else if (strcmp(arg[iarg], "gravity") == 0) { + if (iarg + 2 > narg) + utils::missing_cmd_args(FLERR, fmt::format("fix {} gravity", style), error); delete[] id_gravity; - id_gravity = utils::strdup(arg[iarg+1]); + id_gravity = utils::strdup(arg[iarg + 1]); iarg += 2; - } else error->all(FLERR,"Illegal fix rigid command"); + } else + error->all(FLERR, "Illegal fix {} command", style); } + // clang-format off + // set pstat_flag pstat_flag = 0; for (i = 0; i < 3; i++) if (p_flag[i]) pstat_flag = 1; - if (pcouple == XYZ || (dimension == 2 && pcouple == XY)) pstyle = ISO; + if (pcouple == XYZ || (domain->dimension == 2 && pcouple == XY)) pstyle = ISO; else pstyle = ANISO; // initialize Marsaglia RNG with processor-unique seed - if (langflag) random = new RanMars(lmp,seed + me); + if (langflag) random = new RanMars(lmp, seed + comm->me); else random = nullptr; // initialize vector output quantities in case accessed before run @@ -600,7 +619,7 @@ FixRigid::FixRigid(LAMMPS *lmp, int narg, char **arg) : int nsum = 0; for (ibody = 0; ibody < nbody; ibody++) nsum += nrigid[ibody]; - if (me == 0) + if (comm->me == 0) utils::logmesg(lmp," {} rigid bodies with {} atoms\n",nbody,nsum); } @@ -686,14 +705,15 @@ void FixRigid::init() int count = 0; for (auto &ifix : modify->get_fix_list()) if (ifix->rigid_flag) count++; - if (count > 1 && me == 0) error->warning(FLERR,"More than one fix rigid"); + if (count > 1 && comm->me == 0) + error->warning(FLERR,"More than one fix rigid"); if (earlyflag) { bool rflag = false; for (auto &ifix : modify->get_fix_list()) { if (ifix->rigid_flag) rflag = true; if ((comm->me == 0) && rflag && (ifix->setmask() & POST_FORCE) && !ifix->rigid_flag) - error->warning(FLERR,"Fix {} with ID {} alters forces after fix rigid", + error->warning(FLERR, "Fix {} with ID {} alters forces after fix rigid", ifix->style, ifix->id); } } @@ -856,6 +876,10 @@ void FixRigid::setup(int vflag) torque[ibody][2] = all[ibody][2]; } + // enforce 2d body forces and torques + + if (domain->dimension == 2) enforce2d(); + // zero langextra in case Langevin thermostat not used // no point to calling post_force() here since langextra // is only added to fcm/torque in final_integrate() @@ -936,6 +960,131 @@ void FixRigid::initial_integrate(int vflag) set_xv(); } +/* ---------------------------------------------------------------------- + remap xcm of each rigid body back into periodic simulation box + done during pre_neighbor so will be after call to pbc() + and after fix_deform::pre_exchange() may have flipped box + use domain->remap() in case xcm is far away from box + due to first-time definition of rigid body in setup_bodies_static() + or due to box flip + also adjust imagebody = rigid body image flags, due to xcm remap + also reset body xcmimage flags of all atoms in bodies + xcmimage flags are relative to xcm so that body can be unwrapped + if don't do this, would need xcm to move with true image flags + then a body could end up very far away from box + set_xv() will then compute huge displacements every step to + reset coords of all body atoms to be back inside the box, + ditto for triclinic box flip, which causes numeric problems +------------------------------------------------------------------------- */ + +void FixRigid::pre_neighbor() +{ + for (int ibody = 0; ibody < nbody; ibody++) + domain->remap(xcm[ibody],imagebody[ibody]); + image_shift(); +} + +/* ---------------------------------------------------------------------- */ + +void FixRigid::post_force(int /*vflag*/) +{ + if (langflag) apply_langevin_thermostat(); + if (earlyflag) compute_forces_and_torques(); +} + +/* ---------------------------------------------------------------------- */ + +void FixRigid::final_integrate() +{ + int ibody; + double dtfm; + + // compute forces and torques (after all post_force contributions) + // if 2d model, enforce2d() on body forces/torques + + if (!earlyflag) compute_forces_and_torques(); + if (domain->dimension == 2) enforce2d(); + + // update vcm and angmom + // fflag,tflag = 0 for some dimensions in 2d + + for (ibody = 0; ibody < nbody; ibody++) { + + // update vcm by 1/2 step + + dtfm = dtf / masstotal[ibody]; + vcm[ibody][0] += dtfm * fcm[ibody][0] * fflag[ibody][0]; + vcm[ibody][1] += dtfm * fcm[ibody][1] * fflag[ibody][1]; + vcm[ibody][2] += dtfm * fcm[ibody][2] * fflag[ibody][2]; + + // update angular momentum by 1/2 step + + angmom[ibody][0] += dtf * torque[ibody][0] * tflag[ibody][0]; + angmom[ibody][1] += dtf * torque[ibody][1] * tflag[ibody][1]; + angmom[ibody][2] += dtf * torque[ibody][2] * tflag[ibody][2]; + + MathExtra::angmom_to_omega(angmom[ibody],ex_space[ibody],ey_space[ibody], + ez_space[ibody],inertia[ibody],omega[ibody]); + } + + // set velocity/rotation of atoms in rigid bodies + // virial is already setup from initial_integrate + + set_v(); +} + +/* ---------------------------------------------------------------------- */ + +void FixRigid::initial_integrate_respa(int vflag, int ilevel, int /*iloop*/) +{ + dtv = step_respa[ilevel]; + dtf = 0.5 * step_respa[ilevel] * force->ftm2v; + dtq = 0.5 * step_respa[ilevel]; + + if (ilevel == 0) initial_integrate(vflag); + else final_integrate(); +} + +/* ---------------------------------------------------------------------- */ + +void FixRigid::final_integrate_respa(int ilevel, int /*iloop*/) +{ + dtf = 0.5 * step_respa[ilevel] * force->ftm2v; + final_integrate(); +} + +/* ---------------------------------------------------------------------- + reset body xcmimage flags of atoms in bodies + xcmimage flags are relative to xcm so that body can be unwrapped + xcmimage = true image flag - imagebody flag +------------------------------------------------------------------------- */ + +void FixRigid::image_shift() +{ + int ibody; + imageint tdim,bdim,xdim[3]; + + imageint *image = atom->image; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (body[i] < 0) continue; + ibody = body[i]; + + tdim = image[i] & IMGMASK; + bdim = imagebody[ibody] & IMGMASK; + xdim[0] = IMGMAX + tdim - bdim; + tdim = (image[i] >> IMGBITS) & IMGMASK; + bdim = (imagebody[ibody] >> IMGBITS) & IMGMASK; + xdim[1] = IMGMAX + tdim - bdim; + tdim = image[i] >> IMG2BITS; + bdim = imagebody[ibody] >> IMG2BITS; + xdim[2] = IMGMAX + tdim - bdim; + + xcmimage[i] = (xdim[2] << IMG2BITS) | (xdim[1] << IMGBITS) | xdim[0]; + } +} + /* ---------------------------------------------------------------------- apply Langevin thermostat to all 6 DOF of rigid bodies computed by proc 0, broadcast to other procs @@ -945,7 +1094,7 @@ void FixRigid::initial_integrate(int vflag) void FixRigid::apply_langevin_thermostat() { - if (me == 0) { + if (comm->me == 0) { double gamma1,gamma2; double wbody[3],tbody[3]; double delta = update->ntimestep - update->beginstep; @@ -991,31 +1140,6 @@ void FixRigid::apply_langevin_thermostat() MPI_Bcast(&langextra[0][0],6*nbody,MPI_DOUBLE,0,world); } -/* ---------------------------------------------------------------------- - called from FixEnforce2d post_force() for 2d problems - zero all body values that should be zero for 2d model -------------------------------------------------------------------------- */ - -void FixRigid::enforce2d() -{ - for (int ibody = 0; ibody < nbody; ibody++) { - xcm[ibody][2] = 0.0; - vcm[ibody][2] = 0.0; - fcm[ibody][2] = 0.0; - torque[ibody][0] = 0.0; - torque[ibody][1] = 0.0; - angmom[ibody][0] = 0.0; - angmom[ibody][1] = 0.0; - omega[ibody][0] = 0.0; - omega[ibody][1] = 0.0; - if (langflag && langextra) { - langextra[ibody][2] = 0.0; - langextra[ibody][3] = 0.0; - langextra[ibody][4] = 0.0; - } - } -} - /* ---------------------------------------------------------------------- */ void FixRigid::compute_forces_and_torques() @@ -1093,124 +1217,28 @@ void FixRigid::compute_forces_and_torques() } } -/* ---------------------------------------------------------------------- */ - -void FixRigid::post_force(int /*vflag*/) -{ - if (langflag) apply_langevin_thermostat(); - if (earlyflag) compute_forces_and_torques(); -} - -/* ---------------------------------------------------------------------- */ - -void FixRigid::final_integrate() -{ - int ibody; - double dtfm; - - if (!earlyflag) compute_forces_and_torques(); - - // update vcm and angmom - // fflag,tflag = 0 for some dimensions in 2d - - for (ibody = 0; ibody < nbody; ibody++) { - - // update vcm by 1/2 step - - dtfm = dtf / masstotal[ibody]; - vcm[ibody][0] += dtfm * fcm[ibody][0] * fflag[ibody][0]; - vcm[ibody][1] += dtfm * fcm[ibody][1] * fflag[ibody][1]; - vcm[ibody][2] += dtfm * fcm[ibody][2] * fflag[ibody][2]; - - // update angular momentum by 1/2 step - - angmom[ibody][0] += dtf * torque[ibody][0] * tflag[ibody][0]; - angmom[ibody][1] += dtf * torque[ibody][1] * tflag[ibody][1]; - angmom[ibody][2] += dtf * torque[ibody][2] * tflag[ibody][2]; - - MathExtra::angmom_to_omega(angmom[ibody],ex_space[ibody],ey_space[ibody], - ez_space[ibody],inertia[ibody],omega[ibody]); - } - - // set velocity/rotation of atoms in rigid bodies - // virial is already setup from initial_integrate - - set_v(); -} - -/* ---------------------------------------------------------------------- */ - -void FixRigid::initial_integrate_respa(int vflag, int ilevel, int /*iloop*/) -{ - dtv = step_respa[ilevel]; - dtf = 0.5 * step_respa[ilevel] * force->ftm2v; - dtq = 0.5 * step_respa[ilevel]; - - if (ilevel == 0) initial_integrate(vflag); - else final_integrate(); -} - -/* ---------------------------------------------------------------------- */ - -void FixRigid::final_integrate_respa(int ilevel, int /*iloop*/) -{ - dtf = 0.5 * step_respa[ilevel] * force->ftm2v; - final_integrate(); -} - /* ---------------------------------------------------------------------- - remap xcm of each rigid body back into periodic simulation box - done during pre_neighbor so will be after call to pbc() - and after fix_deform::pre_exchange() may have flipped box - use domain->remap() in case xcm is far away from box - due to first-time definition of rigid body in setup_bodies_static() - or due to box flip - also adjust imagebody = rigid body image flags, due to xcm remap - also reset body xcmimage flags of all atoms in bodies - xcmimage flags are relative to xcm so that body can be unwrapped - if don't do this, would need xcm to move with true image flags - then a body could end up very far away from box - set_xv() will then compute huge displacements every step to - reset coords of all body atoms to be back inside the box, - ditto for triclinic box flip, which causes numeric problems + called from FixEnforce2d post_force() for 2d problems + zero all body values that should be zero for 2d model ------------------------------------------------------------------------- */ -void FixRigid::pre_neighbor() +void FixRigid::enforce2d() { - for (int ibody = 0; ibody < nbody; ibody++) - domain->remap(xcm[ibody],imagebody[ibody]); - image_shift(); -} - -/* ---------------------------------------------------------------------- - reset body xcmimage flags of atoms in bodies - xcmimage flags are relative to xcm so that body can be unwrapped - xcmimage = true image flag - imagebody flag -------------------------------------------------------------------------- */ - -void FixRigid::image_shift() -{ - int ibody; - imageint tdim,bdim,xdim[3]; - - imageint *image = atom->image; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (body[i] < 0) continue; - ibody = body[i]; - - tdim = image[i] & IMGMASK; - bdim = imagebody[ibody] & IMGMASK; - xdim[0] = IMGMAX + tdim - bdim; - tdim = (image[i] >> IMGBITS) & IMGMASK; - bdim = (imagebody[ibody] >> IMGBITS) & IMGMASK; - xdim[1] = IMGMAX + tdim - bdim; - tdim = image[i] >> IMG2BITS; - bdim = imagebody[ibody] >> IMG2BITS; - xdim[2] = IMGMAX + tdim - bdim; - - xcmimage[i] = (xdim[2] << IMG2BITS) | (xdim[1] << IMGBITS) | xdim[0]; + for (int ibody = 0; ibody < nbody; ibody++) { + xcm[ibody][2] = 0.0; + vcm[ibody][2] = 0.0; + fcm[ibody][2] = 0.0; + torque[ibody][0] = 0.0; + torque[ibody][1] = 0.0; + angmom[ibody][0] = 0.0; + angmom[ibody][1] = 0.0; + omega[ibody][0] = 0.0; + omega[ibody][1] = 0.0; + if (langflag && langextra) { + langextra[ibody][2] = 0.0; + langextra[ibody][3] = 0.0; + langextra[ibody][4] = 0.0; + } } } @@ -1264,7 +1292,7 @@ int FixRigid::dof(int tgroup) if (nall[ibody]+mall[ibody] > 0 && nall[ibody]+mall[ibody] != nrigid[ibody]) flag = 1; } - if (flag && me == 0) + if (flag && (comm->me == 0)) error->warning(FLERR,"Computing temperature of portions of rigid bodies"); // remove appropriate DOFs for each rigid body wholly in temperature group @@ -1382,6 +1410,7 @@ void FixRigid::set_xv() // x = displacement from center-of-mass, based on body orientation // v = vcm + omega around center-of-mass + // enforce 2d x and v MathExtra::matvec(ex_space[ibody],ey_space[ibody], ez_space[ibody],displace[i],x[i]); @@ -1390,6 +1419,11 @@ void FixRigid::set_xv() v[i][1] = omega[ibody][2]*x[i][0] - omega[ibody][0]*x[i][2] + vcm[ibody][1]; v[i][2] = omega[ibody][0]*x[i][1] - omega[ibody][1]*x[i][0] + vcm[ibody][2]; + if (domain->dimension == 2) { + x[i][2] = 0.0; + v[i][2] = 0.0; + } + // add center of mass to displacement // map back into periodic box via xbox,ybox,zbox // for triclinic, add in box tilt factors as well @@ -1541,10 +1575,15 @@ void FixRigid::set_v() v2 = v[i][2]; } + // compute new v + // enforce 2d v + v[i][0] = omega[ibody][1]*delta[2] - omega[ibody][2]*delta[1] + vcm[ibody][0]; v[i][1] = omega[ibody][2]*delta[0] - omega[ibody][0]*delta[2] + vcm[ibody][1]; v[i][2] = omega[ibody][0]*delta[1] - omega[ibody][1]*delta[0] + vcm[ibody][2]; + if (domain->dimension == 2) v[i][2] = 0.0; + // virial = unwrapped coords dotted into body constraint force // body constraint force = implied force due to v change minus f external // assume f does not include forces internal to body @@ -1756,8 +1795,7 @@ void FixRigid::setup_bodies_static() if ((xbox && !periodicity[0]) || (ybox && !periodicity[1]) || (zbox && !periodicity[2])) - error->one(FLERR,"Fix rigid atom has non-zero image flag " - "in a non-periodic dimension"); + error->one(FLERR,"Fix rigid atom has non-zero image flag in a non-periodic dimension"); if (triclinic == 0) { xunwrap = x[i][0] + xbox*xprd; @@ -2265,7 +2303,7 @@ void FixRigid::readfile(int which, double *vec, double **array1, double **array2 char line[MAXLINE]; // open file and read and parse first non-empty, non-comment line containing the number of bodies - if (me == 0) { + if (comm->me == 0) { fp = fopen(inpfile,"r"); if (fp == nullptr) error->one(FLERR,"Cannot open fix rigid infile {}: {}", inpfile, utils::getsyserror()); @@ -2290,6 +2328,7 @@ void FixRigid::readfile(int which, double *vec, double **array1, double **array2 auto buffer = new char[CHUNK*MAXLINE]; int nread = 0; + int me = comm->me; while (nread < nlines) { nchunk = MIN(nlines-nread,CHUNK); eofflag = utils::read_lines_from_file(fp,nchunk,MAXLINE,buffer,me,world); @@ -2364,7 +2403,7 @@ void FixRigid::readfile(int which, double *vec, double **array1, double **array2 nread += nchunk; } - if (me == 0) fclose(fp); + if (comm->me == 0) fclose(fp); delete[] buffer; } diff --git a/src/RIGID/fix_rigid.h b/src/RIGID/fix_rigid.h index 1e94adec09..361ddd2720 100644 --- a/src/RIGID/fix_rigid.h +++ b/src/RIGID/fix_rigid.h @@ -50,7 +50,6 @@ class FixRigid : public Fix { void pre_neighbor() override; int dof(int) override; void deform(int) override; - void enforce2d() override; void reset_dt() override; void zero_momentum() override; void zero_rotation() override; @@ -61,7 +60,6 @@ class FixRigid : public Fix { double compute_array(int, int) override; protected: - int me, nprocs; double dtv, dtf, dtq; double *step_respa; int triclinic; @@ -72,7 +70,6 @@ class FixRigid : public Fix { int setupflag; // 1 if body properties are setup, else 0 int earlyflag; // 1 if forces/torques computed at post_force() - int dimension; // # of dimensions int nbody; // # of rigid bodies int nlinear; // # of linear rigid bodies int *nrigid; // # of atoms in each rigid body @@ -146,7 +143,8 @@ class FixRigid : public Fix { void setup_bodies_static(); void setup_bodies_dynamic(); void apply_langevin_thermostat(); - void compute_forces_and_torques(); + virtual void compute_forces_and_torques(); + void enforce2d(); void readfile(int, double *, double **, double **, double **, imageint *, int *); }; diff --git a/src/RIGID/fix_rigid_nh.cpp b/src/RIGID/fix_rigid_nh.cpp index 9c9d582d94..f628b639ab 100644 --- a/src/RIGID/fix_rigid_nh.cpp +++ b/src/RIGID/fix_rigid_nh.cpp @@ -45,12 +45,11 @@ using namespace RigidConst; /* ---------------------------------------------------------------------- */ FixRigidNH::FixRigidNH(LAMMPS *lmp, int narg, char **arg) : - FixRigid(lmp, narg, arg), conjqm(nullptr), w(nullptr), - wdti1(nullptr), wdti2(nullptr), wdti4(nullptr), q_t(nullptr), q_r(nullptr), - eta_t(nullptr), eta_r(nullptr), eta_dot_t(nullptr), eta_dot_r(nullptr), - f_eta_t(nullptr), f_eta_r(nullptr), q_b(nullptr), eta_b(nullptr), - eta_dot_b(nullptr), f_eta_b(nullptr), rfix(nullptr), id_temp(nullptr), - id_press(nullptr), temperature(nullptr), pressure(nullptr) + FixRigid(lmp, narg, arg), conjqm(nullptr), w(nullptr), wdti1(nullptr), wdti2(nullptr), + wdti4(nullptr), q_t(nullptr), q_r(nullptr), eta_t(nullptr), eta_r(nullptr), eta_dot_t(nullptr), + eta_dot_r(nullptr), f_eta_t(nullptr), f_eta_r(nullptr), q_b(nullptr), eta_b(nullptr), + eta_dot_b(nullptr), f_eta_b(nullptr), id_temp(nullptr), id_press(nullptr), + temperature(nullptr), pressure(nullptr) { if (tstat_flag || pstat_flag) ecouple_flag = 1; @@ -59,57 +58,54 @@ FixRigidNH::FixRigidNH(LAMMPS *lmp, int narg, char **arg) : if ((p_flag[0] == 1 && p_period[0] <= 0.0) || (p_flag[1] == 1 && p_period[1] <= 0.0) || (p_flag[2] == 1 && p_period[2] <= 0.0)) - error->all(FLERR,"Fix rigid npt/nph period must be > 0.0"); + error->all(FLERR,"Fix {} period must be > 0.0", style); - if (dimension == 2 && p_flag[2]) - error->all(FLERR,"Invalid fix rigid npt/nph command for a 2d simulation"); - if (dimension == 2 && (pcouple == YZ || pcouple == XZ)) - error->all(FLERR,"Invalid fix rigid npt/nph command for a 2d simulation"); + if (domain->dimension == 2 && p_flag[2]) + error->all(FLERR,"Invalid fix {} command for a 2d simulation", style); + if (domain->dimension == 2 && (pcouple == YZ || pcouple == XZ)) + error->all(FLERR,"Invalid fix {} command for a 2d simulation", style); if (pcouple == XYZ && (p_flag[0] == 0 || p_flag[1] == 0)) - error->all(FLERR,"Invalid fix rigid npt/nph command pressure settings"); - if (pcouple == XYZ && dimension == 3 && p_flag[2] == 0) - error->all(FLERR,"Invalid fix rigid npt/nph command pressure settings"); + error->all(FLERR,"Invalid fix {} command pressure settings", style); + if (pcouple == XYZ && domain->dimension == 3 && p_flag[2] == 0) + error->all(FLERR,"Invalid fix {} command pressure settings", style); if (pcouple == XY && (p_flag[0] == 0 || p_flag[1] == 0)) - error->all(FLERR,"Invalid fix rigid npt/nph command pressure settings"); + error->all(FLERR,"Invalid fix {} command pressure settings", style); if (pcouple == YZ && (p_flag[1] == 0 || p_flag[2] == 0)) - error->all(FLERR,"Invalid fix rigid npt/nph command pressure settings"); + error->all(FLERR,"Invalid fix {} command pressure settings", style); if (pcouple == XZ && (p_flag[0] == 0 || p_flag[2] == 0)) - error->all(FLERR,"Invalid fix rigid npt/nph command pressure settings"); + error->all(FLERR,"Invalid fix {} command pressure settings", style); // require periodicity in tensile dimension if (p_flag[0] && domain->xperiodic == 0) - error->all(FLERR, - "Cannot use fix rigid npt/nph on a non-periodic dimension"); + error->all(FLERR, "Cannot use fix {} on a non-periodic dimension", style); if (p_flag[1] && domain->yperiodic == 0) - error->all(FLERR, - "Cannot use fix rigid npt/nph on a non-periodic dimension"); + error->all(FLERR, "Cannot use fix {} on a non-periodic dimension", style); if (p_flag[2] && domain->zperiodic == 0) - error->all(FLERR, - "Cannot use fix rigid npt/nph on a non-periodic dimension"); + error->all(FLERR, "Cannot use fix {} on a non-periodic dimension", style); - if (pcouple == XYZ && dimension == 3 && + if (pcouple == XYZ && domain->dimension == 3 && (p_start[0] != p_start[1] || p_start[0] != p_start[2] || p_stop[0] != p_stop[1] || p_stop[0] != p_stop[2] || p_period[0] != p_period[1] || p_period[0] != p_period[2])) - error->all(FLERR,"Invalid fix rigid npt/nph command pressure settings"); - if (pcouple == XYZ && dimension == 2 && + error->all(FLERR,"Invalid fix {} command pressure settings", style); + if (pcouple == XYZ && domain->dimension == 2 && (p_start[0] != p_start[1] || p_stop[0] != p_stop[1] || p_period[0] != p_period[1])) - error->all(FLERR,"Invalid fix rigid npt/nph command pressure settings"); + error->all(FLERR,"Invalid fix {} command pressure settings", style); if (pcouple == XY && (p_start[0] != p_start[1] || p_stop[0] != p_stop[1] || p_period[0] != p_period[1])) - error->all(FLERR,"Invalid fix rigid npt/nph command pressure settings"); + error->all(FLERR,"Invalid fix {} command pressure settings", style); if (pcouple == YZ && (p_start[1] != p_start[2] || p_stop[1] != p_stop[2] || p_period[1] != p_period[2])) - error->all(FLERR,"Invalid fix rigid npt/nph command pressure settings"); + error->all(FLERR,"Invalid fix {} command pressure settings", style); if (pcouple == XZ && (p_start[0] != p_start[2] || p_stop[0] != p_stop[2] || p_period[0] != p_period[2])) - error->all(FLERR,"Invalid fix rigid npt/nph command pressure settings"); + error->all(FLERR,"Invalid fix {} command pressure settings", style); if (p_flag[0]) box_change |= BOX_CHANGE_X; if (p_flag[1]) box_change |= BOX_CHANGE_Y; @@ -119,7 +115,7 @@ FixRigidNH::FixRigidNH(LAMMPS *lmp, int narg, char **arg) : (p_flag[0] && p_period[0] <= 0.0) || (p_flag[1] && p_period[1] <= 0.0) || (p_flag[2] && p_period[2] <= 0.0)) - error->all(FLERR,"Fix rigid nvt/npt/nph damping parameters must be > 0.0"); + error->all(FLERR,"Fix {} damping parameters must be > 0.0", style); // memory allocation and initialization @@ -147,11 +143,6 @@ FixRigidNH::FixRigidNH(LAMMPS *lmp, int narg, char **arg) : eta_b[i] = eta_dot_b[i] = 0.0; } - // rigid body pointers - - nrigidfix = 0; - rfix = nullptr; - vol0 = 0.0; t0 = 1.0; @@ -172,16 +163,14 @@ FixRigidNH::~FixRigidNH() deallocate_order(); } - delete[] rfix; - if (tcomputeflag) modify->delete_compute(id_temp); - delete [] id_temp; + delete[] id_temp; // delete pressure if fix created it if (pstat_flag) { if (pcomputeflag) modify->delete_compute(id_press); - delete [] id_press; + delete[] id_press; } } @@ -205,7 +194,7 @@ void FixRigidNH::init() if (allremap == 0) { int idilate = group->find(id_dilate); if (idilate == -1) - error->all(FLERR,"Fix rigid npt/nph dilate group ID does not exist"); + error->all(FLERR,"Fix {} dilate group ID does not exist", style); dilate_group_bit = group->bitmask[idilate]; } @@ -224,6 +213,7 @@ void FixRigidNH::init() if (force->kspace) kspace_flag = 1; else kspace_flag = 0; + int dimension = domain->dimension; nf_t = dimension * nbody; if (dimension == 3) { nf_r = dimension * nbody; @@ -254,28 +244,27 @@ void FixRigidNH::init() } } - int icompute; if (tcomputeflag) { - icompute = modify->find_compute(id_temp); - if (icompute < 0) - error->all(FLERR,"Temperature ID for fix rigid nvt/npt/nph does not exist"); - temperature = modify->compute[icompute]; + temperature = modify->get_compute_by_id(id_temp); + if (!temperature) + error->all(FLERR,"Temperature ID {} for fix {} does not exist", id_temp, style); } if (pstat_flag) { if (domain->triclinic) - error->all(FLERR,"Fix rigid npt/nph does not yet allow triclinic box"); + error->all(FLERR,"Fix {} does not yet allow triclinic box", style); // ensure no conflict with fix deform - for (int i = 0; i < modify->nfix; i++) - if (strcmp(modify->fix[i]->style,"deform") == 0) { - int *dimflag = (dynamic_cast(modify->fix[i]))->dimflag; + for (auto &ifix : modify->get_fix_by_style("^deform")) { + auto deform = dynamic_cast(ifix); + if (deform) { + int *dimflag = deform->dimflag; if ((p_flag[0] && dimflag[0]) || (p_flag[1] && dimflag[1]) || (p_flag[2] && dimflag[2])) - error->all(FLERR,"Cannot use fix rigid npt/nph and fix deform on " - "same component of stress tensor"); + error->all(FLERR,"Cannot use fix {} and fix deform on same component of stress tensor", style); } + } // set frequency @@ -294,27 +283,15 @@ void FixRigidNH::init() // set pressure compute ptr - icompute = modify->find_compute(id_press); - if (icompute < 0) - error->all(FLERR,"Pressure ID for fix rigid npt/nph does not exist"); - pressure = modify->compute[icompute]; + pressure = modify->get_compute_by_id(id_press); + if (!pressure) error->all(FLERR,"Pressure ID {} for fix {} does not exist", id_press, style); // detect if any rigid fixes exist so rigid bodies move on remap - // rfix[] = indices to each fix rigid // this will include self - delete[] rfix; - nrigidfix = 0; - rfix = nullptr; - - for (int i = 0; i < modify->nfix; i++) - if (modify->fix[i]->rigid_flag) nrigidfix++; - if (nrigidfix) { - rfix = new int[nrigidfix]; - nrigidfix = 0; - for (int i = 0; i < modify->nfix; i++) - if (modify->fix[i]->rigid_flag) rfix[nrigidfix++] = i; - } + rfix.clear(); + for (auto &ifix : modify->get_fix_list()) + if (ifix->rigid_flag) rfix.push_back(ifix); } } @@ -391,6 +368,7 @@ void FixRigidNH::setup(int vflag) // initial forces on barostat thermostat variables + int dimension = domain->dimension; if (pstat_flag) { for (int i = 0; i < 3; i++) if (p_flag[i]) { @@ -821,6 +799,7 @@ void FixRigidNH::nhc_press_integrate() // update thermostat masses + int dimension = domain->dimension; double tb_mass = kt / (p_freq_max * p_freq_max); q_b[0] = dimension * dimension * tb_mass; for (i = 1; i < p_chain; i++) { @@ -927,7 +906,7 @@ double FixRigidNH::compute_scalar() energy += e*(0.5/pdim); double vol; - if (dimension == 2) vol = domain->xprd * domain->yprd; + if (domain->dimension == 2) vol = domain->xprd * domain->yprd; else vol = domain->xprd * domain->yprd * domain->zprd; double p0 = (p_target[0] + p_target[1] + p_target[2]) / 3.0; @@ -996,9 +975,7 @@ void FixRigidNH::remap() domain->x2lamda(x[i],x[i]); } - if (nrigidfix) - for (i = 0; i < nrigidfix; i++) - modify->fix[rfix[i]]->deform(0); + for (auto &ifix : rfix) ifix->deform(0); // reset global and local box to new size/shape @@ -1025,9 +1002,7 @@ void FixRigidNH::remap() domain->lamda2x(x[i],x[i]); } - if (nrigidfix) - for (i = 0; i< nrigidfix; i++) - modify->fix[rfix[i]]->deform(1); + for (auto &ifix : rfix) ifix->deform(1); } /* ---------------------------------------------------------------------- @@ -1071,7 +1046,7 @@ void FixRigidNH::nh_epsilon_dot() int i; double volume,scale,f_epsilon; - if (dimension == 2) volume = domain->xprd*domain->yprd; + if (domain->dimension == 2) volume = domain->xprd*domain->yprd; else volume = domain->xprd*domain->yprd*domain->zprd; // MTK terms @@ -1206,13 +1181,11 @@ int FixRigidNH::modify_param(int narg, char **arg) modify->delete_compute(id_temp); tcomputeflag = 0; } - delete [] id_temp; + delete[] id_temp; id_temp = utils::strdup(arg[1]); - int icompute = modify->find_compute(arg[1]); - if (icompute < 0) - error->all(FLERR,"Could not find fix_modify temperature ID"); - temperature = modify->compute[icompute]; + temperature = modify->get_compute_by_id(id_temp); + if (!temperature) error->all(FLERR,"Could not find fix_modify temperature ID {}", id_temp); if (temperature->tempflag == 0) error->all(FLERR, @@ -1223,10 +1196,9 @@ int FixRigidNH::modify_param(int narg, char **arg) // reset id_temp of pressure to new temperature ID if (pstat_flag) { - icompute = modify->find_compute(id_press); - if (icompute < 0) - error->all(FLERR,"Pressure ID for fix modify does not exist"); - modify->compute[icompute]->reset_extra_compute_fix(id_temp); + pressure = modify->get_compute_by_id(id_press); + if (!pressure) error->all(FLERR,"Pressure ID {} for fix modify does not exist", id_press); + pressure->reset_extra_compute_fix(id_temp); } return 2; @@ -1238,15 +1210,13 @@ int FixRigidNH::modify_param(int narg, char **arg) modify->delete_compute(id_press); pcomputeflag = 0; } - delete [] id_press; + delete[] id_press; id_press = utils::strdup(arg[1]); - - int icompute = modify->find_compute(arg[1]); - if (icompute < 0) error->all(FLERR,"Could not find fix_modify pressure ID"); - pressure = modify->compute[icompute]; + pressure = modify->get_compute_by_id(id_press); + if (!pressure) error->all(FLERR,"Could not find fix_modify pressure ID {}", id_press); if (pressure->pressflag == 0) - error->all(FLERR,"Fix_modify pressure ID does not compute pressure"); + error->all(FLERR,"Fix_modify pressure ID {} does not compute pressure", id_press); return 2; } @@ -1298,21 +1268,21 @@ void FixRigidNH::allocate_order() void FixRigidNH::deallocate_chain() { if (tstat_flag) { - delete [] q_t; - delete [] q_r; - delete [] eta_t; - delete [] eta_r; - delete [] eta_dot_t; - delete [] eta_dot_r; - delete [] f_eta_t; - delete [] f_eta_r; + delete[] q_t; + delete[] q_r; + delete[] eta_t; + delete[] eta_r; + delete[] eta_dot_t; + delete[] eta_dot_r; + delete[] f_eta_t; + delete[] f_eta_r; } if (pstat_flag) { - delete [] q_b; - delete [] eta_b; - delete [] eta_dot_b; - delete [] f_eta_b; + delete[] q_b; + delete[] eta_b; + delete[] eta_dot_b; + delete[] f_eta_b; } } @@ -1320,8 +1290,8 @@ void FixRigidNH::deallocate_chain() void FixRigidNH::deallocate_order() { - delete [] w; - delete [] wdti1; - delete [] wdti2; - delete [] wdti4; + delete[] w; + delete[] wdti1; + delete[] wdti2; + delete[] wdti4; } diff --git a/src/RIGID/fix_rigid_nh.h b/src/RIGID/fix_rigid_nh.h index 94600f97d1..7d357cfdf9 100644 --- a/src/RIGID/fix_rigid_nh.h +++ b/src/RIGID/fix_rigid_nh.h @@ -50,9 +50,8 @@ class FixRigidNH : public FixRigid { double *f_eta_b; // thermo forces double akin_t, akin_r; // translational/rotational kinetic energies - int kspace_flag; // 1 if KSpace invoked, 0 if not - int nrigidfix; // number of rigid fixes - int *rfix; // indices of rigid fixes + int kspace_flag; // 1 if KSpace invoked, 0 if not + std::vector rfix; // indices of rigid fixes double vol0; // reference volume double t0; // reference temperature @@ -70,7 +69,7 @@ class FixRigidNH : public FixRigid { int tcomputeflag, pcomputeflag; // 1 = compute was created by fix. 0 = external void couple(); - void remap(); + virtual void remap(); void nhc_temp_integrate(); void nhc_press_integrate(); diff --git a/src/RIGID/fix_rigid_nh_small.cpp b/src/RIGID/fix_rigid_nh_small.cpp index 8d4c015f96..952dc29032 100644 --- a/src/RIGID/fix_rigid_nh_small.cpp +++ b/src/RIGID/fix_rigid_nh_small.cpp @@ -46,83 +46,62 @@ using namespace RigidConst; /* ---------------------------------------------------------------------- */ FixRigidNHSmall::FixRigidNHSmall(LAMMPS *lmp, int narg, char **arg) : - FixRigidSmall(lmp, narg, arg), w(nullptr), wdti1(nullptr), - wdti2(nullptr), wdti4(nullptr), q_t(nullptr), q_r(nullptr), eta_t(nullptr), - eta_r(nullptr), eta_dot_t(nullptr), eta_dot_r(nullptr), f_eta_t(nullptr), - f_eta_r(nullptr), q_b(nullptr), eta_b(nullptr), eta_dot_b(nullptr), - f_eta_b(nullptr), rfix(nullptr), id_temp(nullptr), id_press(nullptr), - temperature(nullptr), pressure(nullptr) + FixRigidSmall(lmp, narg, arg), w(nullptr), wdti1(nullptr), wdti2(nullptr), wdti4(nullptr), + q_t(nullptr), q_r(nullptr), eta_t(nullptr), eta_r(nullptr), eta_dot_t(nullptr), + eta_dot_r(nullptr), f_eta_t(nullptr), f_eta_r(nullptr), q_b(nullptr), eta_b(nullptr), + eta_dot_b(nullptr), f_eta_b(nullptr), id_temp(nullptr), id_press(nullptr), + temperature(nullptr), pressure(nullptr) { if (tstat_flag || pstat_flag) ecouple_flag = 1; // error checks - if ((p_flag[0] == 1 && p_period[0] <= 0.0) || - (p_flag[1] == 1 && p_period[1] <= 0.0) || - (p_flag[2] == 1 && p_period[2] <= 0.0)) - error->all(FLERR,"Fix rigid/small npt/nph period must be > 0.0"); - - dimension = domain->dimension; - - if (dimension == 2 && p_flag[2]) - error->all(FLERR,"Invalid fix rigid/small npt/nph command " - "for a 2d simulation"); - if (dimension == 2 && (pcouple == YZ || pcouple == XZ)) - error->all(FLERR,"Invalid fix rigid/small npt/nph command " - "for a 2d simulation"); + if (domain->dimension == 2 && p_flag[2]) + error->all(FLERR,"Invalid fix {} command for a 2d simulation", style); + if (domain->dimension == 2 && (pcouple == YZ || pcouple == XZ)) + error->all(FLERR,"Invalid fix {} command for a 2d simulation", style); if (pcouple == XYZ && (p_flag[0] == 0 || p_flag[1] == 0)) - error->all(FLERR,"Invalid fix rigid/small npt/nph command " - "pressure settings"); - if (pcouple == XYZ && dimension == 3 && p_flag[2] == 0) - error->all(FLERR,"Invalid fix rigid/small npt/nph command " - "pressure settings"); + error->all(FLERR,"Invalid fix {} command pressure settings", style); + if (pcouple == XYZ && domain->dimension == 3 && p_flag[2] == 0) + error->all(FLERR,"Invalid fix {} command pressure settings", style); if (pcouple == XY && (p_flag[0] == 0 || p_flag[1] == 0)) - error->all(FLERR,"Invalid fix rigid/small npt/nph command " - "pressure settings"); + error->all(FLERR,"Invalid fix {} command pressure settings", style); if (pcouple == YZ && (p_flag[1] == 0 || p_flag[2] == 0)) - error->all(FLERR,"Invalid fix rigid/small npt/nph command " - "pressure settings"); + error->all(FLERR,"Invalid fix {} command pressure settings", style); if (pcouple == XZ && (p_flag[0] == 0 || p_flag[2] == 0)) - error->all(FLERR,"Invalid fix rigid/small npt/nph command " - "pressure settings"); + error->all(FLERR,"Invalid fix {} command pressure settings", style); // require periodicity in tensile dimension if (p_flag[0] && domain->xperiodic == 0) - error->all(FLERR, - "Cannot use fix rigid/small npt/nph on a " - "non-periodic dimension"); + error->all(FLERR, "Cannot use fix {} on a non-periodic dimension", style); if (p_flag[1] && domain->yperiodic == 0) - error->all(FLERR, - "Cannot use fix rigid/small npt/nph on a " - "non-periodic dimension"); + error->all(FLERR, "Cannot use fix {} on a non-periodic dimension", style); if (p_flag[2] && domain->zperiodic == 0) - error->all(FLERR, - "Cannot use fix rigid/small npt/nph on a " - "non-periodic dimension"); + error->all(FLERR, "Cannot use fix {} on a non-periodic dimension", style); - if (pcouple == XYZ && dimension == 3 && + if (pcouple == XYZ && domain->dimension == 3 && (p_start[0] != p_start[1] || p_start[0] != p_start[2] || p_stop[0] != p_stop[1] || p_stop[0] != p_stop[2] || p_period[0] != p_period[1] || p_period[0] != p_period[2])) - error->all(FLERR,"Invalid fix rigid/small npt/nph command pressure settings"); - if (pcouple == XYZ && dimension == 2 && + error->all(FLERR, "Invalid fix {} command pressure settings", style); + if (pcouple == XYZ && domain->dimension == 2 && (p_start[0] != p_start[1] || p_stop[0] != p_stop[1] || p_period[0] != p_period[1])) - error->all(FLERR,"Invalid fix rigid/small npt/nph command pressure settings"); + error->all(FLERR, "Invalid fix {} command pressure settings", style); if (pcouple == XY && (p_start[0] != p_start[1] || p_stop[0] != p_stop[1] || p_period[0] != p_period[1])) - error->all(FLERR,"Invalid fix rigid/small npt/nph command pressure settings"); + error->all(FLERR, "Invalid fix {} command pressure settings", style); if (pcouple == YZ && (p_start[1] != p_start[2] || p_stop[1] != p_stop[2] || p_period[1] != p_period[2])) - error->all(FLERR,"Invalid fix rigid/small npt/nph command pressure settings"); + error->all(FLERR, "Invalid fix {} command pressure settings", style); if (pcouple == XZ && (p_start[0] != p_start[2] || p_stop[0] != p_stop[2] || p_period[0] != p_period[2])) - error->all(FLERR,"Invalid fix rigid/small npt/nph command pressure settings"); + error->all(FLERR, "Invalid fix {} command pressure settings", style); if (p_flag[0]) box_change |= BOX_CHANGE_X; if (p_flag[1]) box_change |= BOX_CHANGE_Y; @@ -132,8 +111,7 @@ FixRigidNHSmall::FixRigidNHSmall(LAMMPS *lmp, int narg, char **arg) : (p_flag[0] && p_period[0] <= 0.0) || (p_flag[1] && p_period[1] <= 0.0) || (p_flag[2] && p_period[2] <= 0.0)) - error->all(FLERR,"Fix rigid/small nvt/npt/nph damping parameters " - "must be > 0.0"); + error->all(FLERR,"Fix {} damping parameters must be > 0.0", style); // memory allocation and initialization @@ -160,19 +138,11 @@ FixRigidNHSmall::FixRigidNHSmall(LAMMPS *lmp, int narg, char **arg) : eta_b[i] = eta_dot_b[i] = 0.0; } - // rigid body pointers - - nrigidfix = 0; - rfix = nullptr; - vol0 = 0.0; t0 = 1.0; tcomputeflag = 0; pcomputeflag = 0; - - id_temp = nullptr; - id_press = nullptr; } /* ---------------------------------------------------------------------- */ @@ -184,16 +154,14 @@ FixRigidNHSmall::~FixRigidNHSmall() deallocate_order(); } - delete[] rfix; - if (tcomputeflag) modify->delete_compute(id_temp); - delete [] id_temp; + delete[] id_temp; // delete pressure if fix created it if (pstat_flag) { if (pcomputeflag) modify->delete_compute(id_press); - delete [] id_press; + delete[] id_press; } } @@ -216,8 +184,7 @@ void FixRigidNHSmall::init() if (allremap == 0) { int idilate = group->find(id_dilate); - if (idilate == -1) - error->all(FLERR,"Fix rigid npt/nph dilate group ID does not exist"); + if (idilate == -1) error->all(FLERR,"Fix {} dilate group ID does not exist", style); dilate_group_bit = group->bitmask[idilate]; } @@ -254,26 +221,26 @@ void FixRigidNHSmall::init() int icompute; if (tcomputeflag) { - icompute = modify->find_compute(id_temp); - if (icompute < 0) - error->all(FLERR,"Temperature ID for fix rigid nvt/npt/nph does not exist"); - temperature = modify->compute[icompute]; + temperature = modify->get_compute_by_id(id_temp); + if (!temperature) + error->all(FLERR,"Temperature ID {} for fix {} does not exist", id_temp, style); } if (pstat_flag) { if (domain->triclinic) - error->all(FLERR,"Fix rigid npt/nph does not yet allow triclinic box"); + error->all(FLERR,"Fix {} does not yet allow triclinic box", style); // ensure no conflict with fix deform - for (int i = 0; i < modify->nfix; i++) - if (strcmp(modify->fix[i]->style,"deform") == 0) { - int *dimflag = (dynamic_cast(modify->fix[i]))->dimflag; + for (auto &ifix : modify->get_fix_by_style("^deform")) { + auto deform = dynamic_cast(ifix); + if (deform) { + int *dimflag = deform->dimflag; if ((p_flag[0] && dimflag[0]) || (p_flag[1] && dimflag[1]) || (p_flag[2] && dimflag[2])) - error->all(FLERR,"Cannot use fix rigid npt/nph and fix deform on " - "same component of stress tensor"); + error->all(FLERR,"Cannot use fix {} and fix deform on same component of stress tensor", style); } + } // set frequency @@ -286,33 +253,21 @@ void FixRigidNHSmall::init() pdim = p_flag[0] + p_flag[1] + p_flag[2]; if (vol0 == 0.0) { - if (dimension == 2) vol0 = domain->xprd * domain->yprd; + if (domain->dimension == 2) vol0 = domain->xprd * domain->yprd; else vol0 = domain->xprd * domain->yprd * domain->zprd; } // set pressure compute ptr - icompute = modify->find_compute(id_press); - if (icompute < 0) - error->all(FLERR,"Pressure ID for fix rigid npt/nph does not exist"); - pressure = modify->compute[icompute]; + pressure = modify->get_compute_by_id(id_press); + if (!pressure) error->all(FLERR,"Pressure ID {} for fix {} does not exist", id_press, style); // detect if any rigid fixes exist so rigid bodies move on remap - // rfix[] = indices to each fix rigid // this will include self - delete[] rfix; - nrigidfix = 0; - rfix = nullptr; - - for (int i = 0; i < modify->nfix; i++) - if (modify->fix[i]->rigid_flag) nrigidfix++; - if (nrigidfix) { - rfix = new int[nrigidfix]; - nrigidfix = 0; - for (int i = 0; i < modify->nfix; i++) - if (modify->fix[i]->rigid_flag) rfix[nrigidfix++] = i; - } + rfix.clear(); + for (auto &ifix : modify->get_fix_list()) + if (ifix->rigid_flag) rfix.push_back(ifix); } } @@ -404,6 +359,7 @@ void FixRigidNHSmall::setup(int vflag) } // initial forces on barostat thermostat variables + int dimension = domain->dimension; if (pstat_flag) { for (int i = 0; i < 3; i++) @@ -855,6 +811,7 @@ void FixRigidNHSmall::nhc_press_integrate() // update thermostat masses + int dimension = domain->dimension; double tb_mass = kt / (p_freq_max * p_freq_max); q_b[0] = dimension * dimension * tb_mass; for (i = 1; i < p_chain; i++) { @@ -1011,7 +968,7 @@ double FixRigidNHSmall::compute_scalar() energy += e*(0.5/pdim); double vol; - if (dimension == 2) vol = domain->xprd * domain->yprd; + if (domain->dimension == 2) vol = domain->xprd * domain->yprd; else vol = domain->xprd * domain->yprd * domain->zprd; double p0 = (p_target[0] + p_target[1] + p_target[2]) / 3.0; @@ -1080,9 +1037,7 @@ void FixRigidNHSmall::remap() domain->x2lamda(x[i],x[i]); } - if (nrigidfix) - for (i = 0; i < nrigidfix; i++) - modify->fix[rfix[i]]->deform(0); + for (auto &ifix : rfix) ifix->deform(0); // reset global and local box to new size/shape @@ -1109,9 +1064,7 @@ void FixRigidNHSmall::remap() domain->lamda2x(x[i],x[i]); } - if (nrigidfix) - for (i = 0; i< nrigidfix; i++) - modify->fix[rfix[i]]->deform(1); + for (auto &ifix : rfix) ifix->deform(1); } /* ---------------------------------------------------------------------- @@ -1155,7 +1108,7 @@ void FixRigidNHSmall::nh_epsilon_dot() int i; double volume,scale,f_epsilon; - if (dimension == 2) volume = domain->xprd*domain->yprd; + if (domain->dimension == 2) volume = domain->xprd*domain->yprd; else volume = domain->xprd*domain->yprd*domain->zprd; // MTK terms @@ -1183,6 +1136,7 @@ void FixRigidNHSmall::nh_epsilon_dot() void FixRigidNHSmall::compute_dof() { // total translational and rotational degrees of freedom + int dimension = domain->dimension; nf_t = dimension * nlocal_body; if (dimension == 3) { @@ -1316,27 +1270,23 @@ int FixRigidNHSmall::modify_param(int narg, char **arg) modify->delete_compute(id_temp); tcomputeflag = 0; } - delete [] id_temp; + delete[] id_temp; id_temp = utils::strdup(arg[1]); - int icompute = modify->find_compute(arg[1]); - if (icompute < 0) - error->all(FLERR,"Could not find fix_modify temperature ID"); - temperature = modify->compute[icompute]; + temperature = modify->get_compute_by_id(id_temp); + if (!temperature) error->all(FLERR,"Could not find fix_modify temperature ID {}", id_temp); if (temperature->tempflag == 0) - error->all(FLERR, - "Fix_modify temperature ID does not compute temperature"); + error->all(FLERR, "Fix_modify temperature ID {} does not compute temperature", id_temp); if (temperature->igroup != 0 && comm->me == 0) error->warning(FLERR,"Temperature for fix modify is not for group all"); // reset id_temp of pressure to new temperature ID if (pstat_flag) { - icompute = modify->find_compute(id_press); - if (icompute < 0) - error->all(FLERR,"Pressure ID for fix modify does not exist"); - modify->compute[icompute]->reset_extra_compute_fix(id_temp); + pressure = modify->get_compute_by_id(id_press); + if (!pressure) error->all(FLERR,"Pressure ID {} for fix modify does not exist", id_press); + pressure->reset_extra_compute_fix(id_temp); } return 2; @@ -1348,15 +1298,14 @@ int FixRigidNHSmall::modify_param(int narg, char **arg) modify->delete_compute(id_press); pcomputeflag = 0; } - delete [] id_press; + delete[] id_press; id_press = utils::strdup(arg[1]); - int icompute = modify->find_compute(arg[1]); - if (icompute < 0) error->all(FLERR,"Could not find fix_modify pressure ID"); - pressure = modify->compute[icompute]; + pressure = modify->get_compute_by_id(id_press); + if (!pressure) error->all(FLERR,"Could not find fix_modify pressure ID {}", id_press); if (pressure->pressflag == 0) - error->all(FLERR,"Fix_modify pressure ID does not compute pressure"); + error->all(FLERR,"Fix_modify pressure ID {} does not compute pressure", id_press); return 2; } @@ -1408,21 +1357,21 @@ void FixRigidNHSmall::allocate_order() void FixRigidNHSmall::deallocate_chain() { if (tstat_flag) { - delete [] q_t; - delete [] q_r; - delete [] eta_t; - delete [] eta_r; - delete [] eta_dot_t; - delete [] eta_dot_r; - delete [] f_eta_t; - delete [] f_eta_r; + delete[] q_t; + delete[] q_r; + delete[] eta_t; + delete[] eta_r; + delete[] eta_dot_t; + delete[] eta_dot_r; + delete[] f_eta_t; + delete[] f_eta_r; } if (pstat_flag) { - delete [] q_b; - delete [] eta_b; - delete [] eta_dot_b; - delete [] f_eta_b; + delete[] q_b; + delete[] eta_b; + delete[] eta_dot_b; + delete[] f_eta_b; } } @@ -1430,8 +1379,8 @@ void FixRigidNHSmall::deallocate_chain() void FixRigidNHSmall::deallocate_order() { - delete [] w; - delete [] wdti1; - delete [] wdti2; - delete [] wdti4; + delete[] w; + delete[] wdti1; + delete[] wdti2; + delete[] wdti4; } diff --git a/src/RIGID/fix_rigid_nh_small.h b/src/RIGID/fix_rigid_nh_small.h index 3d637b6aea..735a15205c 100644 --- a/src/RIGID/fix_rigid_nh_small.h +++ b/src/RIGID/fix_rigid_nh_small.h @@ -36,7 +36,6 @@ class FixRigidNHSmall : public FixRigidSmall { protected: double boltz, nktv2p, mvv2e; // boltzman constant, conversion factors - int dimension; // # of dimensions int nf_t, nf_r; // trans/rot degrees of freedom double *w, *wdti1, *wdti2, *wdti4; // Yoshida-Suzuki coefficients double *q_t, *q_r; // trans/rot thermostat masses @@ -50,9 +49,8 @@ class FixRigidNHSmall : public FixRigidSmall { double *f_eta_b; // thermo forces double akin_t, akin_r; // translational/rotational kinetic energies - int kspace_flag; // 1 if KSpace invoked, 0 if not - int nrigidfix; // number of rigid fixes - int *rfix; // indices of rigid fixes + int kspace_flag; // 1 if KSpace invoked, 0 if not + std::vector rfix; // indices of rigid fixes double vol0; // reference volume double t0; // reference temperature diff --git a/src/RIGID/fix_rigid_small.cpp b/src/RIGID/fix_rigid_small.cpp index bf0a847d48..bd49834f15 100644 --- a/src/RIGID/fix_rigid_small.cpp +++ b/src/RIGID/fix_rigid_small.cpp @@ -72,13 +72,9 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : thermo_virial = 1; create_attribute = 1; dof_flag = 1; - enforce2d_flag = 1; stores_ids = 1; centroidstressflag = CENTROID_AVAIL; - MPI_Comm_rank(world,&me); - MPI_Comm_size(world,&nprocs); - // perform initial allocation of atom-based arrays // register with Atom class @@ -100,10 +96,10 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : tagint *bodyID = nullptr; int nlocal = atom->nlocal; - if (narg < 4) error->all(FLERR,"Illegal fix rigid/small command"); + if (narg < 4) utils::missing_cmd_args(FLERR, fmt::format("fix {}", style), error); if (strcmp(arg[3],"molecule") == 0) { if (atom->molecule_flag == 0) - error->all(FLERR,"Fix rigid/small requires atom attribute molecule"); + error->all(FLERR,"Fix {} requires atom attribute molecule", style); bodyID = atom->molecule; } else if (strcmp(arg[3],"custom") == 0) { @@ -117,9 +113,9 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : int is_double,cols; int custom_index = atom->find_custom(arg[4]+2,is_double,cols); if (custom_index == -1) - error->all(FLERR,"Fix rigid/small custom requires previously defined property/atom"); + error->all(FLERR,"Fix {} custom requires previously defined property/atom", style); else if (is_double || cols) - error->all(FLERR,"Fix rigid/small custom requires integer-valued property/atom vector"); + error->all(FLERR,"Fix {} custom requires integer-valued property/atom vector", style); int minval = INT_MAX; int *value = atom->ivector[custom_index]; for (i = 0; i < nlocal; i++) @@ -135,10 +131,9 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : } else if (utils::strmatch(arg[4],"^v_")) { int ivariable = input->variable->find(arg[4]+2); if (ivariable < 0) - error->all(FLERR,"Variable {} for fix rigid/small custom does not exist", arg[4]+2); + error->all(FLERR,"Variable {} for fix {} custom does not exist", arg[4]+2, style); if (input->variable->atomstyle(ivariable) == 0) - error->all(FLERR,"Fix rigid/small custom variable {} is not atom-style variable", - arg[4]+2); + error->all(FLERR,"Fix {} custom variable {} is not atom-style variable", style, arg[4]+2); auto value = new double[nlocal]; input->variable->compute_atom(ivariable,0,value,1,0); int minval = INT_MAX; @@ -152,11 +147,11 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : bodyID[i] = (tagint)((tagint)value[i] - minval + 1); else bodyID[0] = 0; delete[] value; - } else error->all(FLERR,"Unsupported fix rigid custom property"); - } else error->all(FLERR,"Illegal fix rigid/small command"); + } else error->all(FLERR,"Unsupported fix {} custom property", style, arg[4]); + } else error->all(FLERR,"Unknown fix {} keyword {}", style, arg[3]); if (atom->map_style == Atom::MAP_NONE) - error->all(FLERR,"Fix rigid/small requires an atom map, see atom_modify"); + error->all(FLERR,"Fix {} requires an atom map, see atom_modify", style); // maxmol = largest bodyID # @@ -201,23 +196,21 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : while (iarg < narg) { if (strcmp(arg[iarg],"langevin") == 0) { - if (iarg+5 > narg) error->all(FLERR,"Illegal fix rigid/small command"); - if ((strcmp(style,"rigid/small") != 0) && - (strcmp(style,"rigid/nve/small") != 0) && - (strcmp(style,"rigid/nph/small") != 0)) - error->all(FLERR,"Illegal fix rigid/small command"); + if (iarg+5 > narg) error->all(FLERR,"Illegal fix {} command", style); + if (utils::strmatch(style, "^rigid/n.t/small")) + error->all(FLERR,"Illegal fix {} command", style); langflag = 1; t_start = utils::numeric(FLERR,arg[iarg+1],false,lmp); t_stop = utils::numeric(FLERR,arg[iarg+2],false,lmp); t_period = utils::numeric(FLERR,arg[iarg+3],false,lmp); seed = utils::inumeric(FLERR,arg[iarg+4],false,lmp); if (t_period <= 0.0) - error->all(FLERR,"Fix rigid/small langevin period must be > 0.0"); - if (seed <= 0) error->all(FLERR,"Illegal fix rigid/small command"); + error->all(FLERR,"Fix {} langevin period must be > 0.0", style); + if (seed <= 0) error->all(FLERR,"Illegal fix {} command", style); iarg += 5; } else if (strcmp(arg[iarg],"infile") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid/small command"); + if (iarg+2 > narg) error->all(FLERR,"Illegal fix {} infile command", style); delete[] inpfile; inpfile = utils::strdup(arg[iarg+1]); restart_file = 1; @@ -225,23 +218,24 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : iarg += 2; } else if (strcmp(arg[iarg],"reinit") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid/small command"); + if (iarg+2 > narg) error->all(FLERR,"Illegal fix {} reinit command", style); reinitflag = utils::logical(FLERR,arg[iarg+1],false,lmp); iarg += 2; } else if (strcmp(arg[iarg],"mol") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid/small command"); + if (iarg+2 > narg) error->all(FLERR,"Illegal fix {} mol command", style); int imol = atom->find_molecule(arg[iarg+1]); - if (imol == -1) error->all(FLERR,"Molecule template ID for fix rigid/small does not exist"); + if (imol == -1) + error->all(FLERR,"Molecule template ID {} for fix {} does not exist", arg[iarg+1], style); onemols = &atom->molecules[imol]; nmol = onemols[0]->nset; restart_file = 1; iarg += 2; } else if (strcmp(arg[iarg],"temp") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid/small command"); + if (iarg+4 > narg) error->all(FLERR, "Illegal fix {} temp command", style); if (!utils::strmatch(style,"^rigid/n.t/small")) - error->all(FLERR,"Illegal fix rigid command"); + error->all(FLERR, "Illegal fix {} temp", style); tstat_flag = 1; t_start = utils::numeric(FLERR,arg[iarg+1],false,lmp); t_stop = utils::numeric(FLERR,arg[iarg+2],false,lmp); @@ -249,15 +243,16 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : iarg += 4; } else if (strcmp(arg[iarg],"iso") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid/small command"); + if (iarg+4 > narg) error->all(FLERR, "Illegal fix {} iso command", style); if (!utils::strmatch(style,"^rigid/np./small")) - error->all(FLERR,"Illegal fix rigid/small command"); + error->all(FLERR,"Illegal fix {} iso command", style); pcouple = XYZ; p_start[0] = p_start[1] = p_start[2] = utils::numeric(FLERR,arg[iarg+1],false,lmp); p_stop[0] = p_stop[1] = p_stop[2] = utils::numeric(FLERR,arg[iarg+2],false,lmp); p_period[0] = p_period[1] = p_period[2] = utils::numeric(FLERR,arg[iarg+3],false,lmp); p_flag[0] = p_flag[1] = p_flag[2] = 1; + if (domain->dimension == 2) { p_start[2] = p_stop[2] = p_period[2] = 0.0; p_flag[2] = 0; @@ -265,9 +260,9 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : iarg += 4; } else if (strcmp(arg[iarg],"aniso") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid/small command"); + if (iarg+4 > narg) error->all(FLERR,"Illegal fix {} ansio command", style); if (!utils::strmatch(style,"^rigid/np./small")) - error->all(FLERR,"Illegal fix rigid/small command"); + error->all(FLERR,"Illegal fix {} aniso command", style); p_start[0] = p_start[1] = p_start[2] = utils::numeric(FLERR,arg[iarg+1],false,lmp); p_stop[0] = p_stop[1] = p_stop[2] = utils::numeric(FLERR,arg[iarg+2],false,lmp); p_period[0] = p_period[1] = p_period[2] = @@ -280,9 +275,9 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : iarg += 4; } else if (strcmp(arg[iarg],"x") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid/small command"); + if (iarg+4 > narg) error->all(FLERR,"Illegal fix {} x command", style); if (!utils::strmatch(style,"^rigid/np./small")) - error->all(FLERR,"Illegal fix rigid/small command"); + error->all(FLERR,"Illegal fix {} x command", style); p_start[0] = utils::numeric(FLERR,arg[iarg+1],false,lmp); p_stop[0] = utils::numeric(FLERR,arg[iarg+2],false,lmp); p_period[0] = utils::numeric(FLERR,arg[iarg+3],false,lmp); @@ -290,9 +285,9 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : iarg += 4; } else if (strcmp(arg[iarg],"y") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid/small command"); + if (iarg+4 > narg) error->all(FLERR,"Illegal fix {} y command", style); if (!utils::strmatch(style,"^rigid/np./small")) - error->all(FLERR,"Illegal fix rigid/small command"); + error->all(FLERR,"Illegal fix {} y command", style); p_start[1] = utils::numeric(FLERR,arg[iarg+1],false,lmp); p_stop[1] = utils::numeric(FLERR,arg[iarg+2],false,lmp); p_period[1] = utils::numeric(FLERR,arg[iarg+3],false,lmp); @@ -300,9 +295,9 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : iarg += 4; } else if (strcmp(arg[iarg],"z") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid/small command"); + if (iarg+4 > narg) error->all(FLERR,"Illegal fix {} z command", style); if (!utils::strmatch(style,"^rigid/np./small")) - error->all(FLERR,"Illegal fix rigid/small command"); + error->all(FLERR,"Illegal fix {} z command", style); p_start[2] = utils::numeric(FLERR,arg[iarg+1],false,lmp); p_stop[2] = utils::numeric(FLERR,arg[iarg+2],false,lmp); p_period[2] = utils::numeric(FLERR,arg[iarg+3],false,lmp); @@ -310,18 +305,18 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : iarg += 4; } else if (strcmp(arg[iarg],"couple") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid/small command"); + if (iarg+2 > narg) error->all(FLERR,"Illegal fix {} couple command", style); if (strcmp(arg[iarg+1],"xyz") == 0) pcouple = XYZ; else if (strcmp(arg[iarg+1],"xy") == 0) pcouple = XY; else if (strcmp(arg[iarg+1],"yz") == 0) pcouple = YZ; else if (strcmp(arg[iarg+1],"xz") == 0) pcouple = XZ; else if (strcmp(arg[iarg+1],"none") == 0) pcouple = NONE; - else error->all(FLERR,"Illegal fix rigid/small command"); + else error->all(FLERR,"Illegal fix {} couple command", style); iarg += 2; } else if (strcmp(arg[iarg],"dilate") == 0) { if (iarg+2 > narg) - error->all(FLERR,"Illegal fix rigid/small nvt/npt/nph command"); + error->all(FLERR,"Illegal fix {} dilate command", style); if (strcmp(arg[iarg+1],"all") == 0) allremap = 1; else { allremap = 0; @@ -329,34 +324,33 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : id_dilate = utils::strdup(arg[iarg+1]); int idilate = group->find(id_dilate); if (idilate == -1) - error->all(FLERR,"Fix rigid/small nvt/npt/nph dilate group ID " - "does not exist"); + error->all(FLERR,"Fix {} dilate group ID {} does not exist", style, id_dilate); } iarg += 2; } else if (strcmp(arg[iarg],"tparam") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix rigid/small command"); + if (iarg+4 > narg) error->all(FLERR,"Illegal fix {} tparam command", style); if (!utils::strmatch(style,"^rigid/n.t/small")) - error->all(FLERR,"Illegal fix rigid/small command"); + error->all(FLERR,"Illegal fix {} tparam command", style); t_chain = utils::inumeric(FLERR,arg[iarg+1],false,lmp); t_iter = utils::inumeric(FLERR,arg[iarg+2],false,lmp); t_order = utils::inumeric(FLERR,arg[iarg+3],false,lmp); iarg += 4; } else if (strcmp(arg[iarg],"pchain") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid/small command"); + if (iarg+2 > narg) error->all(FLERR,"Illegal fix {} pchain command", style); if (!utils::strmatch(style,"^rigid/np./small")) - error->all(FLERR,"Illegal fix rigid/small command"); + error->all(FLERR,"Illegal fix {} pchain command", style); p_chain = utils::inumeric(FLERR,arg[iarg+1],false,lmp); iarg += 2; } else if (strcmp(arg[iarg],"gravity") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid/small command"); + if (iarg+2 > narg) error->all(FLERR,"Illegal fix {} gravity command", style); delete[] id_gravity; id_gravity = utils::strdup(arg[iarg+1]); iarg += 2; - } else error->all(FLERR,"Illegal fix rigid/small command"); + } else error->all(FLERR,"Unknown fix {} keyword {}", style, arg[iarg]); } // error check and further setup for Molecule template @@ -364,9 +358,9 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : if (onemols) { for (i = 0; i < nmol; i++) { if (onemols[i]->xflag == 0) - error->all(FLERR,"Fix rigid/small molecule must have coordinates"); + error->all(FLERR,"Fix {} molecule must have coordinates", style); if (onemols[i]->typeflag == 0) - error->all(FLERR,"Fix rigid/small molecule must have atom types"); + error->all(FLERR,"Fix {} molecule must have atom types", style); // fix rigid/small uses center, masstotal, COM, inertia of molecule @@ -452,7 +446,7 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : bigint atomall; MPI_Allreduce(&atomone,&atomall,1,MPI_LMP_BIGINT,MPI_SUM,world); - if (me == 0) { + if (comm->me == 0) { utils::logmesg(lmp," {} rigid bodies with {} atoms\n" " {:.8} = max distance from body owner to body atom\n", nbody,atomall,maxextent); @@ -531,15 +525,16 @@ void FixRigidSmall::init() int count = 0; for (auto &ifix : modify->get_fix_list()) if (ifix->rigid_flag) count++; - if (count > 1 && me == 0) error->warning(FLERR,"More than one fix rigid"); + if (count > 1 && comm->me == 0) + error->warning(FLERR, "More than one fix rigid command"); if (earlyflag) { bool rflag = false; for (auto &ifix : modify->get_fix_list()) { if (ifix->rigid_flag) rflag = true; if ((comm->me == 0) && rflag && (ifix->setmask() & POST_FORCE) && !ifix->rigid_flag) - error->warning(FLERR,"Fix {} with ID {} alters forces after fix rigid/small", - ifix->style, ifix->id); + error->warning(FLERR,"Fix {} with ID {} alters forces after fix {}", + ifix->style, ifix->id, style); } } @@ -568,9 +563,9 @@ void FixRigidSmall::init() if (id_gravity) { auto ifix = modify->get_fix_by_id(id_gravity); - if (!ifix) error->all(FLERR,"Fix rigid/small cannot find fix gravity ID {}", id_gravity); + if (!ifix) error->all(FLERR,"Fix {} cannot find fix gravity ID {}", style, id_gravity); if (!utils::strmatch(ifix->style,"^gravity")) - error->all(FLERR,"Fix rigid/small gravity fix ID {} is not a gravity fix style", id_gravity); + error->all(FLERR,"Fix {} gravity fix ID {} is not a gravity fix style", style, id_gravity); int tmp; gvec = (double *) ifix->extract("gvec", tmp); } @@ -629,7 +624,7 @@ void FixRigidSmall::setup(int vflag) double cutghost = MAX(neighbor->cutneighmax,comm->cutghostuser); if (maxextent > cutghost) - error->all(FLERR,"Rigid body extent > ghost cutoff - use comm_modify cutoff"); + error->all(FLERR,"Rigid body extent {} > ghost atom cutoff - use comm_modify cutoff", maxextent); //check(1); @@ -690,6 +685,10 @@ void FixRigidSmall::setup(int vflag) } } + // enforce 2d body forces and torques + + if (domain->dimension == 2) enforce2d(); + // reverse communicate fcm, torque of all bodies commflag = FORCE_TORQUE; @@ -780,6 +779,151 @@ void FixRigidSmall::initial_integrate(int vflag) set_xv(); } +/* ---------------------------------------------------------------------- + remap xcm of each rigid body back into periodic simulation box + done during pre_neighbor so will be after call to pbc() + and after fix_deform::pre_exchange() may have flipped box + use domain->remap() in case xcm is far away from box + due to first-time definition of rigid body in setup_bodies_static() + or due to box flip + also adjust imagebody = rigid body image flags, due to xcm remap + then communicate bodies so other procs will know of changes to body xcm + then adjust xcmimage flags of all atoms in bodies via image_shift() + for two effects + (1) change in true image flags due to pbc() call during exchange + (2) change in imagebody due to xcm remap + xcmimage flags are always -1,0,-1 so that body can be unwrapped + around in-box xcm and stay close to simulation box + if just inferred unwrapped from atom image flags, + then a body could end up very far away + when unwrapped by true image flags + then set_xv() will compute huge displacements every step to reset coords of + all the body atoms to be back inside the box, ditto for triclinic box flip + note: so just want to avoid that numeric problem? +------------------------------------------------------------------------- */ + +void FixRigidSmall::pre_neighbor() +{ + for (int ibody = 0; ibody < nlocal_body; ibody++) { + Body *b = &body[ibody]; + domain->remap(b->xcm,b->image); + } + + nghost_body = 0; + commflag = FULL_BODY; + comm->forward_comm(this); + reset_atom2body(); + //check(4); + + image_shift(); +} + +/* ---------------------------------------------------------------------- */ + +void FixRigidSmall::post_force(int /*vflag*/) +{ + if (langflag) apply_langevin_thermostat(); + if (earlyflag) compute_forces_and_torques(); +} + +/* ---------------------------------------------------------------------- */ + +void FixRigidSmall::final_integrate() +{ + double dtfm; + + //check(3); + + // compute forces and torques (after all post_force contributions) + // if 2d model, enforce2d() on body forces/torques + + if (!earlyflag) compute_forces_and_torques(); + if (domain->dimension == 2) enforce2d(); + + // update vcm and angmom, recompute omega + + for (int ibody = 0; ibody < nlocal_body; ibody++) { + Body *b = &body[ibody]; + + // update vcm by 1/2 step + + dtfm = dtf / b->mass; + b->vcm[0] += dtfm * b->fcm[0]; + b->vcm[1] += dtfm * b->fcm[1]; + b->vcm[2] += dtfm * b->fcm[2]; + + // update angular momentum by 1/2 step + + b->angmom[0] += dtf * b->torque[0]; + b->angmom[1] += dtf * b->torque[1]; + b->angmom[2] += dtf * b->torque[2]; + + MathExtra::angmom_to_omega(b->angmom,b->ex_space,b->ey_space, + b->ez_space,b->inertia,b->omega); + } + + // forward communicate updated info of all bodies + + commflag = FINAL; + comm->forward_comm(this,10); + + // set velocity/rotation of atoms in rigid bodies + // virial is already setup from initial_integrate + + set_v(); +} + +/* ---------------------------------------------------------------------- */ + +void FixRigidSmall::initial_integrate_respa(int vflag, int ilevel, int /*iloop*/) +{ + dtv = step_respa[ilevel]; + dtf = 0.5 * step_respa[ilevel] * force->ftm2v; + dtq = 0.5 * step_respa[ilevel]; + + if (ilevel == 0) initial_integrate(vflag); + else final_integrate(); +} + +/* ---------------------------------------------------------------------- */ + +void FixRigidSmall::final_integrate_respa(int ilevel, int /*iloop*/) +{ + dtf = 0.5 * step_respa[ilevel] * force->ftm2v; + final_integrate(); +} + +/* ---------------------------------------------------------------------- + reset body xcmimage flags of atoms in bodies + xcmimage flags are relative to xcm so that body can be unwrapped + xcmimage = true image flag - imagebody flag +------------------------------------------------------------------------- */ + +void FixRigidSmall::image_shift() +{ + imageint tdim,bdim,xdim[3]; + + imageint *image = atom->image; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) { + if (atom2body[i] < 0) continue; + Body *b = &body[atom2body[i]]; + + tdim = image[i] & IMGMASK; + bdim = b->image & IMGMASK; + xdim[0] = IMGMAX + tdim - bdim; + tdim = (image[i] >> IMGBITS) & IMGMASK; + bdim = (b->image >> IMGBITS) & IMGMASK; + xdim[1] = IMGMAX + tdim - bdim; + tdim = image[i] >> IMG2BITS; + bdim = b->image >> IMG2BITS; + xdim[2] = IMGMAX + tdim - bdim; + + xcmimage[i] = (xdim[2] << IMG2BITS) | (xdim[1] << IMGBITS) | xdim[0]; + } +} + /* ---------------------------------------------------------------------- apply Langevin thermostat to all 6 DOF of rigid bodies I own unlike fix langevin, this stores extra force in extra arrays, @@ -845,52 +989,9 @@ void FixRigidSmall::apply_langevin_thermostat() // convert langevin torques from body frame back to space frame MathExtra::matvec(ex_space,ey_space,ez_space,tbody,&langextra[ibody][3]); - - // enforce 2d motion - - if (domain->dimension == 2) - langextra[ibody][2] = langextra[ibody][3] = langextra[ibody][4] = 0.0; } } -/* ---------------------------------------------------------------------- - called from FixEnforce post_force() for 2d problems - zero all body values that should be zero for 2d model -------------------------------------------------------------------------- */ - -void FixRigidSmall::enforce2d() -{ - Body *b; - - for (int ibody = 0; ibody < nlocal_body; ibody++) { - b = &body[ibody]; - b->xcm[2] = 0.0; - b->vcm[2] = 0.0; - b->fcm[2] = 0.0; - b->xgc[2] = 0.0; - b->torque[0] = 0.0; - b->torque[1] = 0.0; - b->angmom[0] = 0.0; - b->angmom[1] = 0.0; - b->omega[0] = 0.0; - b->omega[1] = 0.0; - if (langflag && langextra) { - langextra[ibody][2] = 0.0; - langextra[ibody][3] = 0.0; - langextra[ibody][4] = 0.0; - } - } -} - -/* ---------------------------------------------------------------------- */ - -void FixRigidSmall::post_force(int /*vflag*/) -{ - if (langflag) apply_langevin_thermostat(); - if (earlyflag) compute_forces_and_torques(); -} - - /* ---------------------------------------------------------------------- */ void FixRigidSmall::compute_forces_and_torques() @@ -988,136 +1089,32 @@ void FixRigidSmall::compute_forces_and_torques() } } -/* ---------------------------------------------------------------------- */ - -void FixRigidSmall::final_integrate() -{ - double dtfm; - - //check(3); - - if (!earlyflag) compute_forces_and_torques(); - - // update vcm and angmom, recompute omega - - for (int ibody = 0; ibody < nlocal_body; ibody++) { - Body *b = &body[ibody]; - - // update vcm by 1/2 step - - dtfm = dtf / b->mass; - b->vcm[0] += dtfm * b->fcm[0]; - b->vcm[1] += dtfm * b->fcm[1]; - b->vcm[2] += dtfm * b->fcm[2]; - - // update angular momentum by 1/2 step - - b->angmom[0] += dtf * b->torque[0]; - b->angmom[1] += dtf * b->torque[1]; - b->angmom[2] += dtf * b->torque[2]; - - MathExtra::angmom_to_omega(b->angmom,b->ex_space,b->ey_space, - b->ez_space,b->inertia,b->omega); - } - - // forward communicate updated info of all bodies - - commflag = FINAL; - comm->forward_comm(this,10); - - // set velocity/rotation of atoms in rigid bodies - // virial is already setup from initial_integrate - - set_v(); -} - -/* ---------------------------------------------------------------------- */ - -void FixRigidSmall::initial_integrate_respa(int vflag, int ilevel, int /*iloop*/) -{ - dtv = step_respa[ilevel]; - dtf = 0.5 * step_respa[ilevel] * force->ftm2v; - dtq = 0.5 * step_respa[ilevel]; - - if (ilevel == 0) initial_integrate(vflag); - else final_integrate(); -} - -/* ---------------------------------------------------------------------- */ - -void FixRigidSmall::final_integrate_respa(int ilevel, int /*iloop*/) -{ - dtf = 0.5 * step_respa[ilevel] * force->ftm2v; - final_integrate(); -} - /* ---------------------------------------------------------------------- - remap xcm of each rigid body back into periodic simulation box - done during pre_neighbor so will be after call to pbc() - and after fix_deform::pre_exchange() may have flipped box - use domain->remap() in case xcm is far away from box - due to first-time definition of rigid body in setup_bodies_static() - or due to box flip - also adjust imagebody = rigid body image flags, due to xcm remap - then communicate bodies so other procs will know of changes to body xcm - then adjust xcmimage flags of all atoms in bodies via image_shift() - for two effects - (1) change in true image flags due to pbc() call during exchange - (2) change in imagebody due to xcm remap - xcmimage flags are always -1,0,-1 so that body can be unwrapped - around in-box xcm and stay close to simulation box - if just inferred unwrapped from atom image flags, - then a body could end up very far away - when unwrapped by true image flags - then set_xv() will compute huge displacements every step to reset coords of - all the body atoms to be back inside the box, ditto for triclinic box flip - note: so just want to avoid that numeric problem? + called from FixEnforce post_force() for 2d problems + zero all body values that should be zero for 2d model ------------------------------------------------------------------------- */ -void FixRigidSmall::pre_neighbor() +void FixRigidSmall::enforce2d() { + Body *b; + for (int ibody = 0; ibody < nlocal_body; ibody++) { - Body *b = &body[ibody]; - domain->remap(b->xcm,b->image); - } - - nghost_body = 0; - commflag = FULL_BODY; - comm->forward_comm(this); - reset_atom2body(); - //check(4); - - image_shift(); -} - -/* ---------------------------------------------------------------------- - reset body xcmimage flags of atoms in bodies - xcmimage flags are relative to xcm so that body can be unwrapped - xcmimage = true image flag - imagebody flag -------------------------------------------------------------------------- */ - -void FixRigidSmall::image_shift() -{ - imageint tdim,bdim,xdim[3]; - - imageint *image = atom->image; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) { - if (atom2body[i] < 0) continue; - Body *b = &body[atom2body[i]]; - - tdim = image[i] & IMGMASK; - bdim = b->image & IMGMASK; - xdim[0] = IMGMAX + tdim - bdim; - tdim = (image[i] >> IMGBITS) & IMGMASK; - bdim = (b->image >> IMGBITS) & IMGMASK; - xdim[1] = IMGMAX + tdim - bdim; - tdim = image[i] >> IMG2BITS; - bdim = b->image >> IMG2BITS; - xdim[2] = IMGMAX + tdim - bdim; - - xcmimage[i] = (xdim[2] << IMG2BITS) | (xdim[1] << IMGBITS) | xdim[0]; + b = &body[ibody]; + b->xcm[2] = 0.0; + b->vcm[2] = 0.0; + b->fcm[2] = 0.0; + b->xgc[2] = 0.0; + b->torque[0] = 0.0; + b->torque[1] = 0.0; + b->angmom[0] = 0.0; + b->angmom[1] = 0.0; + b->omega[0] = 0.0; + b->omega[1] = 0.0; + if (langflag && langextra) { + langextra[ibody][2] = 0.0; + langextra[ibody][3] = 0.0; + langextra[ibody][4] = 0.0; + } } } @@ -1182,7 +1179,7 @@ int FixRigidSmall::dof(int tgroup) } int flagall; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_MAX,world); - if (flagall && me == 0) + if (flagall && comm->me == 0) error->warning(FLERR,"Computing temperature of portions of rigid bodies"); // remove appropriate DOFs for each rigid body wholly in temperature group @@ -1297,6 +1294,7 @@ void FixRigidSmall::set_xv() // x = displacement from center-of-mass, based on body orientation // v = vcm + omega around center-of-mass + // enforce 2d x and v MathExtra::matvec(b->ex_space,b->ey_space,b->ez_space,displace[i],x[i]); @@ -1304,6 +1302,11 @@ void FixRigidSmall::set_xv() v[i][1] = b->omega[2]*x[i][0] - b->omega[0]*x[i][2] + b->vcm[1]; v[i][2] = b->omega[0]*x[i][1] - b->omega[1]*x[i][0] + b->vcm[2]; + if (domain->dimension == 2) { + x[i][2] = 0.0; + v[i][2] = 0.0; + } + // add center of mass to displacement // map back into periodic box via xbox,ybox,zbox // for triclinic, add in box tilt factors as well @@ -1345,6 +1348,7 @@ void FixRigidSmall::set_xv() } // update the position of geometric center + for (int ibody = 0; ibody < nlocal_body + nghost_body; ibody++) { Body *b = &body[ibody]; MathExtra::matvec(b->ex_space,b->ey_space,b->ez_space, @@ -1462,10 +1466,15 @@ void FixRigidSmall::set_v() v2 = v[i][2]; } + // compute new v + // enforce 2d v + v[i][0] = b->omega[1]*delta[2] - b->omega[2]*delta[1] + b->vcm[0]; v[i][1] = b->omega[2]*delta[0] - b->omega[0]*delta[2] + b->vcm[1]; v[i][2] = b->omega[0]*delta[1] - b->omega[1]*delta[0] + b->vcm[2]; + if (domain->dimension == 2) v[i][2] = 0.0; + // virial = unwrapped coords dotted into body constraint force // body constraint force = implied force due to v change minus f external // assume f does not include forces internal to body @@ -1583,6 +1592,8 @@ void FixRigidSmall::create_bodies(tagint *bodyID) double **x = atom->x; tagint *tag = atom->tag; imageint *image = atom->image; + int me = comm->me; + int nprocs = comm->nprocs; m = 0; for (i = 0; i < nlocal; i++) { @@ -2108,8 +2119,7 @@ void FixRigidSmall::setup_bodies_static() inertia = body[ibody].inertia; ierror = MathEigen::jacobi3(tensor,inertia,evectors); - if (ierror) error->all(FLERR, - "Insufficient Jacobi rotations for rigid body"); + if (ierror) error->all(FLERR, "Insufficient Jacobi rotations for rigid body"); ex = body[ibody].ex_space; ex[0] = evectors[0][0]; @@ -2305,30 +2315,30 @@ void FixRigidSmall::setup_bodies_static() if (inertia[0] == 0.0) { if (fabs(itensor[ibody][0]) > TOLERANCE) - error->all(FLERR,"Fix rigid: Bad principal moments"); + error->all(FLERR,"Fix {}: Bad principal moments", style); } else { if (fabs((itensor[ibody][0]-inertia[0])/inertia[0]) > - TOLERANCE) error->all(FLERR,"Fix rigid: Bad principal moments"); + TOLERANCE) error->all(FLERR,"Fix {}: Bad principal moments", style); } if (inertia[1] == 0.0) { if (fabs(itensor[ibody][1]) > TOLERANCE) - error->all(FLERR,"Fix rigid: Bad principal moments"); + error->all(FLERR,"Fix {}: Bad principal moments", style); } else { if (fabs((itensor[ibody][1]-inertia[1])/inertia[1]) > - TOLERANCE) error->all(FLERR,"Fix rigid: Bad principal moments"); + TOLERANCE) error->all(FLERR,"Fix {}: Bad principal moments", style); } if (inertia[2] == 0.0) { if (fabs(itensor[ibody][2]) > TOLERANCE) - error->all(FLERR,"Fix rigid: Bad principal moments"); + error->all(FLERR,"Fix {}: Bad principal moments", style); } else { if (fabs((itensor[ibody][2]-inertia[2])/inertia[2]) > - TOLERANCE) error->all(FLERR,"Fix rigid: Bad principal moments"); + TOLERANCE) error->all(FLERR,"Fix {}: Bad principal moments", style); } norm = (inertia[0] + inertia[1] + inertia[2]) / 3.0; if (fabs(itensor[ibody][3]/norm) > TOLERANCE || fabs(itensor[ibody][4]/norm) > TOLERANCE || fabs(itensor[ibody][5]/norm) > TOLERANCE) - error->all(FLERR,"Fix rigid: Bad principal moments"); + error->all(FLERR,"Fix {}: Bad principal moments", style); } // clean up @@ -2474,13 +2484,13 @@ void FixRigidSmall::readfile(int which, double **array, int *inbody) // open file and read header - if (me == 0) { + if (comm->me == 0) { fp = fopen(inpfile,"r"); if (fp == nullptr) - error->one(FLERR,"Cannot open fix rigid/small file {}: {}", inpfile, utils::getsyserror()); + error->one(FLERR,"Cannot open fix {} file {}: {}", style, inpfile, utils::getsyserror()); while (true) { eof = fgets(line,MAXLINE,fp); - if (eof == nullptr) error->one(FLERR,"Unexpected end of fix rigid/small file"); + if (eof == nullptr) error->one(FLERR,"Unexpected end of fix {} file", style); start = &line[strspn(line," \t\n\v\f\r")]; if (*start != '\0' && *start != '#') break; } @@ -2495,14 +2505,16 @@ void FixRigidSmall::readfile(int which, double **array, int *inbody) // generation when no infile was previously used. if (nlines == 0) return; - else if (nlines < 0) error->all(FLERR,"Fix rigid infile has incorrect format"); + else if (nlines < 0) error->all(FLERR,"Fix {} infile has incorrect format", style); auto buffer = new char[CHUNK*MAXLINE]; int nread = 0; + int me = comm->me; + while (nread < nlines) { nchunk = MIN(nlines-nread,CHUNK); eofflag = utils::read_lines_from_file(fp,nchunk,MAXLINE,buffer,me,world); - if (eofflag) error->all(FLERR,"Unexpected end of fix rigid/small file"); + if (eofflag) error->all(FLERR,"Unexpected end of fix {} file", style); buf = buffer; next = strchr(buf,'\n'); @@ -2511,7 +2523,7 @@ void FixRigidSmall::readfile(int which, double **array, int *inbody) *next = '\n'; if (nwords != ATTRIBUTE_PERBODY) - error->all(FLERR,"Incorrect rigid body format in fix rigid/small file"); + error->all(FLERR,"Incorrect rigid body format in fix {} file", style); // loop over lines of rigid body attributes // tokenize the line into values @@ -2528,7 +2540,7 @@ void FixRigidSmall::readfile(int which, double **array, int *inbody) tagint id = values.next_tagint(); if (id <= 0 || id > maxmol) - error->all(FLERR,"Invalid rigid body molecude ID {} in fix rigid/small file", id); + error->all(FLERR,"Invalid rigid body molecude ID {} in fix {} file", id, style); if (hash.find(id) == hash.end()) { buf = next + 1; @@ -2565,14 +2577,14 @@ void FixRigidSmall::readfile(int which, double **array, int *inbody) array[m][3] = values.next_double(); } } catch (TokenizerException &e) { - error->all(FLERR, "Invalid fix rigid/small infile: {}", e.what()); + error->all(FLERR, "Invalid fix {} infile: {}", style, e.what()); } buf = next + 1; } nread += nchunk; } - if (me == 0) fclose(fp); + if (comm->me == 0) fclose(fp); delete[] buffer; } @@ -2592,11 +2604,12 @@ void FixRigidSmall::write_restart_file(const char *file) // proc 0 opens file and writes header - if (me == 0) { + if (comm->me == 0) { auto outfile = std::string(file) + ".rigid"; fp = fopen(outfile.c_str(),"w"); if (fp == nullptr) - error->one(FLERR,"Cannot open fix rigid restart file {}: {}",outfile,utils::getsyserror()); + error->one(FLERR, "Cannot open fix {} restart file {}: {}", + style, outfile, utils::getsyserror()); fmt::print(fp,"# fix rigid mass, COM, inertia tensor info for " "{} bodies on timestep {}\n\n",nbody,update->ntimestep); @@ -2613,7 +2626,7 @@ void FixRigidSmall::write_restart_file(const char *file) MPI_Allreduce(&sendrow,&maxrow,1,MPI_INT,MPI_MAX,world); double **buf; - if (me == 0) memory->create(buf,MAX(1,maxrow),ncol,"rigid/small:buf"); + if (comm->me == 0) memory->create(buf,MAX(1,maxrow),ncol,"rigid/small:buf"); else memory->create(buf,MAX(1,sendrow),ncol,"rigid/small:buf"); // pack my rigid body info into buf @@ -2656,10 +2669,10 @@ void FixRigidSmall::write_restart_file(const char *file) int tmp,recvrow; - if (me == 0) { + if (comm->me == 0) { MPI_Status status; MPI_Request request; - for (int iproc = 0; iproc < nprocs; iproc++) { + for (int iproc = 0; iproc < comm->nprocs; iproc++) { if (iproc) { MPI_Irecv(&buf[0][0],maxrow*ncol,MPI_DOUBLE,iproc,0,world,&request); MPI_Send(&tmp,0,MPI_INT,iproc,0,world); @@ -2691,7 +2704,7 @@ void FixRigidSmall::write_restart_file(const char *file) // clean up and close file memory->destroy(buf); - if (me == 0) fclose(fp); + if (comm->me == 0) fclose(fp); } /* ---------------------------------------------------------------------- @@ -3367,9 +3380,8 @@ void FixRigidSmall::reset_atom2body() if (bodytag[i]) { iowner = atom->map(bodytag[i]); if (iowner == -1) - error->one(FLERR,"Rigid body atoms {} {} missing on " - "proc {} at step {}",atom->tag[i], - bodytag[i],comm->me,update->ntimestep); + error->one(FLERR, "Rigid body atoms {} {} missing on proc {} at step {}", + atom->tag[i], bodytag[i], comm->me, update->ntimestep); atom2body[i] = bodyown[iowner]; } diff --git a/src/RIGID/fix_rigid_small.h b/src/RIGID/fix_rigid_small.h index b473026fdb..0070d976df 100644 --- a/src/RIGID/fix_rigid_small.h +++ b/src/RIGID/fix_rigid_small.h @@ -56,7 +56,6 @@ class FixRigidSmall : public Fix { void pre_neighbor() override; int dof(int) override; void deform(int) override; - void enforce2d() override; void reset_dt() override; void zero_momentum() override; void zero_rotation() override; @@ -68,7 +67,6 @@ class FixRigidSmall : public Fix { double memory_usage() override; protected: - int me, nprocs; double dtv, dtf, dtq; double *step_respa; int triclinic; @@ -202,7 +200,8 @@ class FixRigidSmall : public Fix { void setup_bodies_static(); void setup_bodies_dynamic(); void apply_langevin_thermostat(); - void compute_forces_and_torques(); + virtual void compute_forces_and_torques(); + void enforce2d(); void readfile(int, double **, int *); void grow_body(); void reset_atom2body(); diff --git a/src/fix.cpp b/src/fix.cpp index 70e4133cdd..754948fdd1 100644 --- a/src/fix.cpp +++ b/src/fix.cpp @@ -72,7 +72,6 @@ Fix::Fix(LAMMPS *lmp, int /*narg*/, char **arg) : dynamic = 0; dof_flag = 0; special_alter_flag = 0; - enforce2d_flag = 0; respa_level_support = 0; respa_level = -1; maxexchange = 0; diff --git a/src/fix.h b/src/fix.h index 5d55048c28..9b595f0c60 100644 --- a/src/fix.h +++ b/src/fix.h @@ -72,7 +72,6 @@ class Fix : protected Pointers { int dynamic_group_allow; // 1 if can be used with dynamic group, else 0 int dof_flag; // 1 if has dof() method (not min_dof()) int special_alter_flag; // 1 if has special_alter() meth for spec lists - int enforce2d_flag; // 1 if has enforce2d method int respa_level_support; // 1 if fix supports fix_modify respa int respa_level; // which respa level to apply fix (1-Nrespa) int maxexchange; // max # of per-atom values for Comm::exchange() @@ -241,7 +240,6 @@ class Fix : protected Pointers { virtual void deform(int) {} virtual void reset_target(double) {} virtual void reset_dt() {} - virtual void enforce2d() {} virtual void read_data_header(char *) {} virtual void read_data_section(char *, int, char *, tagint) {} diff --git a/src/fix_enforce2d.cpp b/src/fix_enforce2d.cpp index c6816c2355..c13e2147a3 100644 --- a/src/fix_enforce2d.cpp +++ b/src/fix_enforce2d.cpp @@ -27,12 +27,9 @@ using namespace FixConst; /* ---------------------------------------------------------------------- */ FixEnforce2D::FixEnforce2D(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg), - flist(nullptr) + Fix(lmp, narg, arg) { if (narg != 3) error->all(FLERR,"Illegal fix enforce2d command"); - - nfixlist = 0; } /* ---------------------------------------------------------------------- */ @@ -40,8 +37,6 @@ FixEnforce2D::FixEnforce2D(LAMMPS *lmp, int narg, char **arg) : FixEnforce2D::~FixEnforce2D() { if (copymode) return; - - delete [] flist; } /* ---------------------------------------------------------------------- */ @@ -61,29 +56,6 @@ void FixEnforce2D::init() { if (domain->dimension == 3) error->all(FLERR,"Cannot use fix enforce2d with 3d simulation"); - - // list of fixes with enforce2d methods - - nfixlist = 0; - for (int i = 0; i < modify->nfix; i++) - if (modify->fix[i]->enforce2d_flag) nfixlist++; - - if (nfixlist) { - int myindex = -1; - delete [] flist; - flist = new Fix*[nfixlist]; - nfixlist = 0; - for (int i = 0; i < modify->nfix; i++) { - if (modify->fix[i]->enforce2d_flag) { - if (myindex < 0) - flist[nfixlist++] = modify->fix[i]; - else - error->all(FLERR,"Fix enforce2d must be defined after fix {}", - modify->fix[i]->style); - } - if (modify->fix[i] == this) myindex = i; - } - } } /* ---------------------------------------------------------------------- */ @@ -153,12 +125,6 @@ void FixEnforce2D::post_force(int /*vflag*/) torque[i][1] = 0.0; } } - - // invoke other fixes that enforce 2d - // fix rigid variants - - for (int m = 0; m < nfixlist; m++) - flist[m]->enforce2d(); } /* ---------------------------------------------------------------------- */ diff --git a/src/fix_enforce2d.h b/src/fix_enforce2d.h index 4572785158..95429ba7dc 100644 --- a/src/fix_enforce2d.h +++ b/src/fix_enforce2d.h @@ -35,10 +35,6 @@ class FixEnforce2D : public Fix { void post_force(int) override; void post_force_respa(int, int, int) override; void min_post_force(int) override; - - protected: - int nfixlist; - class Fix **flist; }; } // namespace LAMMPS_NS From a716df7e5995304b930266e4673fbe642fc1d8a4 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 13 Nov 2023 14:53:45 -0700 Subject: [PATCH 54/93] Fix bug in Kokkos minimize + fix deform --- src/KOKKOS/npair_kokkos.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/KOKKOS/npair_kokkos.cpp b/src/KOKKOS/npair_kokkos.cpp index 06567cbeb6..2a16ca95b4 100644 --- a/src/KOKKOS/npair_kokkos.cpp +++ b/src/KOKKOS/npair_kokkos.cpp @@ -113,7 +113,7 @@ void NPairKokkos::copy_stencil_info() NPair::copy_stencil_info(); nstencil = ns->nstencil; - if (ns->last_stencil != last_stencil_old) { + if (ns->last_stencil != last_stencil_old || ns->last_stencil == update->ntimestep) { // copy stencil to device as it may have changed last_stencil_old = ns->last_stencil; From 7f41eb6d9a81298f89aa34f32e51ea1fa7c5f697 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 13 Nov 2023 14:58:48 -0700 Subject: [PATCH 55/93] Need force_clear for atom_vec_spin_kokkos --- src/KOKKOS/atom_vec_spin_kokkos.cpp | 32 +++++++++++++++++++++++++++++ src/KOKKOS/atom_vec_spin_kokkos.h | 1 + src/KOKKOS/min_kokkos.cpp | 18 ++++++++++------ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/KOKKOS/atom_vec_spin_kokkos.cpp b/src/KOKKOS/atom_vec_spin_kokkos.cpp index f5b8697352..9de02c3b28 100644 --- a/src/KOKKOS/atom_vec_spin_kokkos.cpp +++ b/src/KOKKOS/atom_vec_spin_kokkos.cpp @@ -586,6 +586,38 @@ int AtomVecSpinKokkos::unpack_exchange_kokkos(DAT::tdual_xfloat_2d &k_buf, int n } } +/* ---------------------------------------------------------------------- + clear extra forces starting at atom N + nbytes = # of bytes to clear for a per-atom vector + include f b/c this is invoked from within SPIN pair styles +------------------------------------------------------------------------- */ + +void AtomVecSpinKokkos::force_clear(int n, size_t nbytes) +{ + int nzero = nbytes/sizeof(double); + + if (nzero) { + atomKK->k_fm.clear_sync_state(); // will be cleared below + atomKK->k_fm_long.clear_sync_state(); // will be cleared below + + // local variables for lambda capture + + auto l_fm = atomKK->k_fm.d_view; + auto l_fm_long = atomKK->k_fm_long.d_view; + + Kokkos::parallel_for(nzero, LAMMPS_LAMBDA(int i) { + l_fm(i,0) = 0.0; + l_fm(i,1) = 0.0; + l_fm(i,2) = 0.0; + l_fm_long(i,0) = 0.0; + l_fm_long(i,1) = 0.0; + l_fm_long(i,2) = 0.0; + }); + + atomKK->modified(Device,FM_MASK|FML_MASK); + } +} + /* ---------------------------------------------------------------------- */ void AtomVecSpinKokkos::sync(ExecutionSpace space, unsigned int mask) diff --git a/src/KOKKOS/atom_vec_spin_kokkos.h b/src/KOKKOS/atom_vec_spin_kokkos.h index d14d01fb62..f0145e4db7 100644 --- a/src/KOKKOS/atom_vec_spin_kokkos.h +++ b/src/KOKKOS/atom_vec_spin_kokkos.h @@ -34,6 +34,7 @@ class AtomVecSpinKokkos : public AtomVecKokkos, public AtomVecSpin { AtomVecSpinKokkos(class LAMMPS *); void grow(int) override; void grow_pointers() override; + void force_clear(int, size_t) override; void sort_kokkos(Kokkos::BinSort &Sorter) override; int pack_border_kokkos(int n, DAT::tdual_int_2d k_sendlist, DAT::tdual_xfloat_2d buf,int iswap, diff --git a/src/KOKKOS/min_kokkos.cpp b/src/KOKKOS/min_kokkos.cpp index bbb9a0bd6e..c01a53c7b3 100644 --- a/src/KOKKOS/min_kokkos.cpp +++ b/src/KOKKOS/min_kokkos.cpp @@ -72,8 +72,7 @@ void MinKokkos::init() void MinKokkos::setup(int flag) { if (comm->me == 0 && screen) { - fmt::print(screen,"Setting up {} style minimization ...\n", - update->minimize_style); + fmt::print(screen,"Setting up {} style minimization ...\n", update->minimize_style); if (flag) { fmt::print(screen," Unit style : {}\n", update->unit_style); fmt::print(screen," Current step : {}\n", update->ntimestep); @@ -92,14 +91,13 @@ void MinKokkos::setup(int flag) fextra = new double[nextra_global]; if (comm->me == 0) error->warning(FLERR, "Energy due to {} extra global DOFs will" - " be included in minimizer energies\n", nextra_global); + " be included in minimizer energies\n",nextra_global); } // compute for potential energy - int id = modify->find_compute("thermo_pe"); - if (id < 0) error->all(FLERR,"Minimization could not find thermo_pe compute"); - pe_compute = modify->compute[id]; + pe_compute = modify->get_compute_by_id("thermo_pe"); + if (!pe_compute) error->all(FLERR,"Minimization could not find thermo_pe compute"); // style-specific setup does two tasks // setup extra global dof vectors @@ -537,6 +535,7 @@ double MinKokkos::energy_force(int resetflag) if (resetflag) fix_minimize_kk->reset_coords(); reset_vectors(); } + return energy; } @@ -575,7 +574,14 @@ void MinKokkos::force_clear() l_torque(i,2) = 0.0; } }); + + if (extraflag) { + size_t nbytes = sizeof(double) * atom->nlocal; + if (force->newton) nbytes += sizeof(double) * atom->nghost; + atom->avec->force_clear(0,nbytes); + } } + atomKK->modified(Device,F_MASK|TORQUE_MASK); } From c272e8f94f9a952c68c73f7a086aa42221dc18b0 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 13 Nov 2023 15:08:49 -0700 Subject: [PATCH 56/93] Avoid integer division --- src/KOKKOS/atom_vec_spin_kokkos.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/KOKKOS/atom_vec_spin_kokkos.cpp b/src/KOKKOS/atom_vec_spin_kokkos.cpp index 9de02c3b28..d2dd3a05ab 100644 --- a/src/KOKKOS/atom_vec_spin_kokkos.cpp +++ b/src/KOKKOS/atom_vec_spin_kokkos.cpp @@ -594,7 +594,7 @@ int AtomVecSpinKokkos::unpack_exchange_kokkos(DAT::tdual_xfloat_2d &k_buf, int n void AtomVecSpinKokkos::force_clear(int n, size_t nbytes) { - int nzero = nbytes/sizeof(double); + int nzero = (double)nbytes/sizeof(double); if (nzero) { atomKK->k_fm.clear_sync_state(); // will be cleared below From 3a2d94822ad7239d84d0f907258a138be7d16a9a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 15 Nov 2023 08:03:15 -0500 Subject: [PATCH 57/93] throw error for illegal replication values --- src/replicate.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/replicate.cpp b/src/replicate.cpp index 01cc1faabb..6a4c8bfd74 100644 --- a/src/replicate.cpp +++ b/src/replicate.cpp @@ -52,8 +52,11 @@ void Replicate::command(int narg, char **arg) int nx = utils::inumeric(FLERR,arg[0],false,lmp); int ny = utils::inumeric(FLERR,arg[1],false,lmp); int nz = utils::inumeric(FLERR,arg[2],false,lmp); - int nrep = nx*ny*nz; + if ((nx <= 0) || (ny <= 0) || (nz <= 0)) + error->all(FLERR, "Illegal replication grid {}x{}x{}. All replications must be > 0", + nx, ny, nz); + int nrep = nx*ny*nz; if (me == 0) utils::logmesg(lmp, "Replication is creating a {}x{}x{} = {} times larger system...\n", nx, ny, nz, nrep); From 67085517ff5feae14ce96025333edcd54fc85dd6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 16 Nov 2023 15:53:23 -0500 Subject: [PATCH 58/93] avoid segfault on command errors in force style unit tests and print error mesage instead --- unittest/force-styles/test_angle_style.cpp | 19 ++++++++++++++-- unittest/force-styles/test_bond_style.cpp | 19 ++++++++++++++-- unittest/force-styles/test_dihedral_style.cpp | 19 ++++++++++++++-- unittest/force-styles/test_improper_style.cpp | 19 ++++++++++++++-- unittest/force-styles/test_pair_style.cpp | 22 ++++++++++++++++--- 5 files changed, 87 insertions(+), 11 deletions(-) diff --git a/unittest/force-styles/test_angle_style.cpp b/unittest/force-styles/test_angle_style.cpp index bd0e3d8859..3476ae8dde 100644 --- a/unittest/force-styles/test_angle_style.cpp +++ b/unittest/force-styles/test_angle_style.cpp @@ -26,6 +26,7 @@ #include "angle.h" #include "atom.h" #include "compute.h" +#include "exceptions.h" #include "fmt/format.h" #include "force.h" #include "info.h" @@ -59,7 +60,7 @@ void cleanup_lammps(LAMMPS *lmp, const TestConfig &cfg) delete lmp; } -LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newton = true) +LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton = true) { LAMMPS *lmp; @@ -90,7 +91,21 @@ LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newto // utility lambdas to improve readability auto command = [&](const std::string &line) { - lmp->input->one(line); + try { + lmp->input->one(line); + } catch (LAMMPSAbortException &ae) { + fprintf(stderr, "LAMMPS Error: %s\n", ae.what()); + exit(2); + } catch (LAMMPSException &e) { + fprintf(stderr, "LAMMPS Error: %s\n", e.what()); + exit(3); + } catch (fmt::format_error &fe) { + fprintf(stderr, "fmt::format_error: %s\n", fe.what()); + exit(4); + } catch (std::exception &e) { + fprintf(stderr, "General exception: %s\n", e.what()); + exit(5); + } }; auto parse_input_script = [&](const std::string &filename) { lmp->input->file(filename.c_str()); diff --git a/unittest/force-styles/test_bond_style.cpp b/unittest/force-styles/test_bond_style.cpp index aa99f41f8d..f7ecd835b0 100644 --- a/unittest/force-styles/test_bond_style.cpp +++ b/unittest/force-styles/test_bond_style.cpp @@ -26,6 +26,7 @@ #include "atom.h" #include "bond.h" #include "compute.h" +#include "exceptions.h" #include "fmt/format.h" #include "force.h" #include "info.h" @@ -59,7 +60,7 @@ void cleanup_lammps(LAMMPS *lmp, const TestConfig &cfg) delete lmp; } -LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newton = true) +LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton = true) { LAMMPS *lmp; @@ -90,7 +91,21 @@ LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newto // utility lambdas to improve readability auto command = [&](const std::string &line) { - lmp->input->one(line); + try { + lmp->input->one(line); + } catch (LAMMPSAbortException &ae) { + fprintf(stderr, "LAMMPS Error: %s\n", ae.what()); + exit(2); + } catch (LAMMPSException &e) { + fprintf(stderr, "LAMMPS Error: %s\n", e.what()); + exit(3); + } catch (fmt::format_error &fe) { + fprintf(stderr, "fmt::format_error: %s\n", fe.what()); + exit(4); + } catch (std::exception &e) { + fprintf(stderr, "General exception: %s\n", e.what()); + exit(5); + } }; auto parse_input_script = [&](const std::string &filename) { lmp->input->file(filename.c_str()); diff --git a/unittest/force-styles/test_dihedral_style.cpp b/unittest/force-styles/test_dihedral_style.cpp index 25690fc33d..662d63909d 100644 --- a/unittest/force-styles/test_dihedral_style.cpp +++ b/unittest/force-styles/test_dihedral_style.cpp @@ -26,6 +26,7 @@ #include "atom.h" #include "compute.h" #include "dihedral.h" +#include "exceptions.h" #include "fmt/format.h" #include "force.h" #include "info.h" @@ -59,7 +60,7 @@ void cleanup_lammps(LAMMPS *lmp, const TestConfig &cfg) delete lmp; } -LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newton = true) +LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton = true) { LAMMPS *lmp = new LAMMPS(args, MPI_COMM_WORLD); @@ -88,7 +89,21 @@ LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newto // utility lambdas to improve readability auto command = [&](const std::string &line) { - lmp->input->one(line); + try { + lmp->input->one(line); + } catch (LAMMPSAbortException &ae) { + fprintf(stderr, "LAMMPS Error: %s\n", ae.what()); + exit(2); + } catch (LAMMPSException &e) { + fprintf(stderr, "LAMMPS Error: %s\n", e.what()); + exit(3); + } catch (fmt::format_error &fe) { + fprintf(stderr, "fmt::format_error: %s\n", fe.what()); + exit(4); + } catch (std::exception &e) { + fprintf(stderr, "General exception: %s\n", e.what()); + exit(5); + } }; auto parse_input_script = [&](const std::string &filename) { lmp->input->file(filename.c_str()); diff --git a/unittest/force-styles/test_improper_style.cpp b/unittest/force-styles/test_improper_style.cpp index b4096df868..dc1b846b5a 100644 --- a/unittest/force-styles/test_improper_style.cpp +++ b/unittest/force-styles/test_improper_style.cpp @@ -25,6 +25,7 @@ #include "atom.h" #include "compute.h" +#include "exceptions.h" #include "fmt/format.h" #include "force.h" #include "improper.h" @@ -59,7 +60,7 @@ void cleanup_lammps(LAMMPS *lmp, const TestConfig &cfg) delete lmp; } -LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newton = true) +LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton = true) { LAMMPS *lmp; @@ -90,7 +91,21 @@ LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newto // utility lambdas to improve readability auto command = [&](const std::string &line) { - lmp->input->one(line); + try { + lmp->input->one(line); + } catch (LAMMPSAbortException &ae) { + fprintf(stderr, "LAMMPS Error: %s\n", ae.what()); + exit(2); + } catch (LAMMPSException &e) { + fprintf(stderr, "LAMMPS Error: %s\n", e.what()); + exit(3); + } catch (fmt::format_error &fe) { + fprintf(stderr, "fmt::format_error: %s\n", fe.what()); + exit(4); + } catch (std::exception &e) { + fprintf(stderr, "General exception: %s\n", e.what()); + exit(5); + } }; auto parse_input_script = [&](const std::string &filename) { lmp->input->file(filename.c_str()); diff --git a/unittest/force-styles/test_pair_style.cpp b/unittest/force-styles/test_pair_style.cpp index 8ad2ce9aaa..9db9c7ac8b 100644 --- a/unittest/force-styles/test_pair_style.cpp +++ b/unittest/force-styles/test_pair_style.cpp @@ -26,6 +26,7 @@ #include "atom.h" #include "compute.h" #include "domain.h" +#include "exceptions.h" #include "force.h" #include "info.h" #include "input.h" @@ -61,7 +62,7 @@ void cleanup_lammps(LAMMPS *lmp, const TestConfig &cfg) delete lmp; } -LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newton = true) +LAMMPS *init_lammps(LAMMPS::argv &args, const TestConfig &cfg, const bool newton = true) { LAMMPS *lmp; @@ -92,8 +93,23 @@ LAMMPS *init_lammps(LAMMPS::argv & args, const TestConfig &cfg, const bool newto // utility lambdas to improve readability auto command = [&](const std::string &line) { - lmp->input->one(line); + try { + lmp->input->one(line); + } catch (LAMMPSAbortException &ae) { + fprintf(stderr, "LAMMPS Error: %s\n", ae.what()); + exit(2); + } catch (LAMMPSException &e) { + fprintf(stderr, "LAMMPS Error: %s\n", e.what()); + exit(3); + } catch (fmt::format_error &fe) { + fprintf(stderr, "fmt::format_error: %s\n", fe.what()); + exit(4); + } catch (std::exception &e) { + fprintf(stderr, "General exception: %s\n", e.what()); + exit(5); + } }; + auto parse_input_script = [&](const std::string &filename) { lmp->input->file(filename.c_str()); }; @@ -760,7 +776,7 @@ TEST(PairStyle, gpu) "screen", "-nocite", "-sf", "gpu"}; LAMMPS::argv args_noneigh = {"PairStyle", "-log", "none", "-echo", "screen", "-nocite", "-sf", "gpu", "-pk", "gpu", "0", "neigh", "no"}; - LAMMPS::argv args = args_neigh; + LAMMPS::argv args = args_neigh; // cannot use GPU neighbor list with hybrid pair style (yet) if (test_config.pair_style.substr(0, 6) == "hybrid") { From 00bccbf06770787b603ee3253eac49bde0f8c282 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 17 Nov 2023 03:16:27 -0500 Subject: [PATCH 59/93] check if creating unix domain socket failed --- src/MISC/fix_ipi.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/MISC/fix_ipi.cpp b/src/MISC/fix_ipi.cpp index 69e0f2a7f3..30a6fe893d 100644 --- a/src/MISC/fix_ipi.cpp +++ b/src/MISC/fix_ipi.cpp @@ -98,7 +98,7 @@ static void open_socket(int &sockfd, int inet, int port, char *host, Error *erro // creates socket sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (sockfd < 0) error->one(FLERR, "Error opening socket"); + if (sockfd < 0) error->one(FLERR, "Error creating socket for fix ipi"); // makes connection if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) @@ -116,6 +116,7 @@ static void open_socket(int &sockfd, int inet, int port, char *host, Error *erro // creates the socket sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) error->one(FLERR, "Error creating socket for fix ipi"); // connects if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) From 938682a751b7b406272d2be5e1325daafd880b4e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 21 Nov 2023 12:58:33 -0500 Subject: [PATCH 60/93] lower the C++ standard to 14 for some files when compiling with intel classic compiler --- cmake/CMakeLists.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 380d722caa..682d27bbfe 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -151,6 +151,7 @@ if(MSVC) add_compile_options(/Zc:__cplusplus) add_compile_options(/wd4244) add_compile_options(/wd4267) + add_compile_options(/wd4250) add_compile_options(/EHsc) endif() add_compile_definitions(_CRT_SECURE_NO_WARNINGS) @@ -438,6 +439,18 @@ if(BUILD_OMP) target_link_libraries(lmp PRIVATE OpenMP::OpenMP_CXX) endif() +# lower C++ standard for fmtlib sources when using Intel classic compiler +if((CMAKE_CXX_COMPILER_ID STREQUAL "Intel") AND (CMAKE_CXX_STANDARD GREATER_EQUAL 17) + AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 2021.10)) + message(STATUS "Lowering C++ standard for compiling fmtlib sources with Intel Classic compiler") + get_filename_component(LMP_UTILS_SRC "${LAMMPS_SOURCE_DIR}/utils.cpp" ABSOLUTE) + get_filename_component(LMP_VARIABLE_SRC "${LAMMPS_SOURCE_DIR}/variable.cpp" ABSOLUTE) + get_filename_component(FMT_FORMAT_SRC "${LAMMPS_SOURCE_DIR}/fmtlib_format.cpp" ABSOLUTE) + get_filename_component(FMT_OS_SRC "${LAMMPS_SOURCE_DIR}/fmtlib_os.cpp" ABSOLUTE) + set_source_files_properties("${FMT_FORMAT_SRC}" "${FMT_OS_SRC}" "${LMP_VARIABLE_SRC}" "${LMP_UTILS_SRC}" + PROPERTIES COMPILE_OPTIONS "-std=c++14") +endif() + if(PKG_MSCG OR PKG_ATC OR PKG_AWPMD OR PKG_ML-QUIP OR PKG_ML-POD OR PKG_ELECTRODE OR BUILD_TOOLS) enable_language(C) if (NOT USE_INTERNAL_LINALG) From 4d06a9928fc5d5eaa8f1591a6c89d33f6ad7248b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 18 Nov 2023 06:22:16 -0500 Subject: [PATCH 61/93] reduce warnings when compiling with intel classic compilers --- cmake/CMakeLists.txt | 2 +- src/MAKE/OPTIONS/Makefile.intel_cpu_intelmpi | 2 +- src/MAKE/OPTIONS/Makefile.intel_cpu_mpich | 2 +- src/MAKE/OPTIONS/Makefile.intel_cpu_openmpi | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 682d27bbfe..b2ee07332b 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -112,7 +112,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") if(CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.3 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.4) set(CMAKE_TUNE_DEFAULT "-xCOMMON-AVX512") else() - set(CMAKE_TUNE_DEFAULT "-xHost -fp-model fast=2 -no-prec-div -qoverride-limits -diag-disable=10441 -diag-disable=2196") + set(CMAKE_TUNE_DEFAULT "-xHost -fp-model fast=2 -no-prec-div -qoverride-limits -diag-disable=10441 -diag-disable=11074 -diag-disable=11076 -diag-disable=2196") endif() endif() endif() diff --git a/src/MAKE/OPTIONS/Makefile.intel_cpu_intelmpi b/src/MAKE/OPTIONS/Makefile.intel_cpu_intelmpi index 3439244b09..8b3bd754cc 100644 --- a/src/MAKE/OPTIONS/Makefile.intel_cpu_intelmpi +++ b/src/MAKE/OPTIONS/Makefile.intel_cpu_intelmpi @@ -6,7 +6,7 @@ SHELL = /bin/sh # compiler/linker settings # specify flags and libraries needed for your compiler -CC = mpiicpc -std=c++11 -diag-disable=10441 -diag-disable=2196 +CC = mpiicpc -std=c++11 -diag-disable=10441 -diag-disable=2196 -diag-disable=11074 -diag-disable=11076 OPTFLAGS = -xHost -O2 -fp-model fast=2 -no-prec-div -qoverride-limits \ -qopt-zmm-usage=high CCFLAGS = -qopenmp -qno-offload -ansi-alias -restrict \ diff --git a/src/MAKE/OPTIONS/Makefile.intel_cpu_mpich b/src/MAKE/OPTIONS/Makefile.intel_cpu_mpich index 042b207c91..21387fe5af 100644 --- a/src/MAKE/OPTIONS/Makefile.intel_cpu_mpich +++ b/src/MAKE/OPTIONS/Makefile.intel_cpu_mpich @@ -6,7 +6,7 @@ SHELL = /bin/sh # compiler/linker settings # specify flags and libraries needed for your compiler -CC = mpicxx -cxx=icc -std=c++11 -diag-disable=10441 -diag-disable=2196 +CC = mpicxx -cxx=icc -std=c++11 -diag-disable=10441 -diag-disable=2196 -diag-disable=11074 -diag-disable=11076 OPTFLAGS = -xHost -O2 -fp-model fast=2 -no-prec-div -qoverride-limits \ -qopt-zmm-usage=high CCFLAGS = -qopenmp -qno-offload -ansi-alias -restrict \ diff --git a/src/MAKE/OPTIONS/Makefile.intel_cpu_openmpi b/src/MAKE/OPTIONS/Makefile.intel_cpu_openmpi index 9f6de64987..537ad5a8dc 100644 --- a/src/MAKE/OPTIONS/Makefile.intel_cpu_openmpi +++ b/src/MAKE/OPTIONS/Makefile.intel_cpu_openmpi @@ -7,7 +7,7 @@ SHELL = /bin/sh # specify flags and libraries needed for your compiler export OMPI_CXX = icc -CC = mpicxx -std=c++11 -diag-disable=10441 -diag-disable=2196 +CC = mpicxx -std=c++11 -diag-disable=10441 -diag-disable=2196 -diag-disable=11074 -diag-disable=11076 OPTFLAGS = -xHost -O2 -fp-model fast=2 -no-prec-div -qoverride-limits \ -qopt-zmm-usage=high CCFLAGS = -qopenmp -qno-offload -ansi-alias -restrict \ From 162b9c3ff357d9d85d2c37eda77712ea13e11b79 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 18 Nov 2023 07:14:38 -0500 Subject: [PATCH 62/93] tweak intel compiler makefile for traditional build --- src/MAKE/OPTIONS/Makefile.intel_coprocessor | 13 +++++++++++++ src/MAKE/OPTIONS/Makefile.intel_cpu_intelmpi | 13 +++++++++++++ src/MAKE/OPTIONS/Makefile.intel_cpu_mpich | 13 +++++++++++++ src/MAKE/OPTIONS/Makefile.intel_cpu_openmpi | 13 +++++++++++++ 4 files changed, 52 insertions(+) diff --git a/src/MAKE/OPTIONS/Makefile.intel_coprocessor b/src/MAKE/OPTIONS/Makefile.intel_coprocessor index 99e8d22d82..d8a67428de 100644 --- a/src/MAKE/OPTIONS/Makefile.intel_coprocessor +++ b/src/MAKE/OPTIONS/Makefile.intel_coprocessor @@ -14,6 +14,7 @@ CCFLAGS = -qopenmp -qoffload -ansi-alias -restrict \ -DLMP_INTEL_USELRT -DLMP_USE_MKL_RNG -DLMP_INTEL_OFFLOAD \ $(OPTFLAGS) -I$(MKLROOT)/include SHFLAGS = -fPIC +FMTFLAGS = -std=c++11 DEPFLAGS = -M LINK = mpiicpc -std=c++11 @@ -118,6 +119,18 @@ $(SHLIB): $(OBJ) $(EXTRA_LINK_DEPENDS) %.o:%.cpp $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) -c $< +variable.o : ../variable.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +utils.o : ../utils.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_format.o : ../fmtlib_format.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_os.o : ../fmtlib_os.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + # Individual dependencies depend : fastdep.exe $(SRC) diff --git a/src/MAKE/OPTIONS/Makefile.intel_cpu_intelmpi b/src/MAKE/OPTIONS/Makefile.intel_cpu_intelmpi index 8b3bd754cc..681bbaabe1 100644 --- a/src/MAKE/OPTIONS/Makefile.intel_cpu_intelmpi +++ b/src/MAKE/OPTIONS/Makefile.intel_cpu_intelmpi @@ -13,6 +13,7 @@ CCFLAGS = -qopenmp -qno-offload -ansi-alias -restrict \ -DLMP_INTEL_USELRT -DLMP_USE_MKL_RNG $(OPTFLAGS) \ -I$(MKLROOT)/include SHFLAGS = -fPIC +FMTFLAGS = -std=c++11 DEPFLAGS = -M LINK = mpiicpc -std=c++11 -diag-disable=10441 -diag-disable=2196 @@ -117,6 +118,18 @@ $(SHLIB): $(OBJ) $(EXTRA_LINK_DEPENDS) %.o:%.cpp $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) -c $< +variable.o : ../variable.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +utils.o : ../utils.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_format.o : ../fmtlib_format.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_os.o : ../fmtlib_os.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + # Individual dependencies depend : fastdep.exe $(SRC) diff --git a/src/MAKE/OPTIONS/Makefile.intel_cpu_mpich b/src/MAKE/OPTIONS/Makefile.intel_cpu_mpich index 21387fe5af..f1a8c97fc6 100644 --- a/src/MAKE/OPTIONS/Makefile.intel_cpu_mpich +++ b/src/MAKE/OPTIONS/Makefile.intel_cpu_mpich @@ -13,6 +13,7 @@ CCFLAGS = -qopenmp -qno-offload -ansi-alias -restrict \ -DLMP_INTEL_USELRT -DLMP_USE_MKL_RNG $(OPTFLAGS) \ -I$(MKLROOT)/include SHFLAGS = -fPIC +FMTFLAGS = -std=c++11 DEPFLAGS = -M LINK = mpicxx -cxx=icc -std=c++11 -diag-disable=10441 -diag-disable=2196 @@ -117,6 +118,18 @@ $(SHLIB): $(OBJ) $(EXTRA_LINK_DEPENDS) %.o:%.cpp $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) -c $< +variable.o : ../variable.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +utils.o : ../utils.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_format.o : ../fmtlib_format.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_os.o : ../fmtlib_os.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + # Individual dependencies depend : fastdep.exe $(SRC) diff --git a/src/MAKE/OPTIONS/Makefile.intel_cpu_openmpi b/src/MAKE/OPTIONS/Makefile.intel_cpu_openmpi index 537ad5a8dc..c3e4451c7c 100644 --- a/src/MAKE/OPTIONS/Makefile.intel_cpu_openmpi +++ b/src/MAKE/OPTIONS/Makefile.intel_cpu_openmpi @@ -14,6 +14,7 @@ CCFLAGS = -qopenmp -qno-offload -ansi-alias -restrict \ -DLMP_INTEL_USELRT -DLMP_USE_MKL_RNG $(OPTFLAGS) \ -I$(MKLROOT)/include SHFLAGS = -fPIC +FMTFLAGS = -std=c++11 DEPFLAGS = -M LINK = mpicxx -std=c++11 -diag-disable=10441 -diag-disable=2196 @@ -118,6 +119,18 @@ $(SHLIB): $(OBJ) $(EXTRA_LINK_DEPENDS) %.o:%.cpp $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) -c $< +variable.o : ../variable.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +utils.o : ../utils.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_format.o : ../fmtlib_format.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_os.o : ../fmtlib_os.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + # Individual dependencies depend : fastdep.exe $(SRC) From 184f5a7f5e0252deb378e4988a1395516416e91d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 18 Nov 2023 11:15:53 -0500 Subject: [PATCH 63/93] copy intel C++17 compiler hack to Kokkos makefiles --- src/MAKE/OPTIONS/Makefile.kokkos_cuda_mpi | 16 +++++++++++++++- src/MAKE/OPTIONS/Makefile.kokkos_mpi_only | 14 ++++++++++++++ src/MAKE/OPTIONS/Makefile.kokkos_omp | 14 ++++++++++++++ src/MAKE/OPTIONS/Makefile.kokkos_phi | 14 ++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/MAKE/OPTIONS/Makefile.kokkos_cuda_mpi b/src/MAKE/OPTIONS/Makefile.kokkos_cuda_mpi index b73c441c71..e78be1acdc 100644 --- a/src/MAKE/OPTIONS/Makefile.kokkos_cuda_mpi +++ b/src/MAKE/OPTIONS/Makefile.kokkos_cuda_mpi @@ -12,6 +12,8 @@ export OMPI_CXX = $(KOKKOS_ABSOLUTE_PATH)/bin/nvcc_wrapper CC = mpicxx CCFLAGS = -g -O3 -DNDEBUG -Xcudafe --diag_suppress=unrecognized_pragma SHFLAGS = -fPIC +# uncomment when compiling with Intel 21.5 or older +FMTFLAGS = # -std=c++11 DEPFLAGS = -M LINK = mpicxx @@ -36,7 +38,7 @@ KOKKOS_ARCH = Volta70 LMP_INC = -DLAMMPS_GZIP # MPI library -# see discussion in Section 2.2 (step 5) of manual +# see discussion in Section 3.4 of the manual # MPI wrapper compiler/linker can provide this info # can point to dummy MPI library in src/STUBS as in Makefile.serial # use -D MPICH and OMPI settings in INC to avoid C++ lib conflicts @@ -118,6 +120,18 @@ $(SHLIB): $(OBJ) $(EXTRA_LINK_DEPENDS) %.o:%.cpp $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) -c $< +variable.o : ../variable.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +utils.o : ../utils.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_format.o : ../fmtlib_format.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_os.o : ../fmtlib_os.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + # Individual dependencies depend : fastdep.exe $(SRC) diff --git a/src/MAKE/OPTIONS/Makefile.kokkos_mpi_only b/src/MAKE/OPTIONS/Makefile.kokkos_mpi_only index 0adb53eef0..e1f7005617 100644 --- a/src/MAKE/OPTIONS/Makefile.kokkos_mpi_only +++ b/src/MAKE/OPTIONS/Makefile.kokkos_mpi_only @@ -9,6 +9,8 @@ SHELL = /bin/sh CC = mpicxx CCFLAGS = -g -O3 -DNDEBUG SHFLAGS = -fPIC +# uncomment when compiling with Intel 21.5 or older +FMTFLAGS = # -std=c++11 DEPFLAGS = -M LINK = mpicxx @@ -114,6 +116,18 @@ $(SHLIB): $(OBJ) $(EXTRA_LINK_DEPENDS) %.o:%.cpp $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) -c $< +variable.o : ../variable.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +utils.o : ../utils.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_format.o : ../fmtlib_format.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_os.o : ../fmtlib_os.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + # Individual dependencies depend : fastdep.exe $(SRC) diff --git a/src/MAKE/OPTIONS/Makefile.kokkos_omp b/src/MAKE/OPTIONS/Makefile.kokkos_omp index 82144652dd..5f91af7a1e 100644 --- a/src/MAKE/OPTIONS/Makefile.kokkos_omp +++ b/src/MAKE/OPTIONS/Makefile.kokkos_omp @@ -9,6 +9,8 @@ SHELL = /bin/sh CC = mpicxx CCFLAGS = -g -O3 -DNDEBUG SHFLAGS = -fPIC +# uncomment when compiling with Intel 21.5 or older +FMTFLAGS = # -std=c++11 DEPFLAGS = -M LINK = mpicxx @@ -114,6 +116,18 @@ $(SHLIB): $(OBJ) $(EXTRA_LINK_DEPENDS) %.o:%.cpp $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) -c $< +variable.o : ../variable.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +utils.o : ../utils.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_format.o : ../fmtlib_format.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_os.o : ../fmtlib_os.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + # Individual dependencies depend : fastdep.exe $(SRC) diff --git a/src/MAKE/OPTIONS/Makefile.kokkos_phi b/src/MAKE/OPTIONS/Makefile.kokkos_phi index 9d5691251c..05b24f8721 100644 --- a/src/MAKE/OPTIONS/Makefile.kokkos_phi +++ b/src/MAKE/OPTIONS/Makefile.kokkos_phi @@ -9,6 +9,8 @@ SHELL = /bin/sh CC = mpicxx CCFLAGS = -g -O3 -DNDEBUG SHFLAGS = -fPIC +# uncomment when compiling with Intel 21.5 or older +FMTFLAGS = # -std=c++11 DEPFLAGS = -M LINK = mpicxx @@ -115,6 +117,18 @@ $(SHLIB): $(OBJ) $(EXTRA_LINK_DEPENDS) %.o:%.cpp $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) -c $< +variable.o : ../variable.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +utils.o : ../utils.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_format.o : ../fmtlib_format.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + +fmtlib_os.o : ../fmtlib_os.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) $(FMTFLAGS) -c $< + # Individual dependencies depend : fastdep.exe $(SRC) From ee0c5dc121da0525d8dda6a5d947d812f3309693 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 21 Nov 2023 15:48:40 -0500 Subject: [PATCH 64/93] Update CODEOWNERS for cmake --- .github/CODEOWNERS | 6 +++--- cmake/CMakeLists.txt | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f99a336dbb..deeea5df90 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -151,12 +151,12 @@ tools/vim/* @hammondkd unittest/* @akohlmey # cmake -cmake/* @rbberger +cmake/* @akohlmey cmake/Modules/LAMMPSInterfacePlugin.cmake @akohlmey cmake/Modules/MPI4WIN.cmake @akohlmey cmake/Modules/OpenCLLoader.cmake @akohlmey -cmake/Modules/Packages/COLVARS.cmake @rbberger @giacomofiorin -cmake/Modules/Packages/KIM.cmake @rbberger @ellio167 +cmake/Modules/Packages/COLVARS.cmake @giacomofiorin +cmake/Modules/Packages/KIM.cmake @ellio167 cmake/presets/*.cmake @akohlmey # python diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index b2ee07332b..eead4d0423 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -2,7 +2,6 @@ ######################################## # CMake build system # This file is part of LAMMPS -# Created by Christoph Junghans and Richard Berger cmake_minimum_required(VERSION 3.10) ######################################## # set policy to silence warnings about ignoring _ROOT but use it From 77db8e422aad1faf8ac2ea79b67a0b61da811d56 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 23 Nov 2023 12:37:49 -0500 Subject: [PATCH 65/93] add check and document that "scale yes" is not supported for scaling atomic parameters with fix adapt/fep --- doc/src/fix_adapt_fep.rst | 4 +++- src/FEP/fix_adapt_fep.cpp | 18 ++++++++++-------- src/fix_adapt.cpp | 4 ++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/doc/src/fix_adapt_fep.rst b/doc/src/fix_adapt_fep.rst index c35986de49..1b2298cd96 100644 --- a/doc/src/fix_adapt_fep.rst +++ b/doc/src/fix_adapt_fep.rst @@ -307,7 +307,9 @@ the :doc:`run ` command. This fix is not invoked during Restrictions """""""""""" - none + +The keyword "scale yes" is not supported for scaling per-atom parameters +diameter and change. You can use :doc:`fix adapt ` for those. Related commands """""""""""""""" diff --git a/src/FEP/fix_adapt_fep.cpp b/src/FEP/fix_adapt_fep.cpp index e050b8cf21..c32b44b081 100644 --- a/src/FEP/fix_adapt_fep.cpp +++ b/src/FEP/fix_adapt_fep.cpp @@ -40,8 +40,8 @@ using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; -enum{PAIR,KSPACE,ATOM}; -enum{DIAMETER,CHARGE}; +enum{PAIR, KSPACE, ATOM}; +enum{DIAMETER, CHARGE}; /* ---------------------------------------------------------------------- */ @@ -165,21 +165,21 @@ FixAdaptFEP::FixAdaptFEP(LAMMPS *lmp, int narg, char **arg) : FixAdaptFEP::~FixAdaptFEP() { for (int m = 0; m < nadapt; m++) { - delete [] adapt[m].var; + delete[] adapt[m].var; if (adapt[m].which == PAIR) { - delete [] adapt[m].pstyle; - delete [] adapt[m].pparam; + delete[] adapt[m].pstyle; + delete[] adapt[m].pparam; memory->destroy(adapt[m].array_orig); } } - delete [] adapt; + delete[] adapt; // check nfix in case all fixes have already been deleted if (id_fix_diam && modify->nfix) modify->delete_fix(id_fix_diam); if (id_fix_chg && modify->nfix) modify->delete_fix(id_fix_chg); - delete [] id_fix_diam; - delete [] id_fix_chg; + delete[] id_fix_diam; + delete[] id_fix_chg; } /* ---------------------------------------------------------------------- */ @@ -434,6 +434,8 @@ void FixAdaptFEP::change_settings() } else if (ad->which == ATOM) { + if (scaleflag) + error->all(FLERR, "Keyword 'scale yes' is not supported with fix adapt/fep for 'atom'"); // reset radius from diameter // also scale rmass to new value diff --git a/src/fix_adapt.cpp b/src/fix_adapt.cpp index 660e3f6107..996597ab8b 100644 --- a/src/fix_adapt.cpp +++ b/src/fix_adapt.cpp @@ -39,8 +39,8 @@ using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; -enum{PAIR,KSPACE,ATOM,BOND,ANGLE}; -enum{DIAMETER,CHARGE}; +enum{PAIR, KSPACE, ATOM, BOND, ANGLE}; +enum{DIAMETER, CHARGE}; /* ---------------------------------------------------------------------- */ From a102d64a9550da623a86057eaa4898e4a96b042d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 23 Nov 2023 00:37:26 -0500 Subject: [PATCH 66/93] detect newer OpenMP standard versions --- src/platform.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/platform.cpp b/src/platform.cpp index b06090094b..a53318958d 100644 --- a/src/platform.cpp +++ b/src/platform.cpp @@ -391,8 +391,16 @@ std::string platform::openmp_standard() // Supported OpenMP version corresponds to the release date of the // specifications as posted at https://www.openmp.org/specifications/ -#if _OPENMP > 202011 - return "OpenMP newer than version 5.1"; +#if _OPENMP > 202411 + return "OpenMP newer than version 6.0"; +#elif _OPENMP == 202411 + return "OpenMP 6.0"; +#elif _OPENMP == 202311 + return "OpenMP 6.0 preview 2"; +#elif _OPENMP == 202211 + return "OpenMP 6.0 preview 1"; +#elif _OPENMP == 202111 + return "OpenMP 5.2"; #elif _OPENMP == 202011 return "OpenMP 5.1"; #elif _OPENMP == 201811 From 4926164050a3d58c3770802ee902e0ba7f4028b2 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 23 Nov 2023 00:24:34 -0500 Subject: [PATCH 67/93] report Kokkos library version and OpenMP standard version --- src/KOKKOS/kokkos.cpp | 3 ++- src/info.cpp | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/KOKKOS/kokkos.cpp b/src/KOKKOS/kokkos.cpp index be8823d8e2..3d94ed8b51 100644 --- a/src/KOKKOS/kokkos.cpp +++ b/src/KOKKOS/kokkos.cpp @@ -104,7 +104,8 @@ KokkosLMP::KokkosLMP(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) int me = 0; MPI_Comm_rank(world,&me); - if (me == 0) error->message(FLERR,"KOKKOS mode is enabled"); + if (me == 0) error->message(FLERR,"KOKKOS mode with Kokkos version {}.{}.{} is enabled", + KOKKOS_VERSION_MAJOR, KOKKOS_VERSION_MINOR, KOKKOS_VERSION_PATCH); // process any command-line args that invoke Kokkos settings diff --git a/src/info.cpp b/src/info.cpp index 4b9a761af5..f6c0bb41dd 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -1243,6 +1243,10 @@ std::string Info::get_accelerator_info(const std::string &package) if (has_accelerator_feature("KOKKOS","precision","single")) mesg += " single"; if (has_accelerator_feature("KOKKOS","precision","mixed")) mesg += " mixed"; if (has_accelerator_feature("KOKKOS","precision","double")) mesg += " double"; +#if LMP_KOKKOS + mesg += "\nKokkos library version: " + std::to_string(KOKKOS_VERSION_MAJOR) + "." + + std::to_string(KOKKOS_VERSION_MINOR) + "." + std::to_string(KOKKOS_VERSION_PATCH); +#endif mesg += "\n"; } if ((package.empty() || (package == "OPENMP")) && has_package("OPENMP")) { @@ -1253,6 +1257,9 @@ std::string Info::get_accelerator_info(const std::string &package) if (has_accelerator_feature("OPENMP","precision","single")) mesg += " single"; if (has_accelerator_feature("OPENMP","precision","mixed")) mesg += " mixed"; if (has_accelerator_feature("OPENMP","precision","double")) mesg += " double"; +#if defined(_OPENMP) + mesg += "\nOpenMP standard: " + platform::openmp_standard(); +#endif mesg += "\n"; } if ((package.empty() || (package == "INTEL")) && has_package("INTEL")) { From 816d74d80cba8b5866ce3a2f21773096067b87b9 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 23 Nov 2023 14:25:05 -0500 Subject: [PATCH 68/93] make compatible with Kokkos 3.7 --- src/KOKKOS/kokkos.cpp | 5 +++-- src/info.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/KOKKOS/kokkos.cpp b/src/KOKKOS/kokkos.cpp index 3d94ed8b51..e3fefd7cad 100644 --- a/src/KOKKOS/kokkos.cpp +++ b/src/KOKKOS/kokkos.cpp @@ -104,8 +104,9 @@ KokkosLMP::KokkosLMP(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) int me = 0; MPI_Comm_rank(world,&me); - if (me == 0) error->message(FLERR,"KOKKOS mode with Kokkos version {}.{}.{} is enabled", - KOKKOS_VERSION_MAJOR, KOKKOS_VERSION_MINOR, KOKKOS_VERSION_PATCH); + if (me == 0) + error->message(FLERR,"KOKKOS mode with Kokkos version {}.{}.{} is enabled", + KOKKOS_VERSION / 10000, (KOKKOS_VERSION % 10000) / 100, KOKKOS_VERSION % 100); // process any command-line args that invoke Kokkos settings diff --git a/src/info.cpp b/src/info.cpp index f6c0bb41dd..73f4ba4bdc 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -1244,8 +1244,8 @@ std::string Info::get_accelerator_info(const std::string &package) if (has_accelerator_feature("KOKKOS","precision","mixed")) mesg += " mixed"; if (has_accelerator_feature("KOKKOS","precision","double")) mesg += " double"; #if LMP_KOKKOS - mesg += "\nKokkos library version: " + std::to_string(KOKKOS_VERSION_MAJOR) + "." - + std::to_string(KOKKOS_VERSION_MINOR) + "." + std::to_string(KOKKOS_VERSION_PATCH); + mesg += fmt::format("\nKokkos library version: {}.{}.{}", KOKKOS_VERSION / 10000, + (KOKKOS_VERSION % 10000) / 100, KOKKOS_VERSION % 100); #endif mesg += "\n"; } From 7035249abd8fe339c3467b135e5d7d761c325266 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 24 Nov 2023 01:02:00 -0500 Subject: [PATCH 69/93] remove redundant code and fix memory leaks --- src/dump_image.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/dump_image.cpp b/src/dump_image.cpp index 1ba433f93f..c426151b00 100644 --- a/src/dump_image.cpp +++ b/src/dump_image.cpp @@ -140,13 +140,9 @@ DumpImage::DumpImage(LAMMPS *lmp, int narg, char **arg) : } char *fixID = nullptr; - thetastr = phistr = nullptr; cflag = STATIC; cx = cy = cz = 0.5; - cxstr = cystr = czstr = nullptr; - upxstr = upystr = upzstr = nullptr; - zoomstr = nullptr; boxflag = YES; boxdiam = 0.02; axesflag = NO; @@ -471,6 +467,16 @@ DumpImage::~DumpImage() memory->destroy(bufcopy); memory->destroy(gbuf); + delete[] upxstr; + delete[] upystr; + delete[] upzstr; + delete[] zoomstr; + delete[] thetastr; + delete[] phistr; + delete[] cxstr; + delete[] cystr; + delete[] czstr; + delete[] id_grid_compute; delete[] id_grid_fix; } From 38b79eeb9bada2e0531027bdaadf26071e8c93f6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 24 Nov 2023 14:46:49 -0500 Subject: [PATCH 70/93] some compilers require a code block to follow OpenMP pragmas, even if empty. --- src/OPENMP/reaxff_forces_omp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/OPENMP/reaxff_forces_omp.cpp b/src/OPENMP/reaxff_forces_omp.cpp index 50157da594..26922add1e 100644 --- a/src/OPENMP/reaxff_forces_omp.cpp +++ b/src/OPENMP/reaxff_forces_omp.cpp @@ -354,6 +354,9 @@ namespace ReaxFF { // Need to wait for all indices and tmp arrays accumulated. #if defined(_OPENMP) #pragma omp barrier + { + ; + } #endif #if defined(_OPENMP) From 609f5ec64b12ee87fd3f96130b442ea46d41334a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 25 Nov 2023 05:58:05 -0500 Subject: [PATCH 71/93] restore using nvcc_wrapper with kokkos-cude.cmake preset --- cmake/presets/kokkos-cuda.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/presets/kokkos-cuda.cmake b/cmake/presets/kokkos-cuda.cmake index ace8ff0879..c3ee081898 100644 --- a/cmake/presets/kokkos-cuda.cmake +++ b/cmake/presets/kokkos-cuda.cmake @@ -6,6 +6,8 @@ set(Kokkos_ENABLE_SERIAL ON CACHE BOOL "" FORCE) set(Kokkos_ENABLE_CUDA ON CACHE BOOL "" FORCE) set(Kokkos_ARCH_PASCAL60 ON CACHE BOOL "" FORCE) set(BUILD_OMP ON CACHE BOOL "" FORCE) +get_filename_component(NVCC_WRAPPER_CMD ${CMAKE_CURRENT_SOURCE_DIR}/../lib/kokkos/bin/nvcc_wrapper ABSOLUTE) +set(CMAKE_CXX_COMPILER ${NVCC_WRAPPER_CMD} CACHE FILEPATH "" FORCE) # hide deprecation warnings temporarily for stable release set(Kokkos_ENABLE_DEPRECATION_WARNINGS OFF CACHE BOOL "" FORCE) From c1fa89186a301b21db227858cea81fa146637352 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 26 Nov 2023 10:31:24 -0500 Subject: [PATCH 72/93] correct fix mvv/* compatibility checks in DPD-MESO package --- src/DPD-MESO/fix_mvv_dpd.cpp | 15 +++++++++++---- src/DPD-MESO/fix_mvv_edpd.cpp | 15 ++++++++++++--- src/DPD-MESO/fix_mvv_tdpd.cpp | 14 ++++++++++++-- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/DPD-MESO/fix_mvv_dpd.cpp b/src/DPD-MESO/fix_mvv_dpd.cpp index 18c88bd293..d51000b15b 100644 --- a/src/DPD-MESO/fix_mvv_dpd.cpp +++ b/src/DPD-MESO/fix_mvv_dpd.cpp @@ -63,13 +63,20 @@ int FixMvvDPD::setmask() void FixMvvDPD::init() { if (!atom->vest_flag) - error->all(FLERR,"Fix mvv/dpd requires atom attribute vest"); + error->all(FLERR,"Fix mvv/dpd requires atom attribute vest e.g. from atom style mdpd"); + + if (!force->pair_match("^mdpd",0) && !force->pair_match("^dpd",0)) { + if (force->pair_match("^hybrid",0)) { + if (!(force->pair_match("^mdpd",0,1) || force->pair_match("^dpd",0),1)) { + error->all(FLERR, "Must use a dpd or mdpd pair style with fix mvv/dpd"); + } + } else { + error->all(FLERR, "Must use a dpd or mdpd pair style with fix mvv/dpd"); + } + } dtv = update->dt; dtf = 0.5 * update->dt * force->ftm2v; - - if (!force->pair_match("^edpd",0) && !force->pair_match("^dpd",0)) - error->all(FLERR, "Must use a dpd or edpd pair style with fix mvv/edpd"); } /* ---------------------------------------------------------------------- diff --git a/src/DPD-MESO/fix_mvv_edpd.cpp b/src/DPD-MESO/fix_mvv_edpd.cpp index 03dd048119..7ac0dc3de7 100644 --- a/src/DPD-MESO/fix_mvv_edpd.cpp +++ b/src/DPD-MESO/fix_mvv_edpd.cpp @@ -71,11 +71,20 @@ int FixMvvEDPD::setmask() void FixMvvEDPD::init() { + if (!atom->edpd_flag) error->all(FLERR,"Fix mvv/edpd requires atom style edpd"); + + if (!force->pair_match("^edpd",0)) { + if (force->pair_match("^hybrid",0)) { + if (!force->pair_match("^edpd",0,1)) { + error->all(FLERR, "Must use pair style edpd with fix mvv/edpd"); + } + } else { + error->all(FLERR, "Must use pair style edpd with fix mvv/edpd"); + } + } + dtv = update->dt; dtf = 0.5 * update->dt * force->ftm2v; - - if (!force->pair_match("^edpd",0)) - error->all(FLERR, "Must use pair style edpd with fix mvv/edpd"); } /* ---------------------------------------------------------------------- diff --git a/src/DPD-MESO/fix_mvv_tdpd.cpp b/src/DPD-MESO/fix_mvv_tdpd.cpp index f3894da214..122fd56365 100644 --- a/src/DPD-MESO/fix_mvv_tdpd.cpp +++ b/src/DPD-MESO/fix_mvv_tdpd.cpp @@ -69,10 +69,20 @@ int FixMvvTDPD::setmask() void FixMvvTDPD::init() { + if (!atom->tdpd_flag) error->all(FLERR,"Fix mvv/tdpd requires atom style tdpd"); + + if (!force->pair_match("^tdpd",0)) { + if (force->pair_match("^hybrid",0)) { + if (!force->pair_match("^tdpd",0,1)) { + error->all(FLERR, "Must use pair style tdpd with fix mvv/tdpd"); + } + } else { + error->all(FLERR, "Must use pair style tdpd with fix mvv/tdpd"); + } + } + dtv = update->dt; dtf = 0.5 * update->dt * force->ftm2v; - if (!force->pair_match("^tdpd",0)) - error->all(FLERR, "Must use pair style tdpd with fix mvv/tdpd"); } /* ---------------------------------------------------------------------- From f79e9a113f136b27aad6bf89f6429898d4551fa7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 27 Nov 2023 07:32:47 -0500 Subject: [PATCH 73/93] error out when no per-type masses are set. warn if both per-type and per-atom masses are used. --- doc/src/fix_atom_swap.rst | 6 ++++++ src/MC/fix_atom_swap.cpp | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/doc/src/fix_atom_swap.rst b/doc/src/fix_atom_swap.rst index ffd14ebb0f..aa8127561c 100644 --- a/doc/src/fix_atom_swap.rst +++ b/doc/src/fix_atom_swap.rst @@ -181,6 +181,12 @@ This fix is part of the MC package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` doc page for more info. +This fix cannot be used with systems that do not have per-type masses +(e.g. atom style sphere) since the implemented algorithm pre-computes +velocity rescaling factors from per-type masses and ignores any per-atom +masses, if present. In case both, per-type and per-atom masses are +present, a warning is printed. + Related commands """""""""""""""" diff --git a/src/MC/fix_atom_swap.cpp b/src/MC/fix_atom_swap.cpp index fa69773d82..6fe0ac98b7 100644 --- a/src/MC/fix_atom_swap.cpp +++ b/src/MC/fix_atom_swap.cpp @@ -203,6 +203,10 @@ int FixAtomSwap::setmask() void FixAtomSwap::init() { + if (!atom->mass) error->all(FLERR, "Fix atom/swap requires per atom type masses"); + if (atom->rmass_flag && (comm->me == 0)) + error->warning(FLERR, "Fix atom/swap will use per-type masses for velocity rescaling"); + c_pe = modify->get_compute_by_id("thermo_pe"); int *type = atom->type; From 8759a18437a3cef3693d815116fbae5055644eb2 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 30 Nov 2023 10:31:30 -0500 Subject: [PATCH 74/93] handle thermo_modify energy yes correctly --- src/QTB/fix_qbmsst.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/QTB/fix_qbmsst.cpp b/src/QTB/fix_qbmsst.cpp index b5fb5ca77c..a8a72b002b 100644 --- a/src/QTB/fix_qbmsst.cpp +++ b/src/QTB/fix_qbmsst.cpp @@ -74,6 +74,7 @@ FixQBMSST::FixQBMSST(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) vector_flag = 1; size_vector = 5; ecouple_flag = 1; + energy_global_flag = 1; qmass = 1.0e1; mu = 0.0; From 413d485617bb1b4043005319165f9a4cbcf284d6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 1 Dec 2023 00:37:42 -0500 Subject: [PATCH 75/93] recreate compute xrd mesh image with reasonable dpi setting and used PNG format --- doc/src/compute_xrd.rst | 2 +- doc/src/img/xrd_mesh.jpg | Bin 121055 -> 0 bytes doc/src/img/xrd_mesh.png | Bin 0 -> 103179 bytes 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 doc/src/img/xrd_mesh.jpg create mode 100644 doc/src/img/xrd_mesh.png diff --git a/doc/src/compute_xrd.rst b/doc/src/compute_xrd.rst index 8673ce9199..fe066f9836 100644 --- a/doc/src/compute_xrd.rst +++ b/doc/src/compute_xrd.rst @@ -72,7 +72,7 @@ reciprocal lattice nodes. The mesh spacing is defined either (a) by the entire simulation domain or (b) manually using selected values as shown in the 2D diagram below. -.. image:: img/xrd_mesh.jpg +.. image:: img/xrd_mesh.png :scale: 75% :align: center diff --git a/doc/src/img/xrd_mesh.jpg b/doc/src/img/xrd_mesh.jpg deleted file mode 100644 index 677234caabd7dad8c2ee156b6d6f9af32782fa27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121055 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ΞZ)ivG~bOixS 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

orR!D5xADd+sy|w@K4@ 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 Date: Fri, 1 Dec 2023 04:31:06 -0500 Subject: [PATCH 76/93] use r_c consistently --- doc/src/pair_beck.rst | 6 +++--- doc/src/pair_lj_smooth_linear.rst | 9 +++++---- doc/src/pair_mie.rst | 2 +- doc/src/pair_morse.rst | 4 ++-- doc/src/pair_soft.rst | 5 +++-- doc/src/pair_spica.rst | 2 +- 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/doc/src/pair_beck.rst b/doc/src/pair_beck.rst index 2bf027515c..6bb4afdc80 100644 --- a/doc/src/pair_beck.rst +++ b/doc/src/pair_beck.rst @@ -30,11 +30,11 @@ Description Style *beck* computes interactions based on the potential by :ref:`(Beck) `, originally designed for simulation of Helium. It -includes truncation at a cutoff distance Rc. +includes truncation at a cutoff distance :math:`r_c`. .. math:: - E(r) &= A \exp\left[-\alpha r - \beta r^6\right] - \frac{B}{\left(r^2+a^2\right)^3} \left(1+\frac{2.709+3a^2}{r^2+a^2}\right) \qquad r < R_c \\ + E(r) &= A \exp\left[-\alpha r - \beta r^6\right] - \frac{B}{\left(r^2+a^2\right)^3} \left(1+\frac{2.709+3a^2}{r^2+a^2}\right) \qquad r < r_c \\ The following coefficients must be defined for each pair of atoms types via the :doc:`pair_coeff ` command as in the examples @@ -50,7 +50,7 @@ commands. * cutoff (distance units) The last coefficient is optional. If not specified, the global cutoff -:math:`R_c` is used. +:math:`r_c` is used. ---------- diff --git a/doc/src/pair_lj_smooth_linear.rst b/doc/src/pair_lj_smooth_linear.rst index 7a3ba7a3d5..20b5e6cbda 100644 --- a/doc/src/pair_lj_smooth_linear.rst +++ b/doc/src/pair_lj_smooth_linear.rst @@ -31,13 +31,13 @@ Style *lj/smooth/linear* computes a truncated and force-shifted LJ interaction (aka Shifted Force Lennard-Jones) that combines the standard 12/6 Lennard-Jones function and subtracts a linear term based on the cutoff distance, so that both, the potential and the force, go -continuously to zero at the cutoff Rc :ref:`(Toxvaerd) `: +continuously to zero at the cutoff :math:`r_c` :ref:`(Toxvaerd) `: .. math:: \phi\left(r\right) & = 4 \epsilon \left[ \left(\frac{\sigma}{r}\right)^{12} - \left(\frac{\sigma}{r}\right)^6 \right] \\ - E\left(r\right) & = \phi\left(r\right) - \phi\left(R_c\right) - \left(r - R_c\right) \left.\frac{d\phi}{d r} \right|_{r=R_c} \qquad r < R_c + E\left(r\right) & = \phi\left(r\right) - \phi\left(r_c\right) - \left(r - r_c\right) \left.\frac{d\phi}{d r} \right|_{r=r_c} \qquad r < r_c The following coefficients must be defined for each pair of atoms types via the :doc:`pair_coeff ` command as in the examples @@ -77,8 +77,9 @@ tail option for adding long-range tail corrections to energy and pressure, since the energy of the pair interaction is smoothed to 0.0 at the cutoff. -This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need -to be specified in an input script that reads a restart file. +This pair style writes its information to :doc:`binary restart files `, +so pair_style and pair_coeff commands do not need to be specified +in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the diff --git a/doc/src/pair_mie.rst b/doc/src/pair_mie.rst index 089f8d3d29..6e9eec1f5c 100644 --- a/doc/src/pair_mie.rst +++ b/doc/src/pair_mie.rst @@ -35,7 +35,7 @@ The *mie/cut* style computes the Mie potential, given by E = C \epsilon \left[ \left(\frac{\sigma}{r}\right)^{\gamma_{rep}} - \left(\frac{\sigma}{r}\right)^{\gamma_{att}} \right] \qquad r < r_c -Rc is the cutoff and C is a function that depends on the repulsive and +:math:`r_c` is the cutoff and C is a function that depends on the repulsive and attractive exponents, given by: .. math:: diff --git a/doc/src/pair_morse.rst b/doc/src/pair_morse.rst index 807882980d..4b93d182bb 100644 --- a/doc/src/pair_morse.rst +++ b/doc/src/pair_morse.rst @@ -53,7 +53,7 @@ Style *morse* computes pairwise interactions with the formula E = D_0 \left[ e^{- 2 \alpha (r - r_0)} - 2 e^{- \alpha (r - r_0)} \right] \qquad r < r_c -Rc is the cutoff. +:math:`r_c` is the cutoff. The following coefficients must be defined for each pair of atoms types via the :doc:`pair_coeff ` command as in the examples @@ -78,7 +78,7 @@ so that both, potential energy and force, go to zero at the cut-off: .. math:: \phi\left(r\right) & = D_0 \left[ e^{- 2 \alpha (r - r_0)} - 2 e^{- \alpha (r - r_0)} \right] \qquad r < r_c \\ - E\left(r\right) & = \phi\left(r\right) - \phi\left(R_c\right) - \left(r - R_c\right) \left.\frac{d\phi}{d r} \right|_{r=R_c} \qquad r < R_c + E\left(r\right) & = \phi\left(r\right) - \phi\left(r_c\right) - \left(r - r_c\right) \left.\frac{d\phi}{d r} \right|_{r=r_c} \qquad r < r_c The syntax of the pair_style and pair_coeff commands are the same for the *morse* and *morse/smooth/linear* styles. diff --git a/doc/src/pair_soft.rst b/doc/src/pair_soft.rst index 1702811ed9..e21ae28432 100644 --- a/doc/src/pair_soft.rst +++ b/doc/src/pair_soft.rst @@ -44,8 +44,9 @@ It is useful for pushing apart overlapping atoms, since it does not blow up as r goes to 0. A is a prefactor that can be made to vary in time from the start to the end of the run (see discussion below), e.g. to start with a very soft potential and slowly harden the -interactions over time. Rc is the cutoff. See the :doc:`fix nve/limit ` command for another way to push apart -overlapping atoms. +interactions over time. :math:`r_c` is the cutoff. +See the :doc:`fix nve/limit ` command for another way +to push apart overlapping atoms. The following coefficients must be defined for each pair of atom types via the :doc:`pair_coeff ` command as in the examples above, diff --git a/doc/src/pair_spica.rst b/doc/src/pair_spica.rst index 74a069d8a2..859506593f 100644 --- a/doc/src/pair_spica.rst +++ b/doc/src/pair_spica.rst @@ -81,7 +81,7 @@ given by as required for the SPICA (formerly called SDK) and the pSPICA Coarse-grained MD parameterization discussed in :ref:`(Shinoda) `, :ref:`(DeVane) `, :ref:`(Seo) `, and :ref:`(Miyazaki) `. -Rc is the cutoff. +:math:`r_c` is the cutoff. Summary information on these force fields can be found at https://www.spica-ff.org Style *lj/spica/coul/long* computes the adds Coulombic interactions From cd21f67cc6f06f94eb3e60046aa48c136727bda0 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 2 Dec 2023 16:22:43 -0500 Subject: [PATCH 77/93] avoid copying over terminating null --- src/balance.cpp | 2 +- src/fix_balance.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/balance.cpp b/src/balance.cpp index 6f28081f13..c3288591e2 100644 --- a/src/balance.cpp +++ b/src/balance.cpp @@ -199,7 +199,7 @@ void Balance::command(int narg, char **arg) if (iarg+4 > narg) error->all(FLERR,"Illegal balance command"); style = SHIFT; if (strlen(arg[iarg+1]) > BSTR_SIZE) error->all(FLERR,"Illegal balance command"); - strncpy(bstr,arg[iarg+1],BSTR_SIZE+1); + strncpy(bstr,arg[iarg+1],BSTR_SIZE); nitermax = utils::inumeric(FLERR,arg[iarg+2],false,lmp); if (nitermax <= 0) error->all(FLERR,"Illegal balance command"); stopthresh = utils::numeric(FLERR,arg[iarg+3],false,lmp); diff --git a/src/fix_balance.cpp b/src/fix_balance.cpp index 844ffe474e..12de63a64a 100644 --- a/src/fix_balance.cpp +++ b/src/fix_balance.cpp @@ -69,7 +69,7 @@ FixBalance::FixBalance(LAMMPS *lmp, int narg, char **arg) : if (iarg+4 > narg) error->all(FLERR,"Illegal fix balance command"); if (strlen(arg[iarg+1]) > Balance::BSTR_SIZE) error->all(FLERR,"Illegal fix balance command"); - strncpy(bstr,arg[iarg+1], Balance::BSTR_SIZE+1); + strncpy(bstr,arg[iarg+1], Balance::BSTR_SIZE); nitermax = utils::inumeric(FLERR,arg[iarg+2],false,lmp); if (nitermax <= 0) error->all(FLERR,"Illegal fix balance command"); stopthresh = utils::numeric(FLERR,arg[iarg+3],false,lmp); From ba8ca9258b560de46eb011d3c371ff9098b2409b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 2 Dec 2023 16:34:32 -0500 Subject: [PATCH 78/93] correct dpi to get proper image scaling in PDF output --- doc/src/compute_saed.rst | 2 +- doc/src/img/saed_mesh.jpg | Bin 110946 -> 0 bytes doc/src/img/saed_mesh.png | Bin 0 -> 92096 bytes 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 doc/src/img/saed_mesh.jpg create mode 100644 doc/src/img/saed_mesh.png diff --git a/doc/src/compute_saed.rst b/doc/src/compute_saed.rst index 9ec455d03b..3079afb7ce 100644 --- a/doc/src/compute_saed.rst +++ b/doc/src/compute_saed.rst @@ -68,7 +68,7 @@ reciprocal lattice nodes. The mesh spacing is defined either (a) by the entire simulation domain or (b) manually using selected values as shown in the 2D diagram below. -.. image:: img/saed_mesh.jpg +.. image:: img/saed_mesh.png :scale: 75% :align: center diff --git a/doc/src/img/saed_mesh.jpg b/doc/src/img/saed_mesh.jpg deleted file mode 100644 index 7b0bf4117f1397345fda738cba8c4229081560ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 110946 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 z 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 diff --git a/doc/src/img/saed_mesh.png b/doc/src/img/saed_mesh.png new file mode 100644 index 0000000000000000000000000000000000000000..bd558ce072e40e1eee9a5384064fedbef908e57a GIT binary patch literal 92096 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 B97q5F literal 0 HcmV?d00001 From 530f487dd7601df4997b78c26d959d59ed558d5f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 3 Dec 2023 11:22:03 -0500 Subject: [PATCH 79/93] must do region check only when region is active --- src/MC/fix_gcmc.cpp | 43 ++++++++++++++++++++++++++++--------------- src/MC/fix_widom.cpp | 44 +++++++++++++++++++++++++++++--------------- 2 files changed, 57 insertions(+), 30 deletions(-) diff --git a/src/MC/fix_gcmc.cpp b/src/MC/fix_gcmc.cpp index ff8c5eb9c9..2e29b403fd 100644 --- a/src/MC/fix_gcmc.cpp +++ b/src/MC/fix_gcmc.cpp @@ -89,6 +89,7 @@ FixGCMC::FixGCMC(LAMMPS *lmp, int narg, char **arg) : ngroups = 0; ngrouptypes = 0; + triclinic = domain->triclinic; // required args @@ -123,8 +124,7 @@ FixGCMC::FixGCMC(LAMMPS *lmp, int narg, char **arg) : // error checks on region and its extent being inside simulation box - region_xlo = region_xhi = region_ylo = region_yhi = - region_zlo = region_zhi = 0.0; + region_xlo = region_xhi = region_ylo = region_yhi = region_zlo = region_zhi = 0.0; if (region) { if (region->bboxflag == 0) error->all(FLERR,"Fix gcmc region does not support a bounding box"); @@ -298,8 +298,7 @@ void FixGCMC::options(int narg, char **arg) } else if (strcmp(arg[iarg],"region") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix gcmc command"); region = domain->get_region_by_id(arg[iarg+1]); - if (!region) - error->all(FLERR,"Region {} for fix gcmc does not exist",arg[iarg+1]); + if (!region) error->all(FLERR,"Region {} for fix gcmc does not exist",arg[iarg+1]); idregion = utils::strdup(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"maxangle") == 0) { @@ -464,6 +463,8 @@ int FixGCMC::setmask() void FixGCMC::init() { + triclinic = domain->triclinic; + // set index and check validity of region if (idregion) { @@ -471,19 +472,31 @@ void FixGCMC::init() if (!region) error->all(FLERR, "Region {} for fix gcmc does not exist", idregion); } - triclinic = domain->triclinic; + if (region) { + if (region->bboxflag == 0) + error->all(FLERR,"Fix gcmc region does not support a bounding box"); + if (region->dynamic_check()) + error->all(FLERR,"Fix gcmc region cannot be dynamic"); - if (triclinic) { - if ((region_xlo < domain->boxlo_bound[0]) || (region_xhi > domain->boxhi_bound[0]) || - (region_ylo < domain->boxlo_bound[1]) || (region_yhi > domain->boxhi_bound[1]) || - (region_zlo < domain->boxlo_bound[2]) || (region_zhi > domain->boxhi_bound[2])) { - error->all(FLERR,"Fix gcmc region extends outside simulation box"); + region_xlo = region->extent_xlo; + region_xhi = region->extent_xhi; + region_ylo = region->extent_ylo; + region_yhi = region->extent_yhi; + region_zlo = region->extent_zlo; + region_zhi = region->extent_zhi; + + if (triclinic) { + if ((region_xlo < domain->boxlo_bound[0]) || (region_xhi > domain->boxhi_bound[0]) || + (region_ylo < domain->boxlo_bound[1]) || (region_yhi > domain->boxhi_bound[1]) || + (region_zlo < domain->boxlo_bound[2]) || (region_zhi > domain->boxhi_bound[2])) { + error->all(FLERR,"Fix gcmc region extends outside simulation box"); + } + } else { + if ((region_xlo < domain->boxlo[0]) || (region_xhi > domain->boxhi[0]) || + (region_ylo < domain->boxlo[1]) || (region_yhi > domain->boxhi[1]) || + (region_zlo < domain->boxlo[2]) || (region_zhi > domain->boxhi[2])) + error->all(FLERR,"Fix gcmc region extends outside simulation box"); } - } else { - if ((region_xlo < domain->boxlo[0]) || (region_xhi > domain->boxhi[0]) || - (region_ylo < domain->boxlo[1]) || (region_yhi > domain->boxhi[1]) || - (region_zlo < domain->boxlo[2]) || (region_zhi > domain->boxhi[2])) - error->all(FLERR,"Fix gcmc region extends outside simulation box"); } // set probabilities for MC moves diff --git a/src/MC/fix_widom.cpp b/src/MC/fix_widom.cpp index cc2f1bc94d..7869b213a0 100644 --- a/src/MC/fix_widom.cpp +++ b/src/MC/fix_widom.cpp @@ -73,6 +73,8 @@ FixWidom::FixWidom(LAMMPS *lmp, int narg, char **arg) : restart_global = 1; time_depend = 1; + triclinic = domain->triclinic; + // required args nevery = utils::inumeric(FLERR,arg[3],false,lmp); @@ -111,18 +113,6 @@ FixWidom::FixWidom(LAMMPS *lmp, int narg, char **arg) : region_zlo = region->extent_zlo; region_zhi = region->extent_zhi; - if (triclinic) { - if ((region_xlo < domain->boxlo_bound[0]) || (region_xhi > domain->boxhi_bound[0]) || - (region_ylo < domain->boxlo_bound[1]) || (region_yhi > domain->boxhi_bound[1]) || - (region_zlo < domain->boxlo_bound[2]) || (region_zhi > domain->boxhi_bound[2])) - error->all(FLERR,"Fix widom region {} extends outside simulation box", region->id); - } else { - if ((region_xlo < domain->boxlo[0]) || (region_xhi > domain->boxhi[0]) || - (region_ylo < domain->boxlo[1]) || (region_yhi > domain->boxhi[1]) || - (region_zlo < domain->boxlo[2]) || (region_zhi > domain->boxhi[2])) - error->all(FLERR,"Fix widom region {} extends outside simulation box", region->id); - } - // estimate region volume using MC trials double coord[3]; @@ -216,8 +206,7 @@ void FixWidom::options(int narg, char **arg) } else if (strcmp(arg[iarg],"region") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix widom command"); region = domain->get_region_by_id(arg[iarg+1]); - if (!region) - error->all(FLERR,"Region {} for fix widom does not exist",arg[iarg+1]); + if (!region) error->all(FLERR,"Region {} for fix widom does not exist",arg[iarg+1]); idregion = utils::strdup(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"charge") == 0) { @@ -292,6 +281,7 @@ int FixWidom::setmask() void FixWidom::init() { + triclinic = domain->triclinic; // set index and check validity of region @@ -300,7 +290,31 @@ void FixWidom::init() if (!region) error->all(FLERR, "Region {} for fix widom does not exist", idregion); } - triclinic = domain->triclinic; + if (region) { + if (region->bboxflag == 0) + error->all(FLERR,"Fix gcmc region does not support a bounding box"); + if (region->dynamic_check()) + error->all(FLERR,"Fix gcmc region cannot be dynamic"); + + region_xlo = region->extent_xlo; + region_xhi = region->extent_xhi; + region_ylo = region->extent_ylo; + region_yhi = region->extent_yhi; + region_zlo = region->extent_zlo; + region_zhi = region->extent_zhi; + + if (triclinic) { + if ((region_xlo < domain->boxlo_bound[0]) || (region_xhi > domain->boxhi_bound[0]) || + (region_ylo < domain->boxlo_bound[1]) || (region_yhi > domain->boxhi_bound[1]) || + (region_zlo < domain->boxlo_bound[2]) || (region_zhi > domain->boxhi_bound[2])) + error->all(FLERR,"Fix widom region {} extends outside simulation box", region->id); + } else { + if ((region_xlo < domain->boxlo[0]) || (region_xhi > domain->boxhi[0]) || + (region_ylo < domain->boxlo[1]) || (region_yhi > domain->boxhi[1]) || + (region_zlo < domain->boxlo[2]) || (region_zhi > domain->boxhi[2])) + error->all(FLERR,"Fix widom region {} extends outside simulation box", region->id); + } + } ave_widom_chemical_potential = 0.0; From c742b20c5a07066288a8974d288e0ba43a2073c5 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 19 Nov 2023 08:59:27 -0500 Subject: [PATCH 80/93] update Purge.list and avoid redundant checks --- cmake/Modules/LAMMPSUtils.cmake | 14 +++++++------- src/Purge.list | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/cmake/Modules/LAMMPSUtils.cmake b/cmake/Modules/LAMMPSUtils.cmake index 1ceec7e06e..d464aa4dca 100644 --- a/cmake/Modules/LAMMPSUtils.cmake +++ b/cmake/Modules/LAMMPSUtils.cmake @@ -83,17 +83,17 @@ function(check_for_autogen_files source_dir) file(GLOB SRC_AUTOGEN_FILES ${CONFIGURE_DEPENDS} ${source_dir}/style_*.h) file(GLOB SRC_AUTOGEN_PACKAGES ${CONFIGURE_DEPENDS} ${source_dir}/packages_*.h) list(APPEND SRC_AUTOGEN_FILES ${SRC_AUTOGEN_PACKAGES} ${source_dir}/lmpinstalledpkgs.h ${source_dir}/lmpgitversion.h) - list(APPEND SRC_AUTOGEN_FILES ${SRC_AUTOGEN_PACKAGES} ${source_dir}/mliap_model_python_couple.h ${source_dir}/mliap_model_python_couple.cpp) + list(APPEND SRC_AUTOGEN_FILES ${source_dir}/mliap_model_python_couple.h ${source_dir}/mliap_model_python_couple.cpp) foreach(_SRC ${SRC_AUTOGEN_FILES}) get_filename_component(FILENAME "${_SRC}" NAME) if(EXISTS ${source_dir}/${FILENAME}) message(FATAL_ERROR "\n########################################################################\n" - "Found header file(s) generated by the make-based build system\n" - "\n" - "Please run\n" - "make -C ${source_dir} purge\n" - "to remove\n" - "########################################################################") + "Found header file ${source_dir}/${FILENAME} generated by the make-based build system\n" + "\n" + "Please run\n" + "make -C ${source_dir} purge\n" + "to remove\n" + "########################################################################") endif() endforeach() endfunction() diff --git a/src/Purge.list b/src/Purge.list index 1d2cdcf06b..42c669c39d 100644 --- a/src/Purge.list +++ b/src/Purge.list @@ -8,6 +8,7 @@ style_compute.h style_dihedral.h style_dump.h style_fix.h +style_gran_sub_mod.h style_improper.h style_integrate.h style_kspace.h @@ -32,6 +33,7 @@ packages_compute.h packages_dihedral.h packages_dump.h packages_fix.h +packages_gran_sub_mod.h packages_improper.h packages_integrate.h packages_kspace.h From 2808e6fc524002a0b253f362baeb119fdc366195 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 5 Dec 2023 22:09:06 -0500 Subject: [PATCH 81/93] fix typo --- doc/src/fix_nh_uef.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/fix_nh_uef.rst b/doc/src/fix_nh_uef.rst index a515375746..2d4cc32c76 100644 --- a/doc/src/fix_nh_uef.rst +++ b/doc/src/fix_nh_uef.rst @@ -62,7 +62,7 @@ performed using the :doc:`fix deform `, :doc:`fix nvt/sllod `, and :doc:`compute temp/deform ` commands. -The applied flow field is set by the *eps* keyword. The values +The applied flow field is set by the *erate* keyword. The values *edot_x* and *edot_y* correspond to the strain rates in the xx and yy directions. It is implicitly assumed that the flow field is traceless, and therefore the strain rate in the zz direction is eqal From 283e2103e30dacddddaaa530c114846bc01f3e23 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 6 Dec 2023 13:54:44 -0500 Subject: [PATCH 82/93] update fix adapt/fep from fix adapt. only supports 2-d parameters for pair styles --- src/FEP/fix_adapt_fep.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/FEP/fix_adapt_fep.cpp b/src/FEP/fix_adapt_fep.cpp index c32b44b081..e0c5868e96 100644 --- a/src/FEP/fix_adapt_fep.cpp +++ b/src/FEP/fix_adapt_fep.cpp @@ -48,9 +48,9 @@ enum{DIAMETER, CHARGE}; FixAdaptFEP::FixAdaptFEP(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { - if (narg < 5) error->all(FLERR,"Illegal fix adapt/fep command"); + if (narg < 5) utils::missing_cmd_args(FLERR,"fix adapt/fep", error); nevery = utils::inumeric(FLERR,arg[3],false,lmp); - if (nevery < 0) error->all(FLERR,"Illegal fix adapt/fep command"); + if (nevery < 0) error->all(FLERR,"Illegal fix adapt/fep every value {}", nevery); dynamic_group_allow = 1; create_attribute = 1; @@ -62,21 +62,21 @@ FixAdaptFEP::FixAdaptFEP(LAMMPS *lmp, int narg, char **arg) : int iarg = 4; while (iarg < narg) { if (strcmp(arg[iarg],"pair") == 0) { - if (iarg+6 > narg) error->all(FLERR,"Illegal fix adapt/fep command"); + if (iarg+6 > narg) utils::missing_cmd_args(FLERR,"fix adapt/fep pair", error); nadapt++; iarg += 6; } else if (strcmp(arg[iarg],"kspace") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix adapt/fep command"); + if (iarg+2 > narg) utils::missing_cmd_args(FLERR,"fix adapt/fep kspace", error); nadapt++; iarg += 2; } else if (strcmp(arg[iarg],"atom") == 0) { - if (iarg+4 > narg) error->all(FLERR,"Illegal fix adapt/fep command"); + if (iarg+4 > narg) utils::missing_cmd_args(FLERR,"fix adapt/fep atom", error); nadapt++; iarg += 4; } else break; } - if (nadapt == 0) error->all(FLERR,"Illegal fix adapt/fep command"); + if (nadapt == 0) error->all(FLERR,"Nothing to adapt in fix adapt/fep command"); adapt = new Adapt[nadapt]; // parse keywords @@ -136,11 +136,11 @@ FixAdaptFEP::FixAdaptFEP(LAMMPS *lmp, int narg, char **arg) : while (iarg < narg) { if (strcmp(arg[iarg],"reset") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix adapt/fep command"); + if (iarg+2 > narg) utils::missing_cmd_args(FLERR,"fix adapt/fep reset", error); resetflag = utils::logical(FLERR,arg[iarg+1],false,lmp); iarg += 2; } else if (strcmp(arg[iarg],"scale") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal fix adapt/fep command"); + if (iarg+2 > narg) utils::missing_cmd_args(FLERR,"fix adapt/fep scale", error); scaleflag = utils::logical(FLERR,arg[iarg+1],false,lmp); iarg += 2; } else if (strcmp(arg[iarg],"after") == 0) { @@ -208,7 +208,7 @@ void FixAdaptFEP::post_constructor() id_fix_diam = nullptr; id_fix_chg = nullptr; - if (diam_flag) { + if (diam_flag && atom->radius_flag) { id_fix_diam = utils::strdup(id + std::string("_FIX_STORE_DIAM")); fix_diam = dynamic_cast( modify->add_fix(fmt::format("{} {} STORE/ATOM 1 0 0 1", id_fix_diam,group->names[igroup]))); @@ -226,7 +226,7 @@ void FixAdaptFEP::post_constructor() } } - if (chgflag) { + if (chgflag && atom->q_flag) { id_fix_chg = utils::strdup(id + std::string("_FIX_STORE_CHG")); fix_chg = dynamic_cast( modify->add_fix(fmt::format("{} {} STORE/ATOM 1 0 0 1",id_fix_chg,group->names[igroup]))); @@ -267,9 +267,9 @@ void FixAdaptFEP::init() ad->ivar = input->variable->find(ad->var); if (ad->ivar < 0) - error->all(FLERR,"Variable name for fix adapt/fep does not exist"); + error->all(FLERR,"Variable name {} for fix adapt/fep does not exist", ad->var); if (!input->variable->equalstyle(ad->ivar)) - error->all(FLERR,"Variable for fix adapt/fep is invalid style"); + error->all(FLERR,"Variable {} for fix adapt/fep is invalid style", ad->var); if (ad->which == PAIR) { anypair = 1; @@ -285,8 +285,9 @@ void FixAdaptFEP::init() if (ptr == nullptr) error->all(FLERR,"Fix adapt/fep pair style param not supported"); - ad->pdim = 2; - if (ad->pdim == 0) ad->scalar = (double *) ptr; + if (ad->pdim != 2) + error->all(FLERR,"Pair style parameter {} is not compatible with fix adapt/fep", ad->pparam); + if (ad->pdim == 2) ad->array = (double **) ptr; // if pair hybrid, test that ilo,ihi,jlo,jhi are valid for sub-style From a40e9222aac9e6f7a10a2d42f0daf677e432c9a6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 13 Dec 2023 00:24:49 -0500 Subject: [PATCH 83/93] add valgrind suppressions for MPICH on Fedora 39 --- tools/valgrind/MPICH.supp | 41 +++++++++++++++++++++++++++++++++++++++ tools/valgrind/README | 1 + 2 files changed, 42 insertions(+) create mode 100644 tools/valgrind/MPICH.supp diff --git a/tools/valgrind/MPICH.supp b/tools/valgrind/MPICH.supp new file mode 100644 index 0000000000..6934cf8fbd --- /dev/null +++ b/tools/valgrind/MPICH.supp @@ -0,0 +1,41 @@ +{ + MPICH_MPI_init1 + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + obj:* + ... + fun:psm3_init + ... + fun:MPIDI_OFI_init_local + ... + fun:PMPI_Init + fun:main +} +{ + MPICH_MPI_init2 + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:strdup + obj:* + ... + fun:fi_ini + ... + fun:MPIDI_OFI_init_local + ... + fun:PMPI_Init + fun:main +} +{ + MPICH_MPI_init3 + Memcheck:Leak + match-leak-kinds: reachable + fun:calloc + obj:* + ... + fun:MPIDI_OFI_init_local + ... + fun:PMPI_Init + fun:main +} diff --git a/tools/valgrind/README b/tools/valgrind/README index 63c440f7b2..e62031da9b 100644 --- a/tools/valgrind/README +++ b/tools/valgrind/README @@ -8,6 +8,7 @@ on running LAMMPS, use a command line like following: valgrind --show-leak-kinds=all --track-origins=yes \ --suppressions=/path/to/lammps/tools/valgrind/OpenMP.supp \ --suppressions=/path/to/lammps/tools/valgrind/OpenMPI.supp \ + --suppressions=/path/to/lammps/tools/valgrind/MPICH.supp \ --suppressions=/path/to/lammps/tools/valgrind/Python3.supp \ --suppressions=/path/to/lammps/tools/valgrind/GTest.supp \ --suppressions=/path/to/lammps/tools/valgrind/FlexiBLAS.supp \ From e69c65431fc3f61ed4820b906ee83fcf7463df39 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 12 Dec 2023 21:52:45 -0500 Subject: [PATCH 84/93] silence preprocessor warning from leaking internal define in cython generated code --- src/PYTHON/python_impl.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/PYTHON/python_impl.cpp b/src/PYTHON/python_impl.cpp index 57f8ea1cf0..a10a810e17 100644 --- a/src/PYTHON/python_impl.cpp +++ b/src/PYTHON/python_impl.cpp @@ -29,19 +29,31 @@ #ifdef MLIAP_PYTHON #include "mliap_model_python.h" +#if defined(__PYX_EXTERN_C) && !defined(CYTHON_EXTERN_C) +#undef __PYX_EXTERN_C +#endif #include "mliap_unified.h" // The above should somehow really be included in the next file. // We could get around this with cython --capi-reexport-cincludes // However, that exposes -too many- headers. #include "mliap_model_python_couple.h" +#if defined(__PYX_EXTERN_C) && !defined(CYTHON_EXTERN_C) +#undef __PYX_EXTERN_C +#endif #include "mliap_unified_couple.h" #ifdef LMP_KOKKOS #include "mliap_model_python_kokkos.h" +#if defined(__PYX_EXTERN_C) && !defined(CYTHON_EXTERN_C) +#undef __PYX_EXTERN_C +#endif #include "mliap_unified_kokkos.h" // The above should somehow really be included in the next file. // We could get around this with cython --capi-reexport-cincludes // However, that exposes -too many- headers. #include "mliap_model_python_couple_kokkos.h" +#if defined(__PYX_EXTERN_C) && !defined(CYTHON_EXTERN_C) +#undef __PYX_EXTERN_C +#endif #include "mliap_unified_couple_kokkos.h" From 016c9ef4b293d3525552d14b8a3d4377a388e015 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Fri, 8 Dec 2023 23:59:41 -0700 Subject: [PATCH 85/93] Use PyConfig to initialize Python --- src/PYTHON/python_impl.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/PYTHON/python_impl.cpp b/src/PYTHON/python_impl.cpp index a10a810e17..c1c26c7bb3 100644 --- a/src/PYTHON/python_impl.cpp +++ b/src/PYTHON/python_impl.cpp @@ -73,16 +73,19 @@ PythonImpl::PythonImpl(LAMMPS *lmp) : Pointers(lmp) nfunc = 0; pfuncs = nullptr; -#if PY_MAJOR_VERSION >= 3 -#ifndef Py_LIMITED_API +#if PY_MAJOR_VERSION >= 3 && !defined(Py_LIMITED_API) // check for PYTHONUNBUFFERED environment variable const char *PYTHONUNBUFFERED = getenv("PYTHONUNBUFFERED"); + // Force the stdout and stderr streams to be unbuffered. + bool unbuffered = PYTHONUNBUFFERED != nullptr && strcmp(PYTHONUNBUFFERED, "1") == 0; - if (PYTHONUNBUFFERED != nullptr && strcmp(PYTHONUNBUFFERED, "1") == 0) { - // Python Global configuration variable - // Force the stdout and stderr streams to be unbuffered. - Py_UnbufferedStdioFlag = 1; - } +#if PY_VERSION_HEX >= 0x030800f0 + PyConfig config; + PyConfig_InitPythonConfig(&config); + config.buffered_stdio = !unbuffered; +#else + // Python Global configuration variable + Py_UnbufferedStdioFlag = unbuffered; #endif #endif @@ -106,12 +109,17 @@ PythonImpl::PythonImpl(LAMMPS *lmp) : Pointers(lmp) #endif #endif +#if PY_VERSION_HEX >= 0x030800f0 && !defined(Py_LIMITED_API) + Py_InitializeFromConfig(&config); + PyConfig_Clear(&config); +#else Py_Initialize(); +#endif // only needed for Python 2.x and Python 3 < 3.7 // With Python 3.7 this function is now called by Py_Initialize() // Deprecated since version 3.9, will be removed in version 3.11 -#if PY_MAJOR_VERSION < 3 || PY_MINOR_VERSION < 7 +#if PY_VERSION_HEX < 0x030700f0 if (!PyEval_ThreadsInitialized()) { PyEval_InitThreads(); } #endif From 2d961e76b369d189cb8df006aa7925783bc395ec Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 13 Dec 2023 00:32:59 -0500 Subject: [PATCH 86/93] flag update #2 to stable release --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index 87d76feb9d..b99170567b 100644 --- a/src/version.h +++ b/src/version.h @@ -1,2 +1,2 @@ #define LAMMPS_VERSION "2 Aug 2023" -#define LAMMPS_UPDATE "Maintenance" +#define LAMMPS_UPDATE "Update 2" From 4128d52e1cf26ecee5a745926e6bc687565aaa91 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Fri, 17 Nov 2023 09:50:03 -0700 Subject: [PATCH 87/93] Bugfix: port missed changes from #3846 --- src/OPENMP/npair_halffull_newton_trim_omp.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/OPENMP/npair_halffull_newton_trim_omp.cpp b/src/OPENMP/npair_halffull_newton_trim_omp.cpp index 1446175013..9fdd4957af 100644 --- a/src/OPENMP/npair_halffull_newton_trim_omp.cpp +++ b/src/OPENMP/npair_halffull_newton_trim_omp.cpp @@ -38,6 +38,8 @@ NPairHalffullNewtonTrimOmp::NPairHalffullNewtonTrimOmp(LAMMPS *lmp) : NPair(lmp) void NPairHalffullNewtonTrimOmp::build(NeighList *list) { const int inum_full = list->listfull->inum; + const double delta = 0.01 * force->angstrom; + const int triclinic = domain->triclinic; NPAIR_OMP_INIT; #if defined(_OPENMP) @@ -86,8 +88,17 @@ void NPairHalffullNewtonTrimOmp::build(NeighList *list) for (jj = 0; jj < jnum; jj++) { joriginal = jlist[jj]; j = joriginal & NEIGHMASK; + if (j < nlocal) { if (i > j) continue; + } else if (triclinic) { + if (fabs(x[j][2]-ztmp) > delta) { + if (x[j][2] < ztmp) continue; + } else if (fabs(x[j][1]-ytmp) > delta) { + if (x[j][1] < ytmp) continue; + } else { + if (x[j][0] < xtmp) continue; + } } else { if (x[j][2] < ztmp) continue; if (x[j][2] == ztmp) { From d9804d7590050c8b7d2b7ec96ed0fb8aed700366 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Thu, 16 Nov 2023 16:21:59 -0700 Subject: [PATCH 88/93] Fix issues with sorting neigh list by cutoff distance --- src/neighbor.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/neighbor.cpp b/src/neighbor.cpp index df1547e5eb..741b469750 100644 --- a/src/neighbor.cpp +++ b/src/neighbor.cpp @@ -1126,15 +1126,14 @@ int Neighbor::init_pair() } /* ---------------------------------------------------------------------- - sort NeighRequests by cutoff distance - to find smallest list for trimming + sort NeighRequests by cutoff distance for trimming ------------------------------------------------------------------------- */ void Neighbor::sort_requests() { - NeighRequest *jrq; + NeighRequest *irq,*jrq; int i,j,jmin; - double jcut; + double icut,jcut; delete[] j_sorted; j_sorted = new int[nrequest]; @@ -1142,20 +1141,24 @@ void Neighbor::sort_requests() for (i = 0; i < nrequest; i++) j_sorted[i] = i; - for (i = 0; i < nrequest; i++) { - double cutoff_min = cutneighmax; + for (i = 0; i < nrequest-1; i++) { + irq = requests[j_sorted[i]]; + if (irq->cut) icut = irq->cutoff; + else icut = cutneighmax; + double cutoff_min = icut; jmin = i; - for (j = i; j < nrequest-1; j++) { + for (j = i+1; j < nrequest; j++) { jrq = requests[j_sorted[j]]; if (jrq->cut) jcut = jrq->cutoff; else jcut = cutneighmax; - if (jcut <= cutoff_min) { + if (jcut < cutoff_min) { cutoff_min = jcut; jmin = j; } } + int tmp = j_sorted[i]; j_sorted[i] = j_sorted[jmin]; j_sorted[jmin] = tmp; From 3f48d48eea2cf53da5716c7dd92777d9ae3f2f60 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 14 Dec 2023 16:00:10 -0500 Subject: [PATCH 89/93] add missing dependency --- src/Depend.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Depend.sh b/src/Depend.sh index 4004f12686..5022d5c734 100755 --- a/src/Depend.sh +++ b/src/Depend.sh @@ -64,6 +64,7 @@ fi if (test $1 = "COLLOID") then depend GPU + depend KOKKOS depend OPENMP fi From ac1db251cb5899a595f33222eac61afe41c15bea Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 14 Dec 2023 16:24:22 -0500 Subject: [PATCH 90/93] recover compilation --- src/OPENMP/npair_halffull_newton_trim_omp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/OPENMP/npair_halffull_newton_trim_omp.cpp b/src/OPENMP/npair_halffull_newton_trim_omp.cpp index 9fdd4957af..98a7d6dd68 100644 --- a/src/OPENMP/npair_halffull_newton_trim_omp.cpp +++ b/src/OPENMP/npair_halffull_newton_trim_omp.cpp @@ -15,7 +15,9 @@ #include "npair_halffull_newton_trim_omp.h" #include "atom.h" +#include "domain.h" #include "error.h" +#include "force.h" #include "my_page.h" #include "neigh_list.h" #include "npair_omp.h" From 85393862af8a0322d264d61a8dcd33ef5f7d5db6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 14 Dec 2023 16:47:36 -0500 Subject: [PATCH 91/93] fix typos --- src/balance.cpp | 2 +- src/fix_balance.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/balance.cpp b/src/balance.cpp index c3288591e2..82755d7e52 100644 --- a/src/balance.cpp +++ b/src/balance.cpp @@ -235,7 +235,7 @@ void Balance::command(int narg, char **arg) } if (style == SHIFT) { - const int blen=strlen(bstr); + const int blen=strlen(bstr) + 1; for (int i = 0; i < blen; i++) { if (bstr[i] != 'x' && bstr[i] != 'y' && bstr[i] != 'z') error->all(FLERR,"Balance shift string is invalid"); diff --git a/src/fix_balance.cpp b/src/fix_balance.cpp index 12de63a64a..98e4205090 100644 --- a/src/fix_balance.cpp +++ b/src/fix_balance.cpp @@ -83,7 +83,7 @@ FixBalance::FixBalance(LAMMPS *lmp, int narg, char **arg) : // error checks if (lbstyle == SHIFT) { - int blen = strlen(bstr); + int blen = strlen(bstr) + 1; for (int i = 0; i < blen; i++) { if (bstr[i] != 'x' && bstr[i] != 'y' && bstr[i] != 'z') error->all(FLERR,"Fix balance shift string is invalid"); From b3e54549db9a4cdb5d840b15cbdbc7b4bb91af6a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 14 Dec 2023 17:32:20 -0500 Subject: [PATCH 92/93] safely copy balance shift dimension string with proper termination --- src/balance.cpp | 8 +++++--- src/fix_balance.cpp | 9 +++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/balance.cpp b/src/balance.cpp index 82755d7e52..f63dc0cc33 100644 --- a/src/balance.cpp +++ b/src/balance.cpp @@ -198,8 +198,10 @@ void Balance::command(int narg, char **arg) if (style != -1) error->all(FLERR,"Illegal balance command"); if (iarg+4 > narg) error->all(FLERR,"Illegal balance command"); style = SHIFT; - if (strlen(arg[iarg+1]) > BSTR_SIZE) error->all(FLERR,"Illegal balance command"); - strncpy(bstr,arg[iarg+1],BSTR_SIZE); + const int blen = strlen(arg[iarg+1]); + if (blen > BSTR_SIZE) error->all(FLERR,"Illegal balance command"); + memset(bstr, 0, BSTR_SIZE+1); + memcpy(bstr,arg[iarg+1],blen); nitermax = utils::inumeric(FLERR,arg[iarg+2],false,lmp); if (nitermax <= 0) error->all(FLERR,"Illegal balance command"); stopthresh = utils::numeric(FLERR,arg[iarg+3],false,lmp); @@ -235,7 +237,7 @@ void Balance::command(int narg, char **arg) } if (style == SHIFT) { - const int blen=strlen(bstr) + 1; + const int blen=strlen(bstr); for (int i = 0; i < blen; i++) { if (bstr[i] != 'x' && bstr[i] != 'y' && bstr[i] != 'z') error->all(FLERR,"Balance shift string is invalid"); diff --git a/src/fix_balance.cpp b/src/fix_balance.cpp index 98e4205090..2de8991d8a 100644 --- a/src/fix_balance.cpp +++ b/src/fix_balance.cpp @@ -67,9 +67,10 @@ FixBalance::FixBalance(LAMMPS *lmp, int narg, char **arg) : int iarg = 5; if (lbstyle == SHIFT) { if (iarg+4 > narg) error->all(FLERR,"Illegal fix balance command"); - if (strlen(arg[iarg+1]) > Balance::BSTR_SIZE) - error->all(FLERR,"Illegal fix balance command"); - strncpy(bstr,arg[iarg+1], Balance::BSTR_SIZE); + const int blen = strlen(arg[iarg+1]); + if (blen > Balance::BSTR_SIZE) error->all(FLERR,"Illegal balance command"); + memset(bstr, 0, Balance::BSTR_SIZE+1); + memcpy(bstr,arg[iarg+1],blen); nitermax = utils::inumeric(FLERR,arg[iarg+2],false,lmp); if (nitermax <= 0) error->all(FLERR,"Illegal fix balance command"); stopthresh = utils::numeric(FLERR,arg[iarg+3],false,lmp); @@ -83,7 +84,7 @@ FixBalance::FixBalance(LAMMPS *lmp, int narg, char **arg) : // error checks if (lbstyle == SHIFT) { - int blen = strlen(bstr) + 1; + int blen = strlen(bstr); for (int i = 0; i < blen; i++) { if (bstr[i] != 'x' && bstr[i] != 'y' && bstr[i] != 'z') error->all(FLERR,"Fix balance shift string is invalid"); From 9befd421ca0e0fa7ae8eaeee60c0a97c84431a30 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 14 Dec 2023 17:59:18 -0500 Subject: [PATCH 93/93] workaround hack for macOS --- src/PYTHON/python_impl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PYTHON/python_impl.cpp b/src/PYTHON/python_impl.cpp index c1c26c7bb3..ea4ac63ce7 100644 --- a/src/PYTHON/python_impl.cpp +++ b/src/PYTHON/python_impl.cpp @@ -79,7 +79,7 @@ PythonImpl::PythonImpl(LAMMPS *lmp) : Pointers(lmp) // Force the stdout and stderr streams to be unbuffered. bool unbuffered = PYTHONUNBUFFERED != nullptr && strcmp(PYTHONUNBUFFERED, "1") == 0; -#if PY_VERSION_HEX >= 0x030800f0 +#if (PY_VERSION_HEX >= 0x030800f0) && !defined(__APPLE__) PyConfig config; PyConfig_InitPythonConfig(&config); config.buffered_stdio = !unbuffered; @@ -87,6 +87,8 @@ PythonImpl::PythonImpl(LAMMPS *lmp) : Pointers(lmp) // Python Global configuration variable Py_UnbufferedStdioFlag = unbuffered; #endif +#else +#warning Cannot force stdout and stderr to be unbuffered #endif #ifdef MLIAP_PYTHON