From 88032a595d59152c86f1ea05a1f7beacf1e3123a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 10 Mar 2026 19:00:49 -0400 Subject: [PATCH 01/16] avoid segfault when invalid color pointer is passed to the draw_pixel() method --- src/GRAPHICS/image.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/GRAPHICS/image.cpp b/src/GRAPHICS/image.cpp index 9ab3e584900..a43f2880c98 100644 --- a/src/GRAPHICS/image.cpp +++ b/src/GRAPHICS/image.cpp @@ -1359,6 +1359,7 @@ void Image::draw_pixel(int ix, int iy, double depth, const double *surface, const double *surfaceColor) { if (!std::isfinite(depth)) return; // reject pixels with invalid depth buffer values + if (!surfaceColor) return; // reject pixels with an invalid color double diffuseKey,diffuseFill,diffuseBack,specularKey; if (depth < 0 || (depthBuffer[ix + iy*width] >= 0 && depth >= depthBuffer[ix + iy*width])) return; From 6f259c1764c4fd7293cb500596b71e9113fa0bd4 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 10 Mar 2026 19:01:04 -0400 Subject: [PATCH 02/16] use symbolic constant --- src/GRAPHICS/image.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/GRAPHICS/image.cpp b/src/GRAPHICS/image.cpp index a43f2880c98..c85ae43b114 100644 --- a/src/GRAPHICS/image.cpp +++ b/src/GRAPHICS/image.cpp @@ -52,6 +52,7 @@ namespace { constexpr int NCOLORS = 140; constexpr int NELEMENTS = 109; constexpr double EPSILON = 1.0e-6; +constexpr double TRANS_DELTA = 0.01; enum { NUMERIC, MINVALUE, MAXVALUE }; enum { CONTINUOUS, DISCRETE, SEQUENTIAL }; @@ -888,9 +889,9 @@ void Image::draw_pixmap(int xc, int yc, int pixwidth, int pixheight, const unsig // we allow a few steps difference for each channel to account // for rounding errors and reduce "bleeding" from interpolation - if ((fabs(pixelcolor[0] - transcolor[0]) < 0.01) && - (fabs(pixelcolor[1] - transcolor[1]) < 0.01) && - (fabs(pixelcolor[2] - transcolor[2]) < 0.01)) continue; + if ((fabs(pixelcolor[0] - transcolor[0]) < TRANS_DELTA) && + (fabs(pixelcolor[1] - transcolor[1]) < TRANS_DELTA) && + (fabs(pixelcolor[2] - transcolor[2]) < TRANS_DELTA)) continue; draw_pixel(ix, iy, dist, normal, pixelcolor); } From 562d2153a2e7bcb0ec12f8ab4affa6899dd20ea8 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 11 Mar 2026 08:59:51 -0600 Subject: [PATCH 03/16] Fix mixed precision compile issues in new code --- src/KOKKOS/atom_vec_ellipsoid_kokkos.cpp | 8 ++++---- src/KOKKOS/atom_vec_ellipsoid_kokkos.h | 6 +++--- src/KOKKOS/fix_langevin_kokkos.h | 2 +- src/KOKKOS/fix_nve_asphere_kokkos.h | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/KOKKOS/atom_vec_ellipsoid_kokkos.cpp b/src/KOKKOS/atom_vec_ellipsoid_kokkos.cpp index 299e2a23ba0..894e60eee8b 100644 --- a/src/KOKKOS/atom_vec_ellipsoid_kokkos.cpp +++ b/src/KOKKOS/atom_vec_ellipsoid_kokkos.cpp @@ -944,7 +944,7 @@ void AtomVecEllipsoidKokkos::sync_pinned(ExecutionSpace space, uint64_t mask, in if ((mask & V_MASK) && atomKK->k_v.need_sync_device()) perform_pinned_copy_transform(atomKK->k_v,space,async_flag); if ((mask & F_MASK) && atomKK->k_f.need_sync_device()) - perform_pinned_copy_transform(atomKK->k_f,space,async_flag); + perform_pinned_copy_transform(atomKK->k_f,space,async_flag); if ((mask & TAG_MASK) && atomKK->k_tag.need_sync_device()) perform_pinned_copy(atomKK->k_tag,space,async_flag); if ((mask & TYPE_MASK) && atomKK->k_type.need_sync_device()) @@ -958,7 +958,7 @@ void AtomVecEllipsoidKokkos::sync_pinned(ExecutionSpace space, uint64_t mask, in if ((mask & ANGMOM_MASK) && atomKK->k_angmom.need_sync_device()) perform_pinned_copy_transform(atomKK->k_angmom,space,async_flag); if ((mask & TORQUE_MASK) && atomKK->k_torque.need_sync_device()) - perform_pinned_copy_transform(atomKK->k_torque,space,async_flag); + perform_pinned_copy_transform(atomKK->k_torque,space,async_flag); if ((mask & ELLIPSOID_MASK) && atomKK->k_ellipsoid.need_sync_device()) perform_pinned_copy(atomKK->k_ellipsoid,space,async_flag); if ((mask & BONUS_MASK) && k_bonus.need_sync_device()) @@ -969,7 +969,7 @@ void AtomVecEllipsoidKokkos::sync_pinned(ExecutionSpace space, uint64_t mask, in if ((mask & V_MASK) && atomKK->k_v.need_sync_host()) perform_pinned_copy_transform(atomKK->k_v,space,async_flag); if ((mask & F_MASK) && atomKK->k_f.need_sync_host()) - perform_pinned_copy_transform(atomKK->k_f,space,async_flag); + perform_pinned_copy_transform(atomKK->k_f,space,async_flag); if ((mask & TAG_MASK) && atomKK->k_tag.need_sync_host()) perform_pinned_copy(atomKK->k_tag,space,async_flag); if ((mask & TYPE_MASK) && atomKK->k_type.need_sync_host()) @@ -983,7 +983,7 @@ void AtomVecEllipsoidKokkos::sync_pinned(ExecutionSpace space, uint64_t mask, in if ((mask & ANGMOM_MASK) && atomKK->k_angmom.need_sync_host()) perform_pinned_copy_transform(atomKK->k_angmom,space,async_flag); if ((mask & TORQUE_MASK) && atomKK->k_torque.need_sync_host()) - perform_pinned_copy_transform(atomKK->k_torque,space,async_flag); + perform_pinned_copy_transform(atomKK->k_torque,space,async_flag); if ((mask & ELLIPSOID_MASK) && atomKK->k_ellipsoid.need_sync_host()) perform_pinned_copy(atomKK->k_ellipsoid,space,async_flag); if ((mask & BONUS_MASK) && k_bonus.need_sync_host()) diff --git a/src/KOKKOS/atom_vec_ellipsoid_kokkos.h b/src/KOKKOS/atom_vec_ellipsoid_kokkos.h index 65d280847fe..a87c9935091 100644 --- a/src/KOKKOS/atom_vec_ellipsoid_kokkos.h +++ b/src/KOKKOS/atom_vec_ellipsoid_kokkos.h @@ -132,14 +132,14 @@ class AtomVecEllipsoidKokkos : public AtomVecKokkos, public AtomVecEllipsoid { DAT::t_kkfloat_1d_3_lr d_x; DAT::t_kkfloat_1d_3 d_v; - DAT::t_kkfloat_1d_3 d_f; + DAT::t_kkacc_1d_3 d_f; DAT::t_kkfloat_1d d_rmass; HAT::t_kkfloat_1d h_rmass; DAT::t_kkfloat_1d_3 d_angmom; HAT::t_kkfloat_1d_3 h_angmom; - DAT::t_kkfloat_1d_3 d_torque; - HAT::t_kkfloat_1d_3 h_torque; + DAT::t_kkacc_1d_3 d_torque; + HAT::t_kkacc_1d_3 h_torque; DAT::t_int_1d d_ellipsoid; HAT::t_int_1d h_ellipsoid; diff --git a/src/KOKKOS/fix_langevin_kokkos.h b/src/KOKKOS/fix_langevin_kokkos.h index 67ced3bbed0..4faad64960e 100644 --- a/src/KOKKOS/fix_langevin_kokkos.h +++ b/src/KOKKOS/fix_langevin_kokkos.h @@ -144,7 +144,7 @@ namespace LAMMPS_NS { // For angmom thermostat class AtomVecEllipsoidKokkos *avecEllipKK; typename AtomVecEllipsoidKokkosBonusArray::t_bonus_1d bonus; - typename ArrayTypes::t_kkfloat_1d_3 torque; + typename ArrayTypes::t_kkacc_1d_3 torque; typename ArrayTypes::t_kkfloat_1d_3 angmom; typename ArrayTypes::t_int_1d ellipsoid; void angmom_thermostat(); diff --git a/src/KOKKOS/fix_nve_asphere_kokkos.h b/src/KOKKOS/fix_nve_asphere_kokkos.h index 744a9e41e09..68556b0f046 100644 --- a/src/KOKKOS/fix_nve_asphere_kokkos.h +++ b/src/KOKKOS/fix_nve_asphere_kokkos.h @@ -54,9 +54,9 @@ class FixNVEAsphereKokkos : public FixNVEAsphere { typename ArrayTypes::t_int_1d ellipsoid; typename ArrayTypes::t_kkfloat_1d_3_lr x; typename ArrayTypes::t_kkfloat_1d_3 v; - typename ArrayTypes::t_kkfloat_1d_3 f; + typename ArrayTypes::t_kkacc_1d_3 f; typename ArrayTypes::t_kkfloat_1d_3 angmom; - typename ArrayTypes::t_kkfloat_1d_3 torque; + typename ArrayTypes::t_kkacc_1d_3 torque; typename ArrayTypes::t_kkfloat_1d rmass; typename ArrayTypes::t_int_1d mask; }; From 458ed1fda82d6defb5ac95009754fa8258cb3962 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 11 Mar 2026 09:00:51 -0600 Subject: [PATCH 04/16] Fix type mismatch found by @lrussell676 --- src/KOKKOS/bond_hybrid_kokkos.h | 2 +- src/KOKKOS/dihedral_hybrid_kokkos.h | 2 +- src/KOKKOS/improper_hybrid_kokkos.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/KOKKOS/bond_hybrid_kokkos.h b/src/KOKKOS/bond_hybrid_kokkos.h index 217beaca5f6..8594d211f74 100644 --- a/src/KOKKOS/bond_hybrid_kokkos.h +++ b/src/KOKKOS/bond_hybrid_kokkos.h @@ -46,7 +46,7 @@ class BondHybridKokkos : public BondHybrid { DAT::tdual_int_1d k_map; // which style each bond type points to DAT::tdual_int_1d k_nbondlist; // # of bonds in sub-style bondlists - DAT::tdual_int_3d k_bondlist; // bondlist for each sub-style + DAT::tdual_int_3d_lr k_bondlist; // bondlist for each sub-style void allocate() override; void deallocate() override; diff --git a/src/KOKKOS/dihedral_hybrid_kokkos.h b/src/KOKKOS/dihedral_hybrid_kokkos.h index 63a59505afe..e88dfe989e8 100644 --- a/src/KOKKOS/dihedral_hybrid_kokkos.h +++ b/src/KOKKOS/dihedral_hybrid_kokkos.h @@ -46,7 +46,7 @@ class DihedralHybridKokkos : public DihedralHybrid { DAT::tdual_int_1d k_map; // which style each dihedral type points to DAT::tdual_int_1d k_ndihedrallist; // # of dihedrals in sub-style dihedrallists - DAT::tdual_int_3d k_dihedrallist; // dihedrallist for each sub-style + DAT::tdual_int_3d_lr k_dihedrallist; // dihedrallist for each sub-style void allocate() override; void deallocate() override; diff --git a/src/KOKKOS/improper_hybrid_kokkos.h b/src/KOKKOS/improper_hybrid_kokkos.h index 78bafe5df69..b8bc5401665 100644 --- a/src/KOKKOS/improper_hybrid_kokkos.h +++ b/src/KOKKOS/improper_hybrid_kokkos.h @@ -46,7 +46,7 @@ class ImproperHybridKokkos : public ImproperHybrid { DAT::tdual_int_1d k_map; // which style each improper type points to DAT::tdual_int_1d k_nimproperlist; // # of impropers in sub-style improperlists - DAT::tdual_int_3d k_improperlist; // improperlist for each sub-style + DAT::tdual_int_3d_lr k_improperlist; // improperlist for each sub-style void allocate() override; void deallocate() override; From 47bc22ffab4e2385d0aafc8f405e16dec68811bf Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 12 Mar 2026 04:26:31 -0400 Subject: [PATCH 05/16] remove incorrect field type override --- src/read_dump.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/read_dump.cpp b/src/read_dump.cpp index 73de684d5d5..3aa9fef6799 100644 --- a/src/read_dump.cpp +++ b/src/read_dump.cpp @@ -1292,10 +1292,6 @@ int ReadDump::fields_and_keywords(int narg, char **arg) if (iarg+2 > narg) utils::missing_cmd_args(FLERR, "read_dump format", error); delete[] readerstyle; readerstyle = utils::strdup(arg[iarg+1]); - // adjust first field type added by default depending on format - if (strcmp(readerstyle, "xyz") == 0) fieldtype[0] = Reader::TYPE; - if (strcmp(readerstyle, "native") == 0) fieldtype[0] = Reader::ID; - if (strcmp(readerstyle, "molfile") == 0) fieldtype[0] = Reader::TYPE; iarg += 2; break; } else error->all(FLERR,"Unknown read_dump keyword: {}",arg[iarg]); From 3cf8de9cd08705164071bdaee248fae6f5b19288 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 12 Mar 2026 13:08:15 -0400 Subject: [PATCH 06/16] fix incorrect scope --- src/fix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fix.cpp b/src/fix.cpp index a7dd0a26ada..f02a656ce0e 100644 --- a/src/fix.cpp +++ b/src/fix.cpp @@ -186,7 +186,7 @@ void Fix::modify_params(int narg, char **arg) } } -void::Fix::set_molecule(int, tagint, int, double *, double *, double *) +void Fix::set_molecule(int, tagint, int, double *, double *, double *) { error->all(FLERR,"Molecule update not implemented for fix {}", style); } From 2ad9ee95f7e62d5ca0d61ab83bada6a1fe470ad9 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 14 Mar 2026 04:15:35 -0400 Subject: [PATCH 07/16] ensure that Image::value2color always returns a non-NULL pointer --- src/GRAPHICS/image.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/GRAPHICS/image.cpp b/src/GRAPHICS/image.cpp index c85ae43b114..c963254cc2d 100644 --- a/src/GRAPHICS/image.cpp +++ b/src/GRAPHICS/image.cpp @@ -2554,5 +2554,6 @@ double *ColorMap::value2color(double value) return mentry[ibin%nentry].color; } - return nullptr; + // always return a non-NULL pointer + return mentry[0].color; } From ba13e9e13ced343e8cd4497e3142ea4edd18be77 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 16 Mar 2026 07:23:11 -0400 Subject: [PATCH 08/16] make unit test compatible with C++20 and later with std::format --- unittest/formats/test_file_operations.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/unittest/formats/test_file_operations.cpp b/unittest/formats/test_file_operations.cpp index 3d6ab281fc8..3a3785b0552 100644 --- a/unittest/formats/test_file_operations.cpp +++ b/unittest/formats/test_file_operations.cpp @@ -231,9 +231,14 @@ TEST_F(FileOperationsTest, read_lines_from_file) if (me == 0) fclose(fp); } +// to detect if compiling with C++20 and using std::format instead of fmt::format +#if __has_include() +#include +#endif + TEST_F(FileOperationsTest, logmesg) { - char buf[64]; + char buf[128]; BEGIN_HIDE_OUTPUT(); command("echo none"); END_HIDE_OUTPUT(); @@ -247,12 +252,21 @@ TEST_F(FileOperationsTest, logmesg) utils::logmesg(lmp, "six {}\n"); command("log none"); std::string out = END_CAPTURE_OUTPUT(); - memset(buf, 0, 64); + memset(buf, 0, 128); FILE *fp = fopen("test_logmesg.log", "r"); - fread(buf, 1, 64, fp); + fread(buf, 1, 128, fp); fclose(fp); + +#if defined(__cpp_lib_format) && (__cpp_lib_format >= 201907L) + ASSERT_THAT( + out, + StrEq("one\ntwo\nthree=3\nformat error: invalid arg-id in format string\nfive\nsix {}\n")); + ASSERT_THAT( + buf, StrEq("two\nthree=3\nformat error: invalid arg-id in format string\nfive\nsix {}\n")); +#else ASSERT_THAT(out, StrEq("one\ntwo\nthree=3\nargument not found\nfive\nsix {}\n")); ASSERT_THAT(buf, StrEq("two\nthree=3\nargument not found\nfive\nsix {}\n")); +#endif remove("test_logmesg.log"); } From 7a8c89b163f6764f6760d443a3132f4465eec216 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 16 Mar 2026 18:42:59 -0400 Subject: [PATCH 09/16] alternate implementation of the group2ndx bugfix from PR #4915 this also fixes a related issue in the Info class. It makes the MAX_GROUP constant extractable with the library interface and allows to get rid of a redundant constant in library.cpp --- src/EXTRA-COMMAND/group2ndx.cpp | 4 +++- src/group.cpp | 7 +++---- src/group.h | 11 ++++++----- src/info.cpp | 8 +++++--- src/library.cpp | 10 ++++++---- 5 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/EXTRA-COMMAND/group2ndx.cpp b/src/EXTRA-COMMAND/group2ndx.cpp index e48b1288249..87beec24c73 100644 --- a/src/EXTRA-COMMAND/group2ndx.cpp +++ b/src/EXTRA-COMMAND/group2ndx.cpp @@ -61,7 +61,9 @@ void Group2Ndx::command(int narg, char **arg) } if (narg == 1) { // write out all groups - for (int i = 0; i < group->ngroup; ++i) { write_group(fp, i); } + for (int i = 0; i < Group::MAX_GROUP; ++i) { + if (group->names[i]) write_group(fp, i); + } } else { // write only selected groups for (int i = 1; i < narg; ++i) { int gid = group->find(arg[i]); diff --git a/src/group.cpp b/src/group.cpp index 4ee2dd79c3d..14bc5096ee2 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -39,7 +39,6 @@ using namespace LAMMPS_NS; -static constexpr int MAX_GROUP = 32; static constexpr double EPSILON = 1.0e-6; enum { NONE, TYPE, MOLECULE, ID }; @@ -152,7 +151,7 @@ void Group::assign(int narg, char **arg) bool created = false; if (igroup == -1) { - if (ngroup == MAX_GROUP) error->all(FLERR, "Too many groups (max {})", MAX_GROUP); + if (ngroup == MAX_GROUP) error->all(FLERR, "Too many groups (max {})", int(MAX_GROUP)); igroup = find_unused(); names[igroup] = utils::strdup(arg[0]); ngroup++; @@ -592,7 +591,7 @@ void Group::create(const std::string &name, int *flag) int igroup = find(name); if (igroup == -1) { - if (ngroup == MAX_GROUP) error->all(FLERR, "Too many groups (max {})", MAX_GROUP); + if (ngroup == MAX_GROUP) error->all(FLERR, "Too many groups (max {})", int(MAX_GROUP)); igroup = find_unused(); names[igroup] = utils::strdup(name); ngroup++; @@ -629,7 +628,7 @@ int Group::find_or_create(const char *name) int igroup = find(name); if (igroup >= 0) return igroup; - if (ngroup == MAX_GROUP) error->all(FLERR, "Too many groups (max {})", MAX_GROUP); + if (ngroup == MAX_GROUP) error->all(FLERR, "Too many groups (max {})", int(MAX_GROUP)); igroup = find_unused(); names[igroup] = utils::strdup(name); ngroup++; diff --git a/src/group.h b/src/group.h index 2c927a141d9..fd2c15857ad 100644 --- a/src/group.h +++ b/src/group.h @@ -23,11 +23,12 @@ class Group : protected Pointers { friend class FixGroup; public: - int ngroup; // # of defined groups - char **names; // name of each group - int *bitmask; // one-bit mask for each group - int *inversemask; // inverse mask for each group - int *dynamic; // 1 if dynamic, 0 if not + enum { MAX_GROUP = 32 }; // max # of groups. limited to 32 because bitmasks are 32-bit int. + int ngroup; // # of defined groups + char **names; // name of each group + int *bitmask; // one-bit mask for each group + int *inversemask; // inverse mask for each group + int *dynamic; // 1 if dynamic, 0 if not Group(class LAMMPS *); ~Group() override; diff --git a/src/info.cpp b/src/info.cpp index 8b83be4cd27..e5febf093d0 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -494,10 +494,12 @@ void Info::command(int narg, char **arg) char **names = group->names; int *dynamic = group->dynamic; fputs("\nGroup information:\n",out); - for (int i=0; i < ngroup; ++i) { - if (names[i]) + for (int i=0; i < Group::MAX_GROUP; ++i) { + // skip over deleted groups + if (names[i]) { utils::print(out,"Group[{:2d}]: {:16} ({})\n", - i, names[i], dynamic[i] ? "dynamic" : "static"); + i, names[i], dynamic[i] ? "dynamic" : "static"); + } } } diff --git a/src/library.cpp b/src/library.cpp index 29cc81867da..5c6962c05f0 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -71,9 +71,6 @@ /// string buffer for error messages of global errors static std::string lammps_last_global_errormessage; -/// maximum number of groups -static constexpr int LMP_MAX_GROUP = 32; - using namespace LAMMPS_NS; // for printing the non-null pointer argument warning only once @@ -1338,6 +1335,9 @@ be called without a valid LAMMPS object handle (it is ignored). * - imageint - size of the ``imageint`` integer type, 4 or 8 bytes. Set at :ref:`compile time `. + * - MAX_GROUP + - size of the bitmask for groups in bits, should be 32. + Currently hard coded. .. _extract_image_masks: @@ -1558,6 +1558,8 @@ int lammps_extract_setting(void *handle, const char *keyword) if (strcmp(keyword,"tagint") == 0) return sizeof(tagint); if (strcmp(keyword,"imageint") == 0) return sizeof(imageint); + if (strcmp(keyword,"MAX_GROUP") == 0) return Group::MAX_GROUP; + if (strcmp(keyword,"IMGMASK") == 0) return IMGMASK; if (strcmp(keyword,"IMGBITS") == 0) return IMGBITS; if (strcmp(keyword,"IMG2BITS") == 0) return IMG2BITS; @@ -7227,7 +7229,7 @@ int lammps_id_name(void *handle, const char *category, int idx, char *buffer, in } } else if (strcmp(category,"group") == 0) { // the list of groups may have "holes". So the available range is always 0 to 32 - if ((idx >= 0) && (idx < LMP_MAX_GROUP)) { + if ((idx >= 0) && (idx < Group::MAX_GROUP)) { if (lmp->group->names[idx]) { strncpy(buffer, lmp->group->names[idx], buf_size); return 1; From 3df1f13b438f57a8b6a158739791ac680f770110 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2026 10:18:08 -0400 Subject: [PATCH 10/16] relax some test epsilons for portability --- unittest/force-styles/tests/fix-timestep-deform_tri.yaml | 2 +- unittest/force-styles/tests/fix-timestep-rigid_nvt.yaml | 2 +- unittest/force-styles/tests/kspace-pppm_conp_charge.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/unittest/force-styles/tests/fix-timestep-deform_tri.yaml b/unittest/force-styles/tests/fix-timestep-deform_tri.yaml index c023c600340..7b08f571cd7 100644 --- a/unittest/force-styles/tests/fix-timestep-deform_tri.yaml +++ b/unittest/force-styles/tests/fix-timestep-deform_tri.yaml @@ -1,7 +1,7 @@ --- lammps_version: 22 Dec 2022 date_generated: Sun Jan 1 12:06:17 2023 -epsilon: 5e-13 +epsilon: 2.0e-12 skip_tests: prerequisites: ! | atom full diff --git a/unittest/force-styles/tests/fix-timestep-rigid_nvt.yaml b/unittest/force-styles/tests/fix-timestep-rigid_nvt.yaml index f15e2a3c7fa..886c8100fc9 100644 --- a/unittest/force-styles/tests/fix-timestep-rigid_nvt.yaml +++ b/unittest/force-styles/tests/fix-timestep-rigid_nvt.yaml @@ -2,7 +2,7 @@ lammps_version: 7 Feb 2024 tags: date_generated: Thu Apr 4 21:27:14 2024 -epsilon: 1e-12 +epsilon: 2e-12 skip_tests: prerequisites: ! | atom full diff --git a/unittest/force-styles/tests/kspace-pppm_conp_charge.yaml b/unittest/force-styles/tests/kspace-pppm_conp_charge.yaml index 38161ee0440..7908a69a6ea 100644 --- a/unittest/force-styles/tests/kspace-pppm_conp_charge.yaml +++ b/unittest/force-styles/tests/kspace-pppm_conp_charge.yaml @@ -1,7 +1,7 @@ --- lammps_version: 7 Feb 2024 date_generated: Mon Mar 4 09:44:31 2024 -epsilon: 3e-12 +epsilon: 5.0e-12 skip_tests: gpu kokkos_omp omp prerequisites: ! | atom full From 8b203c08201169b366cb49ff65976317952bc5a4 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2026 11:02:36 -0400 Subject: [PATCH 11/16] align dump style atom/adios initialization more closely with dump style atom --- src/ADIOS/dump_atom_adios.cpp | 39 ++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/ADIOS/dump_atom_adios.cpp b/src/ADIOS/dump_atom_adios.cpp index 7e64358adf7..ad29182eb4a 100644 --- a/src/ADIOS/dump_atom_adios.cpp +++ b/src/ADIOS/dump_atom_adios.cpp @@ -234,24 +234,29 @@ void DumpAtomADIOS::init_style() // setup column string - std::vector columnNames; - - if (scale_flag == 0 && image_flag == 0) { - columns = (char *) "id type x y z"; - columnNames = {"id", "type", "x", "y", "z"}; - } else if (scale_flag == 0 && image_flag == 1) { - columns = (char *) "id type x y z ix iy iz"; - columnNames = {"id", "type", "x", "y", "z", "ix", "iy", "iz"}; - } else if (scale_flag == 1 && image_flag == 0) { - columns = (char *) "id type xs ys zs"; - columnNames = {"id", "type", "xs", "ys", "zs"}; - } else if (scale_flag == 1 && image_flag == 1) { - columns = (char *) "id type xs ys zs ix iy iz"; - columnNames = {"id", "type", "xs", "ys", "zs", "ix", "iy", "iz"}; - } + std::string default_columns; - for (int icol = 0; icol < (int) columnNames.size(); ++icol) - if (keyword_user[icol].size()) columnNames[icol] = keyword_user[icol]; + if (scale_flag == 0 && image_flag == 0) + default_columns = "id type x y z"; + else if (scale_flag == 0 && image_flag == 1) + default_columns = "id type x y z ix iy iz"; + else if (scale_flag == 1 && image_flag == 0) + default_columns = "id type xs ys zs"; + else if (scale_flag == 1 && image_flag == 1) + default_columns = "id type xs ys zs ix iy iz"; + + std::vector columnNames = utils::split_words(default_columns); + + int icol = 0; + columns.clear(); + for (const auto &item : columnNames) { + if (columns.size()) columns += " "; + if (keyword_user[icol].size()) + columns += keyword_user[icol]; + else + columns += item; + ++icol; + } // setup function ptrs From 751080056bb731bf757bd03595efe107aa3425dc Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2026 11:03:34 -0400 Subject: [PATCH 12/16] avoid embedding multiple copies of the ADIOS default config string --- src/ADIOS/adios_common.h | 23 ++++------------------- src/ADIOS/dump_atom_adios.cpp | 22 ++++++++++++++++++++++ src/ADIOS/dump_custom_adios.cpp | 1 + src/ADIOS/reader_adios.cpp | 1 + 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/ADIOS/adios_common.h b/src/ADIOS/adios_common.h index 3345b1e0713..fcddf8faed6 100644 --- a/src/ADIOS/adios_common.h +++ b/src/ADIOS/adios_common.h @@ -16,24 +16,9 @@ #ifndef LMP_ADIOS_COMMON_H #define LMP_ADIOS_COMMON_H -// common definitions for all ADIOS package classes - -static const char default_config[] = "\n" - "\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - "\n"; +// common definition for all ADIOS package classes +namespace LAMMPS_ADIOS { +extern const char *default_config; +} #endif diff --git a/src/ADIOS/dump_atom_adios.cpp b/src/ADIOS/dump_atom_adios.cpp index ad29182eb4a..9b94c1d4420 100644 --- a/src/ADIOS/dump_atom_adios.cpp +++ b/src/ADIOS/dump_atom_adios.cpp @@ -30,6 +30,28 @@ #include "adios_common.h" using namespace LAMMPS_NS; +using namespace LAMMPS_ADIOS; + +// common definition for all ADIOS package classes + +const char *LAMMPS_ADIOS::default_config = + (const char *) "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; namespace LAMMPS_NS { class DumpAtomADIOSInternal { diff --git a/src/ADIOS/dump_custom_adios.cpp b/src/ADIOS/dump_custom_adios.cpp index 060a5493f2f..2ce7271ddaa 100644 --- a/src/ADIOS/dump_custom_adios.cpp +++ b/src/ADIOS/dump_custom_adios.cpp @@ -35,6 +35,7 @@ #include "adios_common.h" using namespace LAMMPS_NS; +using namespace LAMMPS_ADIOS; namespace LAMMPS_NS { class DumpCustomADIOSInternal { diff --git a/src/ADIOS/reader_adios.cpp b/src/ADIOS/reader_adios.cpp index e29f647233f..77336b0bc5f 100644 --- a/src/ADIOS/reader_adios.cpp +++ b/src/ADIOS/reader_adios.cpp @@ -29,6 +29,7 @@ #include "adios_common.h" using namespace LAMMPS_NS; +using namespace LAMMPS_ADIOS; static constexpr double SMALL = 1.0e-6; From 2da09c8090b636bc99bcd1dc0e0aa818138b6703 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2026 11:47:36 -0400 Subject: [PATCH 13/16] align code with dump style atom/adios --- src/ADIOS/dump_custom_adios.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ADIOS/dump_custom_adios.cpp b/src/ADIOS/dump_custom_adios.cpp index 2ce7271ddaa..11d494380cc 100644 --- a/src/ADIOS/dump_custom_adios.cpp +++ b/src/ADIOS/dump_custom_adios.cpp @@ -81,7 +81,7 @@ DumpCustomADIOS::DumpCustomADIOS(LAMMPS *lmp, int narg, char **arg) : DumpCustom } internal->columnNames.reserve(nfield); - for (int i = 0; i < nfield; ++i) { internal->columnNames.emplace_back(earg[i]); } + for (int i = 0; i < nfield; ++i) internal->columnNames.emplace_back(earg[i]); } /* ---------------------------------------------------------------------- */ @@ -89,7 +89,7 @@ DumpCustomADIOS::DumpCustomADIOS(LAMMPS *lmp, int narg, char **arg) : DumpCustom DumpCustomADIOS::~DumpCustomADIOS() { internal->columnNames.clear(); - if (internal->fh) { internal->fh.Close(); } + if (internal->fh) internal->fh.Close(); delete internal->ad; delete internal; } @@ -217,10 +217,10 @@ void DumpCustomADIOS::write() internal->fh.Put("nme", bnme); internal->fh.Put("offset", atomOffset); // now write the atoms - internal->fh.Put("atoms", buf); + internal->fh.Put(internal->varAtoms, buf); internal->fh.EndStep(); // I/O will happen now... - if (multifile) { internal->fh.Close(); } + if (multifile) internal->fh.Close(); } /* ---------------------------------------------------------------------- */ From da05f1b363f0af08b7ba2c63870e6383aba83a05 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2026 22:54:59 -0400 Subject: [PATCH 14/16] portability improvement --- unittest/formats/test_file_operations.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/unittest/formats/test_file_operations.cpp b/unittest/formats/test_file_operations.cpp index 3a3785b0552..1bbce3b7726 100644 --- a/unittest/formats/test_file_operations.cpp +++ b/unittest/formats/test_file_operations.cpp @@ -26,6 +26,8 @@ using namespace LAMMPS_NS; using testing::StrEq; +using testing::StartsWith; +using testing::EndsWith; using utils::read_lines_from_file; using utils::sfgets; @@ -257,16 +259,10 @@ TEST_F(FileOperationsTest, logmesg) fread(buf, 1, 128, fp); fclose(fp); -#if defined(__cpp_lib_format) && (__cpp_lib_format >= 201907L) - ASSERT_THAT( - out, - StrEq("one\ntwo\nthree=3\nformat error: invalid arg-id in format string\nfive\nsix {}\n")); - ASSERT_THAT( - buf, StrEq("two\nthree=3\nformat error: invalid arg-id in format string\nfive\nsix {}\n")); -#else - ASSERT_THAT(out, StrEq("one\ntwo\nthree=3\nargument not found\nfive\nsix {}\n")); - ASSERT_THAT(buf, StrEq("two\nthree=3\nargument not found\nfive\nsix {}\n")); -#endif + ASSERT_THAT(out,StartsWith("one\ntwo\nthree=3\n")); + ASSERT_THAT(out,EndsWith("\nfive\nsix {}\n")); + ASSERT_THAT(buf,StartsWith("two\nthree=3\n")); + ASSERT_THAT(buf,EndsWith("\nfive\nsix {}\n")); remove("test_logmesg.log"); } From a89e4ad9216eeaf8e3fb8b5f37e1b51195413e89 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Mar 2026 04:36:41 -0400 Subject: [PATCH 15/16] don't need this include anymore --- unittest/formats/test_file_operations.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/unittest/formats/test_file_operations.cpp b/unittest/formats/test_file_operations.cpp index 1bbce3b7726..2319cfc4d83 100644 --- a/unittest/formats/test_file_operations.cpp +++ b/unittest/formats/test_file_operations.cpp @@ -233,11 +233,6 @@ TEST_F(FileOperationsTest, read_lines_from_file) if (me == 0) fclose(fp); } -// to detect if compiling with C++20 and using std::format instead of fmt::format -#if __has_include() -#include -#endif - TEST_F(FileOperationsTest, logmesg) { char buf[128]; From 307a421b0e10e822def90a154b26f48afe800b9c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Mar 2026 11:39:15 -0400 Subject: [PATCH 16/16] floating-point precision fix for fix shake/kk from Trung --- src/KOKKOS/fix_shake_kokkos.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/KOKKOS/fix_shake_kokkos.cpp b/src/KOKKOS/fix_shake_kokkos.cpp index 1c52e47b6b1..13ee3341cc2 100644 --- a/src/KOKKOS/fix_shake_kokkos.cpp +++ b/src/KOKKOS/fix_shake_kokkos.cpp @@ -447,7 +447,7 @@ void FixShakeKokkos::operator()(TagFixShakeMinPostForce