From 3a9796d9b39f6cec89623fc5c8dbd1aa85212ca8 Mon Sep 17 00:00:00 2001 From: Donatas Surblys Date: Mon, 14 Dec 2020 19:29:18 +0900 Subject: [PATCH 001/193] add flags for centroid stress --- src/fix.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/fix.h b/src/fix.h index 69fff154dc..f4ab28874b 100644 --- a/src/fix.h +++ b/src/fix.h @@ -113,6 +113,7 @@ class Fix : protected Pointers { double virial[6]; // virial for this timestep double *eatom, **vatom; // per-atom energy/virial for this timestep + double **cvatom; // per-atom centroid virial for this timestep int centroidstressflag; // centroid stress compared to two-body stress // CENTROID_SAME = same as two-body stress @@ -249,8 +250,8 @@ class Fix : protected Pointers { int evflag; int eflag_either, eflag_global, eflag_atom; - int vflag_either, vflag_global, vflag_atom; - int maxeatom, maxvatom; + int vflag_either, vflag_global, vflag_atom, cvflag_atom; + int maxeatom, maxvatom, maxcvatom; int copymode; // if set, do not deallocate during destruction // required when classes are used as functors by Kokkos @@ -263,7 +264,7 @@ class Fix : protected Pointers { ev_setup(eflag, vflag); else evflag = eflag_either = eflag_global = eflag_atom = vflag_either = vflag_global = vflag_atom = - 0; + cvflag_atom = 0; } void ev_setup(int, int); void ev_tally(int, int *, double, double, double *); @@ -273,7 +274,7 @@ class Fix : protected Pointers { if (vflag && thermo_virial) v_setup(vflag); else - evflag = vflag_either = vflag_global = vflag_atom = 0; + evflag = vflag_either = vflag_global = vflag_atom = cvflag_atom = 0; } void v_setup(int); void v_tally(int, int *, double, double *); From abba1204a8995809fd6372c3a42f76bc13b6f160 Mon Sep 17 00:00:00 2001 From: Donatas Surblys Date: Mon, 6 Dec 2021 17:12:39 +0900 Subject: [PATCH 002/193] support for centroid stress in fixes --- src/fix.cpp | 122 +++++++++++++++++++++++++++++++++++++++++++++++++--- src/fix.h | 1 + 2 files changed, 118 insertions(+), 5 deletions(-) diff --git a/src/fix.cpp b/src/fix.cpp index 996cd9b7d5..029345e6c6 100644 --- a/src/fix.cpp +++ b/src/fix.cpp @@ -35,7 +35,8 @@ int Fix::instance_total = 0; Fix::Fix(LAMMPS *lmp, int /*narg*/, char **arg) : Pointers(lmp), id(nullptr), style(nullptr), extlist(nullptr), vector_atom(nullptr), array_atom(nullptr), - vector_local(nullptr), array_local(nullptr), eatom(nullptr), vatom(nullptr) + vector_local(nullptr), array_local(nullptr), eatom(nullptr), vatom(nullptr), + cvatom(nullptr) { instance_me = instance_total++; @@ -97,8 +98,8 @@ Fix::Fix(LAMMPS *lmp, int /*narg*/, char **arg) : // set vflag_atom = 0 b/c some fixes grow vatom in grow_arrays() // which may occur outside of timestepping - maxeatom = maxvatom = 0; - vflag_atom = 0; + maxeatom = maxvatom = maxcvatom = 0; + vflag_atom = cvflag_atom = 0; centroidstressflag = CENTROID_SAME; // KOKKOS per-fix data masks @@ -122,6 +123,7 @@ Fix::~Fix() delete [] style; memory->destroy(eatom); memory->destroy(vatom); + memory->destroy(cvatom); } /* ---------------------------------------------------------------------- @@ -197,7 +199,13 @@ void Fix::ev_setup(int eflag, int vflag) else { vflag_either = vflag; vflag_global = vflag & (VIRIAL_PAIR | VIRIAL_FDOTR); - vflag_atom = vflag & (VIRIAL_ATOM | VIRIAL_CENTROID); + if (centroidstressflag != CENTROID_AVAIL) { + vflag_atom = vflag & (VIRIAL_ATOM | VIRIAL_CENTROID); + cvflag_atom = 0; + } else { + vflag_atom = vflag & VIRIAL_ATOM; + cvflag_atom = vflag & VIRIAL_CENTROID; + } } // reallocate per-atom arrays if necessary @@ -212,6 +220,11 @@ void Fix::ev_setup(int eflag, int vflag) memory->destroy(vatom); memory->create(vatom,maxvatom,6,"fix:vatom"); } + if (cvflag_atom && atom->nlocal > maxcvatom) { + maxcvatom = atom->nmax; + memory->destroy(cvatom); + memory->create(cvatom,maxcvatom,9,"fix:cvatom"); + } // zero accumulators // no global energy variable to zero (unlike pair,bond,angle,etc) @@ -233,6 +246,20 @@ void Fix::ev_setup(int eflag, int vflag) vatom[i][5] = 0.0; } } + if (cvflag_atom) { + n = atom->nlocal; + for (i = 0; i < n; i++) { + cvatom[i][0] = 0.0; + cvatom[i][1] = 0.0; + cvatom[i][2] = 0.0; + cvatom[i][3] = 0.0; + cvatom[i][4] = 0.0; + cvatom[i][5] = 0.0; + cvatom[i][6] = 0.0; + cvatom[i][7] = 0.0; + cvatom[i][8] = 0.0; + } + } } /* ---------------------------------------------------------------------- @@ -248,7 +275,13 @@ void Fix::v_setup(int vflag) evflag = 1; vflag_global = vflag & (VIRIAL_PAIR | VIRIAL_FDOTR); - vflag_atom = vflag & (VIRIAL_ATOM | VIRIAL_CENTROID); + if (centroidstressflag != CENTROID_AVAIL) { + vflag_atom = vflag & (VIRIAL_ATOM | VIRIAL_CENTROID); + cvflag_atom = 0; + } else { + vflag_atom = vflag & VIRIAL_ATOM; + cvflag_atom = vflag & VIRIAL_CENTROID; + } // reallocate per-atom array if necessary @@ -257,6 +290,11 @@ void Fix::v_setup(int vflag) memory->destroy(vatom); memory->create(vatom,maxvatom,6,"fix:vatom"); } + if (cvflag_atom && atom->nlocal > maxcvatom) { + maxcvatom = atom->nmax; + memory->destroy(cvatom); + memory->create(cvatom,maxcvatom,9,"fix:cvatom"); + } // zero accumulators @@ -272,6 +310,20 @@ void Fix::v_setup(int vflag) vatom[i][5] = 0.0; } } + if (cvflag_atom) { + n = atom->nlocal; + for (i = 0; i < n; i++) { + cvatom[i][0] = 0.0; + cvatom[i][1] = 0.0; + cvatom[i][2] = 0.0; + cvatom[i][3] = 0.0; + cvatom[i][4] = 0.0; + cvatom[i][5] = 0.0; + cvatom[i][6] = 0.0; + cvatom[i][7] = 0.0; + cvatom[i][8] = 0.0; + } + } } /* ---------------------------------------------------------------------- @@ -338,6 +390,66 @@ void Fix::v_tally(int n, int *list, double total, double *v) } } +/* ---------------------------------------------------------------------- + tally virial into global and per-atom accumulators + n = # of local owned atoms involved, with local indices in list + vtot = total virial for the interaction involving total atoms + npair = # of atom pairs with forces beween them + pairlist = indice list of pairs + fpairlist = forces between pairs + dellist = displacement vectors between pairs + increment global virial by n/total fraction + increment per-atom virial of each atom in list by 1/total fraction + add centroid form atomic virial contribution for each atom if available + this method can be used when fix computes forces in post_force() + e.g. fix shake, fix rigid: compute virial only on owned atoms + whether newton_bond is on or off + other procs will tally left-over fractions for atoms they own +------------------------------------------------------------------------- */ + +void Fix::v_tally(int n, int *list, double total, double *vtot, int nlocal, + int npair, int pairlist[][2], double *fpairlist, double dellist[][3]) +{ + + v_tally(n, list, total, vtot); + + if (cvflag_atom) { + double v[6]; + for (int i = 0; i < npair; i++) { + v[0] = 0.5*dellist[i][0]*dellist[i][0]*fpairlist[i]; + v[1] = 0.5*dellist[i][1]*dellist[i][1]*fpairlist[i]; + v[2] = 0.5*dellist[i][2]*dellist[i][2]*fpairlist[i]; + v[3] = 0.5*dellist[i][0]*dellist[i][1]*fpairlist[i]; + v[4] = 0.5*dellist[i][0]*dellist[i][2]*fpairlist[i]; + v[5] = 0.5*dellist[i][1]*dellist[i][2]*fpairlist[i]; + const int i0 = pairlist[i][0]; + const int i1 = pairlist[i][1]; + if (i0 < nlocal) { + cvatom[i0][0] += v[0]; + cvatom[i0][1] += v[1]; + cvatom[i0][2] += v[2]; + cvatom[i0][3] += v[3]; + cvatom[i0][4] += v[4]; + cvatom[i0][5] += v[5]; + cvatom[i0][6] += v[3]; + cvatom[i0][7] += v[4]; + cvatom[i0][8] += v[5]; + } + if (i1 < nlocal) { + cvatom[i1][0] += v[0]; + cvatom[i1][1] += v[1]; + cvatom[i1][2] += v[2]; + cvatom[i1][3] += v[3]; + cvatom[i1][4] += v[4]; + cvatom[i1][5] += v[5]; + cvatom[i1][6] += v[3]; + cvatom[i1][7] += v[4]; + cvatom[i1][8] += v[5]; + } + } + } +} + /* ---------------------------------------------------------------------- tally virial into global and per-atom accumulators i = local index of atom diff --git a/src/fix.h b/src/fix.h index f4ab28874b..1cce08f33f 100644 --- a/src/fix.h +++ b/src/fix.h @@ -278,6 +278,7 @@ class Fix : protected Pointers { } void v_setup(int); void v_tally(int, int *, double, double *); + void v_tally(int,int*,double,double*,int,int,int[][2],double*,double[][3]); void v_tally(int, double *); void v_tally(int, int, double); }; From 8520a7164617b8fd92dcf0e79d4a003e00b9fa9c Mon Sep 17 00:00:00 2001 From: Donatas Surblys Date: Mon, 14 Dec 2020 19:31:38 +0900 Subject: [PATCH 003/193] centroid stress support in shake (and rattle) --- src/RIGID/fix_shake.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/RIGID/fix_shake.cpp b/src/RIGID/fix_shake.cpp index 29739b294c..0904312a75 100644 --- a/src/RIGID/fix_shake.cpp +++ b/src/RIGID/fix_shake.cpp @@ -66,6 +66,7 @@ FixShake::FixShake(LAMMPS *lmp, int narg, char **arg) : create_attribute = 1; dof_flag = 1; stores_ids = 1; + centroidstressflag = CENTROID_AVAIL; // error check @@ -1764,7 +1765,10 @@ void FixShake::shake(int m) v[4] = lamda*r01[0]*r01[2]; v[5] = lamda*r01[1]*r01[2]; - v_tally(nlist,list,2.0,v); + double fpairlist[] = {lamda}; + double dellist[][3] = {{r01[0], r01[1], r01[2]}}; + int pairlist[][2] = {{i0,i1}}; + v_tally(nlist,list,2.0,v,nlocal,1,pairlist,fpairlist,dellist); } } @@ -1937,7 +1941,11 @@ void FixShake::shake3(int m) v[4] = lamda01*r01[0]*r01[2] + lamda02*r02[0]*r02[2]; v[5] = lamda01*r01[1]*r01[2] + lamda02*r02[1]*r02[2]; - v_tally(nlist,list,3.0,v); + double fpairlist[] = {lamda01, lamda02}; + double dellist[][3] = {{r01[0], r01[1], r01[2]}, + {r02[0], r02[1], r02[2]}}; + int pairlist[][2] = {{i0,i1}, {i0,i2}}; + v_tally(nlist,list,3.0,v,nlocal,2,pairlist,fpairlist,dellist); } } @@ -2189,7 +2197,12 @@ void FixShake::shake4(int m) v[4] = lamda01*r01[0]*r01[2]+lamda02*r02[0]*r02[2]+lamda03*r03[0]*r03[2]; v[5] = lamda01*r01[1]*r01[2]+lamda02*r02[1]*r02[2]+lamda03*r03[1]*r03[2]; - v_tally(nlist,list,4.0,v); + double fpairlist[] = {lamda01, lamda02, lamda03}; + double dellist[][3] = {{r01[0], r01[1], r01[2]}, + {r02[0], r02[1], r02[2]}, + {r03[0], r03[1], r03[2]}}; + int pairlist[][2] = {{i0,i1}, {i0,i2}, {i0,i3}}; + v_tally(nlist,list,4.0,v,nlocal,3,pairlist,fpairlist,dellist); } } @@ -2432,7 +2445,12 @@ void FixShake::shake3angle(int m) v[4] = lamda01*r01[0]*r01[2]+lamda02*r02[0]*r02[2]+lamda12*r12[0]*r12[2]; v[5] = lamda01*r01[1]*r01[2]+lamda02*r02[1]*r02[2]+lamda12*r12[1]*r12[2]; - v_tally(nlist,list,3.0,v); + double fpairlist[] = {lamda01, lamda02, lamda12}; + double dellist[][3] = {{r01[0], r01[1], r01[2]}, + {r02[0], r02[1], r02[2]}, + {r12[0], r12[1], r12[2]}}; + int pairlist[][2] = {{i0,i1}, {i0,i2}, {i1,i2}}; + v_tally(nlist,list,3.0,v,nlocal,3,pairlist,fpairlist,dellist); } } From 3ff8d8bf414d57ec7f1235c338cc8a0ef392abea Mon Sep 17 00:00:00 2001 From: Donatas Surblys Date: Mon, 14 Dec 2020 19:41:34 +0900 Subject: [PATCH 004/193] update centroid/stress/atom compute to correctly handle fixes with CENTROID_AVAIL --- src/compute_centroid_stress_atom.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/compute_centroid_stress_atom.cpp b/src/compute_centroid_stress_atom.cpp index a050c8bb6a..66dd11ac43 100644 --- a/src/compute_centroid_stress_atom.cpp +++ b/src/compute_centroid_stress_atom.cpp @@ -268,19 +268,26 @@ void ComputeCentroidStressAtom::compute_peratom() // possible during setup phase if fix has not initialized its vatom yet // e.g. fix ave/spatial defined before fix shake, // and fix ave/spatial uses a per-atom stress from this compute as input - // fix styles are CENTROID_SAME or CENTROID_NOTAVAIL + // fix styles are CENTROID_SAME, CENTROID_AVAIL or CENTROID_NOTAVAIL if (fixflag) { Fix **fix = modify->fix; int nfix = modify->nfix; for (int ifix = 0; ifix < nfix; ifix++) if (fix[ifix]->virial_peratom_flag && fix[ifix]->thermo_virial) { - double **vatom = fix[ifix]->vatom; - if (vatom) - for (i = 0; i < nlocal; i++) { - for (j = 0; j < 6; j++) stress[i][j] += vatom[i][j]; - for (j = 6; j < 9; j++) stress[i][j] += vatom[i][j - 3]; - } + if (modify->fix[ifix]->centroidstressflag == CENTROID_AVAIL) { + double **cvatom = modify->fix[ifix]->cvatom; + if (cvatom) + for (i = 0; i < nlocal; i++) + for (j = 0; j < 9; j++) stress[i][j] += cvatom[i][j]; + } else { + double **vatom = modify->fix[ifix]->vatom; + if (vatom) + for (i = 0; i < nlocal; i++) { + for (j = 0; j < 6; j++) stress[i][j] += vatom[i][j]; + for (j = 6; j < 9; j++) stress[i][j] += vatom[i][j - 3]; + } + } } } From ac7c5592d76d104b1656216da34f4a9278bd1109 Mon Sep 17 00:00:00 2001 From: Donatas Surblys Date: Mon, 6 Dec 2021 17:45:49 +0900 Subject: [PATCH 005/193] add centroid virial tally function in preparation for rigid/small support --- src/fix.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/fix.h | 1 + 2 files changed, 45 insertions(+) diff --git a/src/fix.cpp b/src/fix.cpp index 029345e6c6..83e0650483 100644 --- a/src/fix.cpp +++ b/src/fix.cpp @@ -390,6 +390,50 @@ void Fix::v_tally(int n, int *list, double total, double *v) } } +/* ---------------------------------------------------------------------- + tally virial into global and per-atom accumulators + n = # of local owned atoms involved, with local indices in list + vtot = total virial for the interaction involving total atoms + rlist = list of positional vectors + flist = list of force vectors + center = centroid coordinate + increment global virial by n/total fraction + increment per-atom virial of each atom in list by 1/total fraction + add centroid form atomic virial contribution for each atom if available + this method can be used when fix computes forces in post_force() + and only total forces on each atom in group are easily available + e.g. fix rigid/small: compute virial only on owned atoms + whether newton_bond is on or off + other procs will tally left-over fractions for atoms they own +------------------------------------------------------------------------- */ + +void Fix::v_tally(int n, int *list, double total, double *vtot, + double rlist[][3], double flist[][3], double center[]) +{ + + v_tally(n, list, total, vtot); + + if (cvflag_atom) { + for (int i = 0; i< n; i++) { + const double ri0[3] = { + rlist[i][0]-center[0], + rlist[i][1]-center[1], + rlist[i][2]-center[2], + }; + cvatom[list[i]][0] += ri0[0]*flist[i][0]; + cvatom[list[i]][1] += ri0[1]*flist[i][1]; + cvatom[list[i]][2] += ri0[2]*flist[i][2]; + cvatom[list[i]][3] += ri0[0]*flist[i][1]; + cvatom[list[i]][4] += ri0[0]*flist[i][2]; + cvatom[list[i]][5] += ri0[1]*flist[i][2]; + cvatom[list[i]][6] += ri0[1]*flist[i][0]; + cvatom[list[i]][7] += ri0[2]*flist[i][0]; + cvatom[list[i]][8] += ri0[2]*flist[i][1]; + } + } + +} + /* ---------------------------------------------------------------------- tally virial into global and per-atom accumulators n = # of local owned atoms involved, with local indices in list diff --git a/src/fix.h b/src/fix.h index 1cce08f33f..339da03734 100644 --- a/src/fix.h +++ b/src/fix.h @@ -279,6 +279,7 @@ class Fix : protected Pointers { void v_setup(int); void v_tally(int, int *, double, double *); void v_tally(int,int*,double,double*,int,int,int[][2],double*,double[][3]); + void v_tally(int,int*,double,double*,double[][3],double[][3],double[]); void v_tally(int, double *); void v_tally(int, int, double); }; From b904d256cdf1d66f869f844b8f3154944c7a650c Mon Sep 17 00:00:00 2001 From: Donatas Surblys Date: Tue, 20 Apr 2021 14:06:53 +0900 Subject: [PATCH 006/193] implement keeping track of geometric center in rigid/small --- src/RIGID/fix_rigid_small.cpp | 76 +++++++++++++++++++++++++++++++---- src/RIGID/fix_rigid_small.h | 3 ++ 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/src/RIGID/fix_rigid_small.cpp b/src/RIGID/fix_rigid_small.cpp index 5db24a96d5..db283c6242 100644 --- a/src/RIGID/fix_rigid_small.cpp +++ b/src/RIGID/fix_rigid_small.cpp @@ -785,7 +785,7 @@ void FixRigidSmall::initial_integrate(int vflag) // forward communicate updated info of all bodies commflag = INITIAL; - comm->forward_comm_fix(this,26); + comm->forward_comm_fix(this,29); // set coords/orient and velocity/rotation of atoms in rigid bodies @@ -879,6 +879,7 @@ void FixRigidSmall::enforce2d() 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; @@ -1353,6 +1354,16 @@ 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, + b->xgc_body,b->xgc); + b->xgc[0] += b->xcm[0]; + b->xgc[1] += b->xcm[1]; + b->xgc[2] += b->xcm[2]; + } + // set orientation, omega, angmom of each extended particle if (extended) { @@ -1905,11 +1916,15 @@ void FixRigidSmall::setup_bodies_static() double **x = atom->x; double *xcm; + double *xgc; for (ibody = 0; ibody < nlocal_body+nghost_body; ibody++) { xcm = body[ibody].xcm; + xgc = body[ibody].xgc; xcm[0] = xcm[1] = xcm[2] = 0.0; + xgc[0] = xgc[1] = xgc[2] = 0.0; body[ibody].mass = 0.0; + body[ibody].natoms = 0; } double unwrap[3]; @@ -1924,22 +1939,31 @@ void FixRigidSmall::setup_bodies_static() domain->unmap(x[i],xcmimage[i],unwrap); xcm = b->xcm; + xgc = b->xgc; xcm[0] += unwrap[0] * massone; xcm[1] += unwrap[1] * massone; xcm[2] += unwrap[2] * massone; + xgc[0] += unwrap[0]; + xgc[1] += unwrap[1]; + xgc[2] += unwrap[2]; b->mass += massone; + b->natoms++; } // reverse communicate xcm, mass of all bodies commflag = XCM_MASS; - comm->reverse_comm_fix(this,4); + comm->reverse_comm_fix(this,8); for (ibody = 0; ibody < nlocal_body; ibody++) { xcm = body[ibody].xcm; + xgc = body[ibody].xgc; xcm[0] /= body[ibody].mass; xcm[1] /= body[ibody].mass; xcm[2] /= body[ibody].mass; + xgc[0] /= body[ibody].natoms; + xgc[1] /= body[ibody].natoms; + xgc[2] /= body[ibody].natoms; } // set vcm, angmom = 0.0 in case inpfile is used @@ -2124,12 +2148,22 @@ void FixRigidSmall::setup_bodies_static() // create initial quaternion MathExtra::exyz_to_q(ex,ey,ez,body[ibody].quat); + + // convert geometric center position to principal axis coordinates + // xcm is wrapped, but xgc is not initially + xcm = body[ibody].xcm; + xgc = body[ibody].xgc; + double delta[3]; + MathExtra::sub3(xgc,xcm,delta); + domain->minimum_image(delta); + MathExtra::transpose_matvec(ex,ey,ez,delta,body[ibody].xgc_body); + MathExtra::add3(xcm,delta,xgc); } // forward communicate updated info of all bodies commflag = INITIAL; - comm->forward_comm_fix(this,26); + comm->forward_comm_fix(this,29); // displace = initial atom coords in basis of principal axes // set displace = 0.0 for atoms not in any rigid body @@ -2807,6 +2841,10 @@ void FixRigidSmall::set_molecule(int nlocalprev, tagint tagprev, int imol, if (nlocal_body == nmax_body) grow_body(); Body *b = &body[nlocal_body]; b->mass = onemols[imol]->masstotal; + b->natoms = onemols[imol]->natoms; + b->xgc[0] = xgeom[0]; + b->xgc[1] = xgeom[1]; + b->xgc[2] = xgeom[2]; // new COM = Q (onemols[imol]->xcm - onemols[imol]->center) + xgeom // Q = rotation matrix associated with quat @@ -2829,6 +2867,12 @@ void FixRigidSmall::set_molecule(int nlocalprev, tagint tagprev, int imol, MathExtra::quatquat(quat,onemols[imol]->quat,b->quat); MathExtra::q_to_exyz(b->quat,b->ex_space,b->ey_space,b->ez_space); + MathExtra::transpose_matvec(b->ex_space,b->ey_space,b->ez_space, + ctr2com_rotate,b->xgc_body); + b->xgc_body[0] *= -1; + b->xgc_body[1] *= -1; + b->xgc_body[2] *= -1; + b->angmom[0] = b->angmom[1] = b->angmom[2] = 0.0; b->omega[0] = b->omega[1] = b->omega[2] = 0.0; b->conjqm[0] = b->conjqm[1] = b->conjqm[2] = b->conjqm[3] = 0.0; @@ -2961,7 +3005,7 @@ int FixRigidSmall::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { int i,j; - double *xcm,*vcm,*quat,*omega,*ex_space,*ey_space,*ez_space,*conjqm; + double *xcm,*xgc,*vcm,*quat,*omega,*ex_space,*ey_space,*ez_space,*conjqm; int m = 0; @@ -2973,6 +3017,10 @@ int FixRigidSmall::pack_forward_comm(int n, int *list, double *buf, buf[m++] = xcm[0]; buf[m++] = xcm[1]; buf[m++] = xcm[2]; + xgc = body[bodyown[j]].xgc; + buf[m++] = xgc[0]; + buf[m++] = xgc[1]; + buf[m++] = xgc[2]; vcm = body[bodyown[j]].vcm; buf[m++] = vcm[0]; buf[m++] = vcm[1]; @@ -3048,7 +3096,7 @@ int FixRigidSmall::pack_forward_comm(int n, int *list, double *buf, void FixRigidSmall::unpack_forward_comm(int n, int first, double *buf) { int i,j,last; - double *xcm,*vcm,*quat,*omega,*ex_space,*ey_space,*ez_space,*conjqm; + double *xcm,*xgc,*vcm,*quat,*omega,*ex_space,*ey_space,*ez_space,*conjqm; int m = 0; last = first + n; @@ -3060,6 +3108,10 @@ void FixRigidSmall::unpack_forward_comm(int n, int first, double *buf) xcm[0] = buf[m++]; xcm[1] = buf[m++]; xcm[2] = buf[m++]; + xgc = body[bodyown[i]].xgc; + xgc[0] = buf[m++]; + xgc[1] = buf[m++]; + xgc[2] = buf[m++]; vcm = body[bodyown[i]].vcm; vcm[0] = buf[m++]; vcm[1] = buf[m++]; @@ -3135,7 +3187,7 @@ void FixRigidSmall::unpack_forward_comm(int n, int first, double *buf) int FixRigidSmall::pack_reverse_comm(int n, int first, double *buf) { int i,j,m,last; - double *fcm,*torque,*vcm,*angmom,*xcm; + double *fcm,*torque,*vcm,*angmom,*xcm, *xgc; m = 0; last = first + n; @@ -3170,10 +3222,15 @@ int FixRigidSmall::pack_reverse_comm(int n, int first, double *buf) for (i = first; i < last; i++) { if (bodyown[i] < 0) continue; xcm = body[bodyown[i]].xcm; + xgc = body[bodyown[i]].xgc; buf[m++] = xcm[0]; buf[m++] = xcm[1]; buf[m++] = xcm[2]; + buf[m++] = xgc[0]; + buf[m++] = xgc[1]; + buf[m++] = xgc[2]; buf[m++] = body[bodyown[i]].mass; + buf[m++] = static_cast(body[bodyown[i]].natoms); } } else if (commflag == ITENSOR) { @@ -3208,7 +3265,7 @@ int FixRigidSmall::pack_reverse_comm(int n, int first, double *buf) void FixRigidSmall::unpack_reverse_comm(int n, int *list, double *buf) { int i,j,k; - double *fcm,*torque,*vcm,*angmom,*xcm; + double *fcm,*torque,*vcm,*angmom,*xcm, *xgc; int m = 0; @@ -3245,10 +3302,15 @@ void FixRigidSmall::unpack_reverse_comm(int n, int *list, double *buf) j = list[i]; if (bodyown[j] < 0) continue; xcm = body[bodyown[j]].xcm; + xgc = body[bodyown[j]].xgc; xcm[0] += buf[m++]; xcm[1] += buf[m++]; xcm[2] += buf[m++]; + xgc[0] += buf[m++]; + xgc[1] += buf[m++]; + xgc[2] += buf[m++]; body[bodyown[j]].mass += buf[m++]; + body[bodyown[j]].natoms += static_cast(buf[m++]); } } else if (commflag == ITENSOR) { diff --git a/src/RIGID/fix_rigid_small.h b/src/RIGID/fix_rigid_small.h index 60a4dd1161..e289c179d9 100644 --- a/src/RIGID/fix_rigid_small.h +++ b/src/RIGID/fix_rigid_small.h @@ -85,7 +85,9 @@ class FixRigidSmall : public Fix { struct Body { double mass; // total mass of body + int natoms; // total number of atoms in body double xcm[3]; // COM position + double xgc[3]; // geometric center position double vcm[3]; // COM velocity double fcm[3]; // force on COM double torque[3]; // torque around COM @@ -94,6 +96,7 @@ class FixRigidSmall : public Fix { double ex_space[3]; // principal axes in space coords double ey_space[3]; double ez_space[3]; + double xgc_body[3]; // geometric center relative to xcm in body coords double angmom[3]; // space-frame angular momentum of body double omega[3]; // space-frame omega of body double conjqm[4]; // conjugate quaternion momentum From 0fc73c9d676728ff7226877cd2ee4f6621d731e2 Mon Sep 17 00:00:00 2001 From: Donatas Surblys Date: Mon, 19 Apr 2021 16:18:06 +0900 Subject: [PATCH 007/193] support for centroid virial stress in rigid/small --- src/RIGID/fix_rigid_small.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/RIGID/fix_rigid_small.cpp b/src/RIGID/fix_rigid_small.cpp index db283c6242..14742155db 100644 --- a/src/RIGID/fix_rigid_small.cpp +++ b/src/RIGID/fix_rigid_small.cpp @@ -73,6 +73,7 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : dof_flag = 1; enforce2d_flag = 1; stores_ids = 1; + centroidstressflag = CENTROID_AVAIL; MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); @@ -1350,7 +1351,9 @@ void FixRigidSmall::set_xv() vr[4] = 0.5*x0*fc2; vr[5] = 0.5*x1*fc2; - v_tally(1,&i,1.0,vr); + double rlist[][3] = {x0, x1, x2}; + double flist[][3] = {0.5*fc0, 0.5*fc1, 0.5*fc2}; + v_tally(1,&i,1.0,vr,rlist,flist,b->xgc); } } @@ -1510,7 +1513,9 @@ void FixRigidSmall::set_v() vr[4] = 0.5*x0*fc2; vr[5] = 0.5*x1*fc2; - v_tally(1,&i,1.0,vr); + double rlist[][3] = {x0, x1, x2}; + double flist[][3] = {0.5*fc0, 0.5*fc1, 0.5*fc2}; + v_tally(1,&i,1.0,vr,rlist,flist,b->xgc); } } From fa412c13aa3de31b8af8e6e2ac473f90dd515e21 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Fri, 15 Oct 2021 15:43:26 -0600 Subject: [PATCH 008/193] Add compute phase/atom --- src/KOKKOS/Install.sh | 2 + src/KOKKOS/compute_phase_atom_kokkos.cpp | 210 +++++++++++++++++++ src/KOKKOS/compute_phase_atom_kokkos.h | 73 +++++++ src/compute_phase_atom.cpp | 246 +++++++++++++++++++++++ src/compute_phase_atom.h | 88 ++++++++ 5 files changed, 619 insertions(+) create mode 100644 src/KOKKOS/compute_phase_atom_kokkos.cpp create mode 100644 src/KOKKOS/compute_phase_atom_kokkos.h create mode 100644 src/compute_phase_atom.cpp create mode 100644 src/compute_phase_atom.h diff --git a/src/KOKKOS/Install.sh b/src/KOKKOS/Install.sh index 04bf84ed31..ac5efec076 100755 --- a/src/KOKKOS/Install.sh +++ b/src/KOKKOS/Install.sh @@ -92,6 +92,8 @@ action compute_coord_atom_kokkos.cpp action compute_coord_atom_kokkos.h action compute_orientorder_atom_kokkos.cpp action compute_orientorder_atom_kokkos.h +action compute_phase_atom_kokkos.cpp +action compute_phase_atom_kokkos.h action compute_temp_kokkos.cpp action compute_temp_kokkos.h action compute_temp_deform_kokkos.cpp diff --git a/src/KOKKOS/compute_phase_atom_kokkos.cpp b/src/KOKKOS/compute_phase_atom_kokkos.cpp new file mode 100644 index 0000000000..0b30c5d6fd --- /dev/null +++ b/src/KOKKOS/compute_phase_atom_kokkos.cpp @@ -0,0 +1,210 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://lammps.sandia.gov/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#include "compute_phase_atom_kokkos.h" + +#include "atom_kokkos.h" +#include "atom_masks.h" +#include "comm.h" +#include "error.h" +#include "force.h" +#include "memory_kokkos.h" +#include "modify.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "neighbor_kokkos.h" +#include "pair.h" +#include "update.h" +#include "math_const.h" + +#include +#include + +using namespace LAMMPS_NS; +using namespace MathConst; + + +/* ---------------------------------------------------------------------- */ + +template +ComputePhaseAtomKokkos::ComputePhaseAtomKokkos(LAMMPS *lmp, int narg, char **arg) : + ComputePhaseAtom(lmp, narg, arg) +{ + kokkosable = 1; + atomKK = (AtomKokkos *) atom; + execution_space = ExecutionSpaceFromDevice::space; + datamask_read = EMPTY_MASK; + datamask_modify = EMPTY_MASK; +} + +/* ---------------------------------------------------------------------- */ + +template +ComputePhaseAtomKokkos::~ComputePhaseAtomKokkos() +{ + if (copymode) return; + + memoryKK->destroy_kokkos(k_phase,phase); +} + +/* ---------------------------------------------------------------------- */ + +template +void ComputePhaseAtomKokkos::init() +{ + ComputePhaseAtom::init(); + + // need an occasional full neighbor list + + // irequest = neigh request made by parent class + + int irequest = neighbor->nrequest - 1; + + neighbor->requests[irequest]-> + kokkos_host = std::is_same::value && + !std::is_same::value; + neighbor->requests[irequest]-> + kokkos_device = std::is_same::value; +} + +/* ---------------------------------------------------------------------- */ + +template +void ComputePhaseAtomKokkos::compute_peratom() +{ + invoked_peratom = update->ntimestep; + + // grow phase array if necessary + + if (atom->nmax > nmax) { + memoryKK->destroy_kokkos(k_phase,phase); + nmax = atom->nmax; + memoryKK->create_kokkos(k_phase,phase,nmax,2,"phase/atom:phase"); + d_phase = k_phase.view(); + array_atom = phase; + } + + // need velocities of ghost atoms + + atomKK->sync(Host,V_MASK); + comm->forward_comm_compute(this); + atomKK->modified(Host,V_MASK); + + // invoke full neighbor list (will copy or build if necessary) + + neighbor->build_one(list); + int inum = list->inum; + + NeighListKokkos* k_list = static_cast*>(list); + d_numneigh = k_list->d_numneigh; + d_neighbors = k_list->d_neighbors; + d_ilist = k_list->d_ilist; + + // compute phase for each atom in group + // use full neighbor list to count atoms less than cutoff + + atomKK->sync(execution_space,X_MASK|V_MASK|TYPE_MASK|MASK_MASK); + x = atomKK->k_x.view(); + v = atomKK->k_v.view(); + type = atomKK->k_type.view(); + mask = atomKK->k_mask.view(); + + Kokkos::deep_copy(d_phase,0.0); + + copymode = 1; + typename Kokkos::RangePolicy policy(0,inum); + Kokkos::parallel_for("ComputePhaseAtom",policy,*this); + copymode = 0; + + k_phase.modify(); + k_phase.sync_host(); +} + +template +KOKKOS_INLINE_FUNCTION +void ComputePhaseAtomKokkos::operator()(TagComputePhaseAtom, const int &ii) const +{ + const int i = d_ilist[ii]; + if (mask[i] & groupbit) { + const X_FLOAT xtmp = x(i,0); + const X_FLOAT ytmp = x(i,1); + const X_FLOAT ztmp = x(i,2); + const int jnum = d_numneigh[i]; + + // i atom contribution + + int count = 1; + double vsum[3]; + vsum[0] = v(i,0); + vsum[1] = v(i,1); + vsum[2] = v(i,2); + + for (int jj = 0; jj < jnum; jj++) { + int j = d_neighbors(i,jj); + j &= NEIGHMASK; + + const F_FLOAT delx = x(j,0) - xtmp; + const F_FLOAT dely = x(j,1) - ytmp; + const F_FLOAT delz = x(j,2) - ztmp; + const F_FLOAT rsq = delx*delx + dely*dely + delz*delz; + if (rsq < cutsq) { + count++; + vsum[0] += v(j,0); + vsum[1] += v(j,1); + vsum[2] += v(j,2); + } + } + + double vavg[3]; + vavg[0] = vsum[0]/count; + vavg[1] = vsum[1]/count; + vavg[2] = vsum[2]/count; + + // i atom contribution + + count = 1; + double vnet[3]; + vnet[0] = v(i,0) - vavg[0]; + vnet[1] = v(i,1) - vavg[1]; + vnet[2] = v(i,2) - vavg[2]; + double ke_sum = vnet[0]*vnet[0] + vnet[1]*vnet[1] + vnet[2]*vnet[2]; + + for (int jj = 0; jj < jnum; jj++) { + int j = d_neighbors(i,jj); + j &= NEIGHMASK; + + const F_FLOAT delx = x(j,0) - xtmp; + const F_FLOAT dely = x(j,1) - ytmp; + const F_FLOAT delz = x(j,2) - ztmp; + const F_FLOAT rsq = delx*delx + dely*dely + delz*delz; + if (rsq < cutsq) { + count++; + vnet[0] = v(j,0) - vavg[0]; + vnet[1] = v(j,1) - vavg[1]; + vnet[2] = v(j,2) - vavg[2]; + ke_sum += vnet[0]*vnet[0] + vnet[1]*vnet[1] + vnet[2]*vnet[2]; + } + } + double density = count/sphere_vol; + double temp = ke_sum/3.0/count; + d_phase(i,0) = density; + d_phase(i,1) = temp; + } +} + +namespace LAMMPS_NS { +template class ComputePhaseAtomKokkos; +#ifdef LMP_KOKKOS_GPU +template class ComputePhaseAtomKokkos; +#endif +} diff --git a/src/KOKKOS/compute_phase_atom_kokkos.h b/src/KOKKOS/compute_phase_atom_kokkos.h new file mode 100644 index 0000000000..8cfa35d2c8 --- /dev/null +++ b/src/KOKKOS/compute_phase_atom_kokkos.h @@ -0,0 +1,73 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://lammps.sandia.gov/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(phase/atom/kk,ComputePhaseAtomKokkos) +ComputeStyle(phase/atom/kk/device,ComputePhaseAtomKokkos) +ComputeStyle(phase/atom/kk/host,ComputePhaseAtomKokkos) + +#else + +#ifndef LMP_COMPUTE_PHASE_KOKKOS_ATOM_H +#define LMP_COMPUTE_PHASE_KOKKOS_ATOM_H + +#include "compute_phase_atom.h" +#include "kokkos_type.h" + +namespace LAMMPS_NS { + +struct TagComputePhaseAtom{}; + +template +class ComputePhaseAtomKokkos : public ComputePhaseAtom { + public: + typedef DeviceType device_type; + typedef ArrayTypes AT; + + ComputePhaseAtomKokkos(class LAMMPS *, int, char **); + virtual ~ComputePhaseAtomKokkos(); + void init(); + void compute_peratom(); + + KOKKOS_INLINE_FUNCTION + void operator()(TagComputePhaseAtom, const int&) const; + + private: + typename AT::t_x_array_randomread x; + typename AT::t_v_array_randomread v; + typename ArrayTypes::t_int_1d_randomread type; + typename ArrayTypes::t_int_1d mask; + + typename AT::t_neighbors_2d d_neighbors; + typename AT::t_int_1d_randomread d_ilist; + typename AT::t_int_1d_randomread d_numneigh; + + DAT::tdual_float_2d k_phase; + typename AT::t_float_2d d_phase; +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +*/ diff --git a/src/compute_phase_atom.cpp b/src/compute_phase_atom.cpp new file mode 100644 index 0000000000..0f166b2be2 --- /dev/null +++ b/src/compute_phase_atom.cpp @@ -0,0 +1,246 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://lammps.sandia.gov/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#include "compute_phase_atom.h" + +#include "atom.h" +#include "comm.h" +#include "error.h" +#include "force.h" +#include "group.h" +#include "memory.h" +#include "modify.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "neighbor.h" +#include "pair.h" +#include "update.h" +#include "math_const.h" + +#include +#include + +using namespace LAMMPS_NS; +using namespace MathConst; + + +/* ---------------------------------------------------------------------- */ + +ComputePhaseAtom::ComputePhaseAtom(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg), + phase(nullptr) +{ + if (narg != 4) error->all(FLERR,"Illegal compute phase/atom command"); + + cutoff = utils::numeric(FLERR,arg[3],false,lmp); + cutsq = cutoff*cutoff; + sphere_vol = 4.0/3.0*MY_PI*cutsq*cutoff; + + peratom_flag = 1; + size_peratom_cols = 2; + + comm_forward = 3; + + nmax = 0; +} + +/* ---------------------------------------------------------------------- */ + +ComputePhaseAtom::~ComputePhaseAtom() +{ + if (copymode) return; + + memory->destroy(phase); +} + +/* ---------------------------------------------------------------------- */ + +void ComputePhaseAtom::init() +{ + int cutflag = 1; + if (force->pair && sqrt(cutsq) <= force->pair->cutforce) + cutflag = 0; + + // need an occasional full neighbor list + + int irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->pair = 0; + neighbor->requests[irequest]->compute = 1; + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->full = 1; + neighbor->requests[irequest]->occasional = 1; + if (cutflag) { + neighbor->requests[irequest]->cut = 1; + neighbor->requests[irequest]->cutoff = cutoff; + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputePhaseAtom::init_list(int /*id*/, NeighList *ptr) +{ + list = ptr; +} + +/* ---------------------------------------------------------------------- */ + +void ComputePhaseAtom::compute_peratom() +{ + int i,j,ii,jj,inum,jnum; + double xtmp,ytmp,ztmp,delx,dely,delz,rsq; + int *ilist,*jlist,*numneigh,**firstneigh; + int count; + double vsum[3],vavg[3],vnet[3]; + + invoked_peratom = update->ntimestep; + + // grow phase array if necessary + + if (atom->nmax > nmax) { + memory->destroy(phase); + nmax = atom->nmax; + memory->create(phase,nmax,2,"phase/atom:phase"); + array_atom = phase; + } + + // need velocities of ghost atoms + + comm->forward_comm_compute(this); + + // invoke full neighbor list (will copy or build if necessary) + + neighbor->build_one(list); + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + // compute phase for each atom in group + // use full neighbor list to count atoms less than cutoff + + double **x = atom->x; + double **v = atom->v; + int *type = atom->type; + int *mask = atom->mask; + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + + if (mask[i] & groupbit) { + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + // i atom contribution + + count = 1; + vsum[0] = v[i][0]; + vsum[1] = v[i][1]; + vsum[2] = v[i][2]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx*delx + dely*dely + delz*delz; + if (rsq < cutsq) { + count++; + vsum[0] += v[j][0]; + vsum[1] += v[j][1]; + vsum[2] += v[j][2]; + } + } + + vavg[0] = vsum[0]/count; + vavg[1] = vsum[1]/count; + vavg[2] = vsum[2]/count; + + // i atom contribution + + count = 1; + vnet[0] = v[i][0] - vavg[0]; + vnet[1] = v[i][1] - vavg[1]; + vnet[2] = v[i][2] - vavg[2]; + double ke_sum = vnet[0]*vnet[0] + vnet[1]*vnet[1] + vnet[2]*vnet[2]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx*delx + dely*dely + delz*delz; + if (rsq < cutsq) { + count++; + vnet[0] = v[j][0] - vavg[0]; + vnet[1] = v[j][1] - vavg[1]; + vnet[2] = v[j][2] - vavg[2]; + ke_sum += vnet[0]*vnet[0] + vnet[1]*vnet[1] + vnet[2]*vnet[2]; + } + } + double density = count/sphere_vol; + double temp = ke_sum/3.0/count; + phase[i][0] = density; + phase[i][1] = temp; + } + } +} + +/* ---------------------------------------------------------------------- */ + +int ComputePhaseAtom::pack_forward_comm(int n, int *list, double *buf, + int /*pbc_flag*/, int * /*pbc*/) +{ + double **v = atom->v; + + int i,m=0; + for (i = 0; i < n; ++i) { + buf[m++] = v[list[i]][0]; + buf[m++] = v[list[i]][1]; + buf[m++] = v[list[i]][2]; + } + + return m; +} + +/* ---------------------------------------------------------------------- */ + +void ComputePhaseAtom::unpack_forward_comm(int n, int first, double *buf) +{ + double **v = atom->v; + + int i,last,m=0; + last = first + n; + for (i = first; i < last; ++i) { + v[i][0] = buf[m++]; + v[i][1] = buf[m++]; + v[i][2] = buf[m++]; + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array +------------------------------------------------------------------------- */ + +double ComputePhaseAtom::memory_usage() +{ + double bytes = (double)2*nmax * sizeof(double); + return bytes; +} diff --git a/src/compute_phase_atom.h b/src/compute_phase_atom.h new file mode 100644 index 0000000000..26d9636cc8 --- /dev/null +++ b/src/compute_phase_atom.h @@ -0,0 +1,88 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://lammps.sandia.gov/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMPUTE_CLASS + +ComputeStyle(phase/atom,ComputePhaseAtom) + +#else + +#ifndef LMP_COMPUTE_PHASE_ATOM_H +#define LMP_COMPUTE_PHASE_ATOM_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputePhaseAtom : public Compute { + public: + ComputePhaseAtom(class LAMMPS *, int, char **); + virtual ~ComputePhaseAtom(); + virtual void init(); + void init_list(int, class NeighList *); + virtual void compute_peratom(); + int pack_forward_comm(int, int *, double *, int, int *); + void unpack_forward_comm(int, int, double *); + double memory_usage(); + + protected: + int nmax; + double cutoff,cutsq,sphere_vol; + class NeighList *list; + + double **phase; +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +E: Could not find compute phase/atom compute ID + +UNDOCUMENTED + +E: Compute phase/atom compute ID is not orientorder/atom + +UNDOCUMENTED + +E: Compute phase/atom threshold not between -1 and 1 + +UNDOCUMENTED + +E: Invalid cstyle in compute phase/atom + +UNDOCUMENTED + +E: Compute phase/atom requires components option in compute orientorder/atom + +UNDOCUMENTED + +E: Compute phase/atom requires a pair style be defined + +Self-explanatory. + +E: Compute phase/atom cutoff is longer than pairwise cutoff + +Cannot compute phase at distances longer than the pair cutoff, +since those atoms are not in the neighbor list. + +*/ From 20cd742b4ab6ec6645ba1fd7ed9209f90af2d199 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Fri, 15 Oct 2021 15:59:15 -0600 Subject: [PATCH 009/193] whitespace & urls --- src/KOKKOS/compute_phase_atom_kokkos.cpp | 4 ++-- src/KOKKOS/compute_phase_atom_kokkos.h | 2 +- src/compute_phase_atom.cpp | 20 ++++++++++---------- src/compute_phase_atom.h | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/KOKKOS/compute_phase_atom_kokkos.cpp b/src/KOKKOS/compute_phase_atom_kokkos.cpp index 0b30c5d6fd..b0637526de 100644 --- a/src/KOKKOS/compute_phase_atom_kokkos.cpp +++ b/src/KOKKOS/compute_phase_atom_kokkos.cpp @@ -1,6 +1,6 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://lammps.sandia.gov/, Sandia National Laboratories + https://www.lammps.org/, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract @@ -182,7 +182,7 @@ void ComputePhaseAtomKokkos::operator()(TagComputePhaseAtom, const i for (int jj = 0; jj < jnum; jj++) { int j = d_neighbors(i,jj); j &= NEIGHMASK; - + const F_FLOAT delx = x(j,0) - xtmp; const F_FLOAT dely = x(j,1) - ytmp; const F_FLOAT delz = x(j,2) - ztmp; diff --git a/src/KOKKOS/compute_phase_atom_kokkos.h b/src/KOKKOS/compute_phase_atom_kokkos.h index 8cfa35d2c8..247acd3f03 100644 --- a/src/KOKKOS/compute_phase_atom_kokkos.h +++ b/src/KOKKOS/compute_phase_atom_kokkos.h @@ -1,6 +1,6 @@ /* -*- c++ -*- ---------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://lammps.sandia.gov/, Sandia National Laboratories + https://www.lammps.org/, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract diff --git a/src/compute_phase_atom.cpp b/src/compute_phase_atom.cpp index 0f166b2be2..c1382392d7 100644 --- a/src/compute_phase_atom.cpp +++ b/src/compute_phase_atom.cpp @@ -1,6 +1,6 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://lammps.sandia.gov/, Sandia National Laboratories + https://www.lammps.org/, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract @@ -152,19 +152,19 @@ void ComputePhaseAtom::compute_peratom() vsum[2] = v[i][2]; for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - j &= NEIGHMASK; + j = jlist[jj]; + j &= NEIGHMASK; - delx = xtmp - x[j][0]; - dely = ytmp - x[j][1]; - delz = ztmp - x[j][2]; - rsq = delx*delx + dely*dely + delz*delz; - if (rsq < cutsq) { - count++; + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx*delx + dely*dely + delz*delz; + if (rsq < cutsq) { + count++; vsum[0] += v[j][0]; vsum[1] += v[j][1]; vsum[2] += v[j][2]; - } + } } vavg[0] = vsum[0]/count; diff --git a/src/compute_phase_atom.h b/src/compute_phase_atom.h index 26d9636cc8..ab0dc3081e 100644 --- a/src/compute_phase_atom.h +++ b/src/compute_phase_atom.h @@ -1,6 +1,6 @@ /* -*- c++ -*- ---------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://lammps.sandia.gov/, Sandia National Laboratories + https://www.lammps.org/, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract From 136c15a8bafc43c7245d6f02e6f22eae0cfd40f1 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Thu, 4 Nov 2021 19:59:48 -0600 Subject: [PATCH 010/193] Allow dump sort to work with more than 2 billion atoms --- src/dump.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dump.cpp b/src/dump.cpp index 4c02aa3070..282ea0c696 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -237,7 +237,8 @@ void Dump::init() irregular = new Irregular(lmp); bigint size = group->count(igroup); - if (size > MAXSMALLINT) error->all(FLERR,"Too many atoms to dump sort"); + int bigintflag = 0; + if (size > MAXSMALLINT) bigintflag = 1; int isize = static_cast (size); // set reorderflag = 1 if can simply reorder local atoms rather than sort @@ -252,7 +253,7 @@ void Dump::init() if (utils::strmatch(fix->style,"^gcmc")) gcmcflag = 1; - if (sortcol == 0 && atom->tag_consecutive() && !gcmcflag) { + if (sortcol == 0 && atom->tag_consecutive() && !gcmcflag && !bigintflag) { tagint *tag = atom->tag; int *mask = atom->mask; int nlocal = atom->nlocal; From 07a25144ee23560d7d612df96d73b7eaa9d9bbb0 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Thu, 4 Nov 2021 20:06:30 -0600 Subject: [PATCH 011/193] Remove error from dump.h --- src/dump.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/dump.h b/src/dump.h index 730d4c9ca9..4237faf8b4 100644 --- a/src/dump.h +++ b/src/dump.h @@ -186,10 +186,6 @@ E: Dump sort column is invalid Self-explanatory. -E: Too many atoms to dump sort - -Cannot sort when running with more than 2^31 atoms. - E: Dump could not find refresh compute ID UNDOCUMENTED From ebb3dcd9ff2317665dcb11476aacc0c2e651b0e8 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Thu, 4 Nov 2021 20:20:07 -0600 Subject: [PATCH 012/193] Remove error message --- doc/src/Errors_messages.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/src/Errors_messages.rst b/doc/src/Errors_messages.rst index 3a593b5a3f..c06f4c86e3 100644 --- a/doc/src/Errors_messages.rst +++ b/doc/src/Errors_messages.rst @@ -7772,9 +7772,6 @@ keyword to allow for additional bonds to be formed The system size must fit in a 32-bit integer to use this dump style. -*Too many atoms to dump sort* - Cannot sort when running with more than 2\^31 atoms. - *Too many elements extracted from MEAM library.* Increase 'maxelt' in meam.h and recompile. From 5616336d5e711630857301f9c618d8755b4e5de4 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Thu, 18 Nov 2021 07:59:45 -0700 Subject: [PATCH 013/193] Allow sorting with reorderflag for more than 2 billion atoms --- src/dump.cpp | 9 +++------ src/dump.h | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/dump.cpp b/src/dump.cpp index 282ea0c696..587bd6c9d3 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -237,9 +237,6 @@ void Dump::init() irregular = new Irregular(lmp); bigint size = group->count(igroup); - int bigintflag = 0; - if (size > MAXSMALLINT) bigintflag = 1; - int isize = static_cast (size); // set reorderflag = 1 if can simply reorder local atoms rather than sort // criteria: sorting by ID, atom IDs are consecutive from 1 to Natoms @@ -253,7 +250,7 @@ void Dump::init() if (utils::strmatch(fix->style,"^gcmc")) gcmcflag = 1; - if (sortcol == 0 && atom->tag_consecutive() && !gcmcflag && !bigintflag) { + if (sortcol == 0 && atom->tag_consecutive() && !gcmcflag) { tagint *tag = atom->tag; int *mask = atom->mask; int nlocal = atom->nlocal; @@ -269,7 +266,7 @@ void Dump::init() MPI_Allreduce(&min,&minall,1,MPI_LMP_TAGINT,MPI_MIN,world); MPI_Allreduce(&max,&maxall,1,MPI_LMP_TAGINT,MPI_MAX,world); - if (maxall-minall+1 == isize) { + if (maxall-minall+1 == size) { reorderflag = 1; double range = maxall-minall + EPSILON; idlo = static_cast (range*me/nprocs + minall); @@ -285,7 +282,7 @@ void Dump::init() else if (me+1 != hi) idhi++; nme_reorder = idhi-idlo; - ntotal_reorder = isize; + ntotal_reorder = size; } } } diff --git a/src/dump.h b/src/dump.h index 4237faf8b4..681ce88c96 100644 --- a/src/dump.h +++ b/src/dump.h @@ -116,7 +116,7 @@ class Dump : protected Pointers { bigint ntotal; // total # of per-atom lines in snapshot int reorderflag; // 1 if OK to reorder instead of sort - int ntotal_reorder; // # of atoms that must be in snapshot + bigint ntotal_reorder; // # of atoms that must be in snapshot int nme_reorder; // # of atoms I must own in snapshot tagint idlo; // lowest ID I own when reordering From 94b11964f80c4b4243267c04c6d58244b0226ba6 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Thu, 18 Nov 2021 08:32:41 -0700 Subject: [PATCH 014/193] Write dump header after sort to fix incorrect atom count for multiproc --- src/dump.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/dump.cpp b/src/dump.cpp index 587bd6c9d3..9ca7e61e76 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -367,16 +367,6 @@ void Dump::write() if (multiproc != nprocs) MPI_Allreduce(&nme,&nmax,1,MPI_INT,MPI_MAX,world); else nmax = nme; - // write timestep header - // for multiproc, - // nheader = # of lines in this file via Allreduce on clustercomm - - bigint nheader = ntotal; - if (multiproc) - MPI_Allreduce(&bnme,&nheader,1,MPI_LMP_BIGINT,MPI_SUM,clustercomm); - - if (filewriter && write_header_flag) write_header(nheader); - // insure buf is sized for packing and communicating // use nmax to insure filewriter proc can receive info from others // limit nmax*size_one to int since used as arg in MPI calls @@ -429,6 +419,19 @@ void Dump::write() else pack(nullptr); if (sort_flag) sort(); + // write timestep header + // for multiproc, + // nheader = # of lines in this file via Allreduce on clustercomm + // must come after sort, which can change nme + + bigint nheader = ntotal; + if (multiproc) { + bnme = nme; + MPI_Allreduce(&bnme,&nheader,1,MPI_LMP_BIGINT,MPI_SUM,clustercomm); + } + + if (filewriter && write_header_flag) write_header(nheader); + // if buffering, convert doubles into strings // insure sbuf is sized for communicating // cannot buffer if output is to binary file From 15f1c2d9600562624fb9a9a82f61d4a5b080fceb Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Thu, 18 Nov 2021 08:50:09 -0700 Subject: [PATCH 015/193] Fix inaccurate error message --- doc/src/dump_modify.rst | 4 +++- src/dump.cpp | 2 +- src/dump.h | 5 ++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/src/dump_modify.rst b/doc/src/dump_modify.rst index da7ccffeb2..88b375ecb6 100644 --- a/doc/src/dump_modify.rst +++ b/doc/src/dump_modify.rst @@ -561,7 +561,9 @@ The dump *local* style cannot be sorted by atom ID, since there are typically multiple lines of output per atom. Some dump styles, such as *dcd* and *xtc*, require sorting by atom ID to format the output file correctly. If multiple processors are writing the dump file, via -the "%" wildcard in the dump filename, then sorting cannot be +the "%" wildcard in the dump filename and the *nfile* or *fileper* +keywords are set to non-default values (i.e. the number of dump file +pieces is not equal to the number of procs), then sorting cannot be performed. .. note:: diff --git a/src/dump.cpp b/src/dump.cpp index 9ca7e61e76..2917099ff9 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -228,7 +228,7 @@ void Dump::init() if (sort_flag) { if (multiproc > 1) error->all(FLERR, - "Cannot dump sort when multiple dump files are written"); + "Cannot dump sort when 'nfile' or 'fileper' keywords are set to non-default values"); if (sortcol == 0 && atom->tag_enable == 0) error->all(FLERR,"Cannot dump sort on atom IDs with no atom IDs defined"); if (sortcol && sortcol > size_one) diff --git a/src/dump.h b/src/dump.h index 681ce88c96..468b007096 100644 --- a/src/dump.h +++ b/src/dump.h @@ -173,10 +173,9 @@ E: Dump file MPI-IO output not allowed with % in filename This is because a % signifies one file per processor and MPI-IO creates one large file for all processors. -E: Cannot dump sort when multiple dump files are written +E: Cannot dump sort when 'nfile' or 'fileper' keywords are set to non-default values -In this mode, each processor dumps its atoms to a file, so -no sorting is allowed. +Can only dump sort when the number of dump file pieces using % in filename equals the number of processors E: Cannot dump sort on atom IDs with no atom IDs defined From 1afdd3c011d54a2a828eeb9dd8829bfe40f69a07 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Tue, 7 Dec 2021 09:16:19 -0700 Subject: [PATCH 016/193] new output vars for dumps --- src/dump.cpp | 19 +++++++++++++++ src/output.cpp | 66 ++++++++++++++++++++++++++++++++++---------------- src/output.h | 6 +++-- 3 files changed, 68 insertions(+), 23 deletions(-) diff --git a/src/dump.cpp b/src/dump.cpp index 4c02aa3070..639dc2fc07 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -937,9 +937,28 @@ void Dump::modify_params(int narg, char **arg) n = utils::inumeric(FLERR,arg[iarg+1],false,lmp); if (n <= 0) error->all(FLERR,"Illegal dump_modify command"); } + output->time_dump[idump] = 0; output->every_dump[idump] = n; iarg += 2; + } else if (strcmp(arg[iarg],"delta") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); + int idump; + for (idump = 0; idump < output->ndump; idump++) + if (strcmp(id,output->dump[idump]->id) == 0) break; + double delta; + if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { + delete [] output->var_dump[idump]; + output->var_dump[idump] = utils::strdup(&arg[iarg+1][2]); + delta = 0.0; + } else { + delta = utils::numeric(FLERR,arg[iarg+1],false,lmp); + if (delta <= 0.0) error->all(FLERR,"Illegal dump_modify command"); + } + output->time_dump[idump] = 1; + output->delta_dump[idump] = delta; + iarg += 2; + } else if (strcmp(arg[iarg],"fileper") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); if (!multiproc) diff --git a/src/output.cpp b/src/output.cpp index 9e29caf118..0c283efa55 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -59,7 +59,9 @@ Output::Output(LAMMPS *lmp) : Pointers(lmp) ndump = 0; max_dump = 0; + time_dump = nullptr; every_dump = nullptr; + delta_dump = nullptr; next_dump = nullptr; last_dump = nullptr; var_dump = nullptr; @@ -92,7 +94,9 @@ Output::~Output() if (thermo) delete thermo; delete [] var_thermo; + memory->destroy(time_dump); memory->destroy(every_dump); + memory->destroy(delta_dump); memory->destroy(next_dump); memory->destroy(last_dump); for (int i = 0; i < ndump; i++) delete [] var_dump[i]; @@ -126,12 +130,13 @@ void Output::init() for (int i = 0; i < ndump; i++) dump[i]->init(); for (int i = 0; i < ndump; i++) - if (every_dump[i] == 0) { + if ((time_dump[i] == 0 && every_dump[i] == 0) || + (time_dump[i] == 1 && delta_dump[i] == 0.0)} { ivar_dump[i] = input->variable->find(var_dump[i]); if (ivar_dump[i] < 0) - error->all(FLERR,"Variable name for dump every does not exist"); + error->all(FLERR,"Variable name for dump every or delta does not exist"); if (!input->variable->equalstyle(ivar_dump[i])) - error->all(FLERR,"Variable for dump every is invalid style"); + error->all(FLERR,"Variable for dump every or delta is invalid style"); } if (restart_flag_single && restart_every_single == 0) { @@ -176,7 +181,7 @@ void Output::setup(int memflag) if (ndump && update->restrict_output == 0) { for (int idump = 0; idump < ndump; idump++) { - if (dump[idump]->clearstep || every_dump[idump] == 0) + if (dump[idump]->clearstep || var_dump[idump]) modify->clearstep_compute(); writeflag = 0; if (every_dump[idump] && ntimestep % every_dump[idump] == 0 && @@ -187,6 +192,7 @@ void Output::setup(int memflag) dump[idump]->write(); last_dump[idump] = ntimestep; } + if (every_dump[idump]) next_dump[idump] = (ntimestep/every_dump[idump])*every_dump[idump] + every_dump[idump]; @@ -197,7 +203,8 @@ void Output::setup(int memflag) error->all(FLERR,"Dump every variable returned a bad timestep"); next_dump[idump] = nextdump; } - if (dump[idump]->clearstep || every_dump[idump] == 0) { + + if (dump[idump]->clearstep || var_dump[idump]) { if (writeflag) modify->addstep_compute(next_dump[idump]); else modify->addstep_compute_all(next_dump[idump]); } @@ -287,21 +294,35 @@ void Output::write(bigint ntimestep) if (next_dump_any == ntimestep) { for (int idump = 0; idump < ndump; idump++) { if (next_dump[idump] == ntimestep) { - if (dump[idump]->clearstep || every_dump[idump] == 0) + if (dump[idump]->clearstep || var_dump[idump]) modify->clearstep_compute(); if (last_dump[idump] != ntimestep) { dump[idump]->write(); last_dump[idump] = ntimestep; } - if (every_dump[idump]) next_dump[idump] += every_dump[idump]; - else { - bigint nextdump = static_cast - (input->variable->compute_equal(ivar_dump[idump])); - if (nextdump <= ntimestep) - error->all(FLERR,"Dump every variable returned a bad timestep"); - next_dump[idump] = nextdump; + + if (time_dump[idump] == 0) { + if (every_dump[idump]) next_dump[idump] += every_dump[idump]; + else { + bigint nextdump = static_cast + (input->variable->compute_equal(ivar_dump[idump])); + if (nextdump <= ntimestep) + error->all(FLERR,"Dump every variable returned a bad timestep"); + next_dump[idump] = nextdump; + } + } else { + if (delta_dump[idump] > 0.0) { + bigint nextstep = + next_dump[idump] += every_dump[idump]; + } else { + double nexttime = input->variable->compute_equal(ivar_dump[idump]); + if (nexttime <= current_time) // NOTE: what is current time + error->all(FLERR,"Dump delta variable returned a bad time"); + next_dump[idump] = nextdump; + } } - if (dump[idump]->clearstep || every_dump[idump] == 0) + + if (dump[idump]->clearstep || var_dump[idump]) modify->addstep_compute(next_dump[idump]); } if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]); @@ -547,7 +568,9 @@ void Output::add_dump(int narg, char **arg) max_dump += DELTA; dump = (Dump **) memory->srealloc(dump,max_dump*sizeof(Dump *),"output:dump"); + memory->grow(time_dump,max_dump,"output:time_dump"); memory->grow(every_dump,max_dump,"output:every_dump"); + memory->grow(delta_dump,max_dump,"output:delta_dump"); memory->grow(next_dump,max_dump,"output:next_dump"); memory->grow(last_dump,max_dump,"output:last_dump"); var_dump = (char **) @@ -555,13 +578,6 @@ void Output::add_dump(int narg, char **arg) memory->grow(ivar_dump,max_dump,"output:ivar_dump"); } - // initialize per-dump data to suitable default values - - every_dump[ndump] = 0; - last_dump[ndump] = -1; - var_dump[ndump] = nullptr; - ivar_dump[ndump] = -1; - // create the Dump if (dump_map->find(arg[2]) != dump_map->end()) { @@ -569,10 +585,16 @@ void Output::add_dump(int narg, char **arg) dump[ndump] = dump_creator(lmp, narg, arg); } else error->all(FLERR,utils::check_packages_for_style("dump",arg[2],lmp)); + // initialize per-dump data to suitable default values + + time_dump[ndump] = 0; every_dump[ndump] = utils::inumeric(FLERR,arg[3],false,lmp); if (every_dump[ndump] <= 0) error->all(FLERR,"Illegal dump command"); + delta_dump[ndump] = 0.0; last_dump[ndump] = -1; var_dump[ndump] = nullptr; + ivar_dump[ndump] = -1; + ndump++; } @@ -624,7 +646,9 @@ void Output::delete_dump(char *id) for (int i = idump+1; i < ndump; i++) { dump[i-1] = dump[i]; + time_dump[i-1] = time_dump[i]; every_dump[i-1] = every_dump[i]; + delta_dump[i-1] = delta_dump[i]; next_dump[i-1] = next_dump[i]; last_dump[i-1] = last_dump[i]; var_dump[i-1] = var_dump[i]; diff --git a/src/output.h b/src/output.h index 9ae8b7fc3d..b47ec84dea 100644 --- a/src/output.h +++ b/src/output.h @@ -36,10 +36,12 @@ class Output : protected Pointers { int ndump; // # of Dumps defined int max_dump; // max size of Dump list bigint next_dump_any; // next timestep for any Dump - int *every_dump; // write freq for each Dump, 0 if var + int *time_dump; // 0/1 if write every N timesteps or Delta in sim time + int *every_dump; // write every this many timesteps, 0 if var + double *delta_dump; // write every this delta sim time, 0.0 if var bigint *next_dump; // next timestep to do each Dump bigint *last_dump; // last timestep each snapshot was output - char **var_dump; // variable name for dump frequency + char **var_dump; // variable name for dump frequency (steps or sim time) int *ivar_dump; // variable index for dump frequency Dump **dump; // list of defined Dumps From 26492b13d550f8b490e22e491c8b286f5ee5e4c4 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Tue, 7 Dec 2021 13:46:36 -0700 Subject: [PATCH 017/193] logic for dumps every steps and time delta --- src/dump.cpp | 42 ++++++------ src/output.cpp | 178 ++++++++++++++++++++++++++++++++++++------------- src/output.h | 14 ++-- 3 files changed, 160 insertions(+), 74 deletions(-) diff --git a/src/dump.cpp b/src/dump.cpp index 639dc2fc07..43fdb775b5 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -918,9 +918,22 @@ void Dump::modify_params(int narg, char **arg) else delay_flag = 0; iarg += 2; - } else if (strcmp(arg[iarg],"header") == 0) { + } else if (strcmp(arg[iarg],"delta") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); - header_flag = utils::logical(FLERR,arg[iarg+1],false,lmp); + int idump; + for (idump = 0; idump < output->ndump; idump++) + if (strcmp(id,output->dump[idump]->id) == 0) break; + double delta; + if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { + delete [] output->var_dump[idump]; + output->var_dump[idump] = utils::strdup(&arg[iarg+1][2]); + delta = 0.0; + } else { + delta = utils::numeric(FLERR,arg[iarg+1],false,lmp); + if (delta <= 0.0) error->all(FLERR,"Illegal dump_modify command"); + } + output->mode_dump[idump] = 1; + output->delta_dump[idump] = delta; iarg += 2; } else if (strcmp(arg[iarg],"every") == 0) { @@ -937,28 +950,10 @@ void Dump::modify_params(int narg, char **arg) n = utils::inumeric(FLERR,arg[iarg+1],false,lmp); if (n <= 0) error->all(FLERR,"Illegal dump_modify command"); } - output->time_dump[idump] = 0; + output->mode_dump[idump] = 0; output->every_dump[idump] = n; iarg += 2; - } else if (strcmp(arg[iarg],"delta") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); - int idump; - for (idump = 0; idump < output->ndump; idump++) - if (strcmp(id,output->dump[idump]->id) == 0) break; - double delta; - if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { - delete [] output->var_dump[idump]; - output->var_dump[idump] = utils::strdup(&arg[iarg+1][2]); - delta = 0.0; - } else { - delta = utils::numeric(FLERR,arg[iarg+1],false,lmp); - if (delta <= 0.0) error->all(FLERR,"Illegal dump_modify command"); - } - output->time_dump[idump] = 1; - output->delta_dump[idump] = delta; - iarg += 2; - } else if (strcmp(arg[iarg],"fileper") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); if (!multiproc) @@ -1026,6 +1021,11 @@ void Dump::modify_params(int narg, char **arg) iarg += n; } + } else if (strcmp(arg[iarg],"header") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); + header_flag = utils::logical(FLERR,arg[iarg+1],false,lmp); + iarg += 2; + } else if (strcmp(arg[iarg],"maxfiles") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); if (!multifile) diff --git a/src/output.cpp b/src/output.cpp index 0c283efa55..a47a4f8ec1 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -34,6 +34,7 @@ using namespace LAMMPS_NS; #define DELTA 1 +#define EPSDT 1.0e-6 /* ---------------------------------------------------------------------- initialize all output @@ -59,10 +60,11 @@ Output::Output(LAMMPS *lmp) : Pointers(lmp) ndump = 0; max_dump = 0; - time_dump = nullptr; + mode_dump = nullptr; every_dump = nullptr; delta_dump = nullptr; next_dump = nullptr; + next_time_dump = nullptr; last_dump = nullptr; var_dump = nullptr; ivar_dump = nullptr; @@ -94,10 +96,11 @@ Output::~Output() if (thermo) delete thermo; delete [] var_thermo; - memory->destroy(time_dump); + memory->destroy(mode_dump); memory->destroy(every_dump); memory->destroy(delta_dump); memory->destroy(next_dump); + memory->destroy(next_time_dump); memory->destroy(last_dump); for (int i = 0; i < ndump; i++) delete [] var_dump[i]; memory->sfree(var_dump); @@ -130,8 +133,8 @@ void Output::init() for (int i = 0; i < ndump; i++) dump[i]->init(); for (int i = 0; i < ndump; i++) - if ((time_dump[i] == 0 && every_dump[i] == 0) || - (time_dump[i] == 1 && delta_dump[i] == 0.0)} { + if ((mode_dump[i] == 0 && every_dump[i] == 0) || + (mode_dump[i] == 1 && delta_dump[i] == 0.0)) { ivar_dump[i] = input->variable->find(var_dump[i]); if (ivar_dump[i] < 0) error->all(FLERR,"Variable name for dump every or delta does not exist"); @@ -170,9 +173,9 @@ void Output::setup(int memflag) // current timestep is multiple of every and last dump not >= this step // this is first run after dump created and firstflag is set // note that variable freq will not write unless triggered by firstflag - // set next_dump to multiple of every or variable value + // set next_dump, and also next_time_dump for mode_dump = 1 // set next_dump_any to smallest next_dump - // wrap dumps that invoke computes and variable eval with clear/add + // wrap dumps that invoke computes or do variable eval with clear/add // if dump not written now, use addstep_compute_all() since don't know // what computes the dump write would invoke // if no dumps, set next_dump_any to last+1 so will not influence next @@ -183,9 +186,15 @@ void Output::setup(int memflag) for (int idump = 0; idump < ndump; idump++) { if (dump[idump]->clearstep || var_dump[idump]) modify->clearstep_compute(); + writeflag = 0; - if (every_dump[idump] && ntimestep % every_dump[idump] == 0 && - last_dump[idump] != ntimestep) writeflag = 1; + if (mode_dump[idump] == 0) { + if (every_dump[idump] && (ntimestep % every_dump[idump] == 0) && + last_dump[idump] != ntimestep) writeflag = 1; + } else { + if (delta_dump[idump] >= 0.0 && last_dump[idump] != ntimestep) + writeflag = 1; + } if (last_dump[idump] < 0 && dump[idump]->first_flag == 1) writeflag = 1; if (writeflag) { @@ -193,21 +202,15 @@ void Output::setup(int memflag) last_dump[idump] = ntimestep; } - if (every_dump[idump]) - next_dump[idump] = - (ntimestep/every_dump[idump])*every_dump[idump] + every_dump[idump]; - else { - bigint nextdump = static_cast - (input->variable->compute_equal(ivar_dump[idump])); - if (nextdump <= ntimestep) - error->all(FLERR,"Dump every variable returned a bad timestep"); - next_dump[idump] = nextdump; - } + // set next_dump and next_time_dump, 0 arg for setup() + + calculate_next_dump(0,idump,ntimestep); if (dump[idump]->clearstep || var_dump[idump]) { if (writeflag) modify->addstep_compute(next_dump[idump]); else modify->addstep_compute_all(next_dump[idump]); } + if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]); else next_dump_any = next_dump[0]; } @@ -288,43 +291,40 @@ void Output::setup(int memflag) void Output::write(bigint ntimestep) { - // next_dump does not force output on last step of run - // wrap dumps that invoke computes or eval of variable with clear/add + // perform dump if its next_dump = current ntimestep + // but not if it was already written on this step + // set next_dump and also next_time_dump for mode_dump = 1 + // set next_dump_any to smallest next_dump + // wrap dumps that invoke computes or do variable eval with clear/add + // if dump not written now, use addstep_compute_all() since don't know + // what computes the dump write would invoke + + int writeflag; if (next_dump_any == ntimestep) { for (int idump = 0; idump < ndump; idump++) { if (next_dump[idump] == ntimestep) { if (dump[idump]->clearstep || var_dump[idump]) modify->clearstep_compute(); - if (last_dump[idump] != ntimestep) { + + writeflag = 0; + if (last_dump[idump] != ntimestep) writeflag = 1; + + if (writeflag) { dump[idump]->write(); last_dump[idump] = ntimestep; } - if (time_dump[idump] == 0) { - if (every_dump[idump]) next_dump[idump] += every_dump[idump]; - else { - bigint nextdump = static_cast - (input->variable->compute_equal(ivar_dump[idump])); - if (nextdump <= ntimestep) - error->all(FLERR,"Dump every variable returned a bad timestep"); - next_dump[idump] = nextdump; - } - } else { - if (delta_dump[idump] > 0.0) { - bigint nextstep = - next_dump[idump] += every_dump[idump]; - } else { - double nexttime = input->variable->compute_equal(ivar_dump[idump]); - if (nexttime <= current_time) // NOTE: what is current time - error->all(FLERR,"Dump delta variable returned a bad time"); - next_dump[idump] = nextdump; - } - } + // set next_dump and next_time_dump, 1 arg for write() + + calculate_next_dump(1,idump,ntimestep); - if (dump[idump]->clearstep || var_dump[idump]) - modify->addstep_compute(next_dump[idump]); + if (dump[idump]->clearstep || var_dump[idump]) { + if (writeflag) modify->addstep_compute(next_dump[idump]); + else modify->addstep_compute_all(next_dump[idump]); + } } + if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]); else next_dump_any = next_dump[0]; } @@ -332,7 +332,7 @@ void Output::write(bigint ntimestep) // next_restart does not force output on last step of run // for toggle = 0, replace "*" with current timestep in restart filename - // eval of variable may invoke computes so wrap with clear/add + // next restart variable may invoke computes so wrap with clear/add if (next_restart == ntimestep) { if (next_restart_single == ntimestep) { @@ -417,6 +417,88 @@ void Output::write_dump(bigint ntimestep) } } +/* ---------------------------------------------------------------------- + calculate when next dump occurs for Dump instance idump + operates in one of two modes, based on mode_dump flag + for timestep mode, set next_dump + for simulation time mode, set next_time_dump and next_dump +------------------------------------------------------------------------- */ + + void Output::calculate_next_dump(int which, int idump, bigint ntimestep) +{ + // dump mode is by timestep + // just set next_dump + + if (mode_dump[idump] == 0) { + + // for setup, make next_dump a multiple of every_dump + + if (every_dump[idump]) { + if (which == 1) next_dump[idump] += every_dump[idump]; + else + next_dump[idump] = + (ntimestep/every_dump[idump])*every_dump[idump] + every_dump[idump]; + } else { + next_dump[idump] = static_cast + (input->variable->compute_equal(ivar_dump[idump])); + if (next_dump[idump] <= ntimestep) + error->all(FLERR,"Dump every variable returned a bad timestep"); + } + + // dump mode is by simulation time + // set next_time_dump and next_dump + + } else { + bigint nextdump; + double nexttime; + double tcurrent = update->atime + + (ntimestep - update->atimestep) * update->dt; + + // for setup, make nexttime a multiple of delta_dump + + if (delta_dump[idump] > 0.0) { + if (which == 1) nexttime = next_time_dump[idump] + delta_dump[idump]; + else + nexttime = static_cast (tcurrent/delta_dump[idump]) * + delta_dump[idump] + delta_dump[idump]; + + nextdump = ntimestep + + static_cast ((nexttime - tcurrent + EPSDT*update->dt) / + update->dt); + + // if delta is too small to reach next timestep, use multiple of delta + + if (nextdump == ntimestep) { + double tnext = update->atime + + (ntimestep+1 - update->atimestep) * update->dt; + int multiple = static_cast + ((tnext - nexttime) / delta_dump[idump]); + nexttime = nexttime + (multiple+1)*delta_dump[idump]; + nextdump = ntimestep + + static_cast ((nexttime - tcurrent + EPSDT*update->dt) / + update->dt); + } + + } else { + nexttime = input->variable->compute_equal(ivar_dump[idump]); + if (nexttime <= tcurrent) + error->all(FLERR,"Dump delta variable returned a bad time"); + nextdump = ntimestep + + static_cast ((nexttime - tcurrent + EPSDT*update->dt) / + update->dt); + if (nextdump <= ntimestep) + error->all(FLERR,"Dump delta variable too small for next timestep"); + } + + next_time_dump[idump] = nexttime; + next_dump[idump] = nextdump; + + //printf("END time %20.16g step %ld ratio %g\n", + // next_time_dump[idump],next_dump[idump], + // next_time_dump[idump]/update->dt/(next_dump[idump]+1)); + } +} + /* ---------------------------------------------------------------------- force restart file(s) to be written called from PRD and TAD @@ -568,10 +650,11 @@ void Output::add_dump(int narg, char **arg) max_dump += DELTA; dump = (Dump **) memory->srealloc(dump,max_dump*sizeof(Dump *),"output:dump"); - memory->grow(time_dump,max_dump,"output:time_dump"); + memory->grow(mode_dump,max_dump,"output:mode_dump"); memory->grow(every_dump,max_dump,"output:every_dump"); memory->grow(delta_dump,max_dump,"output:delta_dump"); memory->grow(next_dump,max_dump,"output:next_dump"); + memory->grow(next_time_dump,max_dump,"output:next_time_dump"); memory->grow(last_dump,max_dump,"output:last_dump"); var_dump = (char **) memory->srealloc(var_dump,max_dump*sizeof(char *),"output:var_dump"); @@ -587,7 +670,7 @@ void Output::add_dump(int narg, char **arg) // initialize per-dump data to suitable default values - time_dump[ndump] = 0; + mode_dump[ndump] = 0; every_dump[ndump] = utils::inumeric(FLERR,arg[3],false,lmp); if (every_dump[ndump] <= 0) error->all(FLERR,"Illegal dump command"); delta_dump[ndump] = 0.0; @@ -646,10 +729,11 @@ void Output::delete_dump(char *id) for (int i = idump+1; i < ndump; i++) { dump[i-1] = dump[i]; - time_dump[i-1] = time_dump[i]; + mode_dump[i-1] = mode_dump[i]; every_dump[i-1] = every_dump[i]; delta_dump[i-1] = delta_dump[i]; next_dump[i-1] = next_dump[i]; + next_time_dump[i-1] = next_time_dump[i]; last_dump[i-1] = last_dump[i]; var_dump[i-1] = var_dump[i]; ivar_dump[i-1] = ivar_dump[i]; diff --git a/src/output.h b/src/output.h index b47ec84dea..ed5bfc162b 100644 --- a/src/output.h +++ b/src/output.h @@ -36,13 +36,14 @@ class Output : protected Pointers { int ndump; // # of Dumps defined int max_dump; // max size of Dump list bigint next_dump_any; // next timestep for any Dump - int *time_dump; // 0/1 if write every N timesteps or Delta in sim time - int *every_dump; // write every this many timesteps, 0 if var - double *delta_dump; // write every this delta sim time, 0.0 if var - bigint *next_dump; // next timestep to do each Dump + int *mode_dump; // 0/1 if write every N timesteps or Delta in sim time + int *every_dump; // dump every this many timesteps, 0 if variable + double *delta_dump; // dump every this delta sim time, 0.0 if variable + bigint *next_dump; // next timestep to perform dump + double *next_time_dump; // next simulation time to perform dump (mode = 1) bigint *last_dump; // last timestep each snapshot was output - char **var_dump; // variable name for dump frequency (steps or sim time) - int *ivar_dump; // variable index for dump frequency + char **var_dump; // variable name for next dump (steps or sim time) + int *ivar_dump; // variable index of var_dump name Dump **dump; // list of defined Dumps int restart_flag; // 1 if any restart files are written @@ -89,6 +90,7 @@ class Output : protected Pointers { private: template static Dump *dump_creator(LAMMPS *, int, char **); + void calculate_next_dump(int, int, bigint); }; } // namespace LAMMPS_NS From d4149e913915399c51a2b93b61962847790539b0 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Wed, 8 Dec 2021 16:44:51 -0700 Subject: [PATCH 018/193] bug fixes to make a series of test inputs run correctly --- doc/src/dump.rst | 78 ++++++++------- doc/src/dump_modify.rst | 130 +++++++++++++++++++++---- doc/src/fix_dt_reset.rst | 18 +++- src/dump.cpp | 36 +++---- src/fix_dt_reset.cpp | 3 + src/output.cpp | 204 ++++++++++++++++++++++++++------------- src/output.h | 7 +- src/update.cpp | 26 +++-- 8 files changed, 342 insertions(+), 160 deletions(-) diff --git a/doc/src/dump.rst b/doc/src/dump.rst index c2509e6654..8c5ce6e208 100644 --- a/doc/src/dump.rst +++ b/doc/src/dump.rst @@ -169,11 +169,12 @@ or multiple smaller files). .. note:: - Because periodic boundary conditions are enforced only on - timesteps when neighbor lists are rebuilt, the coordinates of an atom - written to a dump file may be slightly outside the simulation box. - Re-neighbor timesteps will not typically coincide with the timesteps - dump snapshots are written. See the :doc:`dump_modify pbc ` command if you with to force coordinates to be + Because periodic boundary conditions are enforced only on timesteps + when neighbor lists are rebuilt, the coordinates of an atom written + to a dump file may be slightly outside the simulation box. + Re-neighbor timesteps will not typically coincide with the + timesteps dump snapshots are written. See the :doc:`dump_modify + pbc ` command if you with to force coordinates to be strictly inside the simulation box. .. note:: @@ -189,20 +190,21 @@ or multiple smaller files). multiple processors, each of which owns a subset of the atoms. For the *atom*, *custom*, *cfg*, and *local* styles, sorting is off by -default. For the *dcd*, *xtc*, *xyz*, and *molfile* styles, sorting by -atom ID is on by default. See the :doc:`dump_modify ` doc -page for details. +default. For the *dcd*, *xtc*, *xyz*, and *molfile* styles, sorting +by atom ID is on by default. See the :doc:`dump_modify ` +doc page for details. -The *atom/gz*, *cfg/gz*, *custom/gz*, *local/gz*, and *xyz/gz* styles are identical -in command syntax to the corresponding styles without "gz", however, -they generate compressed files using the zlib library. Thus the filename -suffix ".gz" is mandatory. This is an alternative approach to writing -compressed files via a pipe, as done by the regular dump styles, which -may be required on clusters where the interface to the high-speed network -disallows using the fork() library call (which is needed for a pipe). -For the remainder of this doc page, you should thus consider the *atom* -and *atom/gz* styles (etc) to be inter-changeable, with the exception -of the required filename suffix. +The *atom/gz*, *cfg/gz*, *custom/gz*, *local/gz*, and *xyz/gz* styles +are identical in command syntax to the corresponding styles without +"gz", however, they generate compressed files using the zlib +library. Thus the filename suffix ".gz" is mandatory. This is an +alternative approach to writing compressed files via a pipe, as done +by the regular dump styles, which may be required on clusters where +the interface to the high-speed network disallows using the fork() +library call (which is needed for a pipe). For the remainder of this +doc page, you should thus consider the *atom* and *atom/gz* styles +(etc) to be inter-changeable, with the exception of the required +filename suffix. Similarly, the *atom/zstd*, *cfg/zstd*, *custom/zstd*, *local/zstd*, and *xyz/zstd* styles are identical to the gz styles, but use the Zstd @@ -275,10 +277,11 @@ This bounding box is convenient for many visualization programs. The meaning of the 6 character flags for "xx yy zz" is the same as above. Note that the first two numbers on each line are now xlo_bound instead -of xlo, etc, since they represent a bounding box. See the :doc:`Howto triclinic ` page for a geometric description -of triclinic boxes, as defined by LAMMPS, simple formulas for how the -6 bounding box extents (xlo_bound,xhi_bound,etc) are calculated from -the triclinic parameters, and how to transform those parameters to and +of xlo, etc, since they represent a bounding box. See the :doc:`Howto +triclinic ` page for a geometric description of +triclinic boxes, as defined by LAMMPS, simple formulas for how the 6 +bounding box extents (xlo_bound,xhi_bound,etc) are calculated from the +triclinic parameters, and how to transform those parameters to and from other commonly used triclinic representations. The "ITEM: ATOMS" line in each snapshot lists column descriptors for @@ -310,23 +313,24 @@ written to the dump file. This local data is typically calculated by each processor based on the atoms it owns, but there may be zero or more entities per atom, e.g. a list of bond distances. An explanation of the possible dump local attributes is given below. Note that by -using input from the :doc:`compute property/local ` command with dump local, -it is possible to generate information on bonds, angles, etc that can -be cut and pasted directly into a data file read by the -:doc:`read_data ` command. +using input from the :doc:`compute property/local +` command with dump local, it is possible to +generate information on bonds, angles, etc that can be cut and pasted +directly into a data file read by the :doc:`read_data ` +command. Style *cfg* has the same command syntax as style *custom* and writes -extended CFG format files, as used by the -`AtomEye `_ visualization -package. Since the extended CFG format uses a single snapshot of the -system per file, a wildcard "\*" must be included in the filename, as -discussed below. The list of atom attributes for style *cfg* must -begin with either "mass type xs ys zs" or "mass type xsu ysu zsu" -since these quantities are needed to write the CFG files in the -appropriate format (though the "mass" and "type" fields do not appear -explicitly in the file). Any remaining attributes will be stored as -"auxiliary properties" in the CFG files. Note that you will typically -want to use the :doc:`dump_modify element ` command with +extended CFG format files, as used by the `AtomEye +`_ visualization package. +Since the extended CFG format uses a single snapshot of the system per +file, a wildcard "\*" must be included in the filename, as discussed +below. The list of atom attributes for style *cfg* must begin with +either "mass type xs ys zs" or "mass type xsu ysu zsu" since these +quantities are needed to write the CFG files in the appropriate format +(though the "mass" and "type" fields do not appear explicitly in the +file). Any remaining attributes will be stored as "auxiliary +properties" in the CFG files. Note that you will typically want to +use the :doc:`dump_modify element ` command with CFG-formatted files, to associate element names with atom types, so that AtomEye can render atoms appropriately. When unwrapped coordinates *xsu*, *ysu*, and *zsu* are requested, the nominal AtomEye diff --git a/doc/src/dump_modify.rst b/doc/src/dump_modify.rst index da7ccffeb2..42bb4d94fd 100644 --- a/doc/src/dump_modify.rst +++ b/doc/src/dump_modify.rst @@ -17,7 +17,7 @@ Syntax * one or more keyword/value pairs may be appended * these keywords apply to various dump styles -* keyword = *append* or *at* or *buffer* or *delay* or *element* or *every* or *fileper* or *first* or *flush* or *format* or *header* or *image* or *label* or *maxfiles* or *nfile* or *pad* or *pbc* or *precision* or *region* or *refresh* or *scale* or *sfactor* or *sort* or *tfactor* or *thermo* or *thresh* or *time* or *units* or *unwrap* +* keyword = *append* or *at* or *buffer* or *delay* or *element* or *every* or *every/time* or *fileper* or *first* or *flush* or *format* or *header* or *image* or *label* or *maxfiles* or *nfile* or *pad* or *pbc* or *precision* or *region* or *refresh* or *scale* or *sfactor* or *sort* or *tfactor* or *thermo* or *thresh* or *time* or *units* or *unwrap* .. parsed-literal:: @@ -32,6 +32,9 @@ Syntax *every* arg = N N = dump every this many timesteps N can be a variable (see below) + *every/time* arg = Delta + Delta = dump every this interval in simulation time (time units) + Delta can be a variable (see below) *fileper* arg = Np Np = write one file for every this many processors *first* arg = *yes* or *no* @@ -197,11 +200,18 @@ will be accepted. ---------- -The *every* keyword changes the dump frequency originally specified by -the :doc:`dump ` command to a new value. The every keyword can be -specified in one of two ways. It can be a numeric value in which case -it must be > 0. Or it can be an :doc:`equal-style variable `, -which should be specified as v_name, where name is the variable name. +The *every* keyword does two things. It specifies that the interval +between dump snapshots will be specified in timesteps, which is the +default if the *every* or *every/time* keywords are not used. See the +*every/time* keyword for how to specify the interval in simulation +time, i.e. in time units of the :doc:`units ` command. This +command also sets the interval value, which overrides the dump +frequency originally specified by the :doc:`dump ` command. + +The every keyword can be specified in one of two ways. It can be a +numeric value in which case it must be > 0. Or it can be an +:doc:`equal-style variable `, which should be specified as +v_name, where name is the variable name. In this case, the variable is evaluated at the beginning of a run to determine the next timestep at which a dump snapshot will be written @@ -210,11 +220,12 @@ determine the next timestep, etc. Thus the variable should return timestep values. See the stagger() and logfreq() and stride() math functions for :doc:`equal-style variables `, as examples of useful functions to use in this context. Other similar math functions -could easily be added as options for :doc:`equal-style variables `. Also see the next() function, which allows -use of a file-style variable which reads successive values from a -file, each time the variable is evaluated. Used with the *every* -keyword, if the file contains a list of ascending timesteps, you can -output snapshots whenever you wish. +could easily be added as options for :doc:`equal-style variables +`. Also see the next() function, which allows use of a +file-style variable which reads successive values from a file, each +time the variable is evaluated. Used with the *every* keyword, if the +file contains a list of ascending timesteps, you can output snapshots +whenever you wish. Note that when using the variable option with the *every* keyword, you need to use the *first* option if you want an initial snapshot written @@ -255,14 +266,95 @@ in file tmp.times: ---------- +The *every/time* keyword does two things. It specifies that the +interval between dump snapshots will be specified in simulation time, +i.e. in time units of the :doc:`units ` command. This can be +useful when the timestep size varies during a simulation run, e.g. by +use of the :doc:`fix dt/reset ` command. The default is +to specify the interval in timesteps; see the *every* keyword. This +command also sets the interval value. + +Note that since snapshots are output on simulation steps, each +snapshot will be written on the first timestep whose associated +simulation time is >= the exact snapshot time value. + +As with the *every* option, the *Delta* value can be specified in one +of two ways. It can be a numeric value in which case it must be > +0.0. Or it can be an :doc:`equal-style variable `, which +should be specified as v_name, where name is the variable name. + +In this case, the variable is evaluated at the beginning of a run to +determine the next simulation time at which a dump snapshot will be +written out. On that timestep the variable will be evaluated again to +determine the next simulation time, etc. Thus the variable should +return values in time units. Note the current timestep or simulation +time can be used in an :doc:`equal-style variables ` since +they are both thermodynamic keywords. Also see the next() function, +which allows use of a file-style variable which reads successive +values from a file, each time the variable is evaluated. Used with +the *every/time* keyword, if the file contains a list of ascending +simulation times, you can output snapshots whenever you wish. + +Note that when using the variable option with the *every/time* +keyword, you need to use the *first* option if you want an initial +snapshot written to the dump file. The *every/time* keyword cannot be +used with the dump *dcd* style. + +For example, the following commands will write snapshots at successive +simulation times which grow by a factor of 1.5 with each interval. +The dt value used in the variable is to avoid a zero result when the +initial simulation time is 0.0. + +.. code-block:: LAMMPS + + variable increase equal 1.5*(time+dt) + dump 1 all atom 100 tmp.dump + dump_modify 1 every/time v_increase first yes + +The following commands would write snapshots at the times listed in +file tmp.times: + +.. code-block:: LAMMPS + + variable f file tmp.times + variable s equal next(f) + dump 1 all atom 100 tmp.dump + dump_modify 1 every/time v_s + +.. note:: + + When using a file-style variable with the *every* keyword, the file + of timesteps must list a first times that is beyond the time + associated with the current timestep (e.g. it cannot be 0.0). And + it must list one or more times beyond the length of the run you + perform. This is because the dump command will generate an error + if the next time it reads from the file is not a value greater than + the current time. Thus if you wanted output at times 0,15,100 of a + run of length 100 in simulation time, the file should contain the + values 15,100,101 and you should also use the dump_modify first + command. Any final value > 100 could be used in place of 101. + +---------- + The *first* keyword determines whether a dump snapshot is written on the very first timestep after the dump command is invoked. This will -always occur if the current timestep is a multiple of N, the frequency -specified in the :doc:`dump ` command, including timestep 0. But -if this is not the case, a dump snapshot will only be written if the -setting of this keyword is *yes*\ . If it is *no*, which is the +always occur if the current timestep is a multiple of $N$, the +frequency specified in the :doc:`dump ` command or +:doc:`dump_modify every ` command, including timestep 0. +It will also always occur if the current simulation time is a multiple +of *Delta*, the time interval specified in the doc:`dump_modify every/time +` command. + +But if this is not the case, a dump snapshot will only be written if +the setting of this keyword is *yes*\ . If it is *no*, which is the default, then it will not be written. +Note that if the argument to the :doc:`dump_modify every +` doc:`dump_modify every/time ` commands is +a variable and not a numeric value, then specifying *first yes* is the +only way to write a dump snapshot on the first timestep after the dump +command is invoked. + ---------- The *flush* keyword determines whether a flush operation is invoked @@ -342,10 +434,10 @@ The *fileper* keyword is documented below with the *nfile* keyword. ---------- -The *header* keyword toggles whether the dump file will include a header. -Excluding a header will reduce the size of the dump file for fixes such as -:doc:`fix pair/tracker ` which do not require the information -typically written to the header. +The *header* keyword toggles whether the dump file will include a +header. Excluding a header will reduce the size of the dump file for +fixes such as :doc:`fix pair/tracker ` which do not +require the information typically written to the header. ---------- diff --git a/doc/src/fix_dt_reset.rst b/doc/src/fix_dt_reset.rst index c3aa431e18..368a3dcd70 100644 --- a/doc/src/fix_dt_reset.rst +++ b/doc/src/fix_dt_reset.rst @@ -78,13 +78,20 @@ outer loop (largest) timestep, which is the same timestep that the Note that the cumulative simulation time (in time units), which accounts for changes in the timestep size as a simulation proceeds, -can be accessed by the :doc:`thermo_style time ` keyword. +can be accessed by the :doc:`thermo_style time ` +keyword. + +Also note that the :doc:`dump_modify every/time ` option +allows dump files to be written at intervals specified by simulation +time, rather than by timesteps. Simulation time is in time units; +see the :doc:`units ` doc page for details. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" -No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options -are relevant to this fix. +No information about this fix is written to :doc:`binary restart files +`. None of the :doc:`fix_modify ` options are +relevant to this fix. This fix computes a global scalar which can be accessed by various :doc:`output commands `. The scalar stores the last @@ -93,7 +100,8 @@ timestep on which the timestep was reset to a new value. The scalar value calculated by this fix is "intensive". No parameter of this fix can be used with the *start/stop* keywords of -the :doc:`run ` command. This fix is not invoked during :doc:`energy minimization `. +the :doc:`run ` command. This fix is not invoked during +:doc:`energy minimization `. Restrictions """""""""""" @@ -102,7 +110,7 @@ Restrictions Related commands """""""""""""""" -:doc:`timestep ` +:doc:`timestep `, :doc:`dump_modify every/time ` Default """"""" diff --git a/src/dump.cpp b/src/dump.cpp index 43fdb775b5..df39f3738d 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -918,24 +918,6 @@ void Dump::modify_params(int narg, char **arg) else delay_flag = 0; iarg += 2; - } else if (strcmp(arg[iarg],"delta") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); - int idump; - for (idump = 0; idump < output->ndump; idump++) - if (strcmp(id,output->dump[idump]->id) == 0) break; - double delta; - if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { - delete [] output->var_dump[idump]; - output->var_dump[idump] = utils::strdup(&arg[iarg+1][2]); - delta = 0.0; - } else { - delta = utils::numeric(FLERR,arg[iarg+1],false,lmp); - if (delta <= 0.0) error->all(FLERR,"Illegal dump_modify command"); - } - output->mode_dump[idump] = 1; - output->delta_dump[idump] = delta; - iarg += 2; - } else if (strcmp(arg[iarg],"every") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); int idump; @@ -954,6 +936,24 @@ void Dump::modify_params(int narg, char **arg) output->every_dump[idump] = n; iarg += 2; + } else if (strcmp(arg[iarg],"every/time") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); + int idump; + for (idump = 0; idump < output->ndump; idump++) + if (strcmp(id,output->dump[idump]->id) == 0) break; + double delta; + if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { + delete [] output->var_dump[idump]; + output->var_dump[idump] = utils::strdup(&arg[iarg+1][2]); + delta = 0.0; + } else { + delta = utils::numeric(FLERR,arg[iarg+1],false,lmp); + if (delta <= 0.0) error->all(FLERR,"Illegal dump_modify command"); + } + output->mode_dump[idump] = 1; + output->every_time_dump[idump] = delta; + iarg += 2; + } else if (strcmp(arg[iarg],"fileper") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); if (!multiproc) diff --git a/src/fix_dt_reset.cpp b/src/fix_dt_reset.cpp index c80c976504..fbbe7d7c3e 100644 --- a/src/fix_dt_reset.cpp +++ b/src/fix_dt_reset.cpp @@ -197,12 +197,15 @@ void FixDtReset::end_of_step() laststep = update->ntimestep; + // calls to other classes that need to know timestep size changed + update->update_time(); update->dt = dt; update->dt_default = 0; if (respaflag) update->integrate->reset_dt(); if (force->pair) force->pair->reset_dt(); for (int i = 0; i < modify->nfix; i++) modify->fix[i]->reset_dt(); + output->reset_dt(); } /* ---------------------------------------------------------------------- */ diff --git a/src/output.cpp b/src/output.cpp index a47a4f8ec1..9cc90ed4b5 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -29,6 +29,7 @@ #include "variable.h" #include "write_restart.h" +#include #include using namespace LAMMPS_NS; @@ -62,7 +63,7 @@ Output::Output(LAMMPS *lmp) : Pointers(lmp) max_dump = 0; mode_dump = nullptr; every_dump = nullptr; - delta_dump = nullptr; + every_time_dump = nullptr; next_dump = nullptr; next_time_dump = nullptr; last_dump = nullptr; @@ -98,7 +99,7 @@ Output::~Output() memory->destroy(mode_dump); memory->destroy(every_dump); - memory->destroy(delta_dump); + memory->destroy(every_time_dump); memory->destroy(next_dump); memory->destroy(next_time_dump); memory->destroy(last_dump); @@ -134,7 +135,7 @@ void Output::init() for (int i = 0; i < ndump; i++) dump[i]->init(); for (int i = 0; i < ndump; i++) if ((mode_dump[i] == 0 && every_dump[i] == 0) || - (mode_dump[i] == 1 && delta_dump[i] == 0.0)) { + (mode_dump[i] == 1 && every_time_dump[i] == 0.0)) { ivar_dump[i] = input->variable->find(var_dump[i]); if (ivar_dump[i] < 0) error->all(FLERR,"Variable name for dump every or delta does not exist"); @@ -169,42 +170,61 @@ void Output::setup(int memflag) { bigint ntimestep = update->ntimestep; - // perform dump at start of run only if: - // current timestep is multiple of every and last dump not >= this step - // this is first run after dump created and firstflag is set - // note that variable freq will not write unless triggered by firstflag - // set next_dump, and also next_time_dump for mode_dump = 1 - // set next_dump_any to smallest next_dump - // wrap dumps that invoke computes or do variable eval with clear/add - // if dump not written now, use addstep_compute_all() since don't know - // what computes the dump write would invoke - // if no dumps, set next_dump_any to last+1 so will not influence next - - int writeflag; + // consider all dumps + // decide whether to write snapshot and/or calculate next step for dump if (ndump && update->restrict_output == 0) { for (int idump = 0; idump < ndump; idump++) { + + // wrap dumps that invoke computes or do variable eval with clear/add + if (dump[idump]->clearstep || var_dump[idump]) modify->clearstep_compute(); - writeflag = 0; - if (mode_dump[idump] == 0) { - if (every_dump[idump] && (ntimestep % every_dump[idump] == 0) && - last_dump[idump] != ntimestep) writeflag = 1; - } else { - if (delta_dump[idump] >= 0.0 && last_dump[idump] != ntimestep) - writeflag = 1; - } + // write a snapshot at setup only if any of these 3 conditions hold + // (1) this is first run since dump was created and its first_flag = 0 + // (2) mode_dump = 0 and timestep is multiple of every_dump + // (3) mode_dump = 1 and time is multiple of every_time_dump (within EPSDT) + // (2) and (3) only apply for non-variable dump intervals + // finally, do not write if same snapshot written previously, + // i.e. on last timestep of previous run + + int writeflag = 0; + if (last_dump[idump] < 0 && dump[idump]->first_flag == 1) writeflag = 1; + if (mode_dump[idump] == 0) { + if (every_dump[idump] && (ntimestep % every_dump[idump] == 0)) + writeflag = 1; + } else { + if (every_time_dump[idump] > 0.0) { + double tcurrent = update->atime + + (ntimestep - update->atimestep) * update->dt; + double remainder = fmod(tcurrent,every_time_dump[idump]); + if ((remainder < EPSDT*update->dt) || + (every_time_dump[idump] - remainder < EPSDT*update->dt)) + writeflag = 1; + } + } + + if (last_dump[idump] == ntimestep) writeflag = 0; + + // perform dump + if (writeflag) { dump[idump]->write(); last_dump[idump] = ntimestep; } + // calculate timestep and/or time for next dump // set next_dump and next_time_dump, 0 arg for setup() + // only do this if dump written or dump has not been written yet - calculate_next_dump(0,idump,ntimestep); + if (writeflag || last_dump[idump] < 0) + calculate_next_dump(0,idump,ntimestep); + + // if dump not written now, use addstep_compute_all() + // since don't know what computes the dump will invoke if (dump[idump]->clearstep || var_dump[idump]) { if (writeflag) modify->addstep_compute(next_dump[idump]); @@ -214,6 +234,9 @@ void Output::setup(int memflag) if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]); else next_dump_any = next_dump[0]; } + + // if no dumps, set next_dump_any to last+1 so will not influence next + } else next_dump_any = update->laststep + 1; // do not write restart files at start of run @@ -296,33 +319,26 @@ void Output::write(bigint ntimestep) // set next_dump and also next_time_dump for mode_dump = 1 // set next_dump_any to smallest next_dump // wrap dumps that invoke computes or do variable eval with clear/add - // if dump not written now, use addstep_compute_all() since don't know - // what computes the dump write would invoke - + int writeflag; if (next_dump_any == ntimestep) { for (int idump = 0; idump < ndump; idump++) { if (next_dump[idump] == ntimestep) { + if (last_dump[idump] == ntimestep) continue; + if (dump[idump]->clearstep || var_dump[idump]) modify->clearstep_compute(); - writeflag = 0; - if (last_dump[idump] != ntimestep) writeflag = 1; + // perform dump + // reset next_dump and next_time_dump, 1 arg for write() - if (writeflag) { - dump[idump]->write(); - last_dump[idump] = ntimestep; - } - - // set next_dump and next_time_dump, 1 arg for write() - + dump[idump]->write(); + last_dump[idump] = ntimestep; calculate_next_dump(1,idump,ntimestep); - if (dump[idump]->clearstep || var_dump[idump]) { - if (writeflag) modify->addstep_compute(next_dump[idump]); - else modify->addstep_compute_all(next_dump[idump]); - } + if (dump[idump]->clearstep || var_dump[idump]) + modify->addstep_compute(next_dump[idump]); } if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]); @@ -422,6 +438,10 @@ void Output::write_dump(bigint ntimestep) operates in one of two modes, based on mode_dump flag for timestep mode, set next_dump for simulation time mode, set next_time_dump and next_dump + which flag depends on caller + 0 = from setup() at start of run + 1 = from write() during run each time a dump file is written + 2 = from reset_dt() called from fix dt/reset when it changes timestep size ------------------------------------------------------------------------- */ void Output::calculate_next_dump(int which, int idump, bigint ntimestep) @@ -431,13 +451,17 @@ void Output::write_dump(bigint ntimestep) if (mode_dump[idump] == 0) { - // for setup, make next_dump a multiple of every_dump - if (every_dump[idump]) { - if (which == 1) next_dump[idump] += every_dump[idump]; - else + + // which = 0: nextdump = next multiple of every_dump + // which = 1: increment nextdump by every_dump + + if (which == 0) next_dump[idump] = (ntimestep/every_dump[idump])*every_dump[idump] + every_dump[idump]; + else if (which == 1) + next_dump[idump] += every_dump[idump]; + } else { next_dump[idump] = static_cast (input->variable->compute_equal(ivar_dump[idump])); @@ -449,22 +473,29 @@ void Output::write_dump(bigint ntimestep) // set next_time_dump and next_dump } else { + bigint nextdump; double nexttime; double tcurrent = update->atime + (ntimestep - update->atimestep) * update->dt; - // for setup, make nexttime a multiple of delta_dump + if (every_time_dump[idump] > 0.0) { - if (delta_dump[idump] > 0.0) { - if (which == 1) nexttime = next_time_dump[idump] + delta_dump[idump]; - else - nexttime = static_cast (tcurrent/delta_dump[idump]) * - delta_dump[idump] + delta_dump[idump]; + // which = 0: nexttime = next multiple of every_time_dump + // which = 1: increment nexttime by every_time_dump + // which = 2: no change to previous nexttime (only timestep has changed) + + if (which == 0) + nexttime = static_cast (tcurrent/every_time_dump[idump]) * + every_time_dump[idump] + every_time_dump[idump]; + else if (which == 1) + nexttime = next_time_dump[idump] + every_time_dump[idump]; + else if (which == 2) + nexttime = next_time_dump[idump]; nextdump = ntimestep + - static_cast ((nexttime - tcurrent + EPSDT*update->dt) / - update->dt); + static_cast ((nexttime - tcurrent - EPSDT*update->dt) / + update->dt) + 1; // if delta is too small to reach next timestep, use multiple of delta @@ -472,30 +503,35 @@ void Output::write_dump(bigint ntimestep) double tnext = update->atime + (ntimestep+1 - update->atimestep) * update->dt; int multiple = static_cast - ((tnext - nexttime) / delta_dump[idump]); - nexttime = nexttime + (multiple+1)*delta_dump[idump]; + ((tnext - nexttime) / every_time_dump[idump]); + nexttime = nexttime + (multiple+1)*every_time_dump[idump]; nextdump = ntimestep + - static_cast ((nexttime - tcurrent + EPSDT*update->dt) / - update->dt); + static_cast ((nexttime - tcurrent - EPSDT*update->dt) / + update->dt) + 1; } } else { - nexttime = input->variable->compute_equal(ivar_dump[idump]); + + // do not re-evaulate variable for which = 2, leave nexttime as-is + // unless next_time_dump < 0.0, which means variable never yet evaluated + + if (which < 2 || next_time_dump[idump] < 0.0) + nexttime = input->variable->compute_equal(ivar_dump[idump]); + else + nexttime = next_time_dump[idump]; + if (nexttime <= tcurrent) - error->all(FLERR,"Dump delta variable returned a bad time"); + error->all(FLERR,"Dump every/time variable returned a bad time"); + nextdump = ntimestep + - static_cast ((nexttime - tcurrent + EPSDT*update->dt) / - update->dt); + static_cast ((nexttime - tcurrent - EPSDT*update->dt) / + update->dt) + 1; if (nextdump <= ntimestep) - error->all(FLERR,"Dump delta variable too small for next timestep"); + error->all(FLERR,"Dump every/time variable too small for next timestep"); } next_time_dump[idump] = nexttime; next_dump[idump] = nextdump; - - //printf("END time %20.16g step %ld ratio %g\n", - // next_time_dump[idump],next_dump[idump], - // next_time_dump[idump]/update->dt/(next_dump[idump]+1)); } } @@ -529,7 +565,7 @@ void Output::write_restart(bigint ntimestep) /* ---------------------------------------------------------------------- timestep is being changed, called by update->reset_timestep() - reset next timestep values for dumps, restart, thermo output + reset next output values for dumps, restart, thermo output reset to smallest value >= new timestep if next timestep set by variable evaluation, eval for ntimestep-1, so current ntimestep can be returned if needed @@ -626,6 +662,35 @@ void Output::reset_timestep(bigint ntimestep) next = MIN(next,next_thermo); } +/* ---------------------------------------------------------------------- + timestep size is being changed, called by fix dt/reset (at end of step) + reset next output values for dumps which have mode_dump=1 +------------------------------------------------------------------------- */ + +void Output::reset_dt() +{ + next_dump_any = MAXBIGINT; + + for (int idump = 0; idump < ndump; idump++) { + if (mode_dump[idump] == 1) { + + // reset next_dump for unchanged next_time_dump, 2 arg for reset_dt() + + calculate_next_dump(2,idump,update->ntimestep); + + // use compute_all() b/c don't know what computes will be needed + + if (dump[idump]->clearstep || var_dump[idump]) + modify->addstep_compute_all(next_dump[idump]); + } + + next_dump_any = MIN(next_dump_any,next_dump[idump]); + } + + next = MIN(next_dump_any,next_restart); + next = MIN(next,next_thermo); +} + /* ---------------------------------------------------------------------- add a Dump to list of Dumps ------------------------------------------------------------------------- */ @@ -652,7 +717,7 @@ void Output::add_dump(int narg, char **arg) memory->srealloc(dump,max_dump*sizeof(Dump *),"output:dump"); memory->grow(mode_dump,max_dump,"output:mode_dump"); memory->grow(every_dump,max_dump,"output:every_dump"); - memory->grow(delta_dump,max_dump,"output:delta_dump"); + memory->grow(every_time_dump,max_dump,"output:every_time_dump"); memory->grow(next_dump,max_dump,"output:next_dump"); memory->grow(next_time_dump,max_dump,"output:next_time_dump"); memory->grow(last_dump,max_dump,"output:last_dump"); @@ -673,7 +738,8 @@ void Output::add_dump(int narg, char **arg) mode_dump[ndump] = 0; every_dump[ndump] = utils::inumeric(FLERR,arg[3],false,lmp); if (every_dump[ndump] <= 0) error->all(FLERR,"Illegal dump command"); - delta_dump[ndump] = 0.0; + every_time_dump[ndump] = 0.0; + next_time_dump[ndump] = -1.0; last_dump[ndump] = -1; var_dump[ndump] = nullptr; ivar_dump[ndump] = -1; @@ -731,7 +797,7 @@ void Output::delete_dump(char *id) dump[i-1] = dump[i]; mode_dump[i-1] = mode_dump[i]; every_dump[i-1] = every_dump[i]; - delta_dump[i-1] = delta_dump[i]; + every_time_dump[i-1] = every_time_dump[i]; next_dump[i-1] = next_dump[i]; next_time_dump[i-1] = next_time_dump[i]; last_dump[i-1] = last_dump[i]; diff --git a/src/output.h b/src/output.h index ed5bfc162b..c8d3f734e0 100644 --- a/src/output.h +++ b/src/output.h @@ -37,8 +37,8 @@ class Output : protected Pointers { int max_dump; // max size of Dump list bigint next_dump_any; // next timestep for any Dump int *mode_dump; // 0/1 if write every N timesteps or Delta in sim time - int *every_dump; // dump every this many timesteps, 0 if variable - double *delta_dump; // dump every this delta sim time, 0.0 if variable + int *every_dump; // dump every N timesteps, 0 if variable + double *every_time_dump; // dump every Delta of sim time, 0.0 if variable bigint *next_dump; // next timestep to perform dump double *next_time_dump; // next simulation time to perform dump (mode = 1) bigint *last_dump; // last timestep each snapshot was output @@ -75,7 +75,8 @@ class Output : protected Pointers { void write(bigint); // output for current timestep void write_dump(bigint); // force output of dump snapshots void write_restart(bigint); // force output of a restart file - void reset_timestep(bigint); // reset next timestep for all output + void reset_timestep(bigint); // reset output which depeneds on timestep + void reset_dt(); // reset output which depends on dt void add_dump(int, char **); // add a Dump to Dump list void modify_dump(int, char **); // modify a Dump diff --git a/src/update.cpp b/src/update.cpp index 95dc47573e..10b4c573d7 100644 --- a/src/update.cpp +++ b/src/update.cpp @@ -458,7 +458,7 @@ Min *Update::minimize_creator(LAMMPS *lmp) } /* ---------------------------------------------------------------------- - reset timestep as called from input script + reset timestep called from input script ------------------------------------------------------------------------- */ void Update::reset_timestep(int narg, char **arg) @@ -470,24 +470,32 @@ void Update::reset_timestep(int narg, char **arg) /* ---------------------------------------------------------------------- reset timestep - called from rerun command and input script (indirectly) + called from input script (indirectly) or rerun command ------------------------------------------------------------------------- */ void Update::reset_timestep(bigint newstep) { + if (newstep < 0) error->all(FLERR,"Timestep must be >= 0"); + + bigint oldstep = ntimestep; ntimestep = newstep; - if (ntimestep < 0) error->all(FLERR,"Timestep must be >= 0"); - // set atimestep to new timestep - // so future update_time() calls will be correct + // if newstep >= oldstep, update simulation time accordingly + // if newstep < oldstep, zero simulation time - atimestep = ntimestep; + if (newstep >= oldstep) update_time(); - // trigger reset of timestep for output - // do not allow any timestep-dependent fixes to be already defined + if (newstep < oldstep) { + atime = 0.0; + atimestep = newstep; + } + + // changes to output that depend on timestep output->reset_timestep(ntimestep); + // do not allow timestep-dependent fixes to be defined + for (const auto &ifix : modify->get_fix_list()) if (ifix->time_depend) error->all(FLERR, "Cannot reset timestep with time-dependent fix {} defined",ifix->style); @@ -508,7 +516,7 @@ void Update::reset_timestep(bigint newstep) if (icompute->timeflag) icompute->clearstep(); } - // Neighbor Bin/Stencil/Pair classes store timestamps that need to be cleared + // neighbor Bin/Stencil/Pair classes store timestamps that need to be cleared neighbor->reset_timestep(ntimestep); } From e2969d09e1c892db45041dd3b619c80ee2554d1a Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Thu, 9 Dec 2021 11:53:47 -0700 Subject: [PATCH 019/193] bug fix for fix dt/reset freq of 1 --- src/output.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/output.cpp b/src/output.cpp index 9cc90ed4b5..fff3942780 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -515,9 +515,9 @@ void Output::write_dump(bigint ntimestep) // do not re-evaulate variable for which = 2, leave nexttime as-is // unless next_time_dump < 0.0, which means variable never yet evaluated - if (which < 2 || next_time_dump[idump] < 0.0) + if (which < 2 || next_time_dump[idump] < 0.0) { nexttime = input->variable->compute_equal(ivar_dump[idump]); - else + } else nexttime = next_time_dump[idump]; if (nexttime <= tcurrent) @@ -671,17 +671,20 @@ void Output::reset_dt() { next_dump_any = MAXBIGINT; + bigint ntimestep = update->ntimestep; + for (int idump = 0; idump < ndump; idump++) { if (mode_dump[idump] == 1) { // reset next_dump for unchanged next_time_dump, 2 arg for reset_dt() - - calculate_next_dump(2,idump,update->ntimestep); - + // do not invoke for a dump already scheduled for this step // use compute_all() b/c don't know what computes will be needed - if (dump[idump]->clearstep || var_dump[idump]) - modify->addstep_compute_all(next_dump[idump]); + if (next_dump[idump] != ntimestep) { + calculate_next_dump(2,idump,update->ntimestep); + if (dump[idump]->clearstep || var_dump[idump]) + modify->addstep_compute_all(next_dump[idump]); + } } next_dump_any = MIN(next_dump_any,next_dump[idump]); From 5ead32f886d58454a8cc9001c7119aabb702358c Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Fri, 10 Dec 2021 11:13:06 -0700 Subject: [PATCH 020/193] more debugging and features --- src/dump.cpp | 2 ++ src/fix_dt_reset.cpp | 1 + src/input.cpp | 16 +++++++++++++ src/output.cpp | 53 ++++++++++++++++++-------------------------- src/update.cpp | 1 + src/verlet.cpp | 2 ++ 6 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/dump.cpp b/src/dump.cpp index df39f3738d..21c1b16f75 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -330,6 +330,8 @@ void Dump::write() if (delay_flag && update->ntimestep < delaystep) return; + printf("DUMP %ld\n",update->ntimestep); + // if file per timestep, open new file if (multifile) openfile(); diff --git a/src/fix_dt_reset.cpp b/src/fix_dt_reset.cpp index fbbe7d7c3e..b7ab63f2d7 100644 --- a/src/fix_dt_reset.cpp +++ b/src/fix_dt_reset.cpp @@ -198,6 +198,7 @@ void FixDtReset::end_of_step() 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; diff --git a/src/input.cpp b/src/input.cpp index 08f62bdb42..35b04946c0 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -1836,8 +1836,24 @@ void Input::timer_command() void Input::timestep() { if (narg != 1) error->all(FLERR,"Illegal timestep command"); + + update->update_time(); update->dt = utils::numeric(FLERR,arg[0],false,lmp); update->dt_default = 0; + + if (update->first_update == 0) return; + + // calls to other classes that need to know timestep size changed + // similar logic is in FixDtReset::end_of_step() + // only if a run has already occurred + + int respaflag = 0; + if (utils::strmatch(update->integrate_style, "^respa")) respaflag = 1; + if (respaflag) update->integrate->reset_dt(); + + if (force->pair) force->pair->reset_dt(); + for (int i = 0; i < modify->nfix; i++) modify->fix[i]->reset_dt(); + output->reset_dt(); } /* ---------------------------------------------------------------------- */ diff --git a/src/output.cpp b/src/output.cpp index fff3942780..d34aa8d3f7 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -565,42 +565,22 @@ void Output::write_restart(bigint ntimestep) /* ---------------------------------------------------------------------- timestep is being changed, called by update->reset_timestep() - reset next output values for dumps, restart, thermo output + for dumps, require that no dump is "active" + meaning that a snapshot has already been output + reset next output values restart and thermo output reset to smallest value >= new timestep if next timestep set by variable evaluation, eval for ntimestep-1, so current ntimestep can be returned if needed no guarantee that variable can be evaluated for ntimestep-1 - if it depends on computes, but live with that rare case for now + e.g. if it depends on computes, but live with that rare case for now ------------------------------------------------------------------------- */ void Output::reset_timestep(bigint ntimestep) { next_dump_any = MAXBIGINT; - for (int idump = 0; idump < ndump; idump++) { - if (every_dump[idump]) { - next_dump[idump] = (ntimestep/every_dump[idump])*every_dump[idump]; - if (next_dump[idump] < ntimestep) next_dump[idump] += every_dump[idump]; - } else { - // ivar_dump may not be initialized - if (ivar_dump[idump] < 0) { - ivar_dump[idump] = input->variable->find(var_dump[idump]); - if (ivar_dump[idump] < 0) - error->all(FLERR,"Variable name for dump every does not exist"); - if (!input->variable->equalstyle(ivar_dump[idump])) - error->all(FLERR,"Variable for dump every is invalid style"); - } - modify->clearstep_compute(); - update->ntimestep--; - bigint nextdump = static_cast - (input->variable->compute_equal(ivar_dump[idump])); - if (nextdump < ntimestep) - error->all(FLERR,"Dump every variable returned a bad timestep"); - update->ntimestep++; - next_dump[idump] = nextdump; - modify->addstep_compute(next_dump[idump]); - } - next_dump_any = MIN(next_dump_any,next_dump[idump]); - } + for (int idump = 0; idump < ndump; idump++) + if (last_dump[idump] >= 0) + error->all("Cannot reset timestep with active dump - must undump first"); if (restart_flag_single) { if (restart_every_single) { @@ -669,21 +649,30 @@ void Output::reset_timestep(bigint ntimestep) void Output::reset_dt() { - next_dump_any = MAXBIGINT; - bigint ntimestep = update->ntimestep; + next_dump_any = MAXBIGINT; + for (int idump = 0; idump < ndump; idump++) { if (mode_dump[idump] == 1) { - // reset next_dump for unchanged next_time_dump, 2 arg for reset_dt() + // reset next_dump but do not change next_time_dump, 2 arg for reset_dt() // do not invoke for a dump already scheduled for this step // use compute_all() b/c don't know what computes will be needed if (next_dump[idump] != ntimestep) { calculate_next_dump(2,idump,update->ntimestep); - if (dump[idump]->clearstep || var_dump[idump]) - modify->addstep_compute_all(next_dump[idump]); + + // NOTE: think I should not do this here + // for time dumps, calc_next_dump should calc the next timestep + // as one less and not add it to computes + // then on that step, write() should not actually write the dump + // but trigger it on next step and addstep_compute_all for that step + // b/c when write() is called, the next-step timestep is set + // unless run every timestep is invoked in-between! + + //if (dump[idump]->clearstep || var_dump[idump]) + // modify->addstep_compute_all(next_dump[idump]); } } diff --git a/src/update.cpp b/src/update.cpp index 10b4c573d7..da412ee89e 100644 --- a/src/update.cpp +++ b/src/update.cpp @@ -491,6 +491,7 @@ void Update::reset_timestep(bigint newstep) } // changes to output that depend on timestep + // no active dumps allowed output->reset_timestep(ntimestep); diff --git a/src/verlet.cpp b/src/verlet.cpp index 342dc3d951..348639ef05 100644 --- a/src/verlet.cpp +++ b/src/verlet.cpp @@ -252,6 +252,8 @@ void Verlet::run(int n) ntimestep = ++update->ntimestep; ev_set(ntimestep); + printf("VERLET %ld: %d %d\n",ntimestep,eflag,vflag); + // initial time integration timer->stamp(); From d33019d8e462f5fa1d28215516efd3d04134d1b8 Mon Sep 17 00:00:00 2001 From: J Todd Date: Thu, 2 Sep 2021 11:24:52 +0000 Subject: [PATCH 021/193] llvm anonymous struct workaround --- src/fmt/format-inl.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/fmt/format-inl.h b/src/fmt/format-inl.h index 8f2fe7354a..f7e3c6e063 100644 --- a/src/fmt/format-inl.h +++ b/src/fmt/format-inl.h @@ -1785,12 +1785,13 @@ inline bool divisible_by_power_of_5(uint64_t x, int exp) FMT_NOEXCEPT { // Precondition: n <= 2 * pow(5, N + 1). template bool check_divisibility_and_divide_by_pow5(uint32_t& n) FMT_NOEXCEPT { - static constexpr struct { + struct infos1 { uint32_t magic_number; int bits_for_comparison; uint32_t threshold; int shift_amount; - } infos[] = {{0xcccd, 16, 0x3333, 18}, {0xa429, 8, 0x0a, 20}}; + }; + static constexpr infos1 infos[] = {{0xcccd, 16, 0x3333, 18}, {0xa429, 8, 0x0a, 20}}; constexpr auto info = infos[N - 1]; n *= info.magic_number; const uint32_t comparison_mask = (1u << info.bits_for_comparison) - 1; @@ -1802,11 +1803,12 @@ bool check_divisibility_and_divide_by_pow5(uint32_t& n) FMT_NOEXCEPT { // Computes floor(n / pow(10, N)) for small n and N. // Precondition: n <= pow(10, N + 1). template uint32_t small_division_by_pow10(uint32_t n) FMT_NOEXCEPT { - static constexpr struct { + struct infos2 { uint32_t magic_number; int shift_amount; uint32_t divisor_times_10; - } infos[] = {{0xcccd, 19, 100}, {0xa3d8, 22, 1000}}; + }; + static constexpr infos2 infos[] = {{0xcccd, 19, 100}, {0xa3d8, 22, 1000}}; constexpr auto info = infos[N - 1]; FMT_ASSERT(n <= info.divisor_times_10, "n is too large"); return n * info.magic_number >> info.shift_amount; From 94ac1ad4a09154abc9b95f76bbacdbb6f5467ca9 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 13 Dec 2021 11:56:44 -0500 Subject: [PATCH 022/193] update version strings for the next patch release --- doc/lammps.1 | 2 +- src/version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/lammps.1 b/doc/lammps.1 index 78b6c9fd67..a374e62604 100644 --- a/doc/lammps.1 +++ b/doc/lammps.1 @@ -1,4 +1,4 @@ -.TH LAMMPS "1" "27 October 2021" "2021-10-27" +.TH LAMMPS "1" "14 December 2021" "2021-12-14" .SH NAME .B LAMMPS \- Molecular Dynamics Simulator. diff --git a/src/version.h b/src/version.h index 21f49398e0..6bb32291be 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define LAMMPS_VERSION "27 Oct 2021" +#define LAMMPS_VERSION "14 Dec 2021" From d4cec8ebe77b3eaf581d8853166081dffa43822f Mon Sep 17 00:00:00 2001 From: nw13slx Date: Mon, 13 Dec 2021 21:38:16 -0500 Subject: [PATCH 023/193] handle block reading in ReaderNative::read_atoms when binary is True --- src/reader_native.cpp | 60 ++++++++++++++++++++++++++++++------------- src/reader_native.h | 14 ++++++---- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/reader_native.cpp b/src/reader_native.cpp index 7c7d351d74..56a55c642e 100644 --- a/src/reader_native.cpp +++ b/src/reader_native.cpp @@ -68,6 +68,8 @@ int ReaderNative::read_time(bigint &ntimestep) delete[] unit_style; magic_string = nullptr; unit_style = nullptr; + ichunk = 0; + iatom_chunk = 0; fread(&ntimestep, sizeof(bigint), 1, fp); @@ -92,6 +94,7 @@ int ReaderNative::read_time(bigint &ntimestep) // read the real ntimestep read_buf(&ntimestep, sizeof(bigint), 1); } + } else { char *eof = fgets(line,MAXLINE,fp); if (eof == nullptr) return 1; @@ -125,7 +128,7 @@ void ReaderNative::skip() if (binary) { bigint natoms; int triclinic; - skip_buf(sizeof(bigint)); + read_buf(&natoms, sizeof(bigint), 1); read_buf(&triclinic, sizeof(int), 1); skip_buf((sizeof(int)+sizeof(double))*6); if (triclinic) { @@ -137,7 +140,6 @@ void ReaderNative::skip() // read chunk and skip them - int nchunk; read_buf(&nchunk, sizeof(int), 1); int n; @@ -461,25 +463,47 @@ void ReaderNative::read_atoms(int n, int nfield, double **fields) error->one(FLERR,"Unexpected end of dump file"); } + // if this is the beginning of the atom block + if (ichunk == 0 && iatom_chunk == 0) + read_buf(&nchunk, sizeof(int), 1); + + // read chunk and write as size_one values per line + // until end of timestep or end of the reading buffer int i_atom = 0; - int nchunk; - read_buf(&nchunk, sizeof(int), 1); - for (int i = 0; i < nchunk; i++) { + int m; + bool continue_reading = true; + bool continue_chunks = true; + while (continue_reading && continue_chunks){ - read_buf(&n, sizeof(int), 1); + // if the last chunk has finished + if (iatom_chunk == 0) { + read_buf(&natom_chunk, sizeof(int), 1); + read_double_chunk(natom_chunk); + natom_chunk /= size_one; + m = 0; + } - // read chunk and write as size_one values per line - read_double_chunk(n); - n /= size_one; - int m = 0; - for (int j = 0; j < n; j++) - { - double *words = &databuf[m]; - for (int k = 0; k < nfield; k++) - fields[i_atom][k] = words[fieldindex[k]]; - i_atom += 1; - m+=size_one; - } + // read one line of atom + double *words = &databuf[m]; + for (int k = 0; k < nfield; k++) + fields[i_atom][k] = words[fieldindex[k]]; + m+=size_one; + + iatom_chunk++; + i_atom++; + + // hit the end of current chunk + if (iatom_chunk == natom_chunk) + { + iatom_chunk = 0; + ichunk++; + } + + // hit the end of atom block + if (ichunk == nchunk) continue_chunks = false; + + // hit the end of the reading buffer + if (i_atom == n) continue_reading = false; } } else { diff --git a/src/reader_native.h b/src/reader_native.h index 2ca43039c2..e8107ec531 100644 --- a/src/reader_native.h +++ b/src/reader_native.h @@ -46,12 +46,16 @@ class ReaderNative : public Reader { char *unit_style; int *fieldindex; - char *line; // line read from dump file - double *databuf; // buffer for binary data - int nwords; // # of per-atom columns in dump file + char *line; // line read from dump file + double *databuf; // buffer for binary data + int nwords; // # of per-atom columns in dump file - int size_one; // number of double for one atom - int maxbuf; // maximum buffer size + int size_one; // number of double for one atom + int maxbuf; // maximum buffer size + int nchunk; // number of chunks in the binary file + int ichunk; // index of current reading chunk + int natom_chunk; // number of atoms in the current chunks + int iatom_chunk; // index of current atom in the current chunk int find_label(const std::string &label, const std::map &labels); void read_lines(int); From b1d0dd65ea07b9f7669a661dcdd9ddf06fd3c9ad Mon Sep 17 00:00:00 2001 From: nw13slx Date: Mon, 13 Dec 2021 22:57:39 -0500 Subject: [PATCH 024/193] simply the while loop and add correct initial m value --- src/reader_native.cpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/reader_native.cpp b/src/reader_native.cpp index 56a55c642e..8cacb8533b 100644 --- a/src/reader_native.cpp +++ b/src/reader_native.cpp @@ -469,12 +469,10 @@ void ReaderNative::read_atoms(int n, int nfield, double **fields) // read chunk and write as size_one values per line // until end of timestep or end of the reading buffer - int i_atom = 0; - int m; - bool continue_reading = true; - bool continue_chunks = true; - while (continue_reading && continue_chunks){ - + int m=size_one*iatom_chunk; + bool continue_reading = (n>0); + bool continue_chunks = (ichunk maxbuf) { memory->grow(databuf,count,"reader:databuf"); From 7c3deaa04b6b1e7d50385822331fd7097429fd53 Mon Sep 17 00:00:00 2001 From: nw13slx Date: Mon, 13 Dec 2021 23:03:10 -0500 Subject: [PATCH 025/193] limit the skip buf to MAXSMALLINT --- src/reader_native.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/reader_native.cpp b/src/reader_native.cpp index 8cacb8533b..933944b05f 100644 --- a/src/reader_native.cpp +++ b/src/reader_native.cpp @@ -126,9 +126,8 @@ int ReaderNative::read_time(bigint &ntimestep) void ReaderNative::skip() { if (binary) { - bigint natoms; int triclinic; - read_buf(&natoms, sizeof(bigint), 1); + skip_buf(sizeof(bigint)); read_buf(&triclinic, sizeof(int), 1); skip_buf((sizeof(int)+sizeof(double))*6); if (triclinic) { @@ -145,7 +144,13 @@ void ReaderNative::skip() int n; for (int i = 0; i < nchunk; i++) { read_buf(&n, sizeof(int), 1); - skip_buf(n*sizeof(double)); + int nremain = n; + int nbuf; + while (nremain){ + nbuf = MIN(nremain,MAXSMALLINT); + skip_buf(nbuf*sizeof(double)); + nremain -= nbuf; + } } } else { From 91633a4460698c9f177a7bd637705e1e2237f4c6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 14 Dec 2021 06:59:03 -0500 Subject: [PATCH 026/193] make workaround easier to disable and to remove --- src/fmt/format-inl.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/fmt/format-inl.h b/src/fmt/format-inl.h index f7e3c6e063..ada59683b2 100644 --- a/src/fmt/format-inl.h +++ b/src/fmt/format-inl.h @@ -1780,11 +1780,13 @@ inline bool divisible_by_power_of_5(uint64_t x, int exp) FMT_NOEXCEPT { data::divtest_table_for_pow5_64[exp].max_quotient; } +#define LAMMPS_WORKAROUND_FOR_DPCXX 1 // Replaces n by floor(n / pow(5, N)) returning true if and only if n is // divisible by pow(5, N). // Precondition: n <= 2 * pow(5, N + 1). template bool check_divisibility_and_divide_by_pow5(uint32_t& n) FMT_NOEXCEPT { +#if defined(LAMMPS_WORKAROUND_FOR_DPCXX) struct infos1 { uint32_t magic_number; int bits_for_comparison; @@ -1792,6 +1794,14 @@ bool check_divisibility_and_divide_by_pow5(uint32_t& n) FMT_NOEXCEPT { int shift_amount; }; static constexpr infos1 infos[] = {{0xcccd, 16, 0x3333, 18}, {0xa429, 8, 0x0a, 20}}; +#else + static constexpr struct { + uint32_t magic_number; + int bits_for_comparison; + uint32_t threshold; + int shift_amount; + } infos[] = {{0xcccd, 16, 0x3333, 18}, {0xa429, 8, 0x0a, 20}}; +#endif constexpr auto info = infos[N - 1]; n *= info.magic_number; const uint32_t comparison_mask = (1u << info.bits_for_comparison) - 1; @@ -1803,12 +1813,20 @@ bool check_divisibility_and_divide_by_pow5(uint32_t& n) FMT_NOEXCEPT { // Computes floor(n / pow(10, N)) for small n and N. // Precondition: n <= pow(10, N + 1). template uint32_t small_division_by_pow10(uint32_t n) FMT_NOEXCEPT { +#if defined(LAMMPS_WORKAROUND_FOR_DPCXX) struct infos2 { uint32_t magic_number; int shift_amount; uint32_t divisor_times_10; }; static constexpr infos2 infos[] = {{0xcccd, 19, 100}, {0xa3d8, 22, 1000}}; +#else + static constexpr struct { + uint32_t magic_number; + int shift_amount; + uint32_t divisor_times_10; + } infos[] = {{0xcccd, 19, 100}, {0xa3d8, 22, 1000}}; +#endif constexpr auto info = infos[N - 1]; FMT_ASSERT(n <= info.divisor_times_10, "n is too large"); return n * info.magic_number >> info.shift_amount; From 80819f37931b0a1b674422985efa3c26c12fb6aa Mon Sep 17 00:00:00 2001 From: nw13slx Date: Tue, 14 Dec 2021 11:09:36 -0500 Subject: [PATCH 027/193] reverse skip_buf with chunk --- src/reader_native.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/reader_native.cpp b/src/reader_native.cpp index 933944b05f..10cd1f47a4 100644 --- a/src/reader_native.cpp +++ b/src/reader_native.cpp @@ -144,13 +144,7 @@ void ReaderNative::skip() int n; for (int i = 0; i < nchunk; i++) { read_buf(&n, sizeof(int), 1); - int nremain = n; - int nbuf; - while (nremain){ - nbuf = MIN(nremain,MAXSMALLINT); - skip_buf(nbuf*sizeof(double)); - nremain -= nbuf; - } + skip_buf(n*sizeof(double)); } } else { From 5051055c76046f667f649d7761b710858cc94dba Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Tue, 14 Dec 2021 14:33:17 -0500 Subject: [PATCH 028/193] Remove dead code and move nchunk read to read_header --- src/reader_native.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/reader_native.cpp b/src/reader_native.cpp index 10cd1f47a4..dd1a032bda 100644 --- a/src/reader_native.cpp +++ b/src/reader_native.cpp @@ -68,8 +68,6 @@ int ReaderNative::read_time(bigint &ntimestep) delete[] unit_style; magic_string = nullptr; unit_style = nullptr; - ichunk = 0; - iatom_chunk = 0; fread(&ntimestep, sizeof(bigint), 1, fp); @@ -268,6 +266,10 @@ bigint ReaderNative::read_header(double box[3][3], int &boxinfo, int &triclinic, read_buf(labelline, sizeof(char), len); labelline[len] = '\0'; } + + read_buf(&nchunk, sizeof(int), 1); + ichunk = 0; + iatom_chunk = 0; } else { int rv; @@ -462,16 +464,10 @@ void ReaderNative::read_atoms(int n, int nfield, double **fields) error->one(FLERR,"Unexpected end of dump file"); } - // if this is the beginning of the atom block - if (ichunk == 0 && iatom_chunk == 0) - read_buf(&nchunk, sizeof(int), 1); + // read chunks until n atoms have been read + int m = size_one*iatom_chunk; - // read chunk and write as size_one values per line - // until end of timestep or end of the reading buffer - int m=size_one*iatom_chunk; - bool continue_reading = (n>0); - bool continue_chunks = (ichunk Date: Tue, 14 Dec 2021 14:50:38 -0500 Subject: [PATCH 029/193] whitespace --- src/reader_native.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/reader_native.cpp b/src/reader_native.cpp index dd1a032bda..b029b2fe37 100644 --- a/src/reader_native.cpp +++ b/src/reader_native.cpp @@ -486,10 +486,9 @@ void ReaderNative::read_atoms(int n, int nfield, double **fields) iatom_chunk++; - // hit the end of current chunk - if (iatom_chunk == natom_chunk) - { - iatom_chunk = 0; + // hit the end of current chunk + if (iatom_chunk == natom_chunk) { + iatom_chunk = 0; ichunk++; } } From 902f9dd1fa8be9a6eb5f1f6010daf44dc5af56fe Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Wed, 15 Dec 2021 15:05:59 -0500 Subject: [PATCH 030/193] Move allocation to correct location --- src/reader_native.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/reader_native.cpp b/src/reader_native.cpp index b029b2fe37..e577bd240f 100644 --- a/src/reader_native.cpp +++ b/src/reader_native.cpp @@ -212,7 +212,7 @@ bigint ReaderNative::read_header(double box[3][3], int &boxinfo, int &triclinic, { bigint natoms = 0; int len = 0; - char *labelline; + char *labelline = nullptr; if (binary) { read_buf(&natoms, sizeof(bigint), 1); @@ -245,7 +245,6 @@ bigint ReaderNative::read_header(double box[3][3], int &boxinfo, int &triclinic, // newer format includes units string, columns string // and time read_buf(&len, sizeof(int), 1); - labelline = new char[len + 1]; if (len > 0) { // has units @@ -263,6 +262,7 @@ bigint ReaderNative::read_header(double box[3][3], int &boxinfo, int &triclinic, } read_buf(&len, sizeof(int), 1); + labelline = new char[len + 1]; read_buf(labelline, sizeof(char), len); labelline[len] = '\0'; } From 884dcbe4fac486ed4101d39ad3680018bc61361e Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Wed, 15 Dec 2021 16:09:48 -0500 Subject: [PATCH 031/193] Refactor reader_native.cpp - Use std::string instead of error-prone char buffers - Limit reading files to known magic strings DUMPATOM and DUMPCUSTOM --- src/reader_native.cpp | 46 +++++++++++++++++++++++-------------------- src/reader_native.h | 7 +++++-- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/reader_native.cpp b/src/reader_native.cpp index e577bd240f..7be546719f 100644 --- a/src/reader_native.cpp +++ b/src/reader_native.cpp @@ -38,8 +38,6 @@ ReaderNative::ReaderNative(LAMMPS *lmp) : Reader(lmp) fieldindex = nullptr; maxbuf = 0; databuf = nullptr; - magic_string = nullptr; - unit_style = nullptr; } /* ---------------------------------------------------------------------- */ @@ -47,8 +45,6 @@ ReaderNative::ReaderNative(LAMMPS *lmp) : Reader(lmp) ReaderNative::~ReaderNative() { delete[] line; - delete[] magic_string; - delete[] unit_style; memory->destroy(fieldindex); memory->destroy(databuf); } @@ -64,10 +60,8 @@ int ReaderNative::read_time(bigint &ntimestep) if (binary) { int endian = 0x0001; revision = 0x0001; - delete[] magic_string; - delete[] unit_style; - magic_string = nullptr; - unit_style = nullptr; + magic_string = ""; + unit_style = ""; fread(&ntimestep, sizeof(bigint), 1, fp); @@ -79,9 +73,7 @@ int ReaderNative::read_time(bigint &ntimestep) // first bigint encodes negative format name length bigint magic_string_len = -ntimestep; - magic_string = new char[magic_string_len + 1]; - read_buf(magic_string, sizeof(char), magic_string_len); - magic_string[magic_string_len] = '\0'; + magic_string = read_binary_str(magic_string_len); // read endian flag read_buf(&endian, sizeof(int), 1); @@ -168,7 +160,7 @@ void ReaderNative::skip() void ReaderNative::skip_reading_magic_str() { - if (magic_string && revision > 0x0001) { + if (is_known_magic_str() && revision > 0x0001) { int len; read_buf(&len, sizeof(int), 1); @@ -212,7 +204,7 @@ bigint ReaderNative::read_header(double box[3][3], int &boxinfo, int &triclinic, { bigint natoms = 0; int len = 0; - char *labelline = nullptr; + std::string labelline; if (binary) { read_buf(&natoms, sizeof(bigint), 1); @@ -241,16 +233,15 @@ bigint ReaderNative::read_header(double box[3][3], int &boxinfo, int &triclinic, return natoms; } - if (magic_string && revision > 0x0001) { + + if (is_known_magic_str() && revision > 0x0001) { // newer format includes units string, columns string // and time read_buf(&len, sizeof(int), 1); if (len > 0) { // has units - unit_style = new char[len + 1]; - read_buf(unit_style, sizeof(char), len); - unit_style[len] = '\0'; + unit_style = read_binary_str(len); } char flag = 0; @@ -262,9 +253,9 @@ bigint ReaderNative::read_header(double box[3][3], int &boxinfo, int &triclinic, } read_buf(&len, sizeof(int), 1); - labelline = new char[len + 1]; - read_buf(labelline, sizeof(char), len); - labelline[len] = '\0'; + labelline = read_binary_str(len); + } else { + error->one(FLERR, "Unsupported old binary dump format"); } read_buf(&nchunk, sizeof(int), 1); @@ -310,14 +301,15 @@ bigint ReaderNative::read_header(double box[3][3], int &boxinfo, int &triclinic, labelline = &line[strlen("ITEM: ATOMS ")]; } - std::map labels; Tokenizer tokens(labelline); + std::map labels; nwords = 0; while (tokens.has_next()) { labels[tokens.next()] = nwords++; } + if (nwords == 0) { return 1; } @@ -549,6 +541,13 @@ void ReaderNative::read_buf(void * ptr, size_t size, size_t count) if (feof(fp)) error->one(FLERR,"Unexpected end of dump file"); } +std::string ReaderNative::read_binary_str(size_t size) +{ + std::string str(size, '\0'); + read_buf(&str[0], sizeof(char), size); + return str; +} + void ReaderNative::read_double_chunk(size_t count) { if (count < 0) return; @@ -566,3 +565,8 @@ void ReaderNative::skip_buf(size_t size) pos += size; platform::fseek(fp,pos); } + +bool ReaderNative::is_known_magic_str() const +{ + return magic_string == "DUMPATOM" || magic_string == "DUMPCUSTOM"; +} diff --git a/src/reader_native.h b/src/reader_native.h index e8107ec531..c07dbbac08 100644 --- a/src/reader_native.h +++ b/src/reader_native.h @@ -24,6 +24,7 @@ ReaderStyle(native,ReaderNative); #include "reader.h" +#include #include namespace LAMMPS_NS { @@ -42,8 +43,8 @@ class ReaderNative : public Reader { private: int revision; - char *magic_string; - char *unit_style; + std::string magic_string; + std::string unit_style; int *fieldindex; char *line; // line read from dump file @@ -64,6 +65,8 @@ class ReaderNative : public Reader { void read_double_chunk(size_t); void skip_buf(size_t); void skip_reading_magic_str(); + bool is_known_magic_str() const; + std::string read_binary_str(size_t); }; } // namespace LAMMPS_NS From d04f428c1af11ef6381e1fc940a7c777428294e6 Mon Sep 17 00:00:00 2001 From: Luthaf Date: Fri, 17 Dec 2021 10:54:43 +0100 Subject: [PATCH 032/193] netcdf: default to float variable for everything The standard convention require all values to be stored as float, users still have the ability to use double with `dump_modify double yes` --- src/NETCDF/dump_netcdf.cpp | 25 +++++++++++++------------ src/NETCDF/dump_netcdf.h | 2 +- src/NETCDF/dump_netcdf_mpiio.cpp | 24 +++++++++++++----------- src/NETCDF/dump_netcdf_mpiio.h | 2 +- 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/NETCDF/dump_netcdf.cpp b/src/NETCDF/dump_netcdf.cpp index 5f30c941ca..2ad952e885 100644 --- a/src/NETCDF/dump_netcdf.cpp +++ b/src/NETCDF/dump_netcdf.cpp @@ -181,7 +181,7 @@ DumpNetCDF::DumpNetCDF(LAMMPS *lmp, int narg, char **arg) : int_buffer = nullptr; double_buffer = nullptr; - double_precision = false; + type_nc_real = NC_FLOAT; thermo = false; thermovar = nullptr; @@ -381,14 +381,14 @@ void DumpNetCDF::openfile() NCERRX( nc_def_var(ncid, NC_CELL_ANGULAR_STR, NC_CHAR, 2, dims, &cell_angular_var), NC_CELL_ANGULAR_STR ); dims[0] = frame_dim; - NCERRX( nc_def_var(ncid, NC_TIME_STR, NC_DOUBLE, 1, dims, &time_var), NC_TIME_STR); + NCERRX( nc_def_var(ncid, NC_TIME_STR, type_nc_real, 1, dims, &time_var), NC_TIME_STR); dims[0] = frame_dim; dims[1] = cell_spatial_dim; - NCERRX( nc_def_var(ncid, NC_CELL_ORIGIN_STR, NC_DOUBLE, 2, dims, &cell_origin_var), NC_CELL_ORIGIN_STR ); - NCERRX( nc_def_var(ncid, NC_CELL_LENGTHS_STR, NC_DOUBLE, 2, dims, &cell_lengths_var), NC_CELL_LENGTHS_STR ); + NCERRX( nc_def_var(ncid, NC_CELL_ORIGIN_STR, type_nc_real, 2, dims, &cell_origin_var), NC_CELL_ORIGIN_STR ); + NCERRX( nc_def_var(ncid, NC_CELL_LENGTHS_STR, type_nc_real, 2, dims, &cell_lengths_var), NC_CELL_LENGTHS_STR ); dims[0] = frame_dim; dims[1] = cell_angular_dim; - NCERRX( nc_def_var(ncid, NC_CELL_ANGLES_STR, NC_DOUBLE, 2, dims, &cell_angles_var), NC_CELL_ANGLES_STR ); + NCERRX( nc_def_var(ncid, NC_CELL_ANGLES_STR, type_nc_real, 2, dims, &cell_angles_var), NC_CELL_ANGLES_STR ); // variables specified in the input file dims[0] = frame_dim; @@ -397,7 +397,6 @@ void DumpNetCDF::openfile() for (int i = 0; i < n_perat; i++) { nc_type xtype; - // Type mangling if (vtype[perat[i].field[0]] == Dump::INT) { xtype = NC_INT; @@ -406,10 +405,7 @@ void DumpNetCDF::openfile() } else if (vtype[perat[i].field[0]] == Dump::STRING) { error->all(FLERR,"Dump netcdf currently does not support dumping string properties"); } else { - if (double_precision) - xtype = NC_DOUBLE; - else - xtype = NC_FLOAT; + xtype = type_nc_real; } if (perat[i].constant) { @@ -437,7 +433,7 @@ void DumpNetCDF::openfile() Thermo *th = output->thermo; for (int i = 0; i < th->nfield; i++) { if (th->vtype[i] == Thermo::FLOAT) { - NCERRX( nc_def_var(ncid, th->keyword[i], NC_DOUBLE, 1, dims, + NCERRX( nc_def_var(ncid, th->keyword[i], type_nc_real, 1, dims, &thermovar[i]), th->keyword[i] ); } else if (th->vtype[i] == Thermo::INT) { NCERRX( nc_def_var(ncid, th->keyword[i], NC_INT, 1, dims, @@ -872,7 +868,12 @@ int DumpNetCDF::modify_param(int narg, char **arg) if (strcmp(arg[iarg],"double") == 0) { iarg++; if (iarg >= narg) error->all(FLERR,"expected 'yes' or 'no' after 'double' keyword."); - double_precision = utils::logical(FLERR,arg[iarg],false,lmp) == 1; + + if (utils::logical(FLERR,arg[iarg],false,lmp) == 1) + type_nc_real = NC_DOUBLE; + else + type_nc_real = NC_FLOAT; + iarg++; return 2; } else if (strcmp(arg[iarg],"at") == 0) { diff --git a/src/NETCDF/dump_netcdf.h b/src/NETCDF/dump_netcdf.h index dd9c50873e..b3bd055701 100644 --- a/src/NETCDF/dump_netcdf.h +++ b/src/NETCDF/dump_netcdf.h @@ -62,7 +62,7 @@ class DumpNetCDF : public DumpCustom { int *thermovar; // NetCDF variables for thermo output - bool double_precision; // write everything as double precision + int type_nc_real; // netcdf type to use for real variables: float or double bool thermo; // write thermo output to netcdf file bigint n_buffer; // size of buffer diff --git a/src/NETCDF/dump_netcdf_mpiio.cpp b/src/NETCDF/dump_netcdf_mpiio.cpp index 0a76203f96..8241d159ae 100644 --- a/src/NETCDF/dump_netcdf_mpiio.cpp +++ b/src/NETCDF/dump_netcdf_mpiio.cpp @@ -179,7 +179,7 @@ DumpNetCDFMPIIO::DumpNetCDFMPIIO(LAMMPS *lmp, int narg, char **arg) : int_buffer = nullptr; double_buffer = nullptr; - double_precision = false; + type_nc_real = NC_FLOAT; thermo = false; thermovar = nullptr; @@ -382,14 +382,14 @@ void DumpNetCDFMPIIO::openfile() NCERRX( ncmpi_def_var(ncid, NC_CELL_ANGULAR_STR, NC_CHAR, 2, dims, &cell_angular_var), NC_CELL_ANGULAR_STR ); dims[0] = frame_dim; - NCERRX( ncmpi_def_var(ncid, NC_TIME_STR, NC_DOUBLE, 1, dims, &time_var), NC_TIME_STR); + NCERRX( ncmpi_def_var(ncid, NC_TIME_STR, type_nc_real, 1, dims, &time_var), NC_TIME_STR); dims[0] = frame_dim; dims[1] = cell_spatial_dim; - NCERRX( ncmpi_def_var(ncid, NC_CELL_ORIGIN_STR, NC_DOUBLE, 2, dims, &cell_origin_var), NC_CELL_ORIGIN_STR ); - NCERRX( ncmpi_def_var(ncid, NC_CELL_LENGTHS_STR, NC_DOUBLE, 2, dims, &cell_lengths_var), NC_CELL_LENGTHS_STR ); + NCERRX( ncmpi_def_var(ncid, NC_CELL_ORIGIN_STR, type_nc_real, 2, dims, &cell_origin_var), NC_CELL_ORIGIN_STR ); + NCERRX( ncmpi_def_var(ncid, NC_CELL_LENGTHS_STR, type_nc_real, 2, dims, &cell_lengths_var), NC_CELL_LENGTHS_STR ); dims[0] = frame_dim; dims[1] = cell_angular_dim; - NCERRX( ncmpi_def_var(ncid, NC_CELL_ANGLES_STR, NC_DOUBLE, 2, dims, &cell_angles_var), NC_CELL_ANGLES_STR ); + NCERRX( ncmpi_def_var(ncid, NC_CELL_ANGLES_STR, type_nc_real, 2, dims, &cell_angles_var), NC_CELL_ANGLES_STR ); // variables specified in the input file dims[0] = frame_dim; @@ -405,10 +405,7 @@ void DumpNetCDFMPIIO::openfile() } else if (vtype[perat[i].field[0]] == Dump::BIGINT) { xtype = NC_INT64; } else { - if (double_precision) - xtype = NC_DOUBLE; - else - xtype = NC_FLOAT; + xtype = type_nc_real; } if (perat[i].dims == 1) { @@ -425,7 +422,7 @@ void DumpNetCDFMPIIO::openfile() Thermo *th = output->thermo; for (int i = 0; i < th->nfield; i++) { if (th->vtype[i] == Thermo::FLOAT) { - NCERRX( ncmpi_def_var(ncid, th->keyword[i], NC_DOUBLE, 1, dims, &thermovar[i]), th->keyword[i] ); + NCERRX( ncmpi_def_var(ncid, th->keyword[i], type_nc_real, 1, dims, &thermovar[i]), th->keyword[i] ); } else if (th->vtype[i] == Thermo::INT) { NCERRX( ncmpi_def_var(ncid, th->keyword[i], NC_INT, 1, dims, &thermovar[i]), th->keyword[i] ); } else if (th->vtype[i] == Thermo::BIGINT) { @@ -867,7 +864,12 @@ int DumpNetCDFMPIIO::modify_param(int narg, char **arg) if (strcmp(arg[iarg],"double") == 0) { iarg++; if (iarg >= narg) error->all(FLERR,"expected 'yes' or 'no' after 'double' keyword."); - double_precision = utils::logical(FLERR,arg[iarg],false,lmp) == 1; + + if (utils::logical(FLERR,arg[iarg],false,lmp) == 1) + type_nc_real = NC_DOUBLE; + else + type_nc_real = NC_FLOAT; + iarg++; return 2; } else if (strcmp(arg[iarg],"at") == 0) { diff --git a/src/NETCDF/dump_netcdf_mpiio.h b/src/NETCDF/dump_netcdf_mpiio.h index 56c07fc3d3..d1fb4fd364 100644 --- a/src/NETCDF/dump_netcdf_mpiio.h +++ b/src/NETCDF/dump_netcdf_mpiio.h @@ -61,7 +61,7 @@ class DumpNetCDFMPIIO : public DumpCustom { int *thermovar; // NetCDF variables for thermo output - bool double_precision; // write everything as double precision + int type_nc_real; // netcdf type to use for real variables: float or double bool thermo; // write thermo output to netcdf file bigint n_buffer; // size of buffer From 4bf065ed1c43e28fae33893aa122339639ab9e98 Mon Sep 17 00:00:00 2001 From: Luthaf Date: Fri, 17 Dec 2021 10:55:54 +0100 Subject: [PATCH 033/193] netcdf: use float values for scale factors instead of double --- src/NETCDF/dump_netcdf.cpp | 8 ++++---- src/NETCDF/dump_netcdf_mpiio.cpp | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/NETCDF/dump_netcdf.cpp b/src/NETCDF/dump_netcdf.cpp index 2ad952e885..37e99a1a58 100644 --- a/src/NETCDF/dump_netcdf.cpp +++ b/src/NETCDF/dump_netcdf.cpp @@ -341,7 +341,7 @@ void DumpNetCDF::openfile() int dims[NC_MAX_VAR_DIMS]; size_t index[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS]; - double d[1]; + float d[1]; if (singlefile_opened) return; singlefile_opened = 1; @@ -489,11 +489,11 @@ void DumpNetCDF::openfile() NCERR( nc_put_att_text(ncid, cell_angles_var, NC_UNITS_STR,6, "degree") ); d[0] = update->dt; - NCERR( nc_put_att_double(ncid, time_var, NC_SCALE_FACTOR_STR,NC_DOUBLE, 1, d) ); + NCERR( nc_put_att_float(ncid, time_var, NC_SCALE_FACTOR_STR, NC_FLOAT, 1, d) ); d[0] = 1.0; - NCERR( nc_put_att_double(ncid, cell_origin_var, NC_SCALE_FACTOR_STR,NC_DOUBLE, 1, d) ); + NCERR( nc_put_att_float(ncid, cell_origin_var, NC_SCALE_FACTOR_STR, NC_FLOAT, 1, d) ); d[0] = 1.0; - NCERR( nc_put_att_double(ncid, cell_lengths_var, NC_SCALE_FACTOR_STR,NC_DOUBLE, 1, d) ); + NCERR( nc_put_att_float(ncid, cell_lengths_var, NC_SCALE_FACTOR_STR, NC_FLOAT, 1, d) ); /* * Finished with definition diff --git a/src/NETCDF/dump_netcdf_mpiio.cpp b/src/NETCDF/dump_netcdf_mpiio.cpp index 8241d159ae..441cc97bd2 100644 --- a/src/NETCDF/dump_netcdf_mpiio.cpp +++ b/src/NETCDF/dump_netcdf_mpiio.cpp @@ -276,7 +276,6 @@ void DumpNetCDFMPIIO::openfile() error->all(FLERR, "cannot append to non-existent file {}", filecurrent); MPI_Offset index[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS]; - double d[1]; if (singlefile_opened) return; singlefile_opened = 1; @@ -342,7 +341,7 @@ void DumpNetCDFMPIIO::openfile() int dims[NC_MAX_VAR_DIMS]; MPI_Offset index[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS]; - double d[1]; + float d[1]; if (singlefile_opened) return; singlefile_opened = 1; @@ -474,11 +473,11 @@ void DumpNetCDFMPIIO::openfile() NCERR( ncmpi_put_att_text(ncid, cell_angles_var, NC_UNITS_STR, 6, "degree") ); d[0] = update->dt; - NCERR( ncmpi_put_att_double(ncid, time_var, NC_SCALE_FACTOR_STR, NC_DOUBLE, 1, d) ); + NCERR( ncmpi_put_att_float(ncid, time_var, NC_SCALE_FACTOR_STR, NC_FLOAT, 1, d) ); d[0] = 1.0; - NCERR( ncmpi_put_att_double(ncid, cell_origin_var, NC_SCALE_FACTOR_STR, NC_DOUBLE, 1, d) ); + NCERR( ncmpi_put_att_float(ncid, cell_origin_var, NC_SCALE_FACTOR_STR, NC_FLOAT, 1, d) ); d[0] = 1.0; - NCERR( ncmpi_put_att_double(ncid, cell_lengths_var, NC_SCALE_FACTOR_STR, NC_DOUBLE, 1, d) ); + NCERR( ncmpi_put_att_float(ncid, cell_lengths_var, NC_SCALE_FACTOR_STR, NC_FLOAT, 1, d) ); /* * Finished with definition From dc9d539b6c59a84fbdc29079a377b9f341f6dde3 Mon Sep 17 00:00:00 2001 From: Luthaf Date: Fri, 17 Dec 2021 11:48:06 +0100 Subject: [PATCH 034/193] netcdf: fix spatial, cell_spatial and cell_angular variable definitions Dimension 0 refered to the frame dimension, but we need the spatial dimension instead --- src/NETCDF/dump_netcdf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NETCDF/dump_netcdf.cpp b/src/NETCDF/dump_netcdf.cpp index 37e99a1a58..d64ebc6581 100644 --- a/src/NETCDF/dump_netcdf.cpp +++ b/src/NETCDF/dump_netcdf.cpp @@ -373,10 +373,10 @@ void DumpNetCDF::openfile() } // default variables - dims[0] = 0; + dims[0] = vector_dim[3]; NCERRX( nc_def_var(ncid, NC_SPATIAL_STR, NC_CHAR, 1, dims, &spatial_var), NC_SPATIAL_STR ); NCERRX( nc_def_var(ncid, NC_CELL_SPATIAL_STR, NC_CHAR, 1, dims, &cell_spatial_var), NC_CELL_SPATIAL_STR ); - dims[0] = 0; + dims[0] = vector_dim[3]; dims[1] = label_dim; NCERRX( nc_def_var(ncid, NC_CELL_ANGULAR_STR, NC_CHAR, 2, dims, &cell_angular_var), NC_CELL_ANGULAR_STR ); From f8ee6dc680b5d291aae091db81605d2beb89c67d Mon Sep 17 00:00:00 2001 From: Luthaf Date: Fri, 17 Dec 2021 11:41:04 +0100 Subject: [PATCH 035/193] netcf: define units for all variable where this is possible --- src/NETCDF/dump_netcdf.cpp | 149 +++++++++++++++++++++++-------- src/NETCDF/dump_netcdf.h | 14 +++ src/NETCDF/dump_netcdf_mpiio.cpp | 136 +++++++++++++++++++++------- src/NETCDF/dump_netcdf_mpiio.h | 14 +++ 4 files changed, 243 insertions(+), 70 deletions(-) diff --git a/src/NETCDF/dump_netcdf.cpp b/src/NETCDF/dump_netcdf.cpp index d64ebc6581..8f5d6f9efd 100644 --- a/src/NETCDF/dump_netcdf.cpp +++ b/src/NETCDF/dump_netcdf.cpp @@ -101,6 +101,7 @@ DumpNetCDF::DumpNetCDF(LAMMPS *lmp, int narg, char **arg) : int idim = 0; int ndims = 1; std::string mangled = earg[i]; + Quantity quantity = Quantity::Unknown; bool constant = false; // name mangling @@ -109,26 +110,32 @@ DumpNetCDF::DumpNetCDF(LAMMPS *lmp, int narg, char **arg) : idim = mangled[0] - 'x'; ndims = 3; mangled = "coordinates"; + quantity = Quantity::Distance; } else if ((mangled == "vx") || (mangled == "vy") || (mangled == "vz")) { idim = mangled[1] - 'x'; ndims = 3; mangled = "velocities"; + quantity = Quantity::Velocity; } else if ((mangled == "xs") || (mangled == "ys") || (mangled == "zs")) { idim = mangled[0] - 'x'; ndims = 3; mangled = "scaled_coordinates"; + // no unit for scaled coordinates } else if ((mangled == "xu") || (mangled == "yu") || (mangled == "zu")) { idim = mangled[0] - 'x'; ndims = 3; mangled = "unwrapped_coordinates"; + quantity = Quantity::Distance; } else if ((mangled == "fx") || (mangled == "fy") || (mangled == "fz")) { idim = mangled[1] - 'x'; ndims = 3; mangled = "forces"; + quantity = Quantity::Force; } else if ((mangled == "mux") || (mangled == "muy") || (mangled == "muz")) { idim = mangled[2] - 'x'; ndims = 3; mangled = "mu"; + quantity = Quantity::DipoleMoment; } else if (utils::strmatch(mangled, "^c_")) { std::size_t found = mangled.find('['); if (found != std::string::npos) { @@ -175,6 +182,7 @@ DumpNetCDF::DumpNetCDF(LAMMPS *lmp, int narg, char **arg) : perat[inc].constant = constant; perat[inc].ndumped = 0; perat[inc].field[idim] = i; + perat[inc].quantity = quantity; } n_buffer = 0; @@ -341,7 +349,6 @@ void DumpNetCDF::openfile() int dims[NC_MAX_VAR_DIMS]; size_t index[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS]; - float d[1]; if (singlefile_opened) return; singlefile_opened = 1; @@ -426,6 +433,11 @@ void DumpNetCDF::openfile() NCERRX( nc_def_var(ncid, perat[i].name, xtype, 3, dims, &perat[i].var), perat[i].name ); } } + + std::string unit = this->unit_of(perat[i].quantity); + if (!unit.empty()) { + NCERR( nc_put_att_text(ncid, perat[i].var, NC_UNITS_STR, unit.size(), unit.c_str()) ); + } } // perframe variables @@ -457,43 +469,18 @@ void DumpNetCDF::openfile() NCERR( nc_put_att_text(ncid, NC_GLOBAL, "program", 6, "LAMMPS") ); NCERR( nc_put_att_text(ncid, NC_GLOBAL, "programVersion",strlen(lmp->version), lmp->version) ); - // units - if (!strcmp(update->unit_style, "lj")) { - NCERR( nc_put_att_text(ncid, time_var, NC_UNITS_STR, 2, "lj") ); - NCERR( nc_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, 2, "lj") ); - NCERR( nc_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, 2, "lj") ); - } else if (!strcmp(update->unit_style, "real")) { - NCERR( nc_put_att_text(ncid, time_var, NC_UNITS_STR, 11, "femtosecond") ); - NCERR( nc_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, 8, "Angstrom") ); - NCERR( nc_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, 8, "Angstrom") ); - } else if (!strcmp(update->unit_style, "metal")) { - NCERR( nc_put_att_text(ncid, time_var, NC_UNITS_STR, 10, "picosecond") ); - NCERR( nc_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, 8, "Angstrom") ); - NCERR( nc_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, 8, "Angstrom") ); - } else if (!strcmp(update->unit_style, "si")) { - NCERR( nc_put_att_text(ncid, time_var, NC_UNITS_STR, 6, "second") ); - NCERR( nc_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, 5, "meter") ); - NCERR( nc_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, 5, "meter") ); - } else if (!strcmp(update->unit_style, "cgs")) { - NCERR( nc_put_att_text(ncid, time_var, NC_UNITS_STR, 6, "second") ); - NCERR( nc_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, 10, "centimeter") ); - NCERR( nc_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, 10, "centimeter") ); - } else if (!strcmp(update->unit_style, "electron")) { - NCERR( nc_put_att_text(ncid, time_var, NC_UNITS_STR, 11, "femtosecond") ); - NCERR( nc_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, 4, "Bohr") ); - NCERR( nc_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, 4, "Bohr") ); - } else { - error->all(FLERR,"Unsupported unit style: {}", update->unit_style); - } + // units & scale + std::string unit = this->unit_of(Quantity::Time); + NCERR( nc_put_att_text(ncid, time_var, NC_UNITS_STR, unit.size(), unit.c_str()) ); - NCERR( nc_put_att_text(ncid, cell_angles_var, NC_UNITS_STR,6, "degree") ); + unit = this->unit_of(Quantity::Distance); + NCERR( nc_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, unit.size(), unit.c_str()) ); + NCERR( nc_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, unit.size(), unit.c_str()) ); - d[0] = update->dt; - NCERR( nc_put_att_float(ncid, time_var, NC_SCALE_FACTOR_STR, NC_FLOAT, 1, d) ); - d[0] = 1.0; - NCERR( nc_put_att_float(ncid, cell_origin_var, NC_SCALE_FACTOR_STR, NC_FLOAT, 1, d) ); - d[0] = 1.0; - NCERR( nc_put_att_float(ncid, cell_lengths_var, NC_SCALE_FACTOR_STR, NC_FLOAT, 1, d) ); + NCERR( nc_put_att_text(ncid, cell_angles_var, NC_UNITS_STR, 6, "degree") ); + + float scale[1] = {static_cast(update->dt)}; + NCERR( nc_put_att_float(ncid, time_var, NC_SCALE_FACTOR_STR, NC_FLOAT, 1, scale) ); /* * Finished with definition @@ -905,4 +892,94 @@ void DumpNetCDF::ncerr(int err, const char *descr, int line) } } +/* ---------------------------------------------------------------------- */ + +std::string DumpNetCDF::unit_of(Quantity quantity) { + if (!strcmp(update->unit_style, "lj")) { + if (quantity == Quantity::Unknown) { + return ""; + } else { + return "lj"; + } + } else if (!strcmp(update->unit_style, "real")) { + switch (quantity) { + case Quantity::Unknown: + return ""; + case Quantity::Time: + return "femtosecond"; + case Quantity::Distance: + return "Angstrom"; + case Quantity::Velocity: + return "Angstrom/femtosecond"; + case Quantity::Force: + return "(Kcal/mol)/Angstrom)"; + case Quantity::DipoleMoment: + return "e * Angstrom"; + } + } else if (!strcmp(update->unit_style, "metal")) { + switch (quantity) { + case Quantity::Unknown: + return ""; + case Quantity::Time: + return "picosecond"; + case Quantity::Distance: + return "Angstrom"; + case Quantity::Velocity: + return "Angstrom/picosecond"; + case Quantity::Force: + return "eV/Angstrom"; + case Quantity::DipoleMoment: + return "e * Angstrom"; + } + } else if (!strcmp(update->unit_style, "si")) { + switch (quantity) { + case Quantity::Unknown: + return ""; + case Quantity::Time: + return "second"; + case Quantity::Distance: + return "meter"; + case Quantity::Velocity: + return "meter/second"; + case Quantity::Force: + return "Newton"; + case Quantity::DipoleMoment: + return "Coulomb * meter"; + } + } else if (!strcmp(update->unit_style, "cgs")) { + switch (quantity) { + case Quantity::Unknown: + return ""; + case Quantity::Time: + return "second"; + case Quantity::Distance: + return "centimeter"; + case Quantity::Velocity: + return "centimeter/second"; + case Quantity::Force: + return "dynes"; + case Quantity::DipoleMoment: + return "statcoul * cm"; + } + } else if (!strcmp(update->unit_style, "electron")) { + switch (quantity) { + case Quantity::Unknown: + return ""; + case Quantity::Time: + return "second"; + case Quantity::Distance: + return "centimeter"; + case Quantity::Velocity: + return "centimeter/second"; + case Quantity::Force: + return "Hartrees/Bohr"; + case Quantity::DipoleMoment: + return "Debye"; + } + } + + error->all(FLERR, "Unsupported unit style: {}", update->unit_style); + return ""; +} + #endif /* defined(LMP_HAS_NETCDF) */ diff --git a/src/NETCDF/dump_netcdf.h b/src/NETCDF/dump_netcdf.h index b3bd055701..07c104c445 100644 --- a/src/NETCDF/dump_netcdf.h +++ b/src/NETCDF/dump_netcdf.h @@ -40,12 +40,26 @@ class DumpNetCDF : public DumpCustom { virtual void write(); private: + // type of quantity for per-atom values (used to get the unit) + enum Quantity { + Unknown = 0, + + Time, + Distance, + Velocity, + Force, + DipoleMoment, + }; + // get the name of the unit for the given quantity + std::string unit_of(Quantity quantity); + // per-atoms quantities (positions, velocities, etc.) struct nc_perat_t { int dims; // number of dimensions int field[DUMP_NC_MAX_DIMS]; // field indices corresponding to the dim. char name[NC_FIELD_NAME_MAX]; // field name int var; // NetCDF variable + Quantity quantity; // type of the quantity bool constant; // is this property per file (not per frame) int ndumped; // number of enties written for this prop. diff --git a/src/NETCDF/dump_netcdf_mpiio.cpp b/src/NETCDF/dump_netcdf_mpiio.cpp index 441cc97bd2..af0f965e3c 100644 --- a/src/NETCDF/dump_netcdf_mpiio.cpp +++ b/src/NETCDF/dump_netcdf_mpiio.cpp @@ -102,6 +102,7 @@ DumpNetCDFMPIIO::DumpNetCDFMPIIO(LAMMPS *lmp, int narg, char **arg) : int ndims = 1; std::string mangled = earg[i]; bool constant = false; + Quantity quantity = Quantity::Unknown; // name mangling // in the AMBER specification @@ -109,26 +110,32 @@ DumpNetCDFMPIIO::DumpNetCDFMPIIO(LAMMPS *lmp, int narg, char **arg) : idim = mangled[0] - 'x'; ndims = 3; mangled = "coordinates"; + quantity = Quantity::Distance; } else if ((mangled == "vx") || (mangled == "vy") || (mangled == "vz")) { idim = mangled[1] - 'x'; ndims = 3; mangled = "velocities"; + quantity = Quantity::Velocity; } else if ((mangled == "xs") || (mangled == "ys") || (mangled == "zs")) { idim = mangled[0] - 'x'; ndims = 3; mangled = "scaled_coordinates"; + // no quantity for scaled_coordinates } else if ((mangled == "xu") || (mangled == "yu") || (mangled == "zu")) { idim = mangled[0] - 'x'; ndims = 3; mangled = "unwrapped_coordinates"; + quantity = Quantity::Distance; } else if ((mangled == "fx") || (mangled == "fy") || (mangled == "fz")) { idim = mangled[1] - 'x'; ndims = 3; mangled = "forces"; + quantity = Quantity::Force; } else if ((mangled == "mux") || (mangled == "muy") || (mangled == "muz")) { idim = mangled[2] - 'x'; ndims = 3; mangled = "mu"; + quantity = Quantity::DipoleMoment; } else if (utils::strmatch(mangled, "^c_")) { std::size_t found = mangled.find('['); if (found != std::string::npos) { @@ -173,6 +180,7 @@ DumpNetCDFMPIIO::DumpNetCDFMPIIO(LAMMPS *lmp, int narg, char **arg) : } perat[inc].field[idim] = i; + perat[inc].quantity = quantity; } n_buffer = 0; @@ -414,6 +422,11 @@ void DumpNetCDFMPIIO::openfile() dims[2] = vector_dim[perat[i].dims]; NCERRX( ncmpi_def_var(ncid, perat[i].name, xtype, 3, dims, &perat[i].var), perat[i].name ); } + + std::string unit = this->unit_of(perat[i].quantity); + if (!unit.empty()) { + NCERR( ncmpi_put_att_text(ncid, perat[i].var, NC_UNITS_STR, unit.size(), unit.c_str()) ); + } } // perframe variables @@ -441,43 +454,18 @@ void DumpNetCDFMPIIO::openfile() NCERR( ncmpi_put_att_text(ncid, NC_GLOBAL, "program", 6, "LAMMPS") ); NCERR( ncmpi_put_att_text(ncid, NC_GLOBAL, "programVersion", strlen(lmp->version), lmp->version) ); - // units - if (!strcmp(update->unit_style, "lj")) { - NCERR( ncmpi_put_att_text(ncid, time_var, NC_UNITS_STR, 2, "lj") ); - NCERR( ncmpi_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, 2, "lj") ); - NCERR( ncmpi_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, 2, "lj") ); - } else if (!strcmp(update->unit_style, "real")) { - NCERR( ncmpi_put_att_text(ncid, time_var, NC_UNITS_STR, 11, "femtosecond") ); - NCERR( ncmpi_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, 8, "Angstrom") ); - NCERR( ncmpi_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, 8, "Angstrom") ); - } else if (!strcmp(update->unit_style, "metal")) { - NCERR( ncmpi_put_att_text(ncid, time_var, NC_UNITS_STR, 10, "picosecond") ); - NCERR( ncmpi_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, 8, "Angstrom") ); - NCERR( ncmpi_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, 8, "Angstrom") ); - } else if (!strcmp(update->unit_style, "si")) { - NCERR( ncmpi_put_att_text(ncid, time_var, NC_UNITS_STR, 6, "second") ); - NCERR( ncmpi_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, 5, "meter") ); - NCERR( ncmpi_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, 5, "meter") ); - } else if (!strcmp(update->unit_style, "cgs")) { - NCERR( ncmpi_put_att_text(ncid, time_var, NC_UNITS_STR, 6, "second") ); - NCERR( ncmpi_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, 10, "centimeter") ); - NCERR( ncmpi_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, 10, "centimeter") ); - } else if (!strcmp(update->unit_style, "electron")) { - NCERR( ncmpi_put_att_text(ncid, time_var, NC_UNITS_STR, 11, "femtosecond") ); - NCERR( ncmpi_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, 4, "Bohr") ); - NCERR( ncmpi_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, 4, "Bohr") ); - } else { - error->all(FLERR,"Unsupported unit style: {}", update->unit_style); - } + // units & scale + std::string unit = this->unit_of(Quantity::Time); + NCERR( ncmpi_put_att_text(ncid, time_var, NC_UNITS_STR, unit.size(), unit.c_str()) ); + + unit = this->unit_of(Quantity::Distance); + NCERR( ncmpi_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, unit.size(), unit.c_str()) ); + NCERR( ncmpi_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, unit.size(), unit.c_str()) ); NCERR( ncmpi_put_att_text(ncid, cell_angles_var, NC_UNITS_STR, 6, "degree") ); - d[0] = update->dt; - NCERR( ncmpi_put_att_float(ncid, time_var, NC_SCALE_FACTOR_STR, NC_FLOAT, 1, d) ); - d[0] = 1.0; - NCERR( ncmpi_put_att_float(ncid, cell_origin_var, NC_SCALE_FACTOR_STR, NC_FLOAT, 1, d) ); - d[0] = 1.0; - NCERR( ncmpi_put_att_float(ncid, cell_lengths_var, NC_SCALE_FACTOR_STR, NC_FLOAT, 1, d) ); + float scale[1] = {static_cast(update->dt)}; + NCERR( ncmpi_put_att_float(ncid, time_var, NC_SCALE_FACTOR_STR, NC_FLOAT, 1, scale) ); /* * Finished with definition @@ -900,4 +888,84 @@ void DumpNetCDFMPIIO::ncerr(int err, const char *descr, int line) } } +/* ---------------------------------------------------------------------- */ + +std::string DumpNetCDF::unit_of(Quantity quantity) { + if (quantity == Quantity::Unknown) { + return ""; + } + + if (!strcmp(update->unit_style, "lj")) { + return "lj"; + } else if (!strcmp(update->unit_style, "real")) { + switch (quantity) { + case Quantity::Time: + return "femtosecond"; + case Quantity::Distance: + return "Angstrom"; + case Quantity::Velocity: + return "Angstrom/femtosecond"; + case Quantity::Force: + return "(Kcal/mol)/Angstrom)"; + case Quantity::DipoleMoment: + return "e * Angstrom"; + } + } else if (!strcmp(update->unit_style, "metal")) { + switch (quantity) { + case Quantity::Time: + return "picosecond"; + case Quantity::Distance: + return "Angstrom"; + case Quantity::Velocity: + return "Angstrom/picosecond"; + case Quantity::Force: + return "eV/Angstrom"; + case Quantity::DipoleMoment: + return "e * Angstrom"; + } + } else if (!strcmp(update->unit_style, "si")) { + switch (quantity) { + case Quantity::Time: + return "second"; + case Quantity::Distance: + return "meter"; + case Quantity::Velocity: + return "meter/second"; + case Quantity::Force: + return "Newton"; + case Quantity::DipoleMoment: + return "Coulomb * meter"; + } + } else if (!strcmp(update->unit_style, "cgs")) { + switch (quantity) { + case Quantity::Time: + return "second"; + case Quantity::Distance: + return "centimeter"; + case Quantity::Velocity: + return "centimeter/second"; + case Quantity::Force: + return "dynes"; + case Quantity::DipoleMoment: + return "statcoul * cm"; + } + } else if (!strcmp(update->unit_style, "electron")) { + switch (quantity) { + case Quantity::Time: + return "second"; + case Quantity::Distance: + return "centimeter"; + case Quantity::Velocity: + return "centimeter/second"; + case Quantity::Force: + return "Hartrees/Bohr"; + case Quantity::DipoleMoment: + return "Debye"; + } + } + + error->all(FLERR, "Unsupported unit style: {}", update->unit_style); + return ""; +} + #endif /* defined(LMP_HAS_PNETCDF) */ diff --git a/src/NETCDF/dump_netcdf_mpiio.h b/src/NETCDF/dump_netcdf_mpiio.h index d1fb4fd364..eb2cfb7b90 100644 --- a/src/NETCDF/dump_netcdf_mpiio.h +++ b/src/NETCDF/dump_netcdf_mpiio.h @@ -40,12 +40,26 @@ class DumpNetCDFMPIIO : public DumpCustom { virtual void write(); private: + // type of quantity for per-atom values (used to get the unit) + enum Quantity { + Unknown = 0, + + Time, + Distance, + Velocity, + Force, + DipoleMoment, + }; + // get the name of the unit for the given quantity + std::string unit_of(Quantity quantity); + // per-atoms quantities (positions, velocities, etc.) struct nc_perat_t { int dims; // number of dimensions int field[DUMP_NC_MPIIO_MAX_DIMS]; // field indices corresponding to the dim. char name[NC_MPIIO_FIELD_NAME_MAX]; // field name int var; // NetCDF variable + Quantity quantity; // type of the quantity }; typedef void (DumpNetCDFMPIIO::*funcptr_t)(void *); From 1c25c96aaa9a990667b0f463b83cf3e2d444a521 Mon Sep 17 00:00:00 2001 From: Luthaf Date: Fri, 17 Dec 2021 17:13:29 +0100 Subject: [PATCH 036/193] netcdf: deduplicate gettings units as strings --- src/NETCDF/dump_netcdf.cpp | 109 +++-------------------- src/NETCDF/dump_netcdf.h | 14 +-- src/NETCDF/dump_netcdf_mpiio.cpp | 99 +++------------------ src/NETCDF/dump_netcdf_mpiio.h | 14 +-- src/NETCDF/netcdf_units.cpp | 143 +++++++++++++++++++++++++++++++ src/NETCDF/netcdf_units.h | 45 ++++++++++ 6 files changed, 210 insertions(+), 214 deletions(-) create mode 100644 src/NETCDF/netcdf_units.cpp create mode 100644 src/NETCDF/netcdf_units.h diff --git a/src/NETCDF/dump_netcdf.cpp b/src/NETCDF/dump_netcdf.cpp index 8f5d6f9efd..f67bf8c2ff 100644 --- a/src/NETCDF/dump_netcdf.cpp +++ b/src/NETCDF/dump_netcdf.cpp @@ -19,6 +19,7 @@ #if defined(LMP_HAS_NETCDF) #include "dump_netcdf.h" +#include "netcdf_units.h" #include "atom.h" #include "comm.h" @@ -101,7 +102,7 @@ DumpNetCDF::DumpNetCDF(LAMMPS *lmp, int narg, char **arg) : int idim = 0; int ndims = 1; std::string mangled = earg[i]; - Quantity quantity = Quantity::Unknown; + Quantity quantity = Quantity::UNKNOWN; bool constant = false; // name mangling @@ -110,12 +111,12 @@ DumpNetCDF::DumpNetCDF(LAMMPS *lmp, int narg, char **arg) : idim = mangled[0] - 'x'; ndims = 3; mangled = "coordinates"; - quantity = Quantity::Distance; + quantity = Quantity::DISTANCE; } else if ((mangled == "vx") || (mangled == "vy") || (mangled == "vz")) { idim = mangled[1] - 'x'; ndims = 3; mangled = "velocities"; - quantity = Quantity::Velocity; + quantity = Quantity::VELOCITY; } else if ((mangled == "xs") || (mangled == "ys") || (mangled == "zs")) { idim = mangled[0] - 'x'; ndims = 3; @@ -125,17 +126,17 @@ DumpNetCDF::DumpNetCDF(LAMMPS *lmp, int narg, char **arg) : idim = mangled[0] - 'x'; ndims = 3; mangled = "unwrapped_coordinates"; - quantity = Quantity::Distance; + quantity = Quantity::DISTANCE; } else if ((mangled == "fx") || (mangled == "fy") || (mangled == "fz")) { idim = mangled[1] - 'x'; ndims = 3; mangled = "forces"; - quantity = Quantity::Force; + quantity = Quantity::FORCE; } else if ((mangled == "mux") || (mangled == "muy") || (mangled == "muz")) { idim = mangled[2] - 'x'; ndims = 3; mangled = "mu"; - quantity = Quantity::DipoleMoment; + quantity = Quantity::DIPOLE_MOMENT; } else if (utils::strmatch(mangled, "^c_")) { std::size_t found = mangled.find('['); if (found != std::string::npos) { @@ -434,7 +435,7 @@ void DumpNetCDF::openfile() } } - std::string unit = this->unit_of(perat[i].quantity); + std::string unit = get_unit_for(update->unit_style, perat[i].quantity, error); if (!unit.empty()) { NCERR( nc_put_att_text(ncid, perat[i].var, NC_UNITS_STR, unit.size(), unit.c_str()) ); } @@ -470,10 +471,10 @@ void DumpNetCDF::openfile() NCERR( nc_put_att_text(ncid, NC_GLOBAL, "programVersion",strlen(lmp->version), lmp->version) ); // units & scale - std::string unit = this->unit_of(Quantity::Time); + std::string unit = get_unit_for(update->unit_style, Quantity::TIME, error); NCERR( nc_put_att_text(ncid, time_var, NC_UNITS_STR, unit.size(), unit.c_str()) ); - unit = this->unit_of(Quantity::Distance); + unit = get_unit_for(update->unit_style, Quantity::DISTANCE, error); NCERR( nc_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, unit.size(), unit.c_str()) ); NCERR( nc_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, unit.size(), unit.c_str()) ); @@ -892,94 +893,4 @@ void DumpNetCDF::ncerr(int err, const char *descr, int line) } } -/* ---------------------------------------------------------------------- */ - -std::string DumpNetCDF::unit_of(Quantity quantity) { - if (!strcmp(update->unit_style, "lj")) { - if (quantity == Quantity::Unknown) { - return ""; - } else { - return "lj"; - } - } else if (!strcmp(update->unit_style, "real")) { - switch (quantity) { - case Quantity::Unknown: - return ""; - case Quantity::Time: - return "femtosecond"; - case Quantity::Distance: - return "Angstrom"; - case Quantity::Velocity: - return "Angstrom/femtosecond"; - case Quantity::Force: - return "(Kcal/mol)/Angstrom)"; - case Quantity::DipoleMoment: - return "e * Angstrom"; - } - } else if (!strcmp(update->unit_style, "metal")) { - switch (quantity) { - case Quantity::Unknown: - return ""; - case Quantity::Time: - return "picosecond"; - case Quantity::Distance: - return "Angstrom"; - case Quantity::Velocity: - return "Angstrom/picosecond"; - case Quantity::Force: - return "eV/Angstrom"; - case Quantity::DipoleMoment: - return "e * Angstrom"; - } - } else if (!strcmp(update->unit_style, "si")) { - switch (quantity) { - case Quantity::Unknown: - return ""; - case Quantity::Time: - return "second"; - case Quantity::Distance: - return "meter"; - case Quantity::Velocity: - return "meter/second"; - case Quantity::Force: - return "Newton"; - case Quantity::DipoleMoment: - return "Coulomb * meter"; - } - } else if (!strcmp(update->unit_style, "cgs")) { - switch (quantity) { - case Quantity::Unknown: - return ""; - case Quantity::Time: - return "second"; - case Quantity::Distance: - return "centimeter"; - case Quantity::Velocity: - return "centimeter/second"; - case Quantity::Force: - return "dynes"; - case Quantity::DipoleMoment: - return "statcoul * cm"; - } - } else if (!strcmp(update->unit_style, "electron")) { - switch (quantity) { - case Quantity::Unknown: - return ""; - case Quantity::Time: - return "second"; - case Quantity::Distance: - return "centimeter"; - case Quantity::Velocity: - return "centimeter/second"; - case Quantity::Force: - return "Hartrees/Bohr"; - case Quantity::DipoleMoment: - return "Debye"; - } - } - - error->all(FLERR, "Unsupported unit style: {}", update->unit_style); - return ""; -} - #endif /* defined(LMP_HAS_NETCDF) */ diff --git a/src/NETCDF/dump_netcdf.h b/src/NETCDF/dump_netcdf.h index 07c104c445..619aad9138 100644 --- a/src/NETCDF/dump_netcdf.h +++ b/src/NETCDF/dump_netcdf.h @@ -29,6 +29,7 @@ DumpStyle(netcdf,DumpNetCDF); #include "dump_custom.h" namespace LAMMPS_NS { +enum class Quantity; const int NC_FIELD_NAME_MAX = 100; const int DUMP_NC_MAX_DIMS = 100; @@ -40,19 +41,6 @@ class DumpNetCDF : public DumpCustom { virtual void write(); private: - // type of quantity for per-atom values (used to get the unit) - enum Quantity { - Unknown = 0, - - Time, - Distance, - Velocity, - Force, - DipoleMoment, - }; - // get the name of the unit for the given quantity - std::string unit_of(Quantity quantity); - // per-atoms quantities (positions, velocities, etc.) struct nc_perat_t { int dims; // number of dimensions diff --git a/src/NETCDF/dump_netcdf_mpiio.cpp b/src/NETCDF/dump_netcdf_mpiio.cpp index af0f965e3c..ba16b8c0e6 100644 --- a/src/NETCDF/dump_netcdf_mpiio.cpp +++ b/src/NETCDF/dump_netcdf_mpiio.cpp @@ -19,6 +19,7 @@ #if defined(LMP_HAS_PNETCDF) #include "dump_netcdf_mpiio.h" +#include "netcdf_units.h" #include "atom.h" #include "comm.h" @@ -102,7 +103,7 @@ DumpNetCDFMPIIO::DumpNetCDFMPIIO(LAMMPS *lmp, int narg, char **arg) : int ndims = 1; std::string mangled = earg[i]; bool constant = false; - Quantity quantity = Quantity::Unknown; + Quantity quantity = Quantity::UNKNOWN; // name mangling // in the AMBER specification @@ -110,12 +111,12 @@ DumpNetCDFMPIIO::DumpNetCDFMPIIO(LAMMPS *lmp, int narg, char **arg) : idim = mangled[0] - 'x'; ndims = 3; mangled = "coordinates"; - quantity = Quantity::Distance; + quantity = Quantity::DISTANCE; } else if ((mangled == "vx") || (mangled == "vy") || (mangled == "vz")) { idim = mangled[1] - 'x'; ndims = 3; mangled = "velocities"; - quantity = Quantity::Velocity; + quantity = Quantity::VELOCITY; } else if ((mangled == "xs") || (mangled == "ys") || (mangled == "zs")) { idim = mangled[0] - 'x'; ndims = 3; @@ -125,17 +126,17 @@ DumpNetCDFMPIIO::DumpNetCDFMPIIO(LAMMPS *lmp, int narg, char **arg) : idim = mangled[0] - 'x'; ndims = 3; mangled = "unwrapped_coordinates"; - quantity = Quantity::Distance; + quantity = Quantity::DISTANCE; } else if ((mangled == "fx") || (mangled == "fy") || (mangled == "fz")) { idim = mangled[1] - 'x'; ndims = 3; mangled = "forces"; - quantity = Quantity::Force; + quantity = Quantity::FORCE; } else if ((mangled == "mux") || (mangled == "muy") || (mangled == "muz")) { idim = mangled[2] - 'x'; ndims = 3; mangled = "mu"; - quantity = Quantity::DipoleMoment; + quantity = Quantity::DIPOLE_MOMENT; } else if (utils::strmatch(mangled, "^c_")) { std::size_t found = mangled.find('['); if (found != std::string::npos) { @@ -423,7 +424,7 @@ void DumpNetCDFMPIIO::openfile() NCERRX( ncmpi_def_var(ncid, perat[i].name, xtype, 3, dims, &perat[i].var), perat[i].name ); } - std::string unit = this->unit_of(perat[i].quantity); + std::string unit = get_unit_for(update->unit_style, perat[i].quantity, error); if (!unit.empty()) { NCERR( ncmpi_put_att_text(ncid, perat[i].var, NC_UNITS_STR, unit.size(), unit.c_str()) ); } @@ -455,10 +456,10 @@ void DumpNetCDFMPIIO::openfile() NCERR( ncmpi_put_att_text(ncid, NC_GLOBAL, "programVersion", strlen(lmp->version), lmp->version) ); // units & scale - std::string unit = this->unit_of(Quantity::Time); + std::string unit = get_unit_for(update->unit_style, Quantity::TIME, error); NCERR( ncmpi_put_att_text(ncid, time_var, NC_UNITS_STR, unit.size(), unit.c_str()) ); - unit = this->unit_of(Quantity::Distance); + unit = get_unit_for(update->unit_style, Quantity::DISTANCE, error); NCERR( ncmpi_put_att_text(ncid, cell_origin_var, NC_UNITS_STR, unit.size(), unit.c_str()) ); NCERR( ncmpi_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR, unit.size(), unit.c_str()) ); @@ -888,84 +889,4 @@ void DumpNetCDFMPIIO::ncerr(int err, const char *descr, int line) } } -/* ---------------------------------------------------------------------- */ - -std::string DumpNetCDF::unit_of(Quantity quantity) { - if (quantity == Quantity::Unknown) { - return ""; - } - - if (!strcmp(update->unit_style, "lj")) { - return "lj"; - } else if (!strcmp(update->unit_style, "real")) { - switch (quantity) { - case Quantity::Time: - return "femtosecond"; - case Quantity::Distance: - return "Angstrom"; - case Quantity::Velocity: - return "Angstrom/femtosecond"; - case Quantity::Force: - return "(Kcal/mol)/Angstrom)"; - case Quantity::DipoleMoment: - return "e * Angstrom"; - } - } else if (!strcmp(update->unit_style, "metal")) { - switch (quantity) { - case Quantity::Time: - return "picosecond"; - case Quantity::Distance: - return "Angstrom"; - case Quantity::Velocity: - return "Angstrom/picosecond"; - case Quantity::Force: - return "eV/Angstrom"; - case Quantity::DipoleMoment: - return "e * Angstrom"; - } - } else if (!strcmp(update->unit_style, "si")) { - switch (quantity) { - case Quantity::Time: - return "second"; - case Quantity::Distance: - return "meter"; - case Quantity::Velocity: - return "meter/second"; - case Quantity::Force: - return "Newton"; - case Quantity::DipoleMoment: - return "Coulomb * meter"; - } - } else if (!strcmp(update->unit_style, "cgs")) { - switch (quantity) { - case Quantity::Time: - return "second"; - case Quantity::Distance: - return "centimeter"; - case Quantity::Velocity: - return "centimeter/second"; - case Quantity::Force: - return "dynes"; - case Quantity::DipoleMoment: - return "statcoul * cm"; - } - } else if (!strcmp(update->unit_style, "electron")) { - switch (quantity) { - case Quantity::Time: - return "second"; - case Quantity::Distance: - return "centimeter"; - case Quantity::Velocity: - return "centimeter/second"; - case Quantity::Force: - return "Hartrees/Bohr"; - case Quantity::DipoleMoment: - return "Debye"; - } - } - - error->all(FLERR, "Unsupported unit style: {}", update->unit_style); - return ""; -} - #endif /* defined(LMP_HAS_PNETCDF) */ diff --git a/src/NETCDF/dump_netcdf_mpiio.h b/src/NETCDF/dump_netcdf_mpiio.h index eb2cfb7b90..97fad9b805 100644 --- a/src/NETCDF/dump_netcdf_mpiio.h +++ b/src/NETCDF/dump_netcdf_mpiio.h @@ -29,6 +29,7 @@ DumpStyle(netcdf/mpiio,DumpNetCDFMPIIO); #include "dump_custom.h" namespace LAMMPS_NS { +enum class Quantity; const int NC_MPIIO_FIELD_NAME_MAX = 100; const int DUMP_NC_MPIIO_MAX_DIMS = 100; @@ -40,19 +41,6 @@ class DumpNetCDFMPIIO : public DumpCustom { virtual void write(); private: - // type of quantity for per-atom values (used to get the unit) - enum Quantity { - Unknown = 0, - - Time, - Distance, - Velocity, - Force, - DipoleMoment, - }; - // get the name of the unit for the given quantity - std::string unit_of(Quantity quantity); - // per-atoms quantities (positions, velocities, etc.) struct nc_perat_t { int dims; // number of dimensions diff --git a/src/NETCDF/netcdf_units.cpp b/src/NETCDF/netcdf_units.cpp new file mode 100644 index 0000000000..938512755a --- /dev/null +++ b/src/NETCDF/netcdf_units.cpp @@ -0,0 +1,143 @@ +// clang-format off +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Lars Pastewka (University of Freiburg) +------------------------------------------------------------------------- */ + +#if defined(LMP_HAS_NETCDF) || defined(LMP_HAS_PNETCDF) + +#include "netcdf_units.h" + +#include "error.h" + +std::string LAMMPS_NS::get_unit_for(const char* unit_style, Quantity quantity, Error* error) { + if (!strcmp(unit_style, "lj")) { + if (quantity == Quantity::UNKNOWN) { + return ""; + } else { + return "lj"; + } + } else if (!strcmp(unit_style, "real")) { + switch (quantity) { + case Quantity::UNKNOWN: + return ""; + case Quantity::TIME: + return "femtosecond"; + case Quantity::DISTANCE: + return "angstrom"; + case Quantity::VELOCITY: + return "angstrom/femtosecond"; + case Quantity::FORCE: + return "(Kcal/mol)/angstrom)"; + case Quantity::DIPOLE_MOMENT: + return "e * angstrom"; + } + } else if (!strcmp(unit_style, "metal")) { + switch (quantity) { + case Quantity::UNKNOWN: + return ""; + case Quantity::TIME: + return "picosecond"; + case Quantity::DISTANCE: + return "angstrom"; + case Quantity::VELOCITY: + return "angstrom/picosecond"; + case Quantity::FORCE: + return "eV/angstrom"; + case Quantity::DIPOLE_MOMENT: + return "e * angstrom"; + } + } else if (!strcmp(unit_style, "si")) { + switch (quantity) { + case Quantity::UNKNOWN: + return ""; + case Quantity::TIME: + return "second"; + case Quantity::DISTANCE: + return "meter"; + case Quantity::VELOCITY: + return "meter/second"; + case Quantity::FORCE: + return "Newton"; + case Quantity::DIPOLE_MOMENT: + return "Coulomb * meter"; + } + } else if (!strcmp(unit_style, "cgs")) { + switch (quantity) { + case Quantity::UNKNOWN: + return ""; + case Quantity::TIME: + return "second"; + case Quantity::DISTANCE: + return "centimeter"; + case Quantity::VELOCITY: + return "centimeter/second"; + case Quantity::FORCE: + return "dynes"; + case Quantity::DIPOLE_MOMENT: + return "statcoul * cm"; + } + } else if (!strcmp(unit_style, "electron")) { + switch (quantity) { + case Quantity::UNKNOWN: + return ""; + case Quantity::TIME: + return "femtoseconds"; + case Quantity::DISTANCE: + return "Bohr"; + case Quantity::VELOCITY: + return "Bohr/atomic time units"; + case Quantity::FORCE: + return "Hartree/Bohr"; + case Quantity::DIPOLE_MOMENT: + return "Debye"; + } + } else if (!strcmp(unit_style, "micro")) { + switch (quantity) { + case Quantity::UNKNOWN: + return ""; + case Quantity::TIME: + return "microseconds"; + case Quantity::DISTANCE: + return "micrometers"; + case Quantity::VELOCITY: + return "micrometers/microsecond"; + case Quantity::FORCE: + return "picogram * micrometer/microsecond^2"; + case Quantity::DIPOLE_MOMENT: + return "picocoulomb * micrometer"; + } + } else if (!strcmp(unit_style, "nano")) { + switch (quantity) { + case Quantity::UNKNOWN: + return ""; + case Quantity::TIME: + return "nanoseconds"; + case Quantity::DISTANCE: + return "nanometers"; + case Quantity::VELOCITY: + return "nanometers/nanosecond"; + case Quantity::FORCE: + return "attogram * nanometer/nanosecond^2"; + case Quantity::DIPOLE_MOMENT: + return "e * nanometer"; + } + } + + error->all(FLERR, "Unsupported unit style: {}", unit_style); + return ""; +} + +#endif diff --git a/src/NETCDF/netcdf_units.h b/src/NETCDF/netcdf_units.h new file mode 100644 index 0000000000..bb83d983c8 --- /dev/null +++ b/src/NETCDF/netcdf_units.h @@ -0,0 +1,45 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: Lars Pastewka (University of Freiburg), Guillaume Fraux (EPFL) +------------------------------------------------------------------------- */ + +#ifndef LMP_NETCDF_UNITS_H +#define LMP_NETCDF_UNITS_H + +#if defined(LMP_HAS_NETCDF) || defined(LMP_HAS_PNETCDF) + +#include + +namespace LAMMPS_NS { +class Error; + +// type of quantity for per-atom values (used to get the unit) +enum class Quantity { + UNKNOWN = 0, + TIME, + DISTANCE, + VELOCITY, + FORCE, + DIPOLE_MOMENT, +}; + +// get the name of the unit for the given `quantity` in the given LAMMPS +// `unit_style` any error will be reported through `error` +std::string get_unit_for(const char* unit_style, Quantity quantity, Error* error); + +} + +#endif +#endif From a3a60771153eef939ec67eaf3389196f92e396c3 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Fri, 17 Dec 2021 16:58:42 -0500 Subject: [PATCH 037/193] Use sfread and sfgets in reader_native.cpp --- src/reader_native.cpp | 26 +++++++++----------------- src/reader_native.h | 2 +- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/reader_native.cpp b/src/reader_native.cpp index 7be546719f..1ee4712989 100644 --- a/src/reader_native.cpp +++ b/src/reader_native.cpp @@ -63,10 +63,10 @@ int ReaderNative::read_time(bigint &ntimestep) magic_string = ""; unit_style = ""; - fread(&ntimestep, sizeof(bigint), 1, fp); + auto ret = fread(&ntimestep, sizeof(bigint), 1, fp); // detect end-of-file - if (feof(fp)) return 1; + if (ret != 1 || feof(fp)) return 1; // detect newer format if (ntimestep < 0) { @@ -485,12 +485,8 @@ void ReaderNative::read_atoms(int n, int nfield, double **fields) } } } else { - int i,m; - char *eof; - - for (i = 0; i < n; i++) { - eof = fgets(line,MAXLINE,fp); - if (eof == nullptr) error->one(FLERR,"Unexpected end of dump file"); + for (int i = 0; i < n; i++) { + utils::sfgets(FLERR, line, MAXLINE, fp, nullptr, error); // tokenize the line std::vector words = Tokenizer(line).as_vector(); @@ -499,7 +495,7 @@ void ReaderNative::read_atoms(int n, int nfield, double **fields) // convert selected fields to floats - for (m = 0; m < nfield; m++) + for (int m = 0; m < nfield; m++) fields[i][m] = atof(words[fieldindex[m]].c_str()); } } @@ -527,18 +523,14 @@ int ReaderNative::find_label(const std::string &label, const std::mapone(FLERR,"Unexpected end of dump file"); + for (int i = 0; i < n; i++) { + utils::sfgets(FLERR, line, MAXLINE, fp, nullptr, error); + } } void ReaderNative::read_buf(void * ptr, size_t size, size_t count) { - fread(ptr, size, count, fp); - - // detect end-of-file - if (feof(fp)) error->one(FLERR,"Unexpected end of dump file"); + utils::sfread(FLERR, ptr, size, count, fp, nullptr, error); } std::string ReaderNative::read_binary_str(size_t size) diff --git a/src/reader_native.h b/src/reader_native.h index c07dbbac08..f888509dfb 100644 --- a/src/reader_native.h +++ b/src/reader_native.h @@ -52,7 +52,7 @@ class ReaderNative : public Reader { int nwords; // # of per-atom columns in dump file int size_one; // number of double for one atom - int maxbuf; // maximum buffer size + size_t maxbuf; // maximum buffer size int nchunk; // number of chunks in the binary file int ichunk; // index of current reading chunk int natom_chunk; // number of atoms in the current chunks From 3246fd62a7951fc5f97964bb673acf7e1c672bcc Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Fri, 17 Dec 2021 17:10:21 -0500 Subject: [PATCH 038/193] size_t is unsigned, so can't be negative --- src/reader_native.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/reader_native.cpp b/src/reader_native.cpp index 1ee4712989..ba7a576a50 100644 --- a/src/reader_native.cpp +++ b/src/reader_native.cpp @@ -542,7 +542,6 @@ std::string ReaderNative::read_binary_str(size_t size) void ReaderNative::read_double_chunk(size_t count) { - if (count < 0) return; // extend buffer to fit chunk size if (count > maxbuf) { memory->grow(databuf,count,"reader:databuf"); From 88f8e41702c56e2a3a55cf162260890669ed17d2 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 18 Dec 2021 18:22:47 -0500 Subject: [PATCH 039/193] PHONON package is now only a soft dependency on KSPACE --- cmake/CMakeLists.txt | 3 +-- cmake/Modules/Packages/PHONON.cmake | 9 +++++++++ src/PHONON/Install.sh | 10 ---------- 3 files changed, 10 insertions(+), 12 deletions(-) create mode 100644 cmake/Modules/Packages/PHONON.cmake diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index bc79d68c54..408528f6dd 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -339,7 +339,6 @@ pkg_depends(ML-IAP ML-SNAP) pkg_depends(MPIIO MPI) pkg_depends(ATC MANYBODY) pkg_depends(LATBOLTZ MPI) -pkg_depends(PHONON KSPACE) pkg_depends(SCAFACOS MPI) pkg_depends(DIELECTRIC KSPACE) pkg_depends(DIELECTRIC EXTRA-PAIR) @@ -609,7 +608,7 @@ endif() # packages which selectively include variants based on enabled styles # e.g. accelerator packages ###################################################################### -foreach(PKG_WITH_INCL CORESHELL QEQ OPENMP DPD-SMOOTH KOKKOS OPT INTEL GPU) +foreach(PKG_WITH_INCL CORESHELL DPD-SMOOTH PHONON QEQ OPENMP KOKKOS OPT INTEL GPU) if(PKG_${PKG_WITH_INCL}) include(Packages/${PKG_WITH_INCL}) endif() diff --git a/cmake/Modules/Packages/PHONON.cmake b/cmake/Modules/Packages/PHONON.cmake new file mode 100644 index 0000000000..3021868f68 --- /dev/null +++ b/cmake/Modules/Packages/PHONON.cmake @@ -0,0 +1,9 @@ +# fix phonon may only be installed if also the FFT wrappers from KSPACE are installed +if(NOT PKG_KSPACE) + get_property(LAMMPS_FIX_HEADERS GLOBAL PROPERTY FIX) + list(REMOVE_ITEM LAMMPS_FIX_HEADERS ${LAMMPS_SOURCE_DIR}/PHONON/fix_phonon.h) + set_property(GLOBAL PROPERTY FIX "${LAMMPS_FIX_HEADERS}") + get_target_property(LAMMPS_SOURCES lammps SOURCES) + list(REMOVE_ITEM LAMMPS_SOURCES ${LAMMPS_SOURCE_DIR}/PHONON/fix_phonon.cpp) + set_property(TARGET lammps PROPERTY SOURCES "${LAMMPS_SOURCES}") +endif() diff --git a/src/PHONON/Install.sh b/src/PHONON/Install.sh index 4b64fed114..b465f3b1f7 100755 --- a/src/PHONON/Install.sh +++ b/src/PHONON/Install.sh @@ -26,16 +26,6 @@ action () { fi } -# PHONON uses the parallel FFT wrapper used in PPPM, -# so we must require the KSPACE package to be installed. - -if (test $1 = 1) then - if (test ! -e ../fft3d_wrap.h) then - echo "Must install KSPACE package with PHONON" - exit 1 - fi -fi - # list of files with optional dependcies action fix_phonon.cpp fft3d_wrap.h From 461398bc0e66b92d726e4535ad730c0b09250891 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 19 Dec 2021 17:45:57 -0500 Subject: [PATCH 040/193] join lines --- src/MC/fix_gcmc.cpp | 14 ++++---------- src/MC/fix_widom.cpp | 7 ++----- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/MC/fix_gcmc.cpp b/src/MC/fix_gcmc.cpp index 38007b8e2e..2149b03b6c 100644 --- a/src/MC/fix_gcmc.cpp +++ b/src/MC/fix_gcmc.cpp @@ -504,8 +504,7 @@ void FixGCMC::init() int flagall; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); if (flagall && comm->me == 0) - error->all(FLERR, - "Fix gcmc cannot exchange individual atoms belonging to a molecule"); + error->all(FLERR, "Fix gcmc cannot exchange individual atoms belonging to a molecule"); } // if molecules are exchanged or moved, check for unset mol IDs @@ -520,16 +519,13 @@ void FixGCMC::init() int flagall; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); if (flagall && comm->me == 0) - error->all(FLERR, - "All mol IDs should be set for fix gcmc group atoms"); + error->all(FLERR, "All mol IDs should be set for fix gcmc group atoms"); } if (exchmode == EXCHMOL || movemode == MOVEMOL) if (atom->molecule_flag == 0 || !atom->tag_enable || (atom->map_style == Atom::MAP_NONE)) - error->all(FLERR, - "Fix gcmc molecule command requires that " - "atoms have molecule attributes"); + error->all(FLERR, "Fix gcmc molecule command requires that atoms have molecule attributes"); // if rigidflag defined, check for rigid/small fix // its molecule template must be same as this one @@ -541,9 +537,7 @@ void FixGCMC::init() fixrigid = modify->fix[ifix]; int tmp; if (&onemols[imol] != (Molecule **) fixrigid->extract("onemol",tmp)) - error->all(FLERR, - "Fix gcmc and fix rigid/small not using " - "same molecule template ID"); + error->all(FLERR, "Fix gcmc and fix rigid/small not using same molecule template ID"); } // if shakeflag defined, check for SHAKE fix diff --git a/src/MC/fix_widom.cpp b/src/MC/fix_widom.cpp index cc0ea7981e..e2989f8981 100644 --- a/src/MC/fix_widom.cpp +++ b/src/MC/fix_widom.cpp @@ -310,16 +310,13 @@ void FixWidom::init() int flagall; MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); if (flagall && comm->me == 0) - error->all(FLERR, - "All mol IDs should be set for fix widom group atoms"); + error->all(FLERR, "All mol IDs should be set for fix widom group atoms"); } if (exchmode == EXCHMOL) if (atom->molecule_flag == 0 || !atom->tag_enable || (atom->map_style == Atom::MAP_NONE)) - error->all(FLERR, - "Fix widom molecule command requires that " - "atoms have molecule attributes"); + error->all(FLERR, "Fix widom molecule command requires that atoms have molecule attributes"); if (domain->dimension == 2) error->all(FLERR,"Cannot use fix widom in a 2d simulation"); From 97b5651633a8c695c1f38ca8465f8055a7c8ab6e Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Mon, 20 Dec 2021 10:33:05 -0700 Subject: [PATCH 041/193] minor correction to angle class2 --- doc/src/angle_class2.rst | 38 +++++++++++++++++++++++-------------- src/CLASS2/angle_class2.cpp | 5 +++++ 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/doc/src/angle_class2.rst b/doc/src/angle_class2.rst index f257d96dc3..4e8e515564 100644 --- a/doc/src/angle_class2.rst +++ b/doc/src/angle_class2.rst @@ -64,34 +64,44 @@ These are the 4 coefficients for the :math:`E_a` formula: radians internally; hence the various :math:`K` are effectively energy per radian\^2 or radian\^3 or radian\^4. -For the :math:`E_{bb}` formula, each line in a :doc:`angle_coeff ` -command in the input script lists 4 coefficients, the first of which -is "bb" to indicate they are BondBond coefficients. In a data file, -these coefficients should be listed under a "BondBond Coeffs" heading -and you must leave out the "bb", i.e. only list 3 coefficients after -the angle type. +For the :math:`E_{bb}` formula, each line in a :doc:`angle_coeff +` command in the input script lists 4 coefficients, the +first of which is "bb" to indicate they are BondBond coefficients. In +a data file, these coefficients should be listed under a "BondBond +Coeffs" heading and you must leave out the "bb", i.e. only list 3 +coefficients after the angle type. * bb * :math:`M` (energy/distance\^2) * :math:`r_1` (distance) * :math:`r_2` (distance) -For the :math:`E_{ba}` formula, each line in a :doc:`angle_coeff ` -command in the input script lists 5 coefficients, the first of which -is "ba" to indicate they are BondAngle coefficients. In a data file, -these coefficients should be listed under a "BondAngle Coeffs" heading -and you must leave out the "ba", i.e. only list 4 coefficients after -the angle type. +For the :math:`E_{ba}` formula, each line in a :doc:`angle_coeff +` command in the input script lists 5 coefficients, the +first of which is "ba" to indicate they are BondAngle coefficients. +In a data file, these coefficients should be listed under a "BondAngle +Coeffs" heading and you must leave out the "ba", i.e. only list 4 +coefficients after the angle type. * ba -* :math:`N_1` (energy/distance\^2) -* :math:`N_2` (energy/distance\^2) +* :math:`N_1` (energy/distance) +* :math:`N_2` (energy/distance) * :math:`r_1` (distance) * :math:`r_2` (distance) The :math:`\theta_0` value in the :math:`E_{ba}` formula is not specified, since it is the same value from the :math:`E_a` formula. +.. note:: + + It is important that the order of the I,J,K atoms in each angle + listed in the Angles section of the data file read by the + :doc:`read_data ` command be consistent with the order + of the :math:`r_1` and :math:`r_2` BondBond and BondAngle + coefficients. This is because the terms in the formulas for + :math:`E_{bb}` and :math:`E_{ba}` will use the I,J atoms to compute + :math:`r_{ij}` and the J,K atoms to compute :math:`r_{jk}`. + ---------- .. include:: accel_styles.rst diff --git a/src/CLASS2/angle_class2.cpp b/src/CLASS2/angle_class2.cpp index 82e31440f5..c37c5a8f65 100644 --- a/src/CLASS2/angle_class2.cpp +++ b/src/CLASS2/angle_class2.cpp @@ -169,6 +169,8 @@ void AngleClass2::compute(int eflag, int vflag) // force & energy for bond-angle term + dr1 = r1 - ba_r1[type]; + dr2 = r2 - ba_r2[type]; aa1 = s * dr1 * ba_k1[type]; aa2 = s * dr2 * ba_k2[type]; @@ -459,6 +461,9 @@ double AngleClass2::single(int type, int i1, int i2, int i3) double dr2 = r2 - bb_r2[type]; energy += bb_k[type]*dr1*dr2; + dr1 = r1 - ba_r1[type]; + dr2 = r2 - ba_r2[type]; energy += ba_k1[type]*dr1*dtheta + ba_k2[type]*dr2*dtheta; + return energy; } From 2ee88dab7ee31c439df607c408b48c00b7b88b22 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Mon, 20 Dec 2021 10:35:41 -0700 Subject: [PATCH 042/193] same change for angle class2/p6 --- src/MOFFF/angle_class2_p6.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/MOFFF/angle_class2_p6.cpp b/src/MOFFF/angle_class2_p6.cpp index 0fccf6c4cb..e72f9f34fc 100644 --- a/src/MOFFF/angle_class2_p6.cpp +++ b/src/MOFFF/angle_class2_p6.cpp @@ -174,6 +174,8 @@ void AngleClass2P6::compute(int eflag, int vflag) // force & energy for bond-angle term + dr1 = r1 - ba_r1[type]; + dr2 = r2 - ba_r2[type]; aa1 = s * dr1 * ba_k1[type]; aa2 = s * dr2 * ba_k2[type]; @@ -479,6 +481,9 @@ double AngleClass2P6::single(int type, int i1, int i2, int i3) double dr2 = r2 - bb_r2[type]; energy += bb_k[type]*dr1*dr2; + dr1 = r1 - ba_r1[type]; + dr2 = r2 - ba_r2[type]; energy += ba_k1[type]*dr1*dtheta + ba_k2[type]*dr2*dtheta; + return energy; } From 06c45fbe686f80d2b99442978031869618059a5f Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Mon, 20 Dec 2021 14:26:22 -0700 Subject: [PATCH 043/193] fix compiler errors --- src/input.cpp | 9 ++++++--- src/output.cpp | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index 35b04946c0..30424ad5cb 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -27,9 +27,11 @@ #include "dihedral.h" #include "domain.h" #include "error.h" +#include "fix.h" #include "force.h" #include "group.h" #include "improper.h" +#include "integrate.h" #include "kspace.h" #include "memory.h" #include "min.h" @@ -1841,11 +1843,12 @@ void Input::timestep() update->dt = utils::numeric(FLERR,arg[0],false,lmp); update->dt_default = 0; - if (update->first_update == 0) return; - + // timestep command can be invoked between runs or by run every // calls to other classes that need to know timestep size changed // similar logic is in FixDtReset::end_of_step() - // only if a run has already occurred + // only need to do this if a run has already occurred + + if (update->first_update == 0) return; int respaflag = 0; if (utils::strmatch(update->integrate_style, "^respa")) respaflag = 1; diff --git a/src/output.cpp b/src/output.cpp index d34aa8d3f7..30248e449d 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -580,7 +580,8 @@ void Output::reset_timestep(bigint ntimestep) next_dump_any = MAXBIGINT; for (int idump = 0; idump < ndump; idump++) if (last_dump[idump] >= 0) - error->all("Cannot reset timestep with active dump - must undump first"); + error->all(FLERR, + "Cannot reset timestep with active dump - must undump first"); if (restart_flag_single) { if (restart_every_single) { From 4bc85f07e376ddd6a557bc3635663283cb3fb5be Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Mon, 20 Dec 2021 14:29:17 -0700 Subject: [PATCH 044/193] same changes in OPENMP and KOKKOS versions of angle class2 --- src/KOKKOS/angle_class2_kokkos.cpp | 2 ++ src/OPENMP/angle_class2_omp.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/KOKKOS/angle_class2_kokkos.cpp b/src/KOKKOS/angle_class2_kokkos.cpp index 146e8b40ea..0bcc3ad458 100644 --- a/src/KOKKOS/angle_class2_kokkos.cpp +++ b/src/KOKKOS/angle_class2_kokkos.cpp @@ -241,6 +241,8 @@ void AngleClass2Kokkos::operator()(TagAngleClass2Compute Date: Mon, 20 Dec 2021 16:05:44 -0700 Subject: [PATCH 045/193] Remove unused variable --- src/KOKKOS/compute_phase_atom_kokkos.cpp | 1 - src/KOKKOS/compute_phase_atom_kokkos.h | 1 - src/compute_phase_atom.cpp | 1 - 3 files changed, 3 deletions(-) diff --git a/src/KOKKOS/compute_phase_atom_kokkos.cpp b/src/KOKKOS/compute_phase_atom_kokkos.cpp index b0637526de..5a21393252 100644 --- a/src/KOKKOS/compute_phase_atom_kokkos.cpp +++ b/src/KOKKOS/compute_phase_atom_kokkos.cpp @@ -116,7 +116,6 @@ void ComputePhaseAtomKokkos::compute_peratom() atomKK->sync(execution_space,X_MASK|V_MASK|TYPE_MASK|MASK_MASK); x = atomKK->k_x.view(); v = atomKK->k_v.view(); - type = atomKK->k_type.view(); mask = atomKK->k_mask.view(); Kokkos::deep_copy(d_phase,0.0); diff --git a/src/KOKKOS/compute_phase_atom_kokkos.h b/src/KOKKOS/compute_phase_atom_kokkos.h index 247acd3f03..7bcc418d85 100644 --- a/src/KOKKOS/compute_phase_atom_kokkos.h +++ b/src/KOKKOS/compute_phase_atom_kokkos.h @@ -46,7 +46,6 @@ class ComputePhaseAtomKokkos : public ComputePhaseAtom { private: typename AT::t_x_array_randomread x; typename AT::t_v_array_randomread v; - typename ArrayTypes::t_int_1d_randomread type; typename ArrayTypes::t_int_1d mask; typename AT::t_neighbors_2d d_neighbors; diff --git a/src/compute_phase_atom.cpp b/src/compute_phase_atom.cpp index c1382392d7..ed6bbb844f 100644 --- a/src/compute_phase_atom.cpp +++ b/src/compute_phase_atom.cpp @@ -131,7 +131,6 @@ void ComputePhaseAtom::compute_peratom() double **x = atom->x; double **v = atom->v; - int *type = atom->type; int *mask = atom->mask; for (ii = 0; ii < inum; ii++) { From 4d31e300c61b8a2f72a10ee08136ad95ce0624ee Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Mon, 20 Dec 2021 16:39:17 -0700 Subject: [PATCH 046/193] change to checking timestep for time dumps at start of each step --- src/dump.cpp | 2 - src/integrate.cpp | 19 +- src/output.cpp | 824 +++++++++++++++++++++++----------------------- src/output.h | 6 +- src/verlet.cpp | 2 - 5 files changed, 440 insertions(+), 413 deletions(-) diff --git a/src/dump.cpp b/src/dump.cpp index 21c1b16f75..df39f3738d 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -330,8 +330,6 @@ void Dump::write() if (delay_flag && update->ntimestep < delaystep) return; - printf("DUMP %ld\n",update->ntimestep); - // if file per timestep, open new file if (multifile) openfile(); diff --git a/src/integrate.cpp b/src/integrate.cpp index 52d34fb943..7a1dbfaf34 100644 --- a/src/integrate.cpp +++ b/src/integrate.cpp @@ -20,6 +20,7 @@ #include "kspace.h" #include "modify.h" #include "pair.h" +#include "output.h" #include "update.h" using namespace LAMMPS_NS; @@ -115,7 +116,13 @@ void Integrate::ev_setup() /* ---------------------------------------------------------------------- set eflag,vflag for current iteration - based on computes that need energy/virial info on this timestep + based on + (1) computes that need energy/virial info on this timestep + (2) time dumps that need unknown per-atom info on this timestep + NOTE: could not check time dumps if timestep size is not varying + see NOTE in output.cpp + also inefficient to add all per-atom eng/virial computes + but don't know which ones the dump needs invoke matchstep() on all timestep-dependent computes to clear their arrays eflag: set any or no bits ENERGY_GLOBAL bit for global energy @@ -133,6 +140,10 @@ void Integrate::ev_set(bigint ntimestep) { int i,flag; + int tdflag = 0; + if (output->any_time_dumps) + tdflag = output->check_time_dumps(ntimestep); + flag = 0; int eflag_global = 0; for (i = 0; i < nelist_global; i++) @@ -143,7 +154,7 @@ void Integrate::ev_set(bigint ntimestep) int eflag_atom = 0; for (i = 0; i < nelist_atom; i++) if (elist_atom[i]->matchstep(ntimestep)) flag = 1; - if (flag) eflag_atom = ENERGY_ATOM; + if (flag || (tdflag && nelist_atom)) eflag_atom = ENERGY_ATOM; if (eflag_global) update->eflag_global = ntimestep; if (eflag_atom) update->eflag_atom = ntimestep; @@ -159,13 +170,13 @@ void Integrate::ev_set(bigint ntimestep) int vflag_atom = 0; for (i = 0; i < nvlist_atom; i++) if (vlist_atom[i]->matchstep(ntimestep)) flag = 1; - if (flag) vflag_atom = VIRIAL_ATOM; + if (flag || (tdflag && nvlist_atom)) vflag_atom = VIRIAL_ATOM; flag = 0; int cvflag_atom = 0; for (i = 0; i < ncvlist_atom; i++) if (cvlist_atom[i]->matchstep(ntimestep)) flag = 1; - if (flag) cvflag_atom = VIRIAL_CENTROID; + if (flag || (tdflag && ncvlist_atom)) cvflag_atom = VIRIAL_CENTROID; if (vflag_global) update->vflag_global = ntimestep; if (vflag_atom || cvflag_atom) update->vflag_atom = ntimestep; diff --git a/src/output.cpp b/src/output.cpp index 30248e449d..94688cd74c 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -133,7 +133,9 @@ void Output::init() } for (int i = 0; i < ndump; i++) dump[i]->init(); - for (int i = 0; i < ndump; i++) + any_time_dumps = 0; + for (int i = 0; i < ndump; i++) { + if (mode_dump[i]) any_time_dumps = 1; if ((mode_dump[i] == 0 && every_dump[i] == 0) || (mode_dump[i] == 1 && every_time_dump[i] == 0.0)) { ivar_dump[i] = input->variable->find(var_dump[i]); @@ -142,6 +144,7 @@ void Output::init() if (!input->variable->equalstyle(ivar_dump[i])) error->all(FLERR,"Variable for dump every or delta is invalid style"); } + } if (restart_flag_single && restart_every_single == 0) { ivar_restart_single = input->variable->find(var_restart_single); @@ -176,9 +179,11 @@ void Output::setup(int memflag) if (ndump && update->restrict_output == 0) { for (int idump = 0; idump < ndump; idump++) { - // wrap dumps that invoke computes or do variable eval with clear/add + // wrap step dumps that invoke computes or do variable eval with clear/add + // see NOTE in write() about also wrapping time dumps - if (dump[idump]->clearstep || var_dump[idump]) + if (mode_dump[idump] == 0 && + (dump[idump]->clearstep || var_dump[idump])) modify->clearstep_compute(); // write a snapshot at setup only if any of these 3 conditions hold @@ -226,7 +231,8 @@ void Output::setup(int memflag) // if dump not written now, use addstep_compute_all() // since don't know what computes the dump will invoke - if (dump[idump]->clearstep || var_dump[idump]) { + if (mode_dump[idump] == 0 && + (dump[idump]->clearstep || var_dump[idump])) { if (writeflag) modify->addstep_compute(next_dump[idump]); else modify->addstep_compute_all(next_dump[idump]); } @@ -239,413 +245,435 @@ void Output::setup(int memflag) } else next_dump_any = update->laststep + 1; - // do not write restart files at start of run - // set next_restart values to multiple of every or variable value - // wrap variable eval with clear/add - // if no restarts, set next_restart to last+1 so will not influence next + // do not write restart files at start of run + // set next_restart values to multiple of every or variable value + // wrap variable eval with clear/add + // if no restarts, set next_restart to last+1 so will not influence next - if (restart_flag && update->restrict_output == 0) { - if (restart_flag_single) { - if (restart_every_single) - next_restart_single = - (ntimestep/restart_every_single)*restart_every_single + - restart_every_single; - else { - bigint nextrestart = static_cast - (input->variable->compute_equal(ivar_restart_single)); - if (nextrestart <= ntimestep) - error->all(FLERR,"Restart variable returned a bad timestep"); - next_restart_single = nextrestart; - } - } else next_restart_single = update->laststep + 1; - if (restart_flag_double) { - if (restart_every_double) - next_restart_double = - (ntimestep/restart_every_double)*restart_every_double + - restart_every_double; - else { - bigint nextrestart = static_cast - (input->variable->compute_equal(ivar_restart_double)); - if (nextrestart <= ntimestep) - error->all(FLERR,"Restart variable returned a bad timestep"); - next_restart_double = nextrestart; - } - } else next_restart_double = update->laststep + 1; - next_restart = MIN(next_restart_single,next_restart_double); - } else next_restart = update->laststep + 1; + if (restart_flag && update->restrict_output == 0) { + if (restart_flag_single) { + if (restart_every_single) + next_restart_single = + (ntimestep/restart_every_single)*restart_every_single + + restart_every_single; + else { + bigint nextrestart = static_cast + (input->variable->compute_equal(ivar_restart_single)); + if (nextrestart <= ntimestep) + error->all(FLERR,"Restart variable returned a bad timestep"); + next_restart_single = nextrestart; + } + } else next_restart_single = update->laststep + 1; + if (restart_flag_double) { + if (restart_every_double) + next_restart_double = + (ntimestep/restart_every_double)*restart_every_double + + restart_every_double; + else { + bigint nextrestart = static_cast + (input->variable->compute_equal(ivar_restart_double)); + if (nextrestart <= ntimestep) + error->all(FLERR,"Restart variable returned a bad timestep"); + next_restart_double = nextrestart; + } + } else next_restart_double = update->laststep + 1; + next_restart = MIN(next_restart_single,next_restart_double); + } else next_restart = update->laststep + 1; - // print memory usage unless being called between multiple runs + // print memory usage unless being called between multiple runs - if (memflag) memory_usage(); + if (memflag) memory_usage(); - // set next_thermo to multiple of every or variable eval if var defined - // insure thermo output on last step of run - // thermo may invoke computes so wrap with clear/add + // set next_thermo to multiple of every or variable eval if var defined + // insure thermo output on last step of run + // thermo may invoke computes so wrap with clear/add - modify->clearstep_compute(); + modify->clearstep_compute(); - thermo->header(); - thermo->compute(0); - last_thermo = ntimestep; + thermo->header(); + thermo->compute(0); + last_thermo = ntimestep; - if (var_thermo) { - next_thermo = static_cast - (input->variable->compute_equal(ivar_thermo)); - if (next_thermo <= ntimestep) - error->all(FLERR,"Thermo every variable returned a bad timestep"); - } else if (thermo_every) { - next_thermo = (ntimestep/thermo_every)*thermo_every + thermo_every; - next_thermo = MIN(next_thermo,update->laststep); - } else next_thermo = update->laststep; + if (var_thermo) { + next_thermo = static_cast + (input->variable->compute_equal(ivar_thermo)); + if (next_thermo <= ntimestep) + error->all(FLERR,"Thermo every variable returned a bad timestep"); + } else if (thermo_every) { + next_thermo = (ntimestep/thermo_every)*thermo_every + thermo_every; + next_thermo = MIN(next_thermo,update->laststep); + } else next_thermo = update->laststep; - modify->addstep_compute(next_thermo); + modify->addstep_compute(next_thermo); - // next = next timestep any output will be done + // next = next timestep any output will be done - next = MIN(next_dump_any,next_restart); - next = MIN(next,next_thermo); -} + next = MIN(next_dump_any,next_restart); + next = MIN(next,next_thermo); + } -/* ---------------------------------------------------------------------- - perform all output for this timestep - only perform output if next matches current step and last output doesn't - do dump/restart before thermo so thermo CPU time will include them -------------------------------------------------------------------------- */ + /* ---------------------------------------------------------------------- + perform all output for this timestep + only perform output if next matches current step and last output doesn't + do dump/restart before thermo so thermo CPU time will include them + ------------------------------------------------------------------------- */ -void Output::write(bigint ntimestep) + void Output::write(bigint ntimestep) + { + // perform dump if its next_dump = current ntimestep + // but not if it was already written on this step + // set next_dump and also next_time_dump for mode_dump = 1 + // set next_dump_any to smallest next_dump + // wrap step dumps that invoke computes or do variable eval with clear/add + // NOTE: + // could wrap time dumps as well, if timestep size did not vary + // if wrap when timestep size varies frequently, + // then can do many unneeded addstep() --> inefficient + // hard to know if timestep varies, since run every could change it + // can't remove an uneeded addstep from a compute, b/c don't know + // what other command may have added it + + int writeflag; + + if (next_dump_any == ntimestep) { + for (int idump = 0; idump < ndump; idump++) { + if (next_dump[idump] == ntimestep) { + if (last_dump[idump] == ntimestep) continue; + + if (mode_dump[idump] == 0 && + (dump[idump]->clearstep || var_dump[idump])) + modify->clearstep_compute(); + + // perform dump + // reset next_dump and next_time_dump, 1 arg for write() + + dump[idump]->write(); + last_dump[idump] = ntimestep; + calculate_next_dump(1,idump,ntimestep); + + if (mode_dump[idump] == 0 && + (dump[idump]->clearstep || var_dump[idump])) + modify->addstep_compute(next_dump[idump]); + } + + if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]); + else next_dump_any = next_dump[0]; + } + } + + // next_restart does not force output on last step of run + // for toggle = 0, replace "*" with current timestep in restart filename + // next restart variable may invoke computes so wrap with clear/add + + if (next_restart == ntimestep) { + if (next_restart_single == ntimestep) { + + std::string file = restart1; + std::size_t found = file.find('*'); + if (found != std::string::npos) + file.replace(found,1,fmt::format("{}",update->ntimestep)); + + if (last_restart != ntimestep) restart->write(file); + + if (restart_every_single) next_restart_single += restart_every_single; + else { + modify->clearstep_compute(); + bigint nextrestart = static_cast + (input->variable->compute_equal(ivar_restart_single)); + if (nextrestart <= ntimestep) + error->all(FLERR,"Restart variable returned a bad timestep"); + next_restart_single = nextrestart; + modify->addstep_compute(next_restart_single); + } + } + if (next_restart_double == ntimestep) { + if (last_restart != ntimestep) { + if (restart_toggle == 0) { + restart->write(restart2a); + restart_toggle = 1; + } else { + restart->write(restart2b); + restart_toggle = 0; + } + } + if (restart_every_double) next_restart_double += restart_every_double; + else { + modify->clearstep_compute(); + bigint nextrestart = static_cast + (input->variable->compute_equal(ivar_restart_double)); + if (nextrestart <= ntimestep) + error->all(FLERR,"Restart variable returned a bad timestep"); + next_restart_double = nextrestart; + modify->addstep_compute(next_restart_double); + } + } + last_restart = ntimestep; + next_restart = MIN(next_restart_single,next_restart_double); + } + + // insure next_thermo forces output on last step of run + // thermo may invoke computes so wrap with clear/add + + if (next_thermo == ntimestep) { + modify->clearstep_compute(); + if (last_thermo != ntimestep) thermo->compute(1); + last_thermo = ntimestep; + if (var_thermo) { + next_thermo = static_cast + (input->variable->compute_equal(ivar_thermo)); + if (next_thermo <= ntimestep) + error->all(FLERR,"Thermo every variable returned a bad timestep"); + } else if (thermo_every) next_thermo += thermo_every; + else next_thermo = update->laststep; + next_thermo = MIN(next_thermo,update->laststep); + modify->addstep_compute(next_thermo); + } + + // next = next timestep any output will be done + + next = MIN(next_dump_any,next_restart); + next = MIN(next,next_thermo); + } + + /* ---------------------------------------------------------------------- + force a snapshot to be written for all dumps + called from PRD and TAD + ------------------------------------------------------------------------- */ + + void Output::write_dump(bigint ntimestep) + { + for (int idump = 0; idump < ndump; idump++) { + dump[idump]->write(); + last_dump[idump] = ntimestep; + } + } + + /* ---------------------------------------------------------------------- + calculate when next dump occurs for Dump instance idump + operates in one of two modes, based on mode_dump flag + for timestep mode, set next_dump + for simulation time mode, set next_time_dump and next_dump + which flag depends on caller + 0 = from setup() at start of run + 1 = from write() during run each time a dump file is written + 2 = from reset_dt() called from fix dt/reset when it changes timestep size + ------------------------------------------------------------------------- */ + + void Output::calculate_next_dump(int which, int idump, bigint ntimestep) + { + // dump mode is by timestep + // just set next_dump + + if (mode_dump[idump] == 0) { + + if (every_dump[idump]) { + + // which = 0: nextdump = next multiple of every_dump + // which = 1: increment nextdump by every_dump + + if (which == 0) + next_dump[idump] = + (ntimestep/every_dump[idump])*every_dump[idump] + every_dump[idump]; + else if (which == 1) + next_dump[idump] += every_dump[idump]; + + } else { + next_dump[idump] = static_cast + (input->variable->compute_equal(ivar_dump[idump])); + if (next_dump[idump] <= ntimestep) + error->all(FLERR,"Dump every variable returned a bad timestep"); + } + + // dump mode is by simulation time + // set next_time_dump and next_dump + + } else { + + bigint nextdump; + double nexttime; + double tcurrent = update->atime + + (ntimestep - update->atimestep) * update->dt; + + if (every_time_dump[idump] > 0.0) { + + // which = 0: nexttime = next multiple of every_time_dump + // which = 1: increment nexttime by every_time_dump + // which = 2: no change to previous nexttime (only timestep has changed) + + if (which == 0) + nexttime = static_cast (tcurrent/every_time_dump[idump]) * + every_time_dump[idump] + every_time_dump[idump]; + else if (which == 1) + nexttime = next_time_dump[idump] + every_time_dump[idump]; + else if (which == 2) + nexttime = next_time_dump[idump]; + + nextdump = ntimestep + + static_cast ((nexttime - tcurrent - EPSDT*update->dt) / + update->dt) + 1; + + // if delta is too small to reach next timestep, use multiple of delta + + if (nextdump == ntimestep) { + double tnext = update->atime + + (ntimestep+1 - update->atimestep) * update->dt; + int multiple = static_cast + ((tnext - nexttime) / every_time_dump[idump]); + nexttime = nexttime + (multiple+1)*every_time_dump[idump]; + nextdump = ntimestep + + static_cast ((nexttime - tcurrent - EPSDT*update->dt) / + update->dt) + 1; + } + + } else { + + // do not re-evaulate variable for which = 2, leave nexttime as-is + // unless next_time_dump < 0.0, which means variable never yet evaluated + + if (which < 2 || next_time_dump[idump] < 0.0) { + nexttime = input->variable->compute_equal(ivar_dump[idump]); + } else + nexttime = next_time_dump[idump]; + + if (nexttime <= tcurrent) + error->all(FLERR,"Dump every/time variable returned a bad time"); + + nextdump = ntimestep + + static_cast ((nexttime - tcurrent - EPSDT*update->dt) / + update->dt) + 1; + if (nextdump <= ntimestep) + error->all(FLERR,"Dump every/time variable too small for next timestep"); + } + + next_time_dump[idump] = nexttime; + next_dump[idump] = nextdump; + } + } + +/* ---------------------------------------------------------------------- */ + +int Output::check_time_dumps(bigint ntimestep) { - // perform dump if its next_dump = current ntimestep - // but not if it was already written on this step - // set next_dump and also next_time_dump for mode_dump = 1 - // set next_dump_any to smallest next_dump - // wrap dumps that invoke computes or do variable eval with clear/add + int nowflag = 0; + for (int i = 0; i < ndump; i++) + if (mode_dump[i] && next_dump[i] == ntimestep) nowflag = 1; - int writeflag; - - if (next_dump_any == ntimestep) { - for (int idump = 0; idump < ndump; idump++) { - if (next_dump[idump] == ntimestep) { - if (last_dump[idump] == ntimestep) continue; - - if (dump[idump]->clearstep || var_dump[idump]) - modify->clearstep_compute(); - - // perform dump - // reset next_dump and next_time_dump, 1 arg for write() - - dump[idump]->write(); - last_dump[idump] = ntimestep; - calculate_next_dump(1,idump,ntimestep); - - if (dump[idump]->clearstep || var_dump[idump]) - modify->addstep_compute(next_dump[idump]); - } - - if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]); - else next_dump_any = next_dump[0]; - } - } - - // next_restart does not force output on last step of run - // for toggle = 0, replace "*" with current timestep in restart filename - // next restart variable may invoke computes so wrap with clear/add - - if (next_restart == ntimestep) { - if (next_restart_single == ntimestep) { - - std::string file = restart1; - std::size_t found = file.find('*'); - if (found != std::string::npos) - file.replace(found,1,fmt::format("{}",update->ntimestep)); - - if (last_restart != ntimestep) restart->write(file); - - if (restart_every_single) next_restart_single += restart_every_single; - else { - modify->clearstep_compute(); - bigint nextrestart = static_cast - (input->variable->compute_equal(ivar_restart_single)); - if (nextrestart <= ntimestep) - error->all(FLERR,"Restart variable returned a bad timestep"); - next_restart_single = nextrestart; - modify->addstep_compute(next_restart_single); - } - } - if (next_restart_double == ntimestep) { - if (last_restart != ntimestep) { - if (restart_toggle == 0) { - restart->write(restart2a); - restart_toggle = 1; - } else { - restart->write(restart2b); - restart_toggle = 0; - } - } - if (restart_every_double) next_restart_double += restart_every_double; - else { - modify->clearstep_compute(); - bigint nextrestart = static_cast - (input->variable->compute_equal(ivar_restart_double)); - if (nextrestart <= ntimestep) - error->all(FLERR,"Restart variable returned a bad timestep"); - next_restart_double = nextrestart; - modify->addstep_compute(next_restart_double); - } - } - last_restart = ntimestep; - next_restart = MIN(next_restart_single,next_restart_double); - } - - // insure next_thermo forces output on last step of run - // thermo may invoke computes so wrap with clear/add - - if (next_thermo == ntimestep) { - modify->clearstep_compute(); - if (last_thermo != ntimestep) thermo->compute(1); - last_thermo = ntimestep; - if (var_thermo) { - next_thermo = static_cast - (input->variable->compute_equal(ivar_thermo)); - if (next_thermo <= ntimestep) - error->all(FLERR,"Thermo every variable returned a bad timestep"); - } else if (thermo_every) next_thermo += thermo_every; - else next_thermo = update->laststep; - next_thermo = MIN(next_thermo,update->laststep); - modify->addstep_compute(next_thermo); - } - - // next = next timestep any output will be done - - next = MIN(next_dump_any,next_restart); - next = MIN(next,next_thermo); + return nowflag; } -/* ---------------------------------------------------------------------- - force a snapshot to be written for all dumps - called from PRD and TAD -------------------------------------------------------------------------- */ + /* ---------------------------------------------------------------------- + force restart file(s) to be written + called from PRD and TAD + ------------------------------------------------------------------------- */ -void Output::write_dump(bigint ntimestep) -{ - for (int idump = 0; idump < ndump; idump++) { - dump[idump]->write(); - last_dump[idump] = ntimestep; - } -} + void Output::write_restart(bigint ntimestep) + { + if (restart_flag_single) { + std::string file = restart1; + std::size_t found = file.find('*'); + if (found != std::string::npos) + file.replace(found,1,fmt::format("{}",update->ntimestep)); + restart->write(file); + } + + if (restart_flag_double) { + if (restart_toggle == 0) { + restart->write(restart2a); + restart_toggle = 1; + } else { + restart->write(restart2b); + restart_toggle = 0; + } + } + + last_restart = ntimestep; + } + + /* ---------------------------------------------------------------------- + timestep is being changed, called by update->reset_timestep() + for dumps, require that no dump is "active" + meaning that a snapshot has already been output + reset next output values for restart and thermo + reset to smallest value >= new timestep + if next timestep set by variable evaluation, + eval for ntimestep-1, so current ntimestep can be returned if needed + no guarantee that variable can be evaluated for ntimestep-1 + e.g. if it depends on computes, but live with that rare case for now + ------------------------------------------------------------------------- */ + + void Output::reset_timestep(bigint ntimestep) + { + next_dump_any = MAXBIGINT; + for (int idump = 0; idump < ndump; idump++) + if (last_dump[idump] >= 0) + error->all(FLERR, + "Cannot reset timestep with active dump - must undump first"); + + if (restart_flag_single) { + if (restart_every_single) { + next_restart_single = + (ntimestep/restart_every_single)*restart_every_single; + if (next_restart_single < ntimestep) + next_restart_single += restart_every_single; + } else { + modify->clearstep_compute(); + update->ntimestep--; + bigint nextrestart = static_cast + (input->variable->compute_equal(ivar_restart_single)); + if (nextrestart < ntimestep) + error->all(FLERR,"Restart variable returned a bad timestep"); + update->ntimestep++; + next_restart_single = nextrestart; + modify->addstep_compute(next_restart_single); + } + } else next_restart_single = update->laststep + 1; + + if (restart_flag_double) { + if (restart_every_double) { + next_restart_double = + (ntimestep/restart_every_double)*restart_every_double; + if (next_restart_double < ntimestep) + next_restart_double += restart_every_double; + } else { + modify->clearstep_compute(); + update->ntimestep--; + bigint nextrestart = static_cast + (input->variable->compute_equal(ivar_restart_double)); + if (nextrestart < ntimestep) + error->all(FLERR,"Restart variable returned a bad timestep"); + update->ntimestep++; + next_restart_double = nextrestart; + modify->addstep_compute(next_restart_double); + } + } else next_restart_double = update->laststep + 1; + + next_restart = MIN(next_restart_single,next_restart_double); + + if (var_thermo) { + modify->clearstep_compute(); + update->ntimestep--; + next_thermo = static_cast + (input->variable->compute_equal(ivar_thermo)); + if (next_thermo < ntimestep) + error->all(FLERR,"Thermo_modify every variable returned a bad timestep"); + update->ntimestep++; + next_thermo = MIN(next_thermo,update->laststep); + modify->addstep_compute(next_thermo); + } else if (thermo_every) { + next_thermo = (ntimestep/thermo_every)*thermo_every; + if (next_thermo < ntimestep) next_thermo += thermo_every; + next_thermo = MIN(next_thermo,update->laststep); + } else next_thermo = update->laststep; + + next = MIN(next_dump_any,next_restart); + next = MIN(next,next_thermo); + } /* ---------------------------------------------------------------------- - calculate when next dump occurs for Dump instance idump - operates in one of two modes, based on mode_dump flag - for timestep mode, set next_dump - for simulation time mode, set next_time_dump and next_dump - which flag depends on caller - 0 = from setup() at start of run - 1 = from write() during run each time a dump file is written - 2 = from reset_dt() called from fix dt/reset when it changes timestep size -------------------------------------------------------------------------- */ - - void Output::calculate_next_dump(int which, int idump, bigint ntimestep) -{ - // dump mode is by timestep - // just set next_dump - - if (mode_dump[idump] == 0) { - - if (every_dump[idump]) { - - // which = 0: nextdump = next multiple of every_dump - // which = 1: increment nextdump by every_dump - - if (which == 0) - next_dump[idump] = - (ntimestep/every_dump[idump])*every_dump[idump] + every_dump[idump]; - else if (which == 1) - next_dump[idump] += every_dump[idump]; - - } else { - next_dump[idump] = static_cast - (input->variable->compute_equal(ivar_dump[idump])); - if (next_dump[idump] <= ntimestep) - error->all(FLERR,"Dump every variable returned a bad timestep"); - } - - // dump mode is by simulation time - // set next_time_dump and next_dump - - } else { - - bigint nextdump; - double nexttime; - double tcurrent = update->atime + - (ntimestep - update->atimestep) * update->dt; - - if (every_time_dump[idump] > 0.0) { - - // which = 0: nexttime = next multiple of every_time_dump - // which = 1: increment nexttime by every_time_dump - // which = 2: no change to previous nexttime (only timestep has changed) - - if (which == 0) - nexttime = static_cast (tcurrent/every_time_dump[idump]) * - every_time_dump[idump] + every_time_dump[idump]; - else if (which == 1) - nexttime = next_time_dump[idump] + every_time_dump[idump]; - else if (which == 2) - nexttime = next_time_dump[idump]; - - nextdump = ntimestep + - static_cast ((nexttime - tcurrent - EPSDT*update->dt) / - update->dt) + 1; - - // if delta is too small to reach next timestep, use multiple of delta - - if (nextdump == ntimestep) { - double tnext = update->atime + - (ntimestep+1 - update->atimestep) * update->dt; - int multiple = static_cast - ((tnext - nexttime) / every_time_dump[idump]); - nexttime = nexttime + (multiple+1)*every_time_dump[idump]; - nextdump = ntimestep + - static_cast ((nexttime - tcurrent - EPSDT*update->dt) / - update->dt) + 1; - } - - } else { - - // do not re-evaulate variable for which = 2, leave nexttime as-is - // unless next_time_dump < 0.0, which means variable never yet evaluated - - if (which < 2 || next_time_dump[idump] < 0.0) { - nexttime = input->variable->compute_equal(ivar_dump[idump]); - } else - nexttime = next_time_dump[idump]; - - if (nexttime <= tcurrent) - error->all(FLERR,"Dump every/time variable returned a bad time"); - - nextdump = ntimestep + - static_cast ((nexttime - tcurrent - EPSDT*update->dt) / - update->dt) + 1; - if (nextdump <= ntimestep) - error->all(FLERR,"Dump every/time variable too small for next timestep"); - } - - next_time_dump[idump] = nexttime; - next_dump[idump] = nextdump; - } -} - -/* ---------------------------------------------------------------------- - force restart file(s) to be written - called from PRD and TAD -------------------------------------------------------------------------- */ - -void Output::write_restart(bigint ntimestep) -{ - if (restart_flag_single) { - std::string file = restart1; - std::size_t found = file.find('*'); - if (found != std::string::npos) - file.replace(found,1,fmt::format("{}",update->ntimestep)); - restart->write(file); - } - - if (restart_flag_double) { - if (restart_toggle == 0) { - restart->write(restart2a); - restart_toggle = 1; - } else { - restart->write(restart2b); - restart_toggle = 0; - } - } - - last_restart = ntimestep; -} - -/* ---------------------------------------------------------------------- - timestep is being changed, called by update->reset_timestep() - for dumps, require that no dump is "active" - meaning that a snapshot has already been output - reset next output values restart and thermo output - reset to smallest value >= new timestep - if next timestep set by variable evaluation, - eval for ntimestep-1, so current ntimestep can be returned if needed - no guarantee that variable can be evaluated for ntimestep-1 - e.g. if it depends on computes, but live with that rare case for now -------------------------------------------------------------------------- */ - -void Output::reset_timestep(bigint ntimestep) -{ - next_dump_any = MAXBIGINT; - for (int idump = 0; idump < ndump; idump++) - if (last_dump[idump] >= 0) - error->all(FLERR, - "Cannot reset timestep with active dump - must undump first"); - - if (restart_flag_single) { - if (restart_every_single) { - next_restart_single = - (ntimestep/restart_every_single)*restart_every_single; - if (next_restart_single < ntimestep) - next_restart_single += restart_every_single; - } else { - modify->clearstep_compute(); - update->ntimestep--; - bigint nextrestart = static_cast - (input->variable->compute_equal(ivar_restart_single)); - if (nextrestart < ntimestep) - error->all(FLERR,"Restart variable returned a bad timestep"); - update->ntimestep++; - next_restart_single = nextrestart; - modify->addstep_compute(next_restart_single); - } - } else next_restart_single = update->laststep + 1; - - if (restart_flag_double) { - if (restart_every_double) { - next_restart_double = - (ntimestep/restart_every_double)*restart_every_double; - if (next_restart_double < ntimestep) - next_restart_double += restart_every_double; - } else { - modify->clearstep_compute(); - update->ntimestep--; - bigint nextrestart = static_cast - (input->variable->compute_equal(ivar_restart_double)); - if (nextrestart < ntimestep) - error->all(FLERR,"Restart variable returned a bad timestep"); - update->ntimestep++; - next_restart_double = nextrestart; - modify->addstep_compute(next_restart_double); - } - } else next_restart_double = update->laststep + 1; - - next_restart = MIN(next_restart_single,next_restart_double); - - if (var_thermo) { - modify->clearstep_compute(); - update->ntimestep--; - next_thermo = static_cast - (input->variable->compute_equal(ivar_thermo)); - if (next_thermo < ntimestep) - error->all(FLERR,"Thermo_modify every variable returned a bad timestep"); - update->ntimestep++; - next_thermo = MIN(next_thermo,update->laststep); - modify->addstep_compute(next_thermo); - } else if (thermo_every) { - next_thermo = (ntimestep/thermo_every)*thermo_every; - if (next_thermo < ntimestep) next_thermo += thermo_every; - next_thermo = MIN(next_thermo,update->laststep); - } else next_thermo = update->laststep; - - next = MIN(next_dump_any,next_restart); - next = MIN(next,next_thermo); -} - -/* ---------------------------------------------------------------------- - timestep size is being changed, called by fix dt/reset (at end of step) + timestep size is being changed reset next output values for dumps which have mode_dump=1 + called by fix dt/reset (at end of step) + or called by timestep command via run every (also at end of step) ------------------------------------------------------------------------- */ void Output::reset_dt() @@ -659,21 +687,10 @@ void Output::reset_dt() // reset next_dump but do not change next_time_dump, 2 arg for reset_dt() // do not invoke for a dump already scheduled for this step - // use compute_all() b/c don't know what computes will be needed + // since timestep change affects next step if (next_dump[idump] != ntimestep) { calculate_next_dump(2,idump,update->ntimestep); - - // NOTE: think I should not do this here - // for time dumps, calc_next_dump should calc the next timestep - // as one less and not add it to computes - // then on that step, write() should not actually write the dump - // but trigger it on next step and addstep_compute_all for that step - // b/c when write() is called, the next-step timestep is set - // unless run every timestep is invoked in-between! - - //if (dump[idump]->clearstep || var_dump[idump]) - // modify->addstep_compute_all(next_dump[idump]); } } @@ -684,6 +701,7 @@ void Output::reset_dt() next = MIN(next,next_thermo); } + /* ---------------------------------------------------------------------- add a Dump to list of Dumps ------------------------------------------------------------------------- */ diff --git a/src/output.h b/src/output.h index c8d3f734e0..c7c4faf252 100644 --- a/src/output.h +++ b/src/output.h @@ -36,6 +36,7 @@ class Output : protected Pointers { int ndump; // # of Dumps defined int max_dump; // max size of Dump list bigint next_dump_any; // next timestep for any Dump + int any_time_dumps; // 1 if any time dump defined int *mode_dump; // 0/1 if write every N timesteps or Delta in sim time int *every_dump; // dump every N timesteps, 0 if variable double *every_time_dump; // dump every Delta of sim time, 0.0 if variable @@ -75,13 +76,14 @@ class Output : protected Pointers { void write(bigint); // output for current timestep void write_dump(bigint); // force output of dump snapshots void write_restart(bigint); // force output of a restart file - void reset_timestep(bigint); // reset output which depeneds on timestep - void reset_dt(); // reset output which depends on dt + void reset_timestep(bigint); // reset output which depends on timestep + void reset_dt(); // reset output which depends on timestep size void add_dump(int, char **); // add a Dump to Dump list void modify_dump(int, char **); // modify a Dump void delete_dump(char *); // delete a Dump from Dump list int find_dump(const char *); // find a Dump ID + int check_time_dumps(bigint); // check if any time dump is output now void set_thermo(int, char **); // set thermo output freqquency void create_thermo(int, char **); // create a thermo style diff --git a/src/verlet.cpp b/src/verlet.cpp index 348639ef05..342dc3d951 100644 --- a/src/verlet.cpp +++ b/src/verlet.cpp @@ -252,8 +252,6 @@ void Verlet::run(int n) ntimestep = ++update->ntimestep; ev_set(ntimestep); - printf("VERLET %ld: %d %d\n",ntimestep,eflag,vflag); - // initial time integration timer->stamp(); From 6187431399a1ad6711d882061ec28c697dbd45a7 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Tue, 21 Dec 2021 08:34:02 -0700 Subject: [PATCH 047/193] Fix compile error in angle_class2_kokkos --- src/KOKKOS/angle_class2_kokkos.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/KOKKOS/angle_class2_kokkos.cpp b/src/KOKKOS/angle_class2_kokkos.cpp index 0bcc3ad458..2a386f6489 100644 --- a/src/KOKKOS/angle_class2_kokkos.cpp +++ b/src/KOKKOS/angle_class2_kokkos.cpp @@ -224,8 +224,8 @@ void AngleClass2Kokkos::operator()(TagAngleClass2Compute::operator()(TagAngleClass2Compute Date: Tue, 21 Dec 2021 11:28:26 -0500 Subject: [PATCH 048/193] reset force test references for Class2 angle styles --- unittest/force-styles/tests/angle-class2.yaml | 129 ++++++++--------- .../force-styles/tests/angle-class2_p6.yaml | 131 +++++++++--------- 2 files changed, 131 insertions(+), 129 deletions(-) diff --git a/unittest/force-styles/tests/angle-class2.yaml b/unittest/force-styles/tests/angle-class2.yaml index c8896efba1..0b50cce4f6 100644 --- a/unittest/force-styles/tests/angle-class2.yaml +++ b/unittest/force-styles/tests/angle-class2.yaml @@ -1,7 +1,8 @@ --- -lammps_version: 10 Feb 2021 -date_generated: Fri Feb 26 23:09:23 2021 +lammps_version: 14 Dec 2021 +date_generated: Tue Dec 21 11:26:44 2021 epsilon: 1e-12 +skip_tests: prerequisites: ! | atom full angle class2 @@ -21,73 +22,73 @@ angle_coeff: ! | 1 ba 20.0 0.0 1.5 1.5 3 ba 10.0 10.0 1.5 1.5 4 ba 0.0 20.0 1.5 1.5 -equilibrium: 4 1.9216075064457565 1.9373154697137058 2.0943951023931953 1.8936822384138474 +equilibrium: 4 1.9216075064457567 1.9373154697137058 2.0943951023931953 1.8936822384138476 extract: ! "" natoms: 29 -init_energy: 45.6315872862689 +init_energy: 46.440896837749044 init_stress: ! |2- - 1.0380900034455654e+02 -8.5596888576343744e+01 1.0543371457027396e+01 9.3533772092305199e+01 -3.0453078736699425e+01 1.6197471265279837e+00 + 1.1893382158997322e+02 -8.8291447119046992e+01 -1.8868912456859972e+00 1.1299617626314146e+02 -8.5358891009896780e+00 7.6967639957246794e+00 init_forces: ! |2 - 1 4.7202113476907201e+01 9.2452097148049379e+00 -2.1894202744712533e+01 - 2 -1.7062797644104073e+00 -1.3815331678107317e+01 -1.1109216556988997e+01 - 3 -1.0818552868961547e+01 4.2757153900854306e+01 4.0134050204129267e+01 - 4 -1.6107291199158311e+01 -2.0450831607561582e+01 1.2394641799374179e+01 - 5 -4.1997303662023540e+01 -4.1453062742803219e+01 -1.7536792897035419e+01 - 6 5.6639792403457349e+01 -1.3580769610788053e+01 -3.9712060060785255e+01 - 7 -1.8054439727078506e+01 1.6983062508083172e+01 1.5587306726806713e+00 - 8 -1.0525801597483865e+01 -1.5574411954009244e+01 8.4303126221362277e+01 - 9 -1.4606126670427546e+01 1.7088847325775880e+01 3.5265027966992148e+00 - 10 -9.2168170333014618e+00 2.5310906045489432e+01 -6.6219876033939016e+01 + 1 4.9843771864003834e+01 3.0925122596911816e+00 -3.5312722193312226e+01 + 2 -7.6547115157834666e-01 -6.1978334793953476e+00 -4.9838162348189323e+00 + 3 -2.0132137208074248e+01 6.1565994561526715e+01 5.8548546756498347e+01 + 4 -1.1800898073962109e+01 -2.7342191490108263e+01 3.6024091179236257e+00 + 5 -3.5756372747916700e+01 -5.0661360858658405e+01 -1.9085859271498553e+01 + 6 5.0734800121225135e+01 -1.5633459340466136e+01 -3.6451541950394720e+01 + 7 -1.8030285239813821e+01 1.7009172193091111e+01 1.5544411167675971e+00 + 8 -1.5632958318497042e+01 -2.1571227015465091e+01 7.4636601692831320e+01 + 9 -1.4606126670427546e+01 1.7088847325775880e+01 3.5265027966992157e+00 + 10 4.9412614063426892e+00 3.2891848318072718e+01 -5.8999099084298045e+01 11 -2.0537012066379056e+01 -7.0930129287428976e+00 7.5068656204459945e+00 - 12 -2.8436344574011141e-01 -6.5767250423083183e+00 -7.8126221608778286e+00 - 13 3.1055904718024561e+00 8.1431271170459514e+00 -1.2597779054058647e+00 - 14 1.6321646299623836e+01 -6.4737292023940052e+00 -6.0969666237587319e+00 - 15 1.2014703003264437e+01 -4.7819952969181587e+00 1.5497667618539472e+01 - 16 9.3845211462413065e+00 9.2380044230210405e+00 6.9332654848904189e+00 - 17 -8.1437876633224571e-01 1.0335590285580882e+00 -2.1333543461785509e-01 - 18 4.7908728028679270e-01 1.6800089801308631e+00 -5.5268875505867383e+00 - 19 -2.0533806941129176e+00 -2.3525964439530416e+00 2.1320670955883561e+00 - 20 1.5742934138261249e+00 6.7258746382217860e-01 3.3948204549983823e+00 - 21 3.9487378529081880e+00 4.3175316427012014e+00 -1.1481919601133793e+01 - 22 -6.5477089696018744e+00 -4.1918690971369452e+00 3.4304260006102911e+00 - 23 2.5989711166936864e+00 -1.2566254556425660e-01 8.0514936005235018e+00 - 24 -8.4094048868779181e-01 4.6838060982897600e+00 -2.5056979703433946e+00 - 25 -1.3589399152326838e+00 -3.2194810517526529e+00 2.1726606908305435e-01 - 26 2.1998804039204756e+00 -1.4643250465371074e+00 2.2884319012603402e+00 - 27 -1.3120258950869723e-01 2.3248353742613195e+00 -7.0687277526256109e-01 - 28 -7.9798149428972343e-01 -1.3623378004463826e+00 -7.5274691791676882e-02 - 29 9.2918408379842066e-01 -9.6249757381493684e-01 7.8214746705423799e-01 -run_energy: 45.4459195202412 + 12 1.3804183606931298e+01 6.4447653590032914e+00 -2.7232856026007504e+01 + 13 3.5360349619705711e-01 9.1396982628926138e-01 4.4753951517849107e+00 + 14 9.6171168365401805e+00 -1.2052302426663841e+01 -3.9493877514992031e+00 + 15 6.4860723734536965e+00 -7.3468753785680629e+00 2.2291265160011950e+01 + 16 -2.1230106290243054e+00 1.3874285421512146e+01 6.8398804299585079e+00 + 17 3.6034624009792791e+00 -4.9831323468942506e+00 3.0333746689077179e+00 + 18 8.4504245756073892e-01 5.5042293626682808e+00 -2.1046811461460457e+01 + 19 -6.5342341140829419e+00 -7.9348302620004993e+00 8.7785874834232587e+00 + 20 5.6891916565222029e+00 2.4306008993322186e+00 1.2268223978037199e+01 + 21 7.8687847056106097e+00 9.2247825951126554e+00 -2.6147407661059020e+01 + 22 -1.3528173582118603e+01 -8.9511461518324538e+00 8.6148798736605858e+00 + 23 5.6593888765079932e+00 -2.7363644328020120e-01 1.7532527787398436e+01 + 24 -4.3228091413199312e+00 1.8218035887352222e+01 -1.0563459250035294e+01 + 25 -4.1518972409293955e+00 -1.2576945219214169e+01 1.7476216234117312e+00 + 26 8.4747063822493267e+00 -5.6410906681380535e+00 8.8158376266235621e+00 + 27 -1.9941459534406549e+00 1.7618141002760062e+01 -5.9162802776486032e+00 + 28 -4.8714180504657234e+00 -1.0506429973856317e+01 1.3714179563487131e-01 + 29 6.8655640039063783e+00 -7.1117110289037466e+00 5.7791384820137317e+00 +run_energy: 46.04254213414856 run_stress: ! |2- - 1.0224296939567702e+02 -8.5149951148281033e+01 1.1077450496851872e+01 9.2245165502849829e+01 -3.1084418227269154e+01 5.2366663320491313e-01 + 1.1725321346181148e+02 -8.7851127936553254e+01 -1.2820805825603960e+00 1.1164348489319656e+02 -9.3238396977559397e+00 6.5868867241338807e+00 run_forces: ! |2 - 1 4.6696948163060675e+01 9.5469544165543052e+00 -2.1330948302985508e+01 - 2 -1.7341210851964273e+00 -1.4128897827282087e+01 -1.1408863992275160e+01 - 3 -1.0105551089272240e+01 4.2277702428791336e+01 3.9657670069675063e+01 - 4 -1.6122111935066883e+01 -2.0098532812588481e+01 1.2653235408843411e+01 - 5 -4.2111565648427224e+01 -4.1283493356078523e+01 -1.7589964848850386e+01 - 6 5.6633343610296642e+01 -1.3630420678353568e+01 -3.9740642386699271e+01 - 7 -1.8067962126721181e+01 1.7005582120491120e+01 1.5568169485445109e+00 - 8 -1.0459403976386902e+01 -1.5611162457913967e+01 8.4226500676174069e+01 - 9 -1.4631300686651667e+01 1.7116506905325277e+01 3.5366459989463483e+00 - 10 -9.1067423535925318e+00 2.5083637022662394e+01 -6.6120603070314331e+01 - 11 -2.0531188000382802e+01 -7.0572039110412836e+00 7.4976926119744087e+00 - 12 -4.5804053460484440e-01 -6.7408368318088137e+00 -7.3612432437675679e+00 - 13 3.0256565331949181e+00 7.9773964875310250e+00 -1.1599249084139895e+00 - 14 1.6325797226942768e+01 -6.0364594808671850e+00 -6.0596304628457736e+00 - 15 1.2032950547216590e+01 -4.6547008559207024e+00 1.4984306358892226e+01 - 16 9.4390365741788855e+00 9.1831264349550388e+00 6.8856125869099509e+00 - 17 -8.2574521858778427e-01 1.0508023955441044e+00 -2.2665944380799952e-01 - 18 4.1662989783566795e-01 1.4355996853101134e+00 -4.6916036738076876e+00 - 19 -1.7454972366844239e+00 -2.0016596312326365e+00 1.8125096846165301e+00 - 20 1.3288673388487560e+00 5.6605994592252307e-01 2.8790939891911576e+00 - 21 3.7257661846966093e+00 4.0481711597815977e+00 -1.0827752619904448e+01 - 22 -6.1593135050903065e+00 -3.9305106214838132e+00 3.2463364124342222e+00 - 23 2.4335473203936973e+00 -1.1766053829778456e-01 7.5814162074702249e+00 - 24 -7.6007405188534261e-01 4.2086623877720974e+00 -2.2508903613389659e+00 - 25 -1.2107922910240914e+00 -2.8924997143595577e+00 1.9797185345341334e-01 - 26 1.9708663429094340e+00 -1.3161626734125400e+00 2.0529185078855527e+00 - 27 -1.2690270648686752e-01 2.1785298399231308e+00 -6.5914069723159696e-01 - 28 -7.4337188418354749e-01 -1.2769741286441925e+00 -7.1075298614674390e-02 - 29 8.7027459067041502e-01 -9.0155571127893830e-01 7.3021599584627139e-01 + 1 4.9310488854556048e+01 3.4204699131043999e+00 -3.4719646460390109e+01 + 2 -8.0299294685685085e-01 -6.5454065929116556e+00 -5.2863994125400326e+00 + 3 -1.9344188743451483e+01 6.1008236345827427e+01 5.7990450617574737e+01 + 4 -1.1820915021801847e+01 -2.6960419197209372e+01 3.9252515610422387e+00 + 5 -3.5905034771726200e+01 -5.0435101635947014e+01 -1.9146824911182328e+01 + 6 5.0729278972279332e+01 -1.5703691297521928e+01 -3.6490325001299325e+01 + 7 -1.8043757960499846e+01 1.7038616039733434e+01 1.5516900804512148e+00 + 8 -1.5552591757457865e+01 -2.1589081417070179e+01 7.4580844287823936e+01 + 9 -1.4632487393832747e+01 1.7116771489893083e+01 3.5369114786793467e+00 + 10 5.0177324966376649e+00 3.2655409113932286e+01 -5.8914010758009439e+01 + 11 -2.0526018243356614e+01 -7.0603095274350611e+00 7.4991583014498691e+00 + 12 1.3523522841409502e+01 6.2514718031216852e+00 -2.6685798485651077e+01 + 13 3.0043046271322960e-01 7.8431109074530148e-01 4.5328635576848786e+00 + 14 9.6740453376714228e+00 -1.1603919453433887e+01 -3.9205080570168040e+00 + 15 6.5345442098934683e+00 -7.2391735244141353e+00 2.1740136588792641e+01 + 16 -2.0494434617404407e+00 1.3825958913895089e+01 6.7881976680816249e+00 + 17 3.5873871255632257e+00 -4.9641420643094554e+00 3.0180089445086313e+00 + 18 7.9531230378610207e-01 5.2629626454507630e+00 -2.0172279025467247e+01 + 19 -6.1997999385006839e+00 -7.5645533008417640e+00 8.4605118212170112e+00 + 20 5.4044876347145818e+00 2.3015906553910015e+00 1.1711767204250236e+01 + 21 7.6462499201271452e+00 8.9238366526271982e+00 -2.5489460284469285e+01 + 22 -1.3116044133706563e+01 -8.6583255717724796e+00 8.4434021193141291e+00 + 23 5.4697942135794175e+00 -2.6551108085471875e-01 1.7046058165155156e+01 + 24 -4.2497082139356905e+00 1.7742951256065766e+01 -1.0303002556901220e+01 + 25 -3.9777181755411437e+00 -1.2246864111150519e+01 1.7323644652289971e+00 + 26 8.2274263894768342e+00 -5.4960871449152453e+00 8.5706380916722225e+00 + 27 -2.0048516565658536e+00 1.7446299537442144e+01 -5.8315780788096188e+00 + 28 -4.7894277572886974e+00 -1.0406054769833135e+01 1.3027326655161572e-01 + 29 6.7942794138545510e+00 -7.0402447676090096e+00 5.7013048122580035e+00 ... diff --git a/unittest/force-styles/tests/angle-class2_p6.yaml b/unittest/force-styles/tests/angle-class2_p6.yaml index 68676960f7..367dc2f450 100644 --- a/unittest/force-styles/tests/angle-class2_p6.yaml +++ b/unittest/force-styles/tests/angle-class2_p6.yaml @@ -1,7 +1,8 @@ --- -lammps_version: 10 Feb 2021 -date_generated: Fri Feb 26 23:09:23 2021 +lammps_version: 14 Dec 2021 +date_generated: Tue Dec 21 11:26:44 2021 epsilon: 5e-13 +skip_tests: prerequisites: ! | atom full angle class2/p6 @@ -21,73 +22,73 @@ angle_coeff: ! | 1 ba 20.0 0.0 1.5 1.5 3 ba 10.0 10.0 1.5 1.5 4 ba 0.0 20.0 1.5 1.5 -equilibrium: 4 1.9216075064457565 1.9373154697137058 2.0943951023931953 1.8936822384138474 +equilibrium: 4 1.9216075064457567 1.9373154697137058 2.0943951023931953 1.8936822384138476 extract: ! "" natoms: 29 -init_energy: 45.6314933281677 +init_energy: 46.440802879647805 init_stress: ! |2- - 1.0380655176146676e+02 -8.5598294304263064e+01 1.0547225768036466e+01 9.3533997442530364e+01 -3.0452940351933286e+01 1.6213985364060581e+00 + 1.1893137300688346e+02 -8.8292852846966269e+01 -1.8830369346769591e+00 1.1299640161336661e+02 -8.5357507162235464e+00 7.6984154056027378e+00 init_forces: ! |2 - 1 4.7202230480286389e+01 9.2446782757168187e+00 -2.1892853730746999e+01 - 2 -1.7062799943363052e+00 -1.3815333539761312e+01 -1.1109218053986531e+01 - 3 -1.0819442137600213e+01 4.2755643579721394e+01 4.0131978148937094e+01 - 4 -1.6107331786015202e+01 -2.0450833016170897e+01 1.2394698445624217e+01 - 5 -4.1996775288710346e+01 -4.1451276926607676e+01 -1.7536151963373857e+01 - 6 5.6640330905804802e+01 -1.3581373316126099e+01 -3.9714075413905050e+01 - 7 -1.8054191673295325e+01 1.6982840171711775e+01 1.5587849314106879e+00 - 8 -1.0524752828621686e+01 -1.5572494690475857e+01 8.4307006012653105e+01 - 9 -1.4606116746275049e+01 1.7088845087132931e+01 3.5265010989798085e+00 - 10 -9.2183983294618113e+00 2.5308833813269253e+01 -6.6220570658369525e+01 - 11 -2.0536178089795950e+01 -7.0922505905966178e+00 7.5061958159305595e+00 - 12 -2.8507497680544613e-01 -6.5761946491161254e+00 -7.8131884119322397e+00 - 13 3.1055913097859387e+00 8.1431291943766304e+00 -1.2597770427903630e+00 - 14 1.6321556949530429e+01 -6.4737931388148002e+00 -6.0969371866598330e+00 - 15 1.2014697273266693e+01 -4.7819939276460772e+00 1.5497663357748195e+01 - 16 9.3845137052789855e+00 9.2380146356987876e+00 6.9332800900251534e+00 - 17 -8.1437877303591466e-01 1.0335590376878656e+00 -2.1333543954444023e-01 - 18 4.7908727278798890e-01 1.6800089017685975e+00 -5.5268872325673071e+00 - 19 -2.0533806022955563e+00 -2.3525963295672470e+00 2.1320669593942201e+00 - 20 1.5742933295075674e+00 6.7258742779864933e-01 3.3948202731730870e+00 - 21 3.9487365123920992e+00 4.3175299645965515e+00 -1.1481914586060395e+01 - 22 -6.5477065825321601e+00 -4.1918674696340856e+00 3.4304242277121375e+00 - 23 2.5989700701400609e+00 -1.2566249496246562e-01 8.0514903583482571e+00 - 24 -8.4094044796366130e-01 4.6838059399926504e+00 -2.5056978760993669e+00 - 25 -1.3589398825660985e+00 -3.2194809423072277e+00 2.1726605118393005e-01 - 26 2.1998803305297598e+00 -1.4643249976854225e+00 2.2884318249154370e+00 - 27 -1.3120258888530634e-01 2.3248353691437700e+00 -7.0687277351935407e-01 - 28 -7.9798149292664289e-01 -1.3623377973865247e+00 -7.5274691862757134e-02 - 29 9.2918408181194923e-01 -9.6249757175724537e-01 7.8214746538211122e-01 -run_energy: 45.4458285940593 + 1 4.9843888867383036e+01 3.0919808206030721e+00 -3.5311373179346681e+01 + 2 -7.6547138150424543e-01 -6.1978353410493483e+00 -4.9838177318164663e+00 + 3 -2.0133026476712903e+01 6.1564484240393824e+01 5.8546474701306153e+01 + 4 -1.1800938660819003e+01 -2.7342192898717585e+01 3.6024657641736728e+00 + 5 -3.5755844374603512e+01 -5.0659575042462862e+01 -1.9085218337836995e+01 + 6 5.0735338623572588e+01 -1.5634063045804186e+01 -3.6453557303514501e+01 + 7 -1.8030037186030640e+01 1.7008949856719713e+01 1.5544953754976136e+00 + 8 -1.5631909549634866e+01 -2.1569309751931716e+01 7.4640481484122148e+01 + 9 -1.4606116746275049e+01 1.7088845087132935e+01 3.5265010989798080e+00 + 10 4.9396801101823433e+00 3.2889776085852560e+01 -5.8999793708728561e+01 + 11 -2.0536178089795950e+01 -7.0922505905966178e+00 7.5061958159305604e+00 + 12 1.3803472075865960e+01 6.4452957521954772e+00 -2.7233422277061912e+01 + 13 3.5360433418053783e-01 9.1397190361994329e-01 4.4753960144004115e+00 + 14 9.6170274864467693e+00 -1.2052366363084635e+01 -3.9493583144003042e+00 + 15 6.4860666434559526e+00 -7.3468740092959814e+00 2.2291260899220667e+01 + 16 -2.1230180699866263e+00 1.3874295634189895e+01 6.8398950350932433e+00 + 17 3.6034623942756108e+00 -4.9831323377644736e+00 3.0333746639811334e+00 + 18 8.4504245006193557e-01 5.5042292843060157e+00 -2.1046811143441026e+01 + 19 -6.5342340222655810e+00 -7.9348301476147052e+00 8.7785873472291236e+00 + 20 5.6891915722036455e+00 2.4306008633086891e+00 1.2268223796211903e+01 + 21 7.8687833650945196e+00 9.2247809170080028e+00 -2.6147402645985622e+01 + 22 -1.3528171195048888e+01 -8.9511445243295924e+00 8.6148781007624322e+00 + 23 5.6593878299543681e+00 -2.7363639267841045e-01 1.7532524545223190e+01 + 24 -4.3228091005958014e+00 1.8218035729055110e+01 -1.0563459155791266e+01 + 25 -4.1518972082628096e+00 -1.2576945109768744e+01 1.7476216055126070e+00 + 26 8.4747063088586110e+00 -5.6410906192863681e+00 8.8158375502786583e+00 + 27 -1.9941459528172638e+00 1.7618140997642513e+01 -5.9162802759053958e+00 + 28 -4.8714180491026431e+00 -1.0506429970796459e+01 1.3714179556379100e-01 + 29 6.8655640019199069e+00 -7.1117110268460557e+00 5.7791384803416053e+00 +run_energy: 46.04245232805462 run_stress: ! |2- - 1.0224054425179162e+02 -8.5151354715203126e+01 1.1081280882090672e+01 9.2245389115064398e+01 -3.1084294543117402e+01 5.2530572051471558e-01 + 1.1725078883087194e+02 -8.7852531332776422e+01 -1.2782508811995987e+00 1.1164371026778049e+02 -9.3237176305934248e+00 6.5885234111489295e+00 run_forces: ! |2 - 1 4.6697063144899758e+01 9.5464292184313084e+00 -2.1329615486413495e+01 - 2 -1.7341213469343071e+00 -1.4128899311205867e+01 -1.1408865229626386e+01 - 3 -1.0106423829890657e+01 4.2276216760085092e+01 3.9655618981253937e+01 - 4 -1.6122153804166530e+01 -2.0098535935851185e+01 1.2653292967815302e+01 - 5 -4.2111045474433908e+01 -4.1281732299841927e+01 -1.7589329659171515e+01 - 6 5.6633872451307042e+01 -1.3631017853516695e+01 -3.9742648484553712e+01 - 7 -1.8067710814224181e+01 1.7005356519278848e+01 1.5568722867815019e+00 - 8 -1.0458368774535296e+01 -1.5609267760781632e+01 8.4230369919214809e+01 - 9 -1.4631291097137083e+01 1.7116505329041448e+01 3.5366441447941890e+00 - 10 -9.1083165882262076e+00 2.5081593622661249e+01 -6.6121298210985884e+01 - 11 -2.0530357257878578e+01 -7.0564447871249403e+00 7.4970247183653580e+00 - 12 -4.5873997835014801e-01 -6.7403152848189372e+00 -7.3618095936615644e+00 - 13 3.0256572433426814e+00 7.9773984059331964e+00 -1.1599242567025270e+00 - 14 1.6325706512702343e+01 -6.0365250687180749e+00 -6.0596004500231722e+00 - 15 1.2032945183866531e+01 -4.6546995895395877e+00 1.4984301967909428e+01 - 16 9.4390297519529085e+00 9.1831355042234861e+00 6.8856259318712949e+00 - 17 -8.2574532229437936e-01 1.0508025317442151e+00 -2.2665954686757872e-01 - 18 4.1662989358421232e-01 1.4355996421935044e+00 -4.6916034993533247e+00 - 19 -1.7454971864999060e+00 -2.0016595685522596e+00 1.8125096096904596e+00 - 20 1.3288672929156937e+00 5.6605992635875502e-01 2.8790938896628648e+00 - 21 3.7257651397379274e+00 4.0481698601097618e+00 -1.0827748711362894e+01 - 22 -6.1593116505043302e+00 -3.9305093611054267e+00 3.2463350269770475e+00 - 23 2.4335465107664027e+00 -1.1766049900433539e-01 7.5814136843858462e+00 - 24 -7.6007402633523591e-01 4.2086622887143186e+00 -2.2508903023980524e+00 - 25 -1.2107922707762828e+00 -2.8924996458903025e+00 1.9797184221876996e-01 - 26 1.9708662971115187e+00 -1.3161626428240165e+00 2.0529184601792827e+00 - 27 -1.2690270602781828e-01 2.1785298361926788e+00 -6.5914069596767511e-01 - 28 -7.4337188319492098e-01 -1.2769741264135199e+00 -7.1075298663885261e-02 - 29 8.7027458922273926e-01 -9.0155570977915866e-01 7.3021599463156039e-01 + 1 4.9310604335655682e+01 3.4199456337672487e+00 -3.4718316191911107e+01 + 2 -8.0299317271452264e-01 -6.5454081333117653e+00 -5.2864006747626604e+00 + 3 -1.9345060126536442e+01 6.1006753750400470e+01 5.7988403049659411e+01 + 4 -1.1820957153105841e+01 -2.6960422682106536e+01 3.9253092142830135e+00 + 5 -3.5904516097808205e+01 -5.0433344031821314e+01 -1.9146190690682918e+01 + 6 5.0729808044888514e+01 -1.5704289267936588e+01 -3.6492333161602460e+01 + 7 -1.8043506480508537e+01 1.7038390298430201e+01 1.5517454554100727e+00 + 8 -1.5551557230614444e+01 -2.1587186230569777e+01 7.4584717878493251e+01 + 9 -1.4632477702925939e+01 1.7116769814092336e+01 3.5369096257061594e+00 + 10 5.0161578855418893e+00 3.2653366582115979e+01 -5.8914707964769292e+01 + 11 -2.0525187366514267e+01 -7.0595502886286221e+00 7.4984902661515953e+00 + 12 1.3522823846822945e+01 6.2519930281569955e+00 -2.6686365074578834e+01 + 13 3.0043118312382699e-01 7.8431307047186760e-01 4.5328641811452499e+00 + 14 9.6739544192178748e+00 -1.1603985265483198e+01 -3.9204779603734119e+00 + 15 6.5345389143893406e+00 -7.2391722622226151e+00 2.1740132205563690e+01 + 16 -2.0494503520587521e+00 1.3825967887607892e+01 6.7882109957643362e+00 + 17 3.5873870531468781e+00 -4.9641419029625879e+00 3.0180088465038910e+00 + 18 7.9531229968056927e-01 5.2629626038099762e+00 -2.0172278856982508e+01 + 19 -6.1997998900621667e+00 -7.5645532403308380e+00 8.4605117488474431e+00 + 20 5.4044875903815974e+00 2.3015906365208618e+00 1.1711767108135064e+01 + 21 7.6462488915955822e+00 8.9238353733854954e+00 -2.5489456437353834e+01 + 22 -1.3116042308945529e+01 -8.6583243315139509e+00 8.4434007553408890e+00 + 23 5.4697934173499467e+00 -2.6551104187154384e-01 1.7046055682012945e+01 + 24 -4.2497081893768893e+00 1.7742951160854016e+01 -1.0303002500248269e+01 + 25 -3.9777181560986339e+00 -1.2246864045350220e+01 1.7323644544198329e+00 + 26 8.2274263454755232e+00 -5.4960871155037951e+00 8.5706380458284350e+00 + 27 -2.0048516561480048e+00 1.7446299534047586e+01 -5.8315780776594286e+00 + 28 -4.7894277563898591e+00 -1.0406054767803472e+01 1.3027326650644638e-01 + 29 6.7942794125378638e+00 -7.0402447662441157e+00 5.7013048111529825e+00 ... From 65204e5df06b4be860d250b1f8e5011511a06ed9 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Tue, 21 Dec 2021 10:46:00 -0700 Subject: [PATCH 049/193] Add error checks, tweak input --- src/compute_phase_atom.cpp | 49 ++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/src/compute_phase_atom.cpp b/src/compute_phase_atom.cpp index ed6bbb844f..b8c6b374bf 100644 --- a/src/compute_phase_atom.cpp +++ b/src/compute_phase_atom.cpp @@ -40,15 +40,24 @@ ComputePhaseAtom::ComputePhaseAtom(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), phase(nullptr) { - if (narg != 4) error->all(FLERR,"Illegal compute phase/atom command"); + if (narg < 3 || narg > 5) error->all(FLERR,"Illegal compute phase/atom command"); - cutoff = utils::numeric(FLERR,arg[3],false,lmp); - cutsq = cutoff*cutoff; - sphere_vol = 4.0/3.0*MY_PI*cutsq*cutoff; + // process optional args + + cutoff = 0.0; + + int iarg = 3; + while (iarg < narg) { + if (strcmp(arg[iarg],"cutoff") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal compute phase/atom command"); + cutoff = utils::numeric(FLERR,arg[iarg+1],false,lmp); + if (cutoff <= 0.0) error->all(FLERR,"Illegal compute phase/atom command"); + iarg += 2; + } else error->all(FLERR,"Illegal compute phase/atom command"); + } peratom_flag = 1; size_peratom_cols = 2; - comm_forward = 3; nmax = 0; @@ -67,9 +76,35 @@ ComputePhaseAtom::~ComputePhaseAtom() void ComputePhaseAtom::init() { + if (!force->pair && cutoff == 0.0) + error->all(FLERR,"Compute phase/atom requires a cutoff be specified " + "or a pair style be defined"); + + double skin = neighbor->skin; + if (cutoff != 0.0) { + double mycutneigh = cutoff + skin; + + double cutghost; // as computed by Neighbor and Comm + if (force->pair) + cutghost = MAX(force->pair->cutforce+skin,comm->cutghostuser); + else + cutghost = comm->cutghostuser; + + if (mycutneigh > cutghost) + error->all(FLERR,"Compute phase/atom cutoff exceeds ghost atom range - " + "use comm_modify cutoff command"); + } + int cutflag = 1; - if (force->pair && sqrt(cutsq) <= force->pair->cutforce) - cutflag = 0; + if (force->pair) { + if (cutoff == 0.0) { + cutoff = force->pair->cutforce; + } + if (cutoff <= force->pair->cutforce+skin) cutflag = 0; + } + + cutsq = cutoff*cutoff; + sphere_vol = 4.0/3.0*MY_PI*cutsq*cutoff; // need an occasional full neighbor list From 2533abb2668266a8e070f875737735c1bfb559a0 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Tue, 21 Dec 2021 10:46:23 -0700 Subject: [PATCH 050/193] Add doc page --- doc/src/compute_phase_atom.rst | 98 ++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 doc/src/compute_phase_atom.rst diff --git a/doc/src/compute_phase_atom.rst b/doc/src/compute_phase_atom.rst new file mode 100644 index 0000000000..db1e1725f6 --- /dev/null +++ b/doc/src/compute_phase_atom.rst @@ -0,0 +1,98 @@ +.. index:: compute phase/atom +.. index:: compute phase/atom/kk + +compute phase/atom command +================================ + +Accelerator Variants: *phase/atom/kk* + +Syntax +"""""" + +.. parsed-literal:: + + compute ID group-ID phase/atom keyword values ... + +* ID, group-ID are documented in :doc:`compute ` command +* phase/atom = style name of this compute command +* one or more keyword/value pairs may be appended + + .. parsed-literal:: + + keyword = *cutoff* + *cutoff* value = distance cutoff + +Examples +"""""""" + +.. code-block:: LAMMPS + + compute 1 all phase/atom + + compute 1 all phase/atom cutoff 5.0 + comm_modify cutoff 5.0 + +Description +""""""""""" + +Define a computation that calculates the local density and temperature +for each atom and neighbors inside a spherical cutoff. + +The optional keyword *cutoff* defines the distance cutoff +used when searching for neighbors. The default value is the cutoff +specified by the pair style. If the specified cutoff is larger than +that of the pair_style plus neighbor skin, the *comm_modify cutoff* +option must also be set to match the specified cutoff. + +The neighbor list needed to compute this quantity is constructed each +time the calculation is performed (i.e. each time a snapshot of atoms +is dumped). Thus it can be inefficient to compute/dump this quantity +too frequently. + +.. note:: + + If you have a bonded system, then the settings of + :doc:`special_bonds ` command can remove pairwise + interactions between atoms in the same bond, angle, or dihedral. This + is the default setting for the :doc:`special_bonds ` + command, and means those pairwise interactions do not appear in the + neighbor list. Because this fix uses the neighbor list, it also means + those pairs will not be included in the order parameter. This + difficulty can be circumvented by writing a dump file, and using the + :doc:`rerun ` command to compute the order parameter for + snapshots in the dump file. The rerun script can use a + :doc:`special_bonds ` command that includes all pairs in + the neighbor list. + +---------- + + +.. include:: accel_styles.rst + + +---------- + +Output info +""""""""""" + +This compute calculates a per-atom array with two columns: density and temperature. + +These values can be accessed by any command that uses per-atom values +from a compute as input. See the :doc:`Howto output ` doc +page for an overview of LAMMPS output options. + +Restrictions +"""""""""""" + +none + +Related commands +"""""""""""""""" + +:doc:`comm_modify ` + +Default +""""""" + +The option defaults are *cutoff* = pair style cutoff + From ded48cc031ffa255b2e17cc55f13ec04214dd4a3 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Tue, 21 Dec 2021 10:57:42 -0700 Subject: [PATCH 051/193] more optimizations and extend to other dump styles --- doc/src/dump_modify.rst | 49 +++++++++++++++++++++------------- src/COMPRESS/dump_xyz_gz.cpp | 8 +++++- src/COMPRESS/dump_xyz_zstd.cpp | 6 ++++- src/EXTRA-DUMP/dump_dcd.cpp | 8 ++++-- src/EXTRA-DUMP/dump_xtc.cpp | 25 ++++++++++------- src/dump.h | 4 +-- src/dump_xyz.cpp | 7 +++-- src/fix_dt_reset.cpp | 8 ------ src/integrate.cpp | 11 ++++---- src/output.cpp | 38 ++++++++++++++++++-------- src/output.h | 3 ++- 11 files changed, 106 insertions(+), 61 deletions(-) diff --git a/doc/src/dump_modify.rst b/doc/src/dump_modify.rst index 42bb4d94fd..0094fceb7b 100644 --- a/doc/src/dump_modify.rst +++ b/doc/src/dump_modify.rst @@ -200,15 +200,16 @@ will be accepted. ---------- -The *every* keyword does two things. It specifies that the interval -between dump snapshots will be specified in timesteps, which is the -default if the *every* or *every/time* keywords are not used. See the +The *every* keyword can be used with any dump style except the *dcd* +and *xtc* styles. It does two things. It specifies that the interval +between dump snapshots will be set in timesteps, which is the default +if the *every* or *every/time* keywords are not used. See the *every/time* keyword for how to specify the interval in simulation -time, i.e. in time units of the :doc:`units ` command. This -command also sets the interval value, which overrides the dump +time, i.e. in time units of the :doc:`units ` command. The +*every* keyword also sets the interval value, which overrides the dump frequency originally specified by the :doc:`dump ` command. -The every keyword can be specified in one of two ways. It can be a +The *every* keyword can be specified in one of two ways. It can be a numeric value in which case it must be > 0. Or it can be an :doc:`equal-style variable `, which should be specified as v_name, where name is the variable name. @@ -266,13 +267,21 @@ in file tmp.times: ---------- -The *every/time* keyword does two things. It specifies that the -interval between dump snapshots will be specified in simulation time, +The *every/time* keyword can be used with any dump style except the +*dcd* and *xtc* styles. It does two things. It specifies that the +interval between dump snapshots will be set in simulation time, i.e. in time units of the :doc:`units ` command. This can be useful when the timestep size varies during a simulation run, e.g. by use of the :doc:`fix dt/reset ` command. The default is -to specify the interval in timesteps; see the *every* keyword. This -command also sets the interval value. +to specify the interval in timesteps; see the *every* keyword. The +*every/time* command also sets the interval value. + +.. note:: + + If you wish dump styles *atom*, *custom*, *local*, or *xyz* to + include the simulation time as a field in the header portion of + each snapshot, you also need to use the dump_modify *time* keyword + with a setting of *yes*. See its documentation below. Note that since snapshots are output on simulation steps, each snapshot will be written on the first timestep whose associated @@ -323,8 +332,8 @@ file tmp.times: .. note:: - When using a file-style variable with the *every* keyword, the file - of timesteps must list a first times that is beyond the time + When using a file-style variable with the *every/time* keyword, the + file of timesteps must list a first time that is beyond the time associated with the current timestep (e.g. it cannot be 0.0). And it must list one or more times beyond the length of the run you perform. This is because the dump command will generate an error @@ -342,8 +351,8 @@ always occur if the current timestep is a multiple of $N$, the frequency specified in the :doc:`dump ` command or :doc:`dump_modify every ` command, including timestep 0. It will also always occur if the current simulation time is a multiple -of *Delta*, the time interval specified in the doc:`dump_modify every/time -` command. +of *Delta*, the time interval specified in the doc:`dump_modify +every/time ` command. But if this is not the case, a dump snapshot will only be written if the setting of this keyword is *yes*\ . If it is *no*, which is the @@ -731,16 +740,20 @@ threshold criterion is met. Otherwise it is not met. ---------- -The *time* keyword only applies to the dump *atom*, *custom*, and -*local* styles (and their COMPRESS package versions *atom/gz*, -*custom/gz* and *local/gz*\ ). If set to *yes*, each frame will will -contain two extra lines before the "ITEM: TIMESTEP" entry: +The *time* keyword only applies to the dump *atom*, *custom*, *local*, +and *xyz* styles (and their COMPRESS package versions *atom/gz*, +*custom/gz* and *local/gz*\ ). For the first 3 styles, if set to +*yes*, each frame will will contain two extra lines before the "ITEM: +TIMESTEP" entry: .. parsed-literal:: ITEM: TIME \ +For the *xyz* style, the simulation time is included on the same line +as the timestep value. + This will output the current elapsed simulation time in current time units equivalent to the :doc:`thermo keyword ` *time*\ . This is to simplify post-processing of trajectories using a variable time diff --git a/src/COMPRESS/dump_xyz_gz.cpp b/src/COMPRESS/dump_xyz_gz.cpp index 9d38c4673c..cec32090cb 100644 --- a/src/COMPRESS/dump_xyz_gz.cpp +++ b/src/COMPRESS/dump_xyz_gz.cpp @@ -88,11 +88,17 @@ void DumpXYZGZ::openfile() if (multifile) delete[] filecurrent; } +/* ---------------------------------------------------------------------- */ + void DumpXYZGZ::write_header(bigint ndump) { if (me == 0) { std::string header = fmt::format("{}\n", ndump); - header += fmt::format("Atoms. Timestep: {}\n", update->ntimestep); + if (time_flag) + header += fmt::format("Atoms. Timestep: {} Time: {:.6f}\n", + update->ntimestep, update->atime); + else + header += fmt::format("Atoms. Timestep: {}\n", update->ntimestep); writer.write(header.c_str(), header.length()); } } diff --git a/src/COMPRESS/dump_xyz_zstd.cpp b/src/COMPRESS/dump_xyz_zstd.cpp index bcbdc08a24..24d31fe671 100644 --- a/src/COMPRESS/dump_xyz_zstd.cpp +++ b/src/COMPRESS/dump_xyz_zstd.cpp @@ -100,7 +100,11 @@ void DumpXYZZstd::write_header(bigint ndump) { if (me == 0) { std::string header = fmt::format("{}\n", ndump); - header += fmt::format("Atoms. Timestep: {}\n", update->ntimestep); + if (time_flag) + header += fmt::format("Atoms. Timestep: {} Time: {:.6f}\n", + update->ntimestep, update->atime); + else + header += fmt::format("Atoms. Timestep: {}\n", update->ntimestep); writer.write(header.c_str(), header.length()); } } diff --git a/src/EXTRA-DUMP/dump_dcd.cpp b/src/EXTRA-DUMP/dump_dcd.cpp index ec3973448a..3aca5e8a98 100644 --- a/src/EXTRA-DUMP/dump_dcd.cpp +++ b/src/EXTRA-DUMP/dump_dcd.cpp @@ -100,13 +100,17 @@ void DumpDCD::init_style() if (sort_flag == 0 || sortcol != 0) error->all(FLERR,"Dump dcd requires sorting by atom ID"); - // check that dump frequency has not changed and is not a variable - // but only when not being called from the "write_dump" command. + // check that dump modify settings are compatible with dcd + // but only when not being called from the "write_dump" command if (strcmp(id,"WRITE_DUMP") != 0) { int idump; for (idump = 0; idump < output->ndump; idump++) if (strcmp(id,output->dump[idump]->id) == 0) break; + + if (output->mode_dump[idump] == 1) + error->all(FLERR,"Cannot use every/time setting for dump dcd"); + if (output->every_dump[idump] == 0) error->all(FLERR,"Cannot use variable every setting for dump dcd"); diff --git a/src/EXTRA-DUMP/dump_xtc.cpp b/src/EXTRA-DUMP/dump_xtc.cpp index 94846671cd..94271f31a6 100644 --- a/src/EXTRA-DUMP/dump_xtc.cpp +++ b/src/EXTRA-DUMP/dump_xtc.cpp @@ -121,17 +121,24 @@ void DumpXTC::init_style() if (flush_flag) error->all(FLERR,"Cannot set dump_modify flush for dump xtc"); - // check that dump frequency has not changed and is not a variable + // check that dump modify settings are compatible with xtc + // but only when not being called from the "write_dump" command - int idump; - for (idump = 0; idump < output->ndump; idump++) - if (strcmp(id,output->dump[idump]->id) == 0) break; - if (output->every_dump[idump] == 0) - error->all(FLERR,"Cannot use variable every setting for dump xtc"); + if (strcmp(id,"WRITE_DUMP") != 0) { + int idump; + for (idump = 0; idump < output->ndump; idump++) + if (strcmp(id,output->dump[idump]->id) == 0) break; + + if (output->mode_dump[idump] == 1) + error->all(FLERR,"Cannot use every/time setting for dump xtc"); - if (nevery_save == 0) nevery_save = output->every_dump[idump]; - else if (nevery_save != output->every_dump[idump]) - error->all(FLERR,"Cannot change dump_modify every for dump xtc"); + if (output->every_dump[idump] == 0) + error->all(FLERR,"Cannot use every variable setting for dump xtc"); + + if (nevery_save == 0) nevery_save = output->every_dump[idump]; + else if (nevery_save != output->every_dump[idump]) + error->all(FLERR,"Cannot change dump_modify every for dump xtc"); + } } /* ---------------------------------------------------------------------- */ diff --git a/src/dump.h b/src/dump.h index 730d4c9ca9..caeef827c7 100644 --- a/src/dump.h +++ b/src/dump.h @@ -26,7 +26,7 @@ class Dump : protected Pointers { int igroup, groupbit; // group that Dump is performed on int first_flag; // 0 if no initial dump, 1 if yes initial dump - int clearstep; // 1 if dump invokes computes, 0 if not + int clearstep; // 1 if dump can invoke computes, 0 if not int comm_forward; // size of forward communication (0 if none) int comm_reverse; // size of reverse communication (0 if none) @@ -75,7 +75,7 @@ class Dump : protected Pointers { int sortcol; // 0 to sort on ID, 1-N on columns int sortcolm1; // sortcol - 1 int sortorder; // ASCEND or DESCEND - int time_flag; // 1 if output accumulated time + int time_flag; // 1 if output simulation time int unit_flag; // 1 if dump should contain unit information int unit_count; // # of times the unit information was written int delay_flag; // 1 if delay output until delaystep diff --git a/src/dump_xyz.cpp b/src/dump_xyz.cpp index e009937959..db929f9d6e 100644 --- a/src/dump_xyz.cpp +++ b/src/dump_xyz.cpp @@ -131,7 +131,11 @@ void DumpXYZ::write_header(bigint n) { if (me == 0) { fprintf(fp,BIGINT_FORMAT "\n",n); - fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT "\n",update->ntimestep); + if (time_flag) + fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT " Time: %f\n", + update->ntimestep, update->atime); + else + fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT "\n",update->ntimestep); } } @@ -159,7 +163,6 @@ void DumpXYZ::pack(tagint *ids) } } - /* ---------------------------------------------------------------------- convert mybuf of doubles to one big formatted string in sbuf return -1 if strlen exceeds an int, since used as arg in MPI calls in Dump diff --git a/src/fix_dt_reset.cpp b/src/fix_dt_reset.cpp index b7ab63f2d7..adb0082fc8 100644 --- a/src/fix_dt_reset.cpp +++ b/src/fix_dt_reset.cpp @@ -121,14 +121,6 @@ void FixDtReset::init() respaflag = 0; if (utils::strmatch(update->integrate_style, "^respa")) respaflag = 1; - // check for DCD or XTC dumps - - for (int i = 0; i < output->ndump; i++) - if ((strcmp(output->dump[i]->style, "dcd") == 0 || - strcmp(output->dump[i]->style, "xtc") == 0) && - comm->me == 0) - error->warning(FLERR, "Dump dcd/xtc timestamp may be wrong with fix dt/reset"); - ftm2v = force->ftm2v; mvv2e = force->mvv2e; dt = update->dt; diff --git a/src/integrate.cpp b/src/integrate.cpp index 7a1dbfaf34..c111532ee2 100644 --- a/src/integrate.cpp +++ b/src/integrate.cpp @@ -118,11 +118,10 @@ void Integrate::ev_setup() set eflag,vflag for current iteration based on (1) computes that need energy/virial info on this timestep - (2) time dumps that need unknown per-atom info on this timestep - NOTE: could not check time dumps if timestep size is not varying + (2) time dumps that may need per-atom compute info on this timestep + NOTE: inefficient to add all per-atom eng/virial computes + but don't know which ones the dump needs see NOTE in output.cpp - also inefficient to add all per-atom eng/virial computes - but don't know which ones the dump needs invoke matchstep() on all timestep-dependent computes to clear their arrays eflag: set any or no bits ENERGY_GLOBAL bit for global energy @@ -141,8 +140,8 @@ void Integrate::ev_set(bigint ntimestep) int i,flag; int tdflag = 0; - if (output->any_time_dumps) - tdflag = output->check_time_dumps(ntimestep); + if (output->any_time_dumps && + output->next_time_dump_any == ntimestep) tdflag = 1; flag = 0; int eflag_global = 0; diff --git a/src/output.cpp b/src/output.cpp index 94688cd74c..d828b5a417 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -12,6 +12,10 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing author: Michal Kanski (Jagiellonian U) for simulation time dumps +------------------------------------------------------------------------- */ + #include "output.h" #include "style_dump.h" // IWYU pragma: keep @@ -177,6 +181,8 @@ void Output::setup(int memflag) // decide whether to write snapshot and/or calculate next step for dump if (ndump && update->restrict_output == 0) { + next_time_dump_any = MAXBIGINT; + for (int idump = 0; idump < ndump; idump++) { // wrap step dumps that invoke computes or do variable eval with clear/add @@ -237,6 +243,8 @@ void Output::setup(int memflag) else modify->addstep_compute_all(next_dump[idump]); } + if (mode_dump[idump] && (dump[idump]->clearstep || var_dump[idump])) + next_time_dump_any = MIN(next_time_dump_any,next_dump[idump]); if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]); else next_dump_any = next_dump[0]; } @@ -326,6 +334,9 @@ void Output::setup(int memflag) // set next_dump_any to smallest next_dump // wrap step dumps that invoke computes or do variable eval with clear/add // NOTE: + // not wrapping time dumps means that Integrate::ev_set() + // needs to trigger all per-atom eng/virial computes + // on a timestep where any time dump will be output // could wrap time dumps as well, if timestep size did not vary // if wrap when timestep size varies frequently, // then can do many unneeded addstep() --> inefficient @@ -336,7 +347,10 @@ void Output::setup(int memflag) int writeflag; if (next_dump_any == ntimestep) { + for (int idump = 0; idump < ndump; idump++) { + next_time_dump_any = MAXBIGINT; + if (next_dump[idump] == ntimestep) { if (last_dump[idump] == ntimestep) continue; @@ -356,6 +370,8 @@ void Output::setup(int memflag) modify->addstep_compute(next_dump[idump]); } + if (mode_dump[idump] && (dump[idump]->clearstep || var_dump[idump])) + next_time_dump_any = MIN(next_time_dump_any,next_dump[idump]); if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]); else next_dump_any = next_dump[0]; } @@ -680,23 +696,23 @@ void Output::reset_dt() { bigint ntimestep = update->ntimestep; - next_dump_any = MAXBIGINT; + next_time_dump_any = MAXBIGINT; for (int idump = 0; idump < ndump; idump++) { - if (mode_dump[idump] == 1) { + if (mode_dump[idump] == 0) continue; - // reset next_dump but do not change next_time_dump, 2 arg for reset_dt() - // do not invoke for a dump already scheduled for this step - // since timestep change affects next step + // reset next_dump but do not change next_time_dump, 2 arg for reset_dt() + // do not invoke for a dump already scheduled for this step + // since timestep change affects next step + + if (next_dump[idump] != ntimestep) + calculate_next_dump(2,idump,update->ntimestep); - if (next_dump[idump] != ntimestep) { - calculate_next_dump(2,idump,update->ntimestep); - } - } - - next_dump_any = MIN(next_dump_any,next_dump[idump]); + if (dump[idump]->clearstep || var_dump[idump]) + next_time_dump_any = MIN(next_time_dump_any,next_dump[idump]); } + next_dump_any = MIN(next_dump_any,next_time_dump_any); next = MIN(next_dump_any,next_restart); next = MIN(next,next_thermo); } diff --git a/src/output.h b/src/output.h index c7c4faf252..3f557bdef5 100644 --- a/src/output.h +++ b/src/output.h @@ -35,7 +35,8 @@ class Output : protected Pointers { int ndump; // # of Dumps defined int max_dump; // max size of Dump list - bigint next_dump_any; // next timestep for any Dump + bigint next_dump_any; // next timestep for any dump + bigint next_time_dump_any; // next timestep for any time dump with computes int any_time_dumps; // 1 if any time dump defined int *mode_dump; // 0/1 if write every N timesteps or Delta in sim time int *every_dump; // dump every N timesteps, 0 if variable From a2ab59b162f94f665a7db43f756b5a23eb5f43bd Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Tue, 21 Dec 2021 11:07:03 -0700 Subject: [PATCH 052/193] Fix cutoff logic --- src/compute_phase_atom.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/compute_phase_atom.cpp b/src/compute_phase_atom.cpp index b8c6b374bf..f8f5e35abf 100644 --- a/src/compute_phase_atom.cpp +++ b/src/compute_phase_atom.cpp @@ -82,15 +82,13 @@ void ComputePhaseAtom::init() double skin = neighbor->skin; if (cutoff != 0.0) { - double mycutneigh = cutoff + skin; - double cutghost; // as computed by Neighbor and Comm if (force->pair) cutghost = MAX(force->pair->cutforce+skin,comm->cutghostuser); else cutghost = comm->cutghostuser; - if (mycutneigh > cutghost) + if (cutoff > cutghost) error->all(FLERR,"Compute phase/atom cutoff exceeds ghost atom range - " "use comm_modify cutoff command"); } From c780768e91e4a45c06f9997b9853992afbc7fefc Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 21 Dec 2021 13:16:23 -0500 Subject: [PATCH 053/193] put contents of netcdf_units into NetCDFUnits namespace --- src/NETCDF/dump_netcdf.cpp | 2 ++ src/NETCDF/dump_netcdf.h | 4 ++-- src/NETCDF/dump_netcdf_mpiio.cpp | 2 ++ src/NETCDF/dump_netcdf_mpiio.h | 4 ++-- src/NETCDF/netcdf_units.cpp | 4 +++- src/NETCDF/netcdf_units.h | 5 +++-- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/NETCDF/dump_netcdf.cpp b/src/NETCDF/dump_netcdf.cpp index f67bf8c2ff..605b480da0 100644 --- a/src/NETCDF/dump_netcdf.cpp +++ b/src/NETCDF/dump_netcdf.cpp @@ -44,6 +44,8 @@ using namespace LAMMPS_NS; using namespace MathConst; +using NetCDFUnits::Quantity; +using NetCDFUnits::get_unit_for; static const char NC_FRAME_STR[] = "frame"; static const char NC_SPATIAL_STR[] = "spatial"; diff --git a/src/NETCDF/dump_netcdf.h b/src/NETCDF/dump_netcdf.h index 619aad9138..2e0a275425 100644 --- a/src/NETCDF/dump_netcdf.h +++ b/src/NETCDF/dump_netcdf.h @@ -29,7 +29,7 @@ DumpStyle(netcdf,DumpNetCDF); #include "dump_custom.h" namespace LAMMPS_NS { -enum class Quantity; +namespace NetCDFUnits {enum Quantity : int;} // forward declaration const int NC_FIELD_NAME_MAX = 100; const int DUMP_NC_MAX_DIMS = 100; @@ -47,7 +47,7 @@ class DumpNetCDF : public DumpCustom { int field[DUMP_NC_MAX_DIMS]; // field indices corresponding to the dim. char name[NC_FIELD_NAME_MAX]; // field name int var; // NetCDF variable - Quantity quantity; // type of the quantity + NetCDFUnits::Quantity quantity; // type of the quantity bool constant; // is this property per file (not per frame) int ndumped; // number of enties written for this prop. diff --git a/src/NETCDF/dump_netcdf_mpiio.cpp b/src/NETCDF/dump_netcdf_mpiio.cpp index ba16b8c0e6..eb117e1dc0 100644 --- a/src/NETCDF/dump_netcdf_mpiio.cpp +++ b/src/NETCDF/dump_netcdf_mpiio.cpp @@ -44,6 +44,8 @@ using namespace LAMMPS_NS; using namespace MathConst; +using NetCDFUnits::Quantity; +using NetCDFUnits::get_unit_for; static const char NC_FRAME_STR[] = "frame"; static const char NC_SPATIAL_STR[] = "spatial"; diff --git a/src/NETCDF/dump_netcdf_mpiio.h b/src/NETCDF/dump_netcdf_mpiio.h index 97fad9b805..da45887b88 100644 --- a/src/NETCDF/dump_netcdf_mpiio.h +++ b/src/NETCDF/dump_netcdf_mpiio.h @@ -29,7 +29,7 @@ DumpStyle(netcdf/mpiio,DumpNetCDFMPIIO); #include "dump_custom.h" namespace LAMMPS_NS { -enum class Quantity; +namespace NetCDFUnits {enum Quantity : int;} // forward declaration const int NC_MPIIO_FIELD_NAME_MAX = 100; const int DUMP_NC_MPIIO_MAX_DIMS = 100; @@ -47,7 +47,7 @@ class DumpNetCDFMPIIO : public DumpCustom { int field[DUMP_NC_MPIIO_MAX_DIMS]; // field indices corresponding to the dim. char name[NC_MPIIO_FIELD_NAME_MAX]; // field name int var; // NetCDF variable - Quantity quantity; // type of the quantity + NetCDFUnits::Quantity quantity; // type of the quantity }; typedef void (DumpNetCDFMPIIO::*funcptr_t)(void *); diff --git a/src/NETCDF/netcdf_units.cpp b/src/NETCDF/netcdf_units.cpp index 938512755a..907d0d7496 100644 --- a/src/NETCDF/netcdf_units.cpp +++ b/src/NETCDF/netcdf_units.cpp @@ -22,7 +22,9 @@ #include "error.h" -std::string LAMMPS_NS::get_unit_for(const char* unit_style, Quantity quantity, Error* error) { +using namespace LAMMPS_NS; + +std::string NetCDFUnits::get_unit_for(const char* unit_style, Quantity quantity, Error* error) { if (!strcmp(unit_style, "lj")) { if (quantity == Quantity::UNKNOWN) { return ""; diff --git a/src/NETCDF/netcdf_units.h b/src/NETCDF/netcdf_units.h index bb83d983c8..8ec47a96bf 100644 --- a/src/NETCDF/netcdf_units.h +++ b/src/NETCDF/netcdf_units.h @@ -25,8 +25,9 @@ namespace LAMMPS_NS { class Error; +namespace NetCDFUnits { // type of quantity for per-atom values (used to get the unit) -enum class Quantity { +enum Quantity : int { UNKNOWN = 0, TIME, DISTANCE, @@ -38,7 +39,7 @@ enum class Quantity { // get the name of the unit for the given `quantity` in the given LAMMPS // `unit_style` any error will be reported through `error` std::string get_unit_for(const char* unit_style, Quantity quantity, Error* error); - +} } #endif From 364d0be28c6c81ac74a390050f681af2675e1faa Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 21 Dec 2021 13:20:25 -0500 Subject: [PATCH 054/193] apply clang-format --- src/NETCDF/dump_netcdf.h | 18 ++-- src/NETCDF/dump_netcdf_mpiio.h | 8 +- src/NETCDF/netcdf_units.cpp | 172 ++++++++++++++++----------------- src/NETCDF/netcdf_units.h | 16 +-- 4 files changed, 109 insertions(+), 105 deletions(-) diff --git a/src/NETCDF/dump_netcdf.h b/src/NETCDF/dump_netcdf.h index 2e0a275425..0ee1f63d6d 100644 --- a/src/NETCDF/dump_netcdf.h +++ b/src/NETCDF/dump_netcdf.h @@ -29,7 +29,9 @@ DumpStyle(netcdf,DumpNetCDF); #include "dump_custom.h" namespace LAMMPS_NS { -namespace NetCDFUnits {enum Quantity : int;} // forward declaration +namespace NetCDFUnits { + enum Quantity : int; +} // namespace NetCDFUnits const int NC_FIELD_NAME_MAX = 100; const int DUMP_NC_MAX_DIMS = 100; @@ -43,11 +45,11 @@ class DumpNetCDF : public DumpCustom { private: // per-atoms quantities (positions, velocities, etc.) struct nc_perat_t { - int dims; // number of dimensions - int field[DUMP_NC_MAX_DIMS]; // field indices corresponding to the dim. - char name[NC_FIELD_NAME_MAX]; // field name - int var; // NetCDF variable - NetCDFUnits::Quantity quantity; // type of the quantity + int dims; // number of dimensions + int field[DUMP_NC_MAX_DIMS]; // field indices corresponding to the dim. + char name[NC_FIELD_NAME_MAX]; // field name + int var; // NetCDF variable + NetCDFUnits::Quantity quantity; // type of the quantity bool constant; // is this property per file (not per frame) int ndumped; // number of enties written for this prop. @@ -64,8 +66,8 @@ class DumpNetCDF : public DumpCustom { int *thermovar; // NetCDF variables for thermo output - int type_nc_real; // netcdf type to use for real variables: float or double - bool thermo; // write thermo output to netcdf file + int type_nc_real; // netcdf type to use for real variables: float or double + bool thermo; // write thermo output to netcdf file bigint n_buffer; // size of buffer bigint *int_buffer; // buffer for passing data to netcdf diff --git a/src/NETCDF/dump_netcdf_mpiio.h b/src/NETCDF/dump_netcdf_mpiio.h index da45887b88..1046b86c85 100644 --- a/src/NETCDF/dump_netcdf_mpiio.h +++ b/src/NETCDF/dump_netcdf_mpiio.h @@ -29,7 +29,9 @@ DumpStyle(netcdf/mpiio,DumpNetCDFMPIIO); #include "dump_custom.h" namespace LAMMPS_NS { -namespace NetCDFUnits {enum Quantity : int;} // forward declaration +namespace NetCDFUnits { + enum Quantity : int; +} // namespace NetCDFUnits const int NC_MPIIO_FIELD_NAME_MAX = 100; const int DUMP_NC_MPIIO_MAX_DIMS = 100; @@ -63,8 +65,8 @@ class DumpNetCDFMPIIO : public DumpCustom { int *thermovar; // NetCDF variables for thermo output - int type_nc_real; // netcdf type to use for real variables: float or double - bool thermo; // write thermo output to netcdf file + int type_nc_real; // netcdf type to use for real variables: float or double + bool thermo; // write thermo output to netcdf file bigint n_buffer; // size of buffer bigint *int_buffer; // buffer for passing data to netcdf diff --git a/src/NETCDF/netcdf_units.cpp b/src/NETCDF/netcdf_units.cpp index 907d0d7496..47ae184e42 100644 --- a/src/NETCDF/netcdf_units.cpp +++ b/src/NETCDF/netcdf_units.cpp @@ -1,4 +1,3 @@ -// clang-format off /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories @@ -24,7 +23,8 @@ using namespace LAMMPS_NS; -std::string NetCDFUnits::get_unit_for(const char* unit_style, Quantity quantity, Error* error) { +std::string NetCDFUnits::get_unit_for(const char *unit_style, Quantity quantity, Error *error) +{ if (!strcmp(unit_style, "lj")) { if (quantity == Quantity::UNKNOWN) { return ""; @@ -33,108 +33,108 @@ std::string NetCDFUnits::get_unit_for(const char* unit_style, Quantity quantity, } } else if (!strcmp(unit_style, "real")) { switch (quantity) { - case Quantity::UNKNOWN: - return ""; - case Quantity::TIME: - return "femtosecond"; - case Quantity::DISTANCE: - return "angstrom"; - case Quantity::VELOCITY: - return "angstrom/femtosecond"; - case Quantity::FORCE: - return "(Kcal/mol)/angstrom)"; - case Quantity::DIPOLE_MOMENT: - return "e * angstrom"; + case Quantity::UNKNOWN: + return ""; + case Quantity::TIME: + return "femtosecond"; + case Quantity::DISTANCE: + return "angstrom"; + case Quantity::VELOCITY: + return "angstrom/femtosecond"; + case Quantity::FORCE: + return "(Kcal/mol)/angstrom)"; + case Quantity::DIPOLE_MOMENT: + return "e * angstrom"; } } else if (!strcmp(unit_style, "metal")) { switch (quantity) { - case Quantity::UNKNOWN: - return ""; - case Quantity::TIME: - return "picosecond"; - case Quantity::DISTANCE: - return "angstrom"; - case Quantity::VELOCITY: - return "angstrom/picosecond"; - case Quantity::FORCE: - return "eV/angstrom"; - case Quantity::DIPOLE_MOMENT: - return "e * angstrom"; + case Quantity::UNKNOWN: + return ""; + case Quantity::TIME: + return "picosecond"; + case Quantity::DISTANCE: + return "angstrom"; + case Quantity::VELOCITY: + return "angstrom/picosecond"; + case Quantity::FORCE: + return "eV/angstrom"; + case Quantity::DIPOLE_MOMENT: + return "e * angstrom"; } } else if (!strcmp(unit_style, "si")) { switch (quantity) { - case Quantity::UNKNOWN: - return ""; - case Quantity::TIME: - return "second"; - case Quantity::DISTANCE: - return "meter"; - case Quantity::VELOCITY: - return "meter/second"; - case Quantity::FORCE: - return "Newton"; - case Quantity::DIPOLE_MOMENT: - return "Coulomb * meter"; + case Quantity::UNKNOWN: + return ""; + case Quantity::TIME: + return "second"; + case Quantity::DISTANCE: + return "meter"; + case Quantity::VELOCITY: + return "meter/second"; + case Quantity::FORCE: + return "Newton"; + case Quantity::DIPOLE_MOMENT: + return "Coulomb * meter"; } } else if (!strcmp(unit_style, "cgs")) { switch (quantity) { - case Quantity::UNKNOWN: - return ""; - case Quantity::TIME: - return "second"; - case Quantity::DISTANCE: - return "centimeter"; - case Quantity::VELOCITY: - return "centimeter/second"; - case Quantity::FORCE: - return "dynes"; - case Quantity::DIPOLE_MOMENT: - return "statcoul * cm"; + case Quantity::UNKNOWN: + return ""; + case Quantity::TIME: + return "second"; + case Quantity::DISTANCE: + return "centimeter"; + case Quantity::VELOCITY: + return "centimeter/second"; + case Quantity::FORCE: + return "dynes"; + case Quantity::DIPOLE_MOMENT: + return "statcoul * cm"; } } else if (!strcmp(unit_style, "electron")) { switch (quantity) { - case Quantity::UNKNOWN: - return ""; - case Quantity::TIME: - return "femtoseconds"; - case Quantity::DISTANCE: - return "Bohr"; - case Quantity::VELOCITY: - return "Bohr/atomic time units"; - case Quantity::FORCE: - return "Hartree/Bohr"; - case Quantity::DIPOLE_MOMENT: - return "Debye"; + case Quantity::UNKNOWN: + return ""; + case Quantity::TIME: + return "femtoseconds"; + case Quantity::DISTANCE: + return "Bohr"; + case Quantity::VELOCITY: + return "Bohr/atomic time units"; + case Quantity::FORCE: + return "Hartree/Bohr"; + case Quantity::DIPOLE_MOMENT: + return "Debye"; } } else if (!strcmp(unit_style, "micro")) { switch (quantity) { - case Quantity::UNKNOWN: - return ""; - case Quantity::TIME: - return "microseconds"; - case Quantity::DISTANCE: - return "micrometers"; - case Quantity::VELOCITY: - return "micrometers/microsecond"; - case Quantity::FORCE: - return "picogram * micrometer/microsecond^2"; - case Quantity::DIPOLE_MOMENT: - return "picocoulomb * micrometer"; + case Quantity::UNKNOWN: + return ""; + case Quantity::TIME: + return "microseconds"; + case Quantity::DISTANCE: + return "micrometers"; + case Quantity::VELOCITY: + return "micrometers/microsecond"; + case Quantity::FORCE: + return "picogram * micrometer/microsecond^2"; + case Quantity::DIPOLE_MOMENT: + return "picocoulomb * micrometer"; } } else if (!strcmp(unit_style, "nano")) { switch (quantity) { - case Quantity::UNKNOWN: - return ""; - case Quantity::TIME: - return "nanoseconds"; - case Quantity::DISTANCE: - return "nanometers"; - case Quantity::VELOCITY: - return "nanometers/nanosecond"; - case Quantity::FORCE: - return "attogram * nanometer/nanosecond^2"; - case Quantity::DIPOLE_MOMENT: - return "e * nanometer"; + case Quantity::UNKNOWN: + return ""; + case Quantity::TIME: + return "nanoseconds"; + case Quantity::DISTANCE: + return "nanometers"; + case Quantity::VELOCITY: + return "nanometers/nanosecond"; + case Quantity::FORCE: + return "attogram * nanometer/nanosecond^2"; + case Quantity::DIPOLE_MOMENT: + return "e * nanometer"; } } diff --git a/src/NETCDF/netcdf_units.h b/src/NETCDF/netcdf_units.h index 8ec47a96bf..abba927d94 100644 --- a/src/NETCDF/netcdf_units.h +++ b/src/NETCDF/netcdf_units.h @@ -26,21 +26,21 @@ namespace LAMMPS_NS { class Error; namespace NetCDFUnits { -// type of quantity for per-atom values (used to get the unit) -enum Quantity : int { + // type of quantity for per-atom values (used to get the unit) + enum Quantity : int { UNKNOWN = 0, TIME, DISTANCE, VELOCITY, FORCE, DIPOLE_MOMENT, -}; + }; -// get the name of the unit for the given `quantity` in the given LAMMPS -// `unit_style` any error will be reported through `error` -std::string get_unit_for(const char* unit_style, Quantity quantity, Error* error); -} -} + // get the name of the unit for the given `quantity` in the given LAMMPS + // `unit_style` any error will be reported through `error` + std::string get_unit_for(const char *unit_style, Quantity quantity, Error *error); +} // namespace NetCDFUnits +} // namespace LAMMPS_NS #endif #endif From 0576d525ad1715c280c246e35809be365f040d51 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 21 Dec 2021 13:39:00 -0500 Subject: [PATCH 055/193] simplify and avoid redundant output --- src/NETCDF/dump_netcdf.cpp | 8 ++++---- src/NETCDF/dump_netcdf_mpiio.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/NETCDF/dump_netcdf.cpp b/src/NETCDF/dump_netcdf.cpp index 605b480da0..bc715c7b1d 100644 --- a/src/NETCDF/dump_netcdf.cpp +++ b/src/NETCDF/dump_netcdf.cpp @@ -888,10 +888,10 @@ int DumpNetCDF::modify_param(int narg, char **arg) void DumpNetCDF::ncerr(int err, const char *descr, int line) { if (err != NC_NOERR) { - if (descr) error->one(FLERR,"NetCDF failed with error '{}' (while accessing '{}') " - " in line {} of {}.", nc_strerror(err), descr, line, __FILE__); - else error->one(FLERR,"NetCDF failed with error '{}' in line {} of {}.", - nc_strerror(err), line, __FILE__); + if (descr) error->one(__FILE__, line, "NetCDF failed with error '{}' (while accessing '{}') ", + nc_strerror(err), descr, line); + else error->one(__FILE__, line,"NetCDF failed with error '{}' in line {} of {}.", + nc_strerror(err)); } } diff --git a/src/NETCDF/dump_netcdf_mpiio.cpp b/src/NETCDF/dump_netcdf_mpiio.cpp index eb117e1dc0..de5c3e3e4a 100644 --- a/src/NETCDF/dump_netcdf_mpiio.cpp +++ b/src/NETCDF/dump_netcdf_mpiio.cpp @@ -884,10 +884,10 @@ int DumpNetCDFMPIIO::modify_param(int narg, char **arg) void DumpNetCDFMPIIO::ncerr(int err, const char *descr, int line) { if (err != NC_NOERR) { - if (descr) error->one(FLERR,"NetCDF failed with error '{}' (while accessing '{}') " - " in line {} of {}.", ncmpi_strerror(err), descr, line, __FILE__); - else error->one(FLERR,"NetCDF failed with error '{}' in line {} of {}.", - ncmpi_strerror(err), line, __FILE__); + if (descr) error->one(__FILE__, line, "NetCDF failed with error '{}' (while accessing '{}') ", + ncmpi_strerror(err), descr); + else error->one(__FILE__, line,"NetCDF failed with error '{}' in line {} of {}.", + ncmpi_strerror(err)); } } From c98f7b3e50bdde536d9b3333950675ab4ce35d15 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Tue, 21 Dec 2021 11:40:04 -0700 Subject: [PATCH 056/193] Clean up error message text --- src/KOKKOS/compute_phase_atom_kokkos.h | 6 ------ src/compute_phase_atom.h | 27 +++----------------------- 2 files changed, 3 insertions(+), 30 deletions(-) diff --git a/src/KOKKOS/compute_phase_atom_kokkos.h b/src/KOKKOS/compute_phase_atom_kokkos.h index 7bcc418d85..d65f3d571e 100644 --- a/src/KOKKOS/compute_phase_atom_kokkos.h +++ b/src/KOKKOS/compute_phase_atom_kokkos.h @@ -63,10 +63,4 @@ class ComputePhaseAtomKokkos : public ComputePhaseAtom { /* ERROR/WARNING messages: -E: Illegal ... command - -Self-explanatory. Check the input script syntax and compare to the -documentation for the command. You can use -echo screen as a -command-line option when running LAMMPS to see the offending line. - */ diff --git a/src/compute_phase_atom.h b/src/compute_phase_atom.h index ab0dc3081e..b39026b3b5 100644 --- a/src/compute_phase_atom.h +++ b/src/compute_phase_atom.h @@ -56,33 +56,12 @@ Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. -E: Could not find compute phase/atom compute ID - -UNDOCUMENTED - -E: Compute phase/atom compute ID is not orientorder/atom - -UNDOCUMENTED - -E: Compute phase/atom threshold not between -1 and 1 - -UNDOCUMENTED - -E: Invalid cstyle in compute phase/atom - -UNDOCUMENTED - -E: Compute phase/atom requires components option in compute orientorder/atom - -UNDOCUMENTED - -E: Compute phase/atom requires a pair style be defined +E: Compute phase/atom requires a cutoff be specified or a pair style be defined Self-explanatory. -E: Compute phase/atom cutoff is longer than pairwise cutoff +E: Compute phase/atom cutoff exceeds ghost atom range - use comm_modify cutoff command -Cannot compute phase at distances longer than the pair cutoff, -since those atoms are not in the neighbor list. +Self-explanatory. */ From e06222099a45884040503823995c451b7fdf63da Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Tue, 21 Dec 2021 11:51:30 -0700 Subject: [PATCH 057/193] Small tweak to docs --- doc/src/compute_phase_atom.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/src/compute_phase_atom.rst b/doc/src/compute_phase_atom.rst index db1e1725f6..6540e52041 100644 --- a/doc/src/compute_phase_atom.rst +++ b/doc/src/compute_phase_atom.rst @@ -40,9 +40,11 @@ for each atom and neighbors inside a spherical cutoff. The optional keyword *cutoff* defines the distance cutoff used when searching for neighbors. The default value is the cutoff -specified by the pair style. If the specified cutoff is larger than -that of the pair_style plus neighbor skin, the *comm_modify cutoff* -option must also be set to match the specified cutoff. +specified by the pair style. If no pair style is defined, then a cutoff +must be defined using this keyword. If the specified cutoff is larger than +that of the pair_style plus neighbor skin (or no pair style is defined), +the *comm_modify cutoff* option must also be set to match that of the +*cutoff* keyword. The neighbor list needed to compute this quantity is constructed each time the calculation is performed (i.e. each time a snapshot of atoms From 576e7878399c02caeb426fca26be32ff27b32f3f Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Tue, 21 Dec 2021 12:18:26 -0700 Subject: [PATCH 058/193] make xyz dumps print out current simulation time --- src/COMPRESS/dump_xyz_gz.cpp | 11 +++++++---- src/COMPRESS/dump_xyz_zstd.cpp | 15 ++++++++++----- src/dump_xyz.cpp | 9 ++++++--- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/COMPRESS/dump_xyz_gz.cpp b/src/COMPRESS/dump_xyz_gz.cpp index cec32090cb..a43a27ca7d 100644 --- a/src/COMPRESS/dump_xyz_gz.cpp +++ b/src/COMPRESS/dump_xyz_gz.cpp @@ -94,11 +94,14 @@ void DumpXYZGZ::write_header(bigint ndump) { if (me == 0) { std::string header = fmt::format("{}\n", ndump); - if (time_flag) - header += fmt::format("Atoms. Timestep: {} Time: {:.6f}\n", - update->ntimestep, update->atime); - else + if (time_flag) { + double tcurrent = update->atime + + (update->ntimestep-update->atimestep) + update->dt; + fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT " Time: %f\n", + update->ntimestep, tcurrent); + } else { header += fmt::format("Atoms. Timestep: {}\n", update->ntimestep); + } writer.write(header.c_str(), header.length()); } } diff --git a/src/COMPRESS/dump_xyz_zstd.cpp b/src/COMPRESS/dump_xyz_zstd.cpp index 24d31fe671..e955a0e3ba 100644 --- a/src/COMPRESS/dump_xyz_zstd.cpp +++ b/src/COMPRESS/dump_xyz_zstd.cpp @@ -96,15 +96,20 @@ void DumpXYZZstd::openfile() if (multifile) delete[] filecurrent; } +/* ---------------------------------------------------------------------- */ + void DumpXYZZstd::write_header(bigint ndump) { if (me == 0) { std::string header = fmt::format("{}\n", ndump); - if (time_flag) - header += fmt::format("Atoms. Timestep: {} Time: {:.6f}\n", - update->ntimestep, update->atime); - else - header += fmt::format("Atoms. Timestep: {}\n", update->ntimestep); + if (time_flag) { + double tcurrent = update->atime + + (update->ntimestep-update->atimestep) + update->dt; + fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT " Time: %f\n", + update->ntimestep, tcurrent); + } else { + fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT "\n",update->ntimestep); + } writer.write(header.c_str(), header.length()); } } diff --git a/src/dump_xyz.cpp b/src/dump_xyz.cpp index db929f9d6e..26e84d145d 100644 --- a/src/dump_xyz.cpp +++ b/src/dump_xyz.cpp @@ -131,11 +131,14 @@ void DumpXYZ::write_header(bigint n) { if (me == 0) { fprintf(fp,BIGINT_FORMAT "\n",n); - if (time_flag) + if (time_flag) { + double tcurrent = update->atime + + (update->ntimestep-update->atimestep) + update->dt; fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT " Time: %f\n", - update->ntimestep, update->atime); - else + update->ntimestep, tcurrent); + } else { fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT "\n",update->ntimestep); + } } } From cc4d7215f1778057c8cee1afa4f64963a76d7b93 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 21 Dec 2021 14:37:34 -0500 Subject: [PATCH 059/193] simplify. only output absolute time during MD. --- src/dump_xyz.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/dump_xyz.cpp b/src/dump_xyz.cpp index db929f9d6e..cb0a73eb81 100644 --- a/src/dump_xyz.cpp +++ b/src/dump_xyz.cpp @@ -130,12 +130,10 @@ int DumpXYZ::modify_param(int narg, char **arg) void DumpXYZ::write_header(bigint n) { if (me == 0) { - fprintf(fp,BIGINT_FORMAT "\n",n); - if (time_flag) - fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT " Time: %f\n", - update->ntimestep, update->atime); + if (time_flag && (update->whichflag == 1)) + fmt::print(fp,"{}\n Atoms. Timestep: {} Time: {:.6f}\n", update->ntimestep, update->atime); else - fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT "\n",update->ntimestep); + fmt::print(fp,"{}\n Atoms. Timestep: {}\n", update->ntimestep); } } From 2fec3eee6b18f5fc2f21ed392bc5ef6ffc16bd53 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Tue, 21 Dec 2021 13:28:36 -0700 Subject: [PATCH 060/193] Add overflow check to dump_h5md --- src/H5MD/dump_h5md.cpp | 1 + src/H5MD/dump_h5md.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/H5MD/dump_h5md.cpp b/src/H5MD/dump_h5md.cpp index bc9c98caa0..a59de9773c 100644 --- a/src/H5MD/dump_h5md.cpp +++ b/src/H5MD/dump_h5md.cpp @@ -181,6 +181,7 @@ DumpH5MD::DumpH5MD(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg) // allocate global array for atom coords bigint n = group->count(igroup); + if ((bigint) domain->dimension*n > MAXSMALLINT) error->all(FLERR,"Too many atoms for dump h5md"); natoms = static_cast (n); if (every_position>=0) diff --git a/src/H5MD/dump_h5md.h b/src/H5MD/dump_h5md.h index 28b74649c6..5e3f3f8279 100644 --- a/src/H5MD/dump_h5md.h +++ b/src/H5MD/dump_h5md.h @@ -90,6 +90,11 @@ E: Dump h5md requires sorting by atom ID Use the dump_modify sort command to enable this. +E: Too many atoms for dump h5md + +The system size must fit in a 32-bit integer to use this dump +style. + E: Cannot use variable every setting for dump xtc The format of this file requires snapshots at regular intervals. From 6a442e1df43f1f029ae0387b6b4e3330e62f6719 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Tue, 21 Dec 2021 14:05:16 -0700 Subject: [PATCH 061/193] use compute_time() func in xyz output --- src/COMPRESS/dump_xyz_gz.cpp | 9 +++------ src/COMPRESS/dump_xyz_zstd.cpp | 9 +++------ src/dump.cpp | 1 + src/dump_xyz.cpp | 10 ++++------ 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/COMPRESS/dump_xyz_gz.cpp b/src/COMPRESS/dump_xyz_gz.cpp index a43a27ca7d..f017cb3b3e 100644 --- a/src/COMPRESS/dump_xyz_gz.cpp +++ b/src/COMPRESS/dump_xyz_gz.cpp @@ -94,14 +94,11 @@ void DumpXYZGZ::write_header(bigint ndump) { if (me == 0) { std::string header = fmt::format("{}\n", ndump); - if (time_flag) { - double tcurrent = update->atime + - (update->ntimestep-update->atimestep) + update->dt; + if (time_flag) fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT " Time: %f\n", - update->ntimestep, tcurrent); - } else { + update->ntimestep, compute_time()); + else header += fmt::format("Atoms. Timestep: {}\n", update->ntimestep); - } writer.write(header.c_str(), header.length()); } } diff --git a/src/COMPRESS/dump_xyz_zstd.cpp b/src/COMPRESS/dump_xyz_zstd.cpp index e955a0e3ba..46833f3c74 100644 --- a/src/COMPRESS/dump_xyz_zstd.cpp +++ b/src/COMPRESS/dump_xyz_zstd.cpp @@ -102,14 +102,11 @@ void DumpXYZZstd::write_header(bigint ndump) { if (me == 0) { std::string header = fmt::format("{}\n", ndump); - if (time_flag) { - double tcurrent = update->atime + - (update->ntimestep-update->atimestep) + update->dt; + if (time_flag) fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT " Time: %f\n", - update->ntimestep, tcurrent); - } else { + update->ntimestep, compute_time()); + else fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT "\n",update->ntimestep); - } writer.write(header.c_str(), header.length()); } } diff --git a/src/dump.cpp b/src/dump.cpp index df39f3738d..0f338e99b5 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -1132,6 +1132,7 @@ double Dump::compute_time() { return update->atime + (update->ntimestep - update->atimestep)*update->dt; } + /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ diff --git a/src/dump_xyz.cpp b/src/dump_xyz.cpp index 26e84d145d..9943dd57a6 100644 --- a/src/dump_xyz.cpp +++ b/src/dump_xyz.cpp @@ -131,14 +131,12 @@ void DumpXYZ::write_header(bigint n) { if (me == 0) { fprintf(fp,BIGINT_FORMAT "\n",n); - if (time_flag) { - double tcurrent = update->atime + - (update->ntimestep-update->atimestep) + update->dt; + if (time_flag) fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT " Time: %f\n", - update->ntimestep, tcurrent); - } else { + update->ntimestep, compute_time()); + else fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT "\n",update->ntimestep); - } + } } } From 1bbf45784bd7c7b6be26351907921547b0743ec6 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Tue, 21 Dec 2021 16:29:11 -0700 Subject: [PATCH 062/193] Rename and relocate --- ...e_atom.rst => compute_ave_sphere_atom.rst} | 19 ++++---- src/Depend.sh | 4 ++ .../compute_ave_sphere_atom.cpp} | 48 +++++++++---------- .../compute_ave_sphere_atom.h} | 18 +++---- src/KOKKOS/Install.sh | 4 +- ...cpp => compute_ave_sphere_atom_kokkos.cpp} | 48 +++++++++---------- ...kos.h => compute_ave_sphere_atom_kokkos.h} | 26 +++++----- 7 files changed, 86 insertions(+), 81 deletions(-) rename doc/src/{compute_phase_atom.rst => compute_ave_sphere_atom.rst} (82%) rename src/{compute_phase_atom.cpp => EXTRA-COMPUTE/compute_ave_sphere_atom.cpp} (82%) rename src/{compute_phase_atom.h => EXTRA-COMPUTE/compute_ave_sphere_atom.h} (74%) rename src/KOKKOS/{compute_phase_atom_kokkos.cpp => compute_ave_sphere_atom_kokkos.cpp} (79%) rename src/KOKKOS/{compute_phase_atom_kokkos.h => compute_ave_sphere_atom_kokkos.h} (63%) diff --git a/doc/src/compute_phase_atom.rst b/doc/src/compute_ave_sphere_atom.rst similarity index 82% rename from doc/src/compute_phase_atom.rst rename to doc/src/compute_ave_sphere_atom.rst index 6540e52041..db04682865 100644 --- a/doc/src/compute_phase_atom.rst +++ b/doc/src/compute_ave_sphere_atom.rst @@ -1,20 +1,20 @@ -.. index:: compute phase/atom -.. index:: compute phase/atom/kk +.. index:: compute ave/sphere/atom +.. index:: compute ave/sphere/atom/kk -compute phase/atom command +compute ave/sphere/atom command ================================ -Accelerator Variants: *phase/atom/kk* +Accelerator Variants: *ave/sphere/atom/kk* Syntax """""" .. parsed-literal:: - compute ID group-ID phase/atom keyword values ... + compute ID group-ID ave/sphere/atom keyword values ... * ID, group-ID are documented in :doc:`compute ` command -* phase/atom = style name of this compute command +* ave/sphere/atom = style name of this compute command * one or more keyword/value pairs may be appended .. parsed-literal:: @@ -27,9 +27,9 @@ Examples .. code-block:: LAMMPS - compute 1 all phase/atom + compute 1 all ave/sphere/atom - compute 1 all phase/atom cutoff 5.0 + compute 1 all ave/sphere/atom cutoff 5.0 comm_modify cutoff 5.0 Description @@ -86,7 +86,8 @@ page for an overview of LAMMPS output options. Restrictions """""""""""" -none +This compute is part of the EXTRA-COMPUTE package. It is only enabled if +LAMMPS was built with that package. See the :doc:`Build package ` page for more info. Related commands """""""""""""""" diff --git a/src/Depend.sh b/src/Depend.sh index af88f24bb4..a8e17e0546 100755 --- a/src/Depend.sh +++ b/src/Depend.sh @@ -77,6 +77,10 @@ if (test $1 = "DPD-BASIC") then depend INTEL fi +if (test $1 = "EXTRA-COMPUTE") then + depend KOKKOS +fi + if (test $1 = "EXTRA-MOLECULE") then depend GPU depend OPENMP diff --git a/src/compute_phase_atom.cpp b/src/EXTRA-COMPUTE/compute_ave_sphere_atom.cpp similarity index 82% rename from src/compute_phase_atom.cpp rename to src/EXTRA-COMPUTE/compute_ave_sphere_atom.cpp index f8f5e35abf..14a4c364a1 100644 --- a/src/compute_phase_atom.cpp +++ b/src/EXTRA-COMPUTE/compute_ave_sphere_atom.cpp @@ -11,7 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ -#include "compute_phase_atom.h" +#include "compute_ave_sphere_atom.h" #include "atom.h" #include "comm.h" @@ -36,11 +36,11 @@ using namespace MathConst; /* ---------------------------------------------------------------------- */ -ComputePhaseAtom::ComputePhaseAtom(LAMMPS *lmp, int narg, char **arg) : +ComputeAveSphereAtom::ComputeAveSphereAtom(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), - phase(nullptr) + result(nullptr) { - if (narg < 3 || narg > 5) error->all(FLERR,"Illegal compute phase/atom command"); + if (narg < 3 || narg > 5) error->all(FLERR,"Illegal compute ave/sphere/atom command"); // process optional args @@ -49,11 +49,11 @@ ComputePhaseAtom::ComputePhaseAtom(LAMMPS *lmp, int narg, char **arg) : int iarg = 3; while (iarg < narg) { if (strcmp(arg[iarg],"cutoff") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal compute phase/atom command"); + if (iarg+2 > narg) error->all(FLERR,"Illegal compute ave/sphere/atom command"); cutoff = utils::numeric(FLERR,arg[iarg+1],false,lmp); - if (cutoff <= 0.0) error->all(FLERR,"Illegal compute phase/atom command"); + if (cutoff <= 0.0) error->all(FLERR,"Illegal compute ave/sphere/atom command"); iarg += 2; - } else error->all(FLERR,"Illegal compute phase/atom command"); + } else error->all(FLERR,"Illegal compute ave/sphere/atom command"); } peratom_flag = 1; @@ -65,19 +65,19 @@ ComputePhaseAtom::ComputePhaseAtom(LAMMPS *lmp, int narg, char **arg) : /* ---------------------------------------------------------------------- */ -ComputePhaseAtom::~ComputePhaseAtom() +ComputeAveSphereAtom::~ComputeAveSphereAtom() { if (copymode) return; - memory->destroy(phase); + memory->destroy(result); } /* ---------------------------------------------------------------------- */ -void ComputePhaseAtom::init() +void ComputeAveSphereAtom::init() { if (!force->pair && cutoff == 0.0) - error->all(FLERR,"Compute phase/atom requires a cutoff be specified " + error->all(FLERR,"Compute ave/sphere/atom requires a cutoff be specified " "or a pair style be defined"); double skin = neighbor->skin; @@ -89,7 +89,7 @@ void ComputePhaseAtom::init() cutghost = comm->cutghostuser; if (cutoff > cutghost) - error->all(FLERR,"Compute phase/atom cutoff exceeds ghost atom range - " + error->all(FLERR,"Compute ave/sphere/atom cutoff exceeds ghost atom range - " "use comm_modify cutoff command"); } @@ -120,14 +120,14 @@ void ComputePhaseAtom::init() /* ---------------------------------------------------------------------- */ -void ComputePhaseAtom::init_list(int /*id*/, NeighList *ptr) +void ComputeAveSphereAtom::init_list(int /*id*/, NeighList *ptr) { list = ptr; } /* ---------------------------------------------------------------------- */ -void ComputePhaseAtom::compute_peratom() +void ComputeAveSphereAtom::compute_peratom() { int i,j,ii,jj,inum,jnum; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; @@ -137,13 +137,13 @@ void ComputePhaseAtom::compute_peratom() invoked_peratom = update->ntimestep; - // grow phase array if necessary + // grow result array if necessary if (atom->nmax > nmax) { - memory->destroy(phase); + memory->destroy(result); nmax = atom->nmax; - memory->create(phase,nmax,2,"phase/atom:phase"); - array_atom = phase; + memory->create(result,nmax,2,"ave/sphere/atom:result"); + array_atom = result; } // need velocities of ghost atoms @@ -159,7 +159,7 @@ void ComputePhaseAtom::compute_peratom() numneigh = list->numneigh; firstneigh = list->firstneigh; - // compute phase for each atom in group + // compute properties for each atom in group // use full neighbor list to count atoms less than cutoff double **x = atom->x; @@ -229,15 +229,15 @@ void ComputePhaseAtom::compute_peratom() } double density = count/sphere_vol; double temp = ke_sum/3.0/count; - phase[i][0] = density; - phase[i][1] = temp; + result[i][0] = density; + result[i][1] = temp; } } } /* ---------------------------------------------------------------------- */ -int ComputePhaseAtom::pack_forward_comm(int n, int *list, double *buf, +int ComputeAveSphereAtom::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/) { double **v = atom->v; @@ -254,7 +254,7 @@ int ComputePhaseAtom::pack_forward_comm(int n, int *list, double *buf, /* ---------------------------------------------------------------------- */ -void ComputePhaseAtom::unpack_forward_comm(int n, int first, double *buf) +void ComputeAveSphereAtom::unpack_forward_comm(int n, int first, double *buf) { double **v = atom->v; @@ -271,7 +271,7 @@ void ComputePhaseAtom::unpack_forward_comm(int n, int first, double *buf) memory usage of local atom-based array ------------------------------------------------------------------------- */ -double ComputePhaseAtom::memory_usage() +double ComputeAveSphereAtom::memory_usage() { double bytes = (double)2*nmax * sizeof(double); return bytes; diff --git a/src/compute_phase_atom.h b/src/EXTRA-COMPUTE/compute_ave_sphere_atom.h similarity index 74% rename from src/compute_phase_atom.h rename to src/EXTRA-COMPUTE/compute_ave_sphere_atom.h index b39026b3b5..9b5e38750b 100644 --- a/src/compute_phase_atom.h +++ b/src/EXTRA-COMPUTE/compute_ave_sphere_atom.h @@ -13,21 +13,21 @@ #ifdef COMPUTE_CLASS -ComputeStyle(phase/atom,ComputePhaseAtom) +ComputeStyle(ave/sphere/atom,ComputeAveSphereAtom) #else -#ifndef LMP_COMPUTE_PHASE_ATOM_H -#define LMP_COMPUTE_PHASE_ATOM_H +#ifndef LMP_COMPUTE_AVE_SPHERE_ATOM_H +#define LMP_COMPUTE_AVE_SPHERE_ATOM_H #include "compute.h" namespace LAMMPS_NS { -class ComputePhaseAtom : public Compute { +class ComputeAveSphereAtom : public Compute { public: - ComputePhaseAtom(class LAMMPS *, int, char **); - virtual ~ComputePhaseAtom(); + ComputeAveSphereAtom(class LAMMPS *, int, char **); + virtual ~ComputeAveSphereAtom(); virtual void init(); void init_list(int, class NeighList *); virtual void compute_peratom(); @@ -40,7 +40,7 @@ class ComputePhaseAtom : public Compute { double cutoff,cutsq,sphere_vol; class NeighList *list; - double **phase; + double **result; }; } @@ -56,11 +56,11 @@ Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. -E: Compute phase/atom requires a cutoff be specified or a pair style be defined +E: Compute ave/sphere/atom requires a cutoff be specified or a pair style be defined Self-explanatory. -E: Compute phase/atom cutoff exceeds ghost atom range - use comm_modify cutoff command +E: Compute ave/sphere/atom cutoff exceeds ghost atom range - use comm_modify cutoff command Self-explanatory. diff --git a/src/KOKKOS/Install.sh b/src/KOKKOS/Install.sh index ac5efec076..261a4d807a 100755 --- a/src/KOKKOS/Install.sh +++ b/src/KOKKOS/Install.sh @@ -88,12 +88,12 @@ action comm_kokkos.cpp action comm_kokkos.h action comm_tiled_kokkos.cpp action comm_tiled_kokkos.h +action compute_ave_sphere_atom_kokkos.cpp +action compute_ave_sphere_atom_kokkos.h action compute_coord_atom_kokkos.cpp action compute_coord_atom_kokkos.h action compute_orientorder_atom_kokkos.cpp action compute_orientorder_atom_kokkos.h -action compute_phase_atom_kokkos.cpp -action compute_phase_atom_kokkos.h action compute_temp_kokkos.cpp action compute_temp_kokkos.h action compute_temp_deform_kokkos.cpp diff --git a/src/KOKKOS/compute_phase_atom_kokkos.cpp b/src/KOKKOS/compute_ave_sphere_atom_kokkos.cpp similarity index 79% rename from src/KOKKOS/compute_phase_atom_kokkos.cpp rename to src/KOKKOS/compute_ave_sphere_atom_kokkos.cpp index 5a21393252..3f83c24fb6 100644 --- a/src/KOKKOS/compute_phase_atom_kokkos.cpp +++ b/src/KOKKOS/compute_ave_sphere_atom_kokkos.cpp @@ -11,7 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ -#include "compute_phase_atom_kokkos.h" +#include "compute_ave_sphere_atom_kokkos.h" #include "atom_kokkos.h" #include "atom_masks.h" @@ -37,8 +37,8 @@ using namespace MathConst; /* ---------------------------------------------------------------------- */ template -ComputePhaseAtomKokkos::ComputePhaseAtomKokkos(LAMMPS *lmp, int narg, char **arg) : - ComputePhaseAtom(lmp, narg, arg) +ComputeAveSphereAtomKokkos::ComputeAveSphereAtomKokkos(LAMMPS *lmp, int narg, char **arg) : + ComputeAveSphereAtom(lmp, narg, arg) { kokkosable = 1; atomKK = (AtomKokkos *) atom; @@ -50,19 +50,19 @@ ComputePhaseAtomKokkos::ComputePhaseAtomKokkos(LAMMPS *lmp, int narg /* ---------------------------------------------------------------------- */ template -ComputePhaseAtomKokkos::~ComputePhaseAtomKokkos() +ComputeAveSphereAtomKokkos::~ComputeAveSphereAtomKokkos() { if (copymode) return; - memoryKK->destroy_kokkos(k_phase,phase); + memoryKK->destroy_kokkos(k_result,result); } /* ---------------------------------------------------------------------- */ template -void ComputePhaseAtomKokkos::init() +void ComputeAveSphereAtomKokkos::init() { - ComputePhaseAtom::init(); + ComputeAveSphereAtom::init(); // need an occasional full neighbor list @@ -80,18 +80,18 @@ void ComputePhaseAtomKokkos::init() /* ---------------------------------------------------------------------- */ template -void ComputePhaseAtomKokkos::compute_peratom() +void ComputeAveSphereAtomKokkos::compute_peratom() { invoked_peratom = update->ntimestep; - // grow phase array if necessary + // grow result array if necessary if (atom->nmax > nmax) { - memoryKK->destroy_kokkos(k_phase,phase); + memoryKK->destroy_kokkos(k_result,result); nmax = atom->nmax; - memoryKK->create_kokkos(k_phase,phase,nmax,2,"phase/atom:phase"); - d_phase = k_phase.view(); - array_atom = phase; + memoryKK->create_kokkos(k_result,result,nmax,2,"ave/sphere/atom:result"); + d_result = k_result.view(); + array_atom = result; } // need velocities of ghost atoms @@ -110,7 +110,7 @@ void ComputePhaseAtomKokkos::compute_peratom() d_neighbors = k_list->d_neighbors; d_ilist = k_list->d_ilist; - // compute phase for each atom in group + // compute properties for each atom in group // use full neighbor list to count atoms less than cutoff atomKK->sync(execution_space,X_MASK|V_MASK|TYPE_MASK|MASK_MASK); @@ -118,20 +118,20 @@ void ComputePhaseAtomKokkos::compute_peratom() v = atomKK->k_v.view(); mask = atomKK->k_mask.view(); - Kokkos::deep_copy(d_phase,0.0); + Kokkos::deep_copy(d_result,0.0); copymode = 1; - typename Kokkos::RangePolicy policy(0,inum); - Kokkos::parallel_for("ComputePhaseAtom",policy,*this); + typename Kokkos::RangePolicy policy(0,inum); + Kokkos::parallel_for("ComputeAveSphereAtom",policy,*this); copymode = 0; - k_phase.modify(); - k_phase.sync_host(); + k_result.modify(); + k_result.sync_host(); } template KOKKOS_INLINE_FUNCTION -void ComputePhaseAtomKokkos::operator()(TagComputePhaseAtom, const int &ii) const +void ComputeAveSphereAtomKokkos::operator()(TagComputeAveSphereAtom, const int &ii) const { const int i = d_ilist[ii]; if (mask[i] & groupbit) { @@ -196,14 +196,14 @@ void ComputePhaseAtomKokkos::operator()(TagComputePhaseAtom, const i } double density = count/sphere_vol; double temp = ke_sum/3.0/count; - d_phase(i,0) = density; - d_phase(i,1) = temp; + d_result(i,0) = density; + d_result(i,1) = temp; } } namespace LAMMPS_NS { -template class ComputePhaseAtomKokkos; +template class ComputeAveSphereAtomKokkos; #ifdef LMP_KOKKOS_GPU -template class ComputePhaseAtomKokkos; +template class ComputeAveSphereAtomKokkos; #endif } diff --git a/src/KOKKOS/compute_phase_atom_kokkos.h b/src/KOKKOS/compute_ave_sphere_atom_kokkos.h similarity index 63% rename from src/KOKKOS/compute_phase_atom_kokkos.h rename to src/KOKKOS/compute_ave_sphere_atom_kokkos.h index d65f3d571e..42607e5239 100644 --- a/src/KOKKOS/compute_phase_atom_kokkos.h +++ b/src/KOKKOS/compute_ave_sphere_atom_kokkos.h @@ -13,35 +13,35 @@ #ifdef COMPUTE_CLASS -ComputeStyle(phase/atom/kk,ComputePhaseAtomKokkos) -ComputeStyle(phase/atom/kk/device,ComputePhaseAtomKokkos) -ComputeStyle(phase/atom/kk/host,ComputePhaseAtomKokkos) +ComputeStyle(ave/sphere/atom/kk,ComputeAveSphereAtomKokkos) +ComputeStyle(ave/sphere/atom/kk/device,ComputeAveSphereAtomKokkos) +ComputeStyle(ave/sphere/atom/kk/host,ComputeAveSphereAtomKokkos) #else -#ifndef LMP_COMPUTE_PHASE_KOKKOS_ATOM_H -#define LMP_COMPUTE_PHASE_KOKKOS_ATOM_H +#ifndef LMP_COMPUTE_AVE_SPHERE_ATOM_KOKKOS_H +#define LMP_COMPUTE_AVE_SPHERE_ATOM_KOKKOS_H -#include "compute_phase_atom.h" +#include "compute_ave_sphere_atom.h" #include "kokkos_type.h" namespace LAMMPS_NS { -struct TagComputePhaseAtom{}; +struct TagComputeAveSphereAtom{}; template -class ComputePhaseAtomKokkos : public ComputePhaseAtom { +class ComputeAveSphereAtomKokkos : public ComputeAveSphereAtom { public: typedef DeviceType device_type; typedef ArrayTypes AT; - ComputePhaseAtomKokkos(class LAMMPS *, int, char **); - virtual ~ComputePhaseAtomKokkos(); + ComputeAveSphereAtomKokkos(class LAMMPS *, int, char **); + virtual ~ComputeAveSphereAtomKokkos(); void init(); void compute_peratom(); KOKKOS_INLINE_FUNCTION - void operator()(TagComputePhaseAtom, const int&) const; + void operator()(TagComputeAveSphereAtom, const int&) const; private: typename AT::t_x_array_randomread x; @@ -52,8 +52,8 @@ class ComputePhaseAtomKokkos : public ComputePhaseAtom { typename AT::t_int_1d_randomread d_ilist; typename AT::t_int_1d_randomread d_numneigh; - DAT::tdual_float_2d k_phase; - typename AT::t_float_2d d_phase; + DAT::tdual_float_2d k_result; + typename AT::t_float_2d d_result; }; } From 9271323cc0ccef50818b8044dcb8814aa1d205b9 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Tue, 21 Dec 2021 16:33:14 -0700 Subject: [PATCH 063/193] Add dependency --- src/KOKKOS/Install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/KOKKOS/Install.sh b/src/KOKKOS/Install.sh index 261a4d807a..45fa0654a9 100755 --- a/src/KOKKOS/Install.sh +++ b/src/KOKKOS/Install.sh @@ -88,8 +88,8 @@ action comm_kokkos.cpp action comm_kokkos.h action comm_tiled_kokkos.cpp action comm_tiled_kokkos.h -action compute_ave_sphere_atom_kokkos.cpp -action compute_ave_sphere_atom_kokkos.h +action compute_ave_sphere_atom_kokkos.cpp compute_ave_sphere_atom.cpp +action compute_ave_sphere_atom_kokkos.h compute_ave_sphere_atom.h action compute_coord_atom_kokkos.cpp action compute_coord_atom_kokkos.h action compute_orientorder_atom_kokkos.cpp From 2788bc666a3ce67d0c364fc66ed6b829557ac0ce Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Tue, 21 Dec 2021 16:44:14 -0700 Subject: [PATCH 064/193] Update .gitignore --- src/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/.gitignore b/src/.gitignore index 19bafa4b52..695c9a19af 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -429,6 +429,8 @@ /commgrid.h /compute_ackland_atom.cpp /compute_ackland_atom.h +/compute_ave_sphere_atom.cpp +/compute_ave_sphere_atom.h /compute_basal_atom.cpp /compute_basal_atom.h /compute_body_local.cpp From cde7dd34fdc02215a89c9c13e56e1cdc9454fbe5 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Tue, 21 Dec 2021 16:46:53 -0700 Subject: [PATCH 065/193] Doc update --- doc/src/Commands_compute.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/src/Commands_compute.rst b/doc/src/Commands_compute.rst index 2c67d44f24..91910ccdaa 100644 --- a/doc/src/Commands_compute.rst +++ b/doc/src/Commands_compute.rst @@ -28,6 +28,7 @@ KOKKOS, o = OPENMP, t = OPT. * :doc:`angle ` * :doc:`angle/local ` * :doc:`angmom/chunk ` + * :doc:`ave/sphere/atom (k) ` * :doc:`basal/atom ` * :doc:`body/local ` * :doc:`bond ` From 8f62cd79f4be90edf24a9ccae41bac786ee620fe Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 22 Dec 2021 19:55:06 -0500 Subject: [PATCH 066/193] add missing list entry --- doc/src/compute.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/src/compute.rst b/doc/src/compute.rst index 71d3bada76..9edd7e8474 100644 --- a/doc/src/compute.rst +++ b/doc/src/compute.rst @@ -174,6 +174,7 @@ The individual style names on the :doc:`Commands compute ` pag * :doc:`angle ` - energy of each angle sub-style * :doc:`angle/local ` - theta and energy of each angle * :doc:`angmom/chunk ` - angular momentum for each chunk +* :doc:`ave/sphere/atom ` - compute local density and temperature around each atom * :doc:`basal/atom ` - calculates the hexagonal close-packed "c" lattice vector of each atom * :doc:`body/local ` - attributes of body sub-particles * :doc:`bond ` - energy of each bond sub-style From 3dcfc0dfc664a1955c02f11d0446075f67521978 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 22 Dec 2021 20:13:30 -0500 Subject: [PATCH 067/193] skip redundant KOKKOS host/device styles info/help lists --- src/info.cpp | 5 +++-- src/lammps.cpp | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/info.cpp b/src/info.cpp index 7e8dbd37b9..297633cd9d 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -1059,8 +1059,9 @@ static void print_columns(FILE *fp, std::map *styles) for (typename std::map::iterator it = styles->begin(); it != styles->end(); ++it) { const std::string &style_name = it->first; - // skip "secret" styles - if (isupper(style_name[0])) continue; + // skip "internal" styles + if (isupper(style_name[0]) || utils::strmatch(style_name,"/kk/host$") + || utils::strmatch(style_name,"/kk/device$")) continue; int len = style_name.length(); if (pos + len > 80) { diff --git a/src/lammps.cpp b/src/lammps.cpp index 0829c4fdbd..55b7755c83 100644 --- a/src/lammps.cpp +++ b/src/lammps.cpp @@ -1305,12 +1305,14 @@ void _noopt LAMMPS::help() /* ---------------------------------------------------------------------- print style names in columns - skip any style that starts with upper-case letter, since internal + skip any internal style that starts with an upper-case letter + also skip "redundant" KOKKOS styles ending in kk/host or kk/device ------------------------------------------------------------------------- */ void print_style(FILE *fp, const char *str, int &pos) { - if (isupper(str[0])) return; + if (isupper(str[0]) || utils::strmatch(str,"/kk/host$") + || utils::strmatch(str,"/kk/device$")) return; int len = strlen(str); if (pos+len > 80) { From 3b183bafbb952208a3701bd51ac7fbb9b99becca Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 22 Dec 2021 23:29:56 -0500 Subject: [PATCH 068/193] cosmetic changes (simplify, use constexpr, remove dead code, join wrapped lines) --- src/NETCDF/dump_netcdf.cpp | 5 ++--- src/NETCDF/dump_netcdf.h | 13 +++++------ src/NETCDF/dump_netcdf_mpiio.cpp | 38 ++++++++++++-------------------- src/NETCDF/dump_netcdf_mpiio.h | 13 ++++------- src/NETCDF/netcdf_units.cpp | 2 +- src/NETCDF/netcdf_units.h | 4 ++-- 6 files changed, 28 insertions(+), 47 deletions(-) diff --git a/src/NETCDF/dump_netcdf.cpp b/src/NETCDF/dump_netcdf.cpp index bc715c7b1d..f455678925 100644 --- a/src/NETCDF/dump_netcdf.cpp +++ b/src/NETCDF/dump_netcdf.cpp @@ -66,7 +66,6 @@ static const char NC_SCALE_FACTOR_STR[] = "scale_factor"; static constexpr int THIS_IS_A_FIX = -1; static constexpr int THIS_IS_A_COMPUTE = -2; static constexpr int THIS_IS_A_VARIABLE = -3; -static constexpr int THIS_IS_A_BIGINT = -4; /* ---------------------------------------------------------------------- */ @@ -104,8 +103,8 @@ DumpNetCDF::DumpNetCDF(LAMMPS *lmp, int narg, char **arg) : int idim = 0; int ndims = 1; std::string mangled = earg[i]; - Quantity quantity = Quantity::UNKNOWN; bool constant = false; + int quantity = Quantity::UNKNOWN; // name mangling // in the AMBER specification @@ -889,7 +888,7 @@ void DumpNetCDF::ncerr(int err, const char *descr, int line) { if (err != NC_NOERR) { if (descr) error->one(__FILE__, line, "NetCDF failed with error '{}' (while accessing '{}') ", - nc_strerror(err), descr, line); + nc_strerror(err), descr); else error->one(__FILE__, line,"NetCDF failed with error '{}' in line {} of {}.", nc_strerror(err)); } diff --git a/src/NETCDF/dump_netcdf.h b/src/NETCDF/dump_netcdf.h index 0ee1f63d6d..8e468692c5 100644 --- a/src/NETCDF/dump_netcdf.h +++ b/src/NETCDF/dump_netcdf.h @@ -24,17 +24,11 @@ DumpStyle(netcdf,DumpNetCDF); #else #ifndef LMP_DUMP_NETCDF_H -#define LMP_DUMP_NETCDFC_H +#define LMP_DUMP_NETCDF_H #include "dump_custom.h" namespace LAMMPS_NS { -namespace NetCDFUnits { - enum Quantity : int; -} // namespace NetCDFUnits - -const int NC_FIELD_NAME_MAX = 100; -const int DUMP_NC_MAX_DIMS = 100; class DumpNetCDF : public DumpCustom { public: @@ -43,13 +37,16 @@ class DumpNetCDF : public DumpCustom { virtual void write(); private: + static constexpr int NC_FIELD_NAME_MAX = 100; + static constexpr int DUMP_NC_MAX_DIMS = 100; + // per-atoms quantities (positions, velocities, etc.) struct nc_perat_t { int dims; // number of dimensions int field[DUMP_NC_MAX_DIMS]; // field indices corresponding to the dim. char name[NC_FIELD_NAME_MAX]; // field name int var; // NetCDF variable - NetCDFUnits::Quantity quantity; // type of the quantity + int quantity; // type of the quantity bool constant; // is this property per file (not per frame) int ndumped; // number of enties written for this prop. diff --git a/src/NETCDF/dump_netcdf_mpiio.cpp b/src/NETCDF/dump_netcdf_mpiio.cpp index de5c3e3e4a..6d381dcba2 100644 --- a/src/NETCDF/dump_netcdf_mpiio.cpp +++ b/src/NETCDF/dump_netcdf_mpiio.cpp @@ -66,7 +66,6 @@ static const char NC_SCALE_FACTOR_STR[] = "scale_factor"; static constexpr int THIS_IS_A_FIX = -1; static constexpr int THIS_IS_A_COMPUTE = -2; static constexpr int THIS_IS_A_VARIABLE = -3; -static constexpr int THIS_IS_A_BIGINT = -4; /* ---------------------------------------------------------------------- */ @@ -104,8 +103,7 @@ DumpNetCDFMPIIO::DumpNetCDFMPIIO(LAMMPS *lmp, int narg, char **arg) : int idim = 0; int ndims = 1; std::string mangled = earg[i]; - bool constant = false; - Quantity quantity = Quantity::UNKNOWN; + int quantity = Quantity::UNKNOWN; // name mangling // in the AMBER specification @@ -123,7 +121,7 @@ DumpNetCDFMPIIO::DumpNetCDFMPIIO(LAMMPS *lmp, int narg, char **arg) : idim = mangled[0] - 'x'; ndims = 3; mangled = "scaled_coordinates"; - // no quantity for scaled_coordinates + // no unit for scaled coordinates } else if ((mangled == "xu") || (mangled == "yu") || (mangled == "zu")) { idim = mangled[0] - 'x'; ndims = 3; @@ -222,8 +220,7 @@ void DumpNetCDFMPIIO::openfile() char *ptr = strchr(filestar,'*'); *ptr = '\0'; if (padflag == 0) - sprintf(filecurrent,"%s" BIGINT_FORMAT "%s", - filestar,update->ntimestep,ptr+1); + sprintf(filecurrent,"%s" BIGINT_FORMAT "%s", filestar,update->ntimestep,ptr+1); else { char bif[8],pad[16]; strcpy(bif,BIGINT_FORMAT); @@ -286,8 +283,6 @@ void DumpNetCDFMPIIO::openfile() if (!platform::file_is_readable(filecurrent)) error->all(FLERR, "cannot append to non-existent file {}", filecurrent); - MPI_Offset index[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS]; - if (singlefile_opened) return; singlefile_opened = 1; @@ -352,7 +347,6 @@ void DumpNetCDFMPIIO::openfile() int dims[NC_MAX_VAR_DIMS]; MPI_Offset index[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS]; - float d[1]; if (singlefile_opened) return; singlefile_opened = 1; @@ -367,18 +361,18 @@ void DumpNetCDFMPIIO::openfile() NCERRX( ncmpi_def_dim(ncid, NC_LABEL_STR, 10, &label_dim), NC_LABEL_STR ); for (int i = 0; i < n_perat; i++) { - int dims = perat[i].dims; - if (vector_dim[dims] < 0) { + int dim = perat[i].dims; + if (vector_dim[dim] < 0) { char dimstr[1024]; - if (dims == 3) { + if (dim == 3) { strcpy(dimstr, NC_SPATIAL_STR); - } else if (dims == 6) { + } else if (dim == 6) { strcpy(dimstr, NC_VOIGT_STR); } else { - sprintf(dimstr, "vec%i", dims); + sprintf(dimstr, "vec%i", dim); } - if (dims != 1) { - NCERRX( ncmpi_def_dim(ncid, dimstr, dims, &vector_dim[dims]), dimstr ); + if (dim != 1) { + NCERRX( ncmpi_def_dim(ncid, dimstr, dim, &vector_dim[dim]), dimstr ); } } } @@ -489,16 +483,13 @@ void DumpNetCDFMPIIO::openfile() index[1] = 0; count[0] = 1; count[1] = 5; - NCERR( ncmpi_put_vara_text(ncid, cell_angular_var, index, count, - "alpha") ); + NCERR( ncmpi_put_vara_text(ncid, cell_angular_var, index, count, "alpha") ); index[0] = 1; count[1] = 4; - NCERR( ncmpi_put_vara_text(ncid, cell_angular_var, index, count, - "beta") ); + NCERR( ncmpi_put_vara_text(ncid, cell_angular_var, index, count, "beta") ); index[0] = 2; count[1] = 5; - NCERR( ncmpi_put_vara_text(ncid, cell_angular_var, index, count, - "gamma") ); + NCERR( ncmpi_put_vara_text(ncid, cell_angular_var, index, count, "gamma") ); } NCERR( ncmpi_end_indep_data(ncid) ); @@ -886,8 +877,7 @@ void DumpNetCDFMPIIO::ncerr(int err, const char *descr, int line) if (err != NC_NOERR) { if (descr) error->one(__FILE__, line, "NetCDF failed with error '{}' (while accessing '{}') ", ncmpi_strerror(err), descr); - else error->one(__FILE__, line,"NetCDF failed with error '{}' in line {} of {}.", - ncmpi_strerror(err)); + else error->one(__FILE__, line,"NetCDF failed with error '{}'.", ncmpi_strerror(err)); } } diff --git a/src/NETCDF/dump_netcdf_mpiio.h b/src/NETCDF/dump_netcdf_mpiio.h index 1046b86c85..ec6cbaec04 100644 --- a/src/NETCDF/dump_netcdf_mpiio.h +++ b/src/NETCDF/dump_netcdf_mpiio.h @@ -29,12 +29,6 @@ DumpStyle(netcdf/mpiio,DumpNetCDFMPIIO); #include "dump_custom.h" namespace LAMMPS_NS { -namespace NetCDFUnits { - enum Quantity : int; -} // namespace NetCDFUnits - -const int NC_MPIIO_FIELD_NAME_MAX = 100; -const int DUMP_NC_MPIIO_MAX_DIMS = 100; class DumpNetCDFMPIIO : public DumpCustom { public: @@ -43,17 +37,18 @@ class DumpNetCDFMPIIO : public DumpCustom { virtual void write(); private: + static constexpr int NC_MPIIO_FIELD_NAME_MAX = 100; + static constexpr int DUMP_NC_MPIIO_MAX_DIMS = 100; + // per-atoms quantities (positions, velocities, etc.) struct nc_perat_t { int dims; // number of dimensions int field[DUMP_NC_MPIIO_MAX_DIMS]; // field indices corresponding to the dim. char name[NC_MPIIO_FIELD_NAME_MAX]; // field name int var; // NetCDF variable - NetCDFUnits::Quantity quantity; // type of the quantity + int quantity; // type of the quantity }; - typedef void (DumpNetCDFMPIIO::*funcptr_t)(void *); - int framei; // current frame index int blocki; // current block index int ndata; // number of data blocks to expect diff --git a/src/NETCDF/netcdf_units.cpp b/src/NETCDF/netcdf_units.cpp index 47ae184e42..0ee0ebbde0 100644 --- a/src/NETCDF/netcdf_units.cpp +++ b/src/NETCDF/netcdf_units.cpp @@ -23,7 +23,7 @@ using namespace LAMMPS_NS; -std::string NetCDFUnits::get_unit_for(const char *unit_style, Quantity quantity, Error *error) +std::string NetCDFUnits::get_unit_for(const char *unit_style, int quantity, Error *error) { if (!strcmp(unit_style, "lj")) { if (quantity == Quantity::UNKNOWN) { diff --git a/src/NETCDF/netcdf_units.h b/src/NETCDF/netcdf_units.h index abba927d94..abb48965ef 100644 --- a/src/NETCDF/netcdf_units.h +++ b/src/NETCDF/netcdf_units.h @@ -27,7 +27,7 @@ class Error; namespace NetCDFUnits { // type of quantity for per-atom values (used to get the unit) - enum Quantity : int { + enum Quantity { UNKNOWN = 0, TIME, DISTANCE, @@ -38,7 +38,7 @@ namespace NetCDFUnits { // get the name of the unit for the given `quantity` in the given LAMMPS // `unit_style` any error will be reported through `error` - std::string get_unit_for(const char *unit_style, Quantity quantity, Error *error); + std::string get_unit_for(const char *unit_style, int quantity, Error *error); } // namespace NetCDFUnits } // namespace LAMMPS_NS From 93c7b6928f3f2817716a582c5a75f1830f949f25 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 23 Dec 2021 01:32:31 -0500 Subject: [PATCH 069/193] remove dead code, silence compiler warnings --- src/MOLECULE/fix_cmap.cpp | 4 ++-- src/fix_nve_sphere.cpp | 4 ---- src/min_linesearch.cpp | 8 ++------ 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/MOLECULE/fix_cmap.cpp b/src/MOLECULE/fix_cmap.cpp index 26a0ab2542..a763c5d14c 100644 --- a/src/MOLECULE/fix_cmap.cpp +++ b/src/MOLECULE/fix_cmap.cpp @@ -1072,10 +1072,10 @@ void FixCMAP::read_data_header(char *line) store CMAP interactions as if newton_bond = OFF, even if actually ON ------------------------------------------------------------------------- */ -void FixCMAP::read_data_section(char *keyword, int n, char *buf, +void FixCMAP::read_data_section(char * /*keyword*/, int /*n*/, char *buf, tagint id_offset) { - int m,tmp,itype; + int m,itype; tagint atom1,atom2,atom3,atom4,atom5; auto lines = utils::split_lines(buf); diff --git a/src/fix_nve_sphere.cpp b/src/fix_nve_sphere.cpp index 543b94b46b..5cc9167ed5 100644 --- a/src/fix_nve_sphere.cpp +++ b/src/fix_nve_sphere.cpp @@ -294,7 +294,6 @@ void FixNVESphere::final_integrate() // update v,omega for all particles // d_omega/dt = torque / inertia - double rke = 0.0; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { dtfm = dtf / rmass[i]; @@ -306,8 +305,5 @@ void FixNVESphere::final_integrate() omega[i][0] += dtirotate * torque[i][0]; omega[i][1] += dtirotate * torque[i][1]; omega[i][2] += dtirotate * torque[i][2]; - rke += (omega[i][0]*omega[i][0] + omega[i][1]*omega[i][1] + - omega[i][2]*omega[i][2])*radius[i]*radius[i]*rmass[i]; } - } diff --git a/src/min_linesearch.cpp b/src/min_linesearch.cpp index c4c10d8a1f..2e7066daed 100644 --- a/src/min_linesearch.cpp +++ b/src/min_linesearch.cpp @@ -328,7 +328,7 @@ int MinLineSearch::linemin_quadratic(double eoriginal, double &alpha) int i,m,n; double fdothall,fdothme,hme,hmax,hmaxall; double de_ideal,de; - double delfh,engprev,relerr,alphaprev,fhprev,ff,fh,alpha0; + double delfh,engprev,relerr,alphaprev,fhprev,fh,alpha0; double dot[2],dotall[2]; double *xatom,*x0atom,*fatom,*hatom; double alphamax; @@ -439,12 +439,8 @@ int MinLineSearch::linemin_quadratic(double eoriginal, double &alpha) dotall[1] += fextra[i]*hextra[i]; } } - ff = dotall[0]; fh = dotall[1]; - if (output->thermo->normflag) { - ff /= atom->natoms; - fh /= atom->natoms; - } + if (output->thermo->normflag) fh /= atom->natoms; delfh = fh - fhprev; From 3748a145824949f4cc13249401aa3ae3179e60ba Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 23 Dec 2021 01:59:45 -0500 Subject: [PATCH 070/193] warn about problems with the MPIIO package --- doc/src/Packages_details.rst | 6 ++++++ doc/src/dump.rst | 12 +++++++++++- src/MPIIO/dump_atom_mpiio.cpp | 7 ++++++- src/MPIIO/dump_cfg_mpiio.cpp | 6 +++++- src/MPIIO/dump_custom_mpiio.cpp | 7 ++++++- src/MPIIO/dump_xyz_mpiio.cpp | 5 ++++- src/dump.cpp | 3 +-- src/output.cpp | 6 +++--- src/write_restart.cpp | 5 ++++- 9 files changed, 46 insertions(+), 11 deletions(-) diff --git a/doc/src/Packages_details.rst b/doc/src/Packages_details.rst index 5474d0fff9..1b4b82a5e7 100644 --- a/doc/src/Packages_details.rst +++ b/doc/src/Packages_details.rst @@ -1880,6 +1880,12 @@ MPIIO library. It adds :doc:`dump styles ` with a "mpiio" in their style name. Restart files with an ".mpiio" suffix are also written and read in parallel. +.. warning:: + + The MPIIO package is currently unmaintained and has become + unreliable. Use with caution. + + **Install:** The MPIIO package requires that LAMMPS is build in :ref:`MPI parallel mode `. diff --git a/doc/src/dump.rst b/doc/src/dump.rst index 145e3c83a5..3e1e36421d 100644 --- a/doc/src/dump.rst +++ b/doc/src/dump.rst @@ -137,7 +137,7 @@ Examples dump myDump all atom/gz 100 dump.atom.gz dump myDump all atom/zstd 100 dump.atom.zst dump 2 subgroup atom 50 dump.run.bin - dump 2 subgroup atom 50 dump.run.mpiio.bin + dump 2 subgroup atom/mpiio 50 dump.run.mpiio.bin dump 4a all custom 100 dump.myforce.* id type x y vx fx dump 4b flow custom 100 dump.%.myforce id type c_myF[3] v_ke dump 4b flow custom 100 dump.%.myforce id type c_myF[*] v_ke @@ -219,6 +219,11 @@ you should thus consider the *atom* and *atom/mpiio* styles (etc) to be inter-changeable. The one exception is how the filename is specified for the MPI-IO styles, as explained below. +.. warning:: + + The MPIIO package is currently unmaintained and has become + unreliable. Use with caution. + The precision of values output to text-based dump files can be controlled by the :doc:`dump_modify format ` command and its options. @@ -452,6 +457,11 @@ use the :doc:`read_dump ` command or perform other post-processing, just as if the dump file was not written using MPI-IO. +.. warning:: + + The MPIIO package is currently unmaintained and has become + unreliable. Use with caution. + Note that MPI-IO dump files are one large file which all processors write to. You thus cannot use the "%" wildcard character described above in the filename since that specifies generation of multiple diff --git a/src/MPIIO/dump_atom_mpiio.cpp b/src/MPIIO/dump_atom_mpiio.cpp index dc3dffbf80..522950ab8b 100644 --- a/src/MPIIO/dump_atom_mpiio.cpp +++ b/src/MPIIO/dump_atom_mpiio.cpp @@ -38,7 +38,12 @@ using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ -DumpAtomMPIIO::DumpAtomMPIIO(LAMMPS *lmp, int narg, char **arg) : DumpAtom(lmp, narg, arg) {} +DumpAtomMPIIO::DumpAtomMPIIO(LAMMPS *lmp, int narg, char **arg) + : DumpAtom(lmp, narg, arg) +{ + if (me == 0) + error->warning(FLERR,"MPI-IO output is unmaintained and unreliable. Use with caution."); +} /* ---------------------------------------------------------------------- */ diff --git a/src/MPIIO/dump_cfg_mpiio.cpp b/src/MPIIO/dump_cfg_mpiio.cpp index cd0f1bfaaf..978709b787 100644 --- a/src/MPIIO/dump_cfg_mpiio.cpp +++ b/src/MPIIO/dump_cfg_mpiio.cpp @@ -51,7 +51,11 @@ using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ DumpCFGMPIIO::DumpCFGMPIIO(LAMMPS *lmp, int narg, char **arg) : - DumpCFG(lmp, narg, arg) {} + DumpCFG(lmp, narg, arg) +{ + if (me == 0) + error->warning(FLERR,"MPI-IO output is unmaintained and unreliable. Use with caution."); +} /* ---------------------------------------------------------------------- */ diff --git a/src/MPIIO/dump_custom_mpiio.cpp b/src/MPIIO/dump_custom_mpiio.cpp index 5e7ce7dbb7..68c5896361 100644 --- a/src/MPIIO/dump_custom_mpiio.cpp +++ b/src/MPIIO/dump_custom_mpiio.cpp @@ -53,7 +53,12 @@ enum{ LT, LE, GT, GE, EQ, NEQ }; // clang-format on /* ---------------------------------------------------------------------- */ -DumpCustomMPIIO::DumpCustomMPIIO(LAMMPS *lmp, int narg, char **arg) : DumpCustom(lmp, narg, arg) {} +DumpCustomMPIIO::DumpCustomMPIIO(LAMMPS *lmp, int narg, char **arg) + : DumpCustom(lmp, narg, arg) +{ + if (me == 0) + error->warning(FLERR,"MPI-IO output is unmaintained and unreliable. Use with caution."); +} /* ---------------------------------------------------------------------- */ diff --git a/src/MPIIO/dump_xyz_mpiio.cpp b/src/MPIIO/dump_xyz_mpiio.cpp index f322a0da58..e4bfe4ef13 100644 --- a/src/MPIIO/dump_xyz_mpiio.cpp +++ b/src/MPIIO/dump_xyz_mpiio.cpp @@ -52,7 +52,10 @@ enum{LT,LE,GT,GE,EQ,NEQ}; /* ---------------------------------------------------------------------- */ DumpXYZMPIIO::DumpXYZMPIIO(LAMMPS *lmp, int narg, char **arg) : - DumpXYZ(lmp, narg, arg) {} + DumpXYZ(lmp, narg, arg) { + if (me == 0) + error->warning(FLERR,"MPI-IO output is unmaintained and unreliable. Use with caution."); +} /* ---------------------------------------------------------------------- */ diff --git a/src/dump.cpp b/src/dump.cpp index 4c02aa3070..3e574e84e5 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -128,8 +128,7 @@ Dump::Dump(LAMMPS *lmp, int /*narg*/, char **arg) : Pointers(lmp) char *ptr; if ((ptr = strchr(filename,'%'))) { if (strstr(style,"mpiio")) - error->all(FLERR, - "Dump file MPI-IO output not allowed with % in filename"); + error->all(FLERR,"Dump file MPI-IO output not allowed with % in filename"); multiproc = 1; nclusterprocs = 1; filewriter = 1; diff --git a/src/output.cpp b/src/output.cpp index 9e29caf118..674a596ed4 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -782,12 +782,12 @@ void Output::create_restart(int narg, char **arg) } int mpiioflag; - if (strstr(arg[1],".mpi")) mpiioflag = 1; + if (utils::strmatch(arg[1],"\\.mpiio$")) mpiioflag = 1; else mpiioflag = 0; if (nfile == 2) { - if (mpiioflag && !strstr(arg[2],".mpi")) + if (mpiioflag && !utils::strmatch(arg[2],"\\.mpiio$")) error->all(FLERR,"Both restart files must use MPI-IO or neither"); - if (!mpiioflag && strstr(arg[2],".mpi")) + if (!mpiioflag && utils::strmatch(arg[2],"\\.mpiio$")) error->all(FLERR,"Both restart files must use MPI-IO or neither"); } diff --git a/src/write_restart.cpp b/src/write_restart.cpp index 661585605d..41532feaf3 100644 --- a/src/write_restart.cpp +++ b/src/write_restart.cpp @@ -73,9 +73,12 @@ void WriteRestart::command(int narg, char **arg) if (strchr(arg[0],'%')) multiproc = nprocs; else multiproc = 0; - if (strstr(arg[0],".mpiio")) mpiioflag = 1; + if (utils::strmatch(arg[0],"\\.mpiio$")) mpiioflag = 1; else mpiioflag = 0; + if ((comm->me == 0) && mpiioflag) + error->warning(FLERR,"MPI-IO output is unmaintained and unreliable. Use with caution."); + // setup output style and process optional args // also called by Output class for periodic restart files From b2adb4df475e2f6218cb3b59e8405a40ec5cdbd3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 23 Dec 2021 08:20:28 -0500 Subject: [PATCH 071/193] have internal fix/compute ids include the fix id for fix reaxff/species this allows using the fix multiple times also remove code and warning that checks for multiple fix instances --- src/REAXFF/fix_reaxff_species.cpp | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/REAXFF/fix_reaxff_species.cpp b/src/REAXFF/fix_reaxff_species.cpp index 3438d57977..4f44cc7c64 100644 --- a/src/REAXFF/fix_reaxff_species.cpp +++ b/src/REAXFF/fix_reaxff_species.cpp @@ -1,4 +1,3 @@ -// clang-format off /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories @@ -247,8 +246,8 @@ FixReaxFFSpecies::~FixReaxFFSpecies() if (posflag && multipos_opened) fclose(pos); } - modify->delete_compute("SPECATOM"); - modify->delete_fix("SPECBOND"); + modify->delete_compute(fmt::format("SPECATOM_{}",id)); + modify->delete_fix(fmt::format("SPECBOND_{}",id)); } /* ---------------------------------------------------------------------- */ @@ -288,22 +287,16 @@ void FixReaxFFSpecies::init() if (nvalid != update->ntimestep) nvalid = update->ntimestep+nfreq; - // check if this fix has been called twice - int count = 0; - for (int i = 0; i < modify->nfix; i++) - if (strcmp(modify->fix[i]->style,"reaxff/species") == 0) count++; - if (count > 1 && comm->me == 0) - error->warning(FLERR,"More than one fix reaxff/species"); - if (!setupflag) { // create a compute to store properties - modify->add_compute("SPECATOM all SPEC/ATOM q x y z vx vy vz abo01 abo02 abo03 abo04 " - "abo05 abo06 abo07 abo08 abo09 abo10 abo11 abo12 abo13 abo14 " - "abo15 abo16 abo17 abo18 abo19 abo20 abo21 abo22 abo23 abo24"); + modify->add_compute(fmt::format("SPECATOM_{} all SPEC/ATOM q x y z vx vy vz abo01 abo02 " + "abo03 abo04 abo05 abo06 abo07 abo08 abo09 abo10 abo11 " + "abo12 abo13 abo14 abo15 abo16 abo17 abo18 abo19 abo20 " + "abo21 abo22 abo23 abo24",id)); // create a fix to point to fix_ave_atom for averaging stored properties - auto fixcmd = fmt::format("SPECBOND all ave/atom {} {} {}",nevery,nrepeat,nfreq); - for (int i = 1; i < 32; ++i) fixcmd += " c_SPECATOM[" + std::to_string(i) + "]"; + auto fixcmd = fmt::format("SPECBOND_{} all ave/atom {} {} {}",id,nevery,nrepeat,nfreq); + for (int i = 1; i < 32; ++i) fixcmd += fmt::format(" c_SPECATOM_{}[{}]",id,i); f_SPECBOND = (FixAveAtom *) modify->add_fix(fixcmd); setupflag = 1; } From 1185591c768dc65fbedb2e14efa8ff1f2f429465 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 23 Dec 2021 08:20:47 -0500 Subject: [PATCH 072/193] add missing fclose() --- src/REAXFF/reaxff_ffield.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/REAXFF/reaxff_ffield.cpp b/src/REAXFF/reaxff_ffield.cpp index 34db1c232d..ac22609317 100644 --- a/src/REAXFF/reaxff_ffield.cpp +++ b/src/REAXFF/reaxff_ffield.cpp @@ -583,6 +583,7 @@ namespace ReaxFF { } catch (std::exception &e) { error->one(FLERR,e.what()); } + fclose(fp); } // broadcast global parameters and allocate list on ranks != 0 From d694b7cc1c3380c166f8a1da60520bf9152e0e8b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 23 Dec 2021 14:34:49 -0500 Subject: [PATCH 073/193] recover compilation --- src/dump_xyz.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dump_xyz.cpp b/src/dump_xyz.cpp index 9943dd57a6..949ddf1a11 100644 --- a/src/dump_xyz.cpp +++ b/src/dump_xyz.cpp @@ -137,7 +137,6 @@ void DumpXYZ::write_header(bigint n) else fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT "\n",update->ntimestep); } - } } /* ---------------------------------------------------------------------- */ From a653ee6b2ce37920c64596c03ed141d826933aa7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 23 Dec 2021 15:19:17 -0500 Subject: [PATCH 074/193] recover failing unit tests and whitespace fixes --- src/EXTRA-DUMP/dump_xtc.cpp | 2 +- src/integrate.cpp | 4 +-- src/output.cpp | 40 +++++++++++++-------------- unittest/formats/test_dump_atom.cpp | 9 ++++++ unittest/formats/test_dump_custom.cpp | 10 +++++++ 5 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/EXTRA-DUMP/dump_xtc.cpp b/src/EXTRA-DUMP/dump_xtc.cpp index 94271f31a6..41b78ab64c 100644 --- a/src/EXTRA-DUMP/dump_xtc.cpp +++ b/src/EXTRA-DUMP/dump_xtc.cpp @@ -128,7 +128,7 @@ void DumpXTC::init_style() int idump; for (idump = 0; idump < output->ndump; idump++) if (strcmp(id,output->dump[idump]->id) == 0) break; - + if (output->mode_dump[idump] == 1) error->all(FLERR,"Cannot use every/time setting for dump xtc"); diff --git a/src/integrate.cpp b/src/integrate.cpp index c111532ee2..256291ed3b 100644 --- a/src/integrate.cpp +++ b/src/integrate.cpp @@ -120,7 +120,7 @@ void Integrate::ev_setup() (1) computes that need energy/virial info on this timestep (2) time dumps that may need per-atom compute info on this timestep NOTE: inefficient to add all per-atom eng/virial computes - but don't know which ones the dump needs + but don't know which ones the dump needs see NOTE in output.cpp invoke matchstep() on all timestep-dependent computes to clear their arrays eflag: set any or no bits @@ -140,7 +140,7 @@ void Integrate::ev_set(bigint ntimestep) int i,flag; int tdflag = 0; - if (output->any_time_dumps && + if (output->any_time_dumps && output->next_time_dump_any == ntimestep) tdflag = 1; flag = 0; diff --git a/src/output.cpp b/src/output.cpp index d828b5a417..b7b1a0d8c1 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -199,9 +199,9 @@ void Output::setup(int memflag) // (2) and (3) only apply for non-variable dump intervals // finally, do not write if same snapshot written previously, // i.e. on last timestep of previous run - + int writeflag = 0; - + if (last_dump[idump] < 0 && dump[idump]->first_flag == 1) writeflag = 1; if (mode_dump[idump] == 0) { @@ -209,7 +209,7 @@ void Output::setup(int memflag) writeflag = 1; } else { if (every_time_dump[idump] > 0.0) { - double tcurrent = update->atime + + double tcurrent = update->atime + (ntimestep - update->atimestep) * update->dt; double remainder = fmod(tcurrent,every_time_dump[idump]); if ((remainder < EPSDT*update->dt) || @@ -234,7 +234,7 @@ void Output::setup(int memflag) if (writeflag || last_dump[idump] < 0) calculate_next_dump(0,idump,ntimestep); - // if dump not written now, use addstep_compute_all() + // if dump not written now, use addstep_compute_all() // since don't know what computes the dump will invoke if (mode_dump[idump] == 0 && @@ -354,7 +354,7 @@ void Output::setup(int memflag) if (next_dump[idump] == ntimestep) { if (last_dump[idump] == ntimestep) continue; - if (mode_dump[idump] == 0 && + if (mode_dump[idump] == 0 && (dump[idump]->clearstep || var_dump[idump])) modify->clearstep_compute(); @@ -365,7 +365,7 @@ void Output::setup(int memflag) last_dump[idump] = ntimestep; calculate_next_dump(1,idump,ntimestep); - if (mode_dump[idump] == 0 && + if (mode_dump[idump] == 0 && (dump[idump]->clearstep || var_dump[idump])) modify->addstep_compute(next_dump[idump]); } @@ -490,7 +490,7 @@ void Output::setup(int memflag) if (which == 0) next_dump[idump] = (ntimestep/every_dump[idump])*every_dump[idump] + every_dump[idump]; - else if (which == 1) + else if (which == 1) next_dump[idump] += every_dump[idump]; } else { @@ -507,7 +507,7 @@ void Output::setup(int memflag) bigint nextdump; double nexttime; - double tcurrent = update->atime + + double tcurrent = update->atime + (ntimestep - update->atimestep) * update->dt; if (every_time_dump[idump] > 0.0) { @@ -517,27 +517,27 @@ void Output::setup(int memflag) // which = 2: no change to previous nexttime (only timestep has changed) if (which == 0) - nexttime = static_cast (tcurrent/every_time_dump[idump]) * + nexttime = static_cast (tcurrent/every_time_dump[idump]) * every_time_dump[idump] + every_time_dump[idump]; - else if (which == 1) + else if (which == 1) nexttime = next_time_dump[idump] + every_time_dump[idump]; else if (which == 2) nexttime = next_time_dump[idump]; - nextdump = ntimestep + - static_cast ((nexttime - tcurrent - EPSDT*update->dt) / + nextdump = ntimestep + + static_cast ((nexttime - tcurrent - EPSDT*update->dt) / update->dt) + 1; // if delta is too small to reach next timestep, use multiple of delta if (nextdump == ntimestep) { - double tnext = update->atime + + double tnext = update->atime + (ntimestep+1 - update->atimestep) * update->dt; - int multiple = static_cast + int multiple = static_cast ((tnext - nexttime) / every_time_dump[idump]); nexttime = nexttime + (multiple+1)*every_time_dump[idump]; - nextdump = ntimestep + - static_cast ((nexttime - tcurrent - EPSDT*update->dt) / + nextdump = ntimestep + + static_cast ((nexttime - tcurrent - EPSDT*update->dt) / update->dt) + 1; } @@ -548,14 +548,14 @@ void Output::setup(int memflag) if (which < 2 || next_time_dump[idump] < 0.0) { nexttime = input->variable->compute_equal(ivar_dump[idump]); - } else + } else nexttime = next_time_dump[idump]; if (nexttime <= tcurrent) error->all(FLERR,"Dump every/time variable returned a bad time"); - nextdump = ntimestep + - static_cast ((nexttime - tcurrent - EPSDT*update->dt) / + nextdump = ntimestep + + static_cast ((nexttime - tcurrent - EPSDT*update->dt) / update->dt) + 1; if (nextdump <= ntimestep) error->all(FLERR,"Dump every/time variable too small for next timestep"); @@ -704,7 +704,7 @@ void Output::reset_dt() // reset next_dump but do not change next_time_dump, 2 arg for reset_dt() // do not invoke for a dump already scheduled for this step // since timestep change affects next step - + if (next_dump[idump] != ntimestep) calculate_next_dump(2,idump,update->ntimestep); diff --git a/unittest/formats/test_dump_atom.cpp b/unittest/formats/test_dump_atom.cpp index 1d00e00610..a73204fb92 100644 --- a/unittest/formats/test_dump_atom.cpp +++ b/unittest/formats/test_dump_atom.cpp @@ -74,6 +74,13 @@ public: END_HIDE_OUTPUT(); } + void close_dump() + { + BEGIN_HIDE_OUTPUT(); + command("undump id"); + END_HIDE_OUTPUT(); + } + void generate_text_and_binary_dump(std::string text_file, std::string binary_file, std::string dump_modify_options, int ntimesteps) { @@ -505,6 +512,7 @@ TEST_F(DumpAtomTest, rerun) ASSERT_FILE_EXISTS(dump_file); ASSERT_EQ(count_lines(dump_file), 82); continue_dump(1); + close_dump(); lmp->output->thermo->evaluate_keyword("pe", &pe_2); ASSERT_FILE_EXISTS(dump_file); ASSERT_EQ(count_lines(dump_file), 123); @@ -532,6 +540,7 @@ TEST_F(DumpAtomTest, rerun_bin) lmp->output->thermo->evaluate_keyword("pe", &pe_1); ASSERT_FILE_EXISTS(dump_file); continue_dump(1); + close_dump(); lmp->output->thermo->evaluate_keyword("pe", &pe_2); ASSERT_FILE_EXISTS(dump_file); HIDE_OUTPUT([&] { diff --git a/unittest/formats/test_dump_custom.cpp b/unittest/formats/test_dump_custom.cpp index 921b584217..434acf462c 100644 --- a/unittest/formats/test_dump_custom.cpp +++ b/unittest/formats/test_dump_custom.cpp @@ -73,6 +73,13 @@ public: END_HIDE_OUTPUT(); } + void close_dump() + { + BEGIN_HIDE_OUTPUT(); + command("undump id"); + END_HIDE_OUTPUT(); + } + void generate_text_and_binary_dump(std::string text_file, std::string binary_file, std::string fields, std::string dump_modify_options, int ntimesteps) @@ -330,6 +337,7 @@ TEST_F(DumpCustomTest, rerun) ASSERT_FILE_EXISTS(dump_file); ASSERT_EQ(count_lines(dump_file), 82); continue_dump(1); + close_dump(); lmp->output->thermo->evaluate_keyword("pe", &pe_2); ASSERT_FILE_EXISTS(dump_file); ASSERT_EQ(count_lines(dump_file), 123); @@ -338,6 +346,7 @@ TEST_F(DumpCustomTest, rerun) }); lmp->output->thermo->evaluate_keyword("pe", &pe_rerun); ASSERT_DOUBLE_EQ(pe_1, pe_rerun); + HIDE_OUTPUT([&] { command(fmt::format("rerun {} first 2 last 2 every 1 post yes dump x y z", dump_file)); }); @@ -359,6 +368,7 @@ TEST_F(DumpCustomTest, rerun_bin) lmp->output->thermo->evaluate_keyword("pe", &pe_1); ASSERT_FILE_EXISTS(dump_file); continue_dump(1); + close_dump(); lmp->output->thermo->evaluate_keyword("pe", &pe_2); ASSERT_FILE_EXISTS(dump_file); HIDE_OUTPUT([&] { From 30af0cb3256f91878818c2d89ac603408bdda65f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 26 Dec 2021 17:15:13 -0500 Subject: [PATCH 075/193] define and use LMP_MAX_VAR_DIMS instead of NC_MAX_VAR_DIMS to avoid stack overflows --- src/NETCDF/dump_netcdf.cpp | 27 ++++++++++++++------------- src/NETCDF/dump_netcdf_mpiio.cpp | 32 ++++++++++++++++++-------------- src/NETCDF/netcdf_units.h | 3 +++ 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/NETCDF/dump_netcdf.cpp b/src/NETCDF/dump_netcdf.cpp index f455678925..137d6368c2 100644 --- a/src/NETCDF/dump_netcdf.cpp +++ b/src/NETCDF/dump_netcdf.cpp @@ -46,6 +46,7 @@ using namespace LAMMPS_NS; using namespace MathConst; using NetCDFUnits::Quantity; using NetCDFUnits::get_unit_for; +using NetCDFUnits::LMP_MAX_VAR_DIMS; static const char NC_FRAME_STR[] = "frame"; static const char NC_SPATIAL_STR[] = "spatial"; @@ -206,7 +207,7 @@ DumpNetCDF::~DumpNetCDF() closefile(); delete[] perat; - if (thermovar) delete[] thermovar; + delete[] thermovar; if (int_buffer) memory->sfree(int_buffer); if (double_buffer) memory->sfree(double_buffer); @@ -234,7 +235,7 @@ void DumpNetCDF::openfile() } if (thermo && !singlefile_opened) { - if (thermovar) delete[] thermovar; + delete[] thermovar; thermovar = new int[output->thermo->nfield]; } @@ -300,18 +301,18 @@ void DumpNetCDF::openfile() NCERRX( nc_inq_dimid(ncid, NC_LABEL_STR, &label_dim), NC_LABEL_STR ); for (int i = 0; i < n_perat; i++) { - int dims = perat[i].dims; - if (vector_dim[dims] < 0) { + int dim = perat[i].dims; + if (vector_dim[dim] < 0) { char dimstr[1024]; - if (dims == 3) { + if (dim == 3) { strcpy(dimstr, NC_SPATIAL_STR); - } else if (dims == 6) { + } else if (dim == 6) { strcpy(dimstr, NC_VOIGT_STR); } else { - sprintf(dimstr, "vec%i", dims); + sprintf(dimstr, "vec%i", dim); } - if (dims != 1) { - NCERRX( nc_inq_dimid(ncid, dimstr, &vector_dim[dims]), dimstr ); + if (dim != 1) { + NCERRX( nc_inq_dimid(ncid, dimstr, &vector_dim[dim]), dimstr ); } } } @@ -349,8 +350,8 @@ void DumpNetCDF::openfile() if (framei != 0 && !multifile) error->all(FLERR,"at keyword requires use of 'append yes'"); - int dims[NC_MAX_VAR_DIMS]; - size_t index[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS]; + int dims[LMP_MAX_VAR_DIMS]; + size_t index[LMP_MAX_VAR_DIMS], count[LMP_MAX_VAR_DIMS]; if (singlefile_opened) return; singlefile_opened = 1; @@ -720,8 +721,8 @@ void DumpNetCDF::write_header(bigint n) void DumpNetCDF::write_data(int n, double *mybuf) { - size_t start[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS]; - ptrdiff_t stride[NC_MAX_VAR_DIMS]; + size_t start[LMP_MAX_VAR_DIMS], count[LMP_MAX_VAR_DIMS]; + ptrdiff_t stride[LMP_MAX_VAR_DIMS]; if (!int_buffer) { n_buffer = n; diff --git a/src/NETCDF/dump_netcdf_mpiio.cpp b/src/NETCDF/dump_netcdf_mpiio.cpp index 6d381dcba2..a1c9d20e61 100644 --- a/src/NETCDF/dump_netcdf_mpiio.cpp +++ b/src/NETCDF/dump_netcdf_mpiio.cpp @@ -46,6 +46,7 @@ using namespace LAMMPS_NS; using namespace MathConst; using NetCDFUnits::Quantity; using NetCDFUnits::get_unit_for; +using NetCDFUnits::LMP_MAX_VAR_DIMS; static const char NC_FRAME_STR[] = "frame"; static const char NC_SPATIAL_STR[] = "spatial"; @@ -203,7 +204,7 @@ DumpNetCDFMPIIO::~DumpNetCDFMPIIO() closefile(); delete[] perat; - if (thermovar) delete[] thermovar; + delete[] thermovar; if (int_buffer) memory->sfree(int_buffer); if (double_buffer) memory->sfree(double_buffer); @@ -231,7 +232,7 @@ void DumpNetCDFMPIIO::openfile() } if (thermo && !singlefile_opened) { - if (thermovar) delete[] thermovar; + delete[] thermovar; thermovar = new int[output->thermo->nfield]; } @@ -296,18 +297,18 @@ void DumpNetCDFMPIIO::openfile() NCERRX( ncmpi_inq_dimid(ncid, NC_LABEL_STR, &label_dim), NC_LABEL_STR ); for (int i = 0; i < n_perat; i++) { - int dims = perat[i].dims; - if (vector_dim[dims] < 0) { + int dim = perat[i].dims; + if (vector_dim[dim] < 0) { char dimstr[1024]; - if (dims == 3) { + if (dim == 3) { strcpy(dimstr, NC_SPATIAL_STR); - } else if (dims == 6) { + } else if (dim == 6) { strcpy(dimstr, NC_VOIGT_STR); } else { - sprintf(dimstr, "vec%i", dims); + sprintf(dimstr, "vec%i", dim); } - if (dims != 1) { - NCERRX( ncmpi_inq_dimid(ncid, dimstr, &vector_dim[dims]), dimstr ); + if (dim != 1) { + NCERRX( ncmpi_inq_dimid(ncid, dimstr, &vector_dim[dim]), dimstr ); } } } @@ -345,8 +346,8 @@ void DumpNetCDFMPIIO::openfile() if (framei != 0 && !multifile) error->all(FLERR,"at keyword requires use of 'append yes'"); - int dims[NC_MAX_VAR_DIMS]; - MPI_Offset index[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS]; + int dims[LMP_MAX_VAR_DIMS]; + MPI_Offset index[LMP_MAX_VAR_DIMS], count[LMP_MAX_VAR_DIMS]; if (singlefile_opened) return; singlefile_opened = 1; @@ -360,6 +361,11 @@ void DumpNetCDFMPIIO::openfile() NCERRX( ncmpi_def_dim(ncid, NC_CELL_ANGULAR_STR, 3, &cell_angular_dim), NC_CELL_ANGULAR_STR ); NCERRX( ncmpi_def_dim(ncid, NC_LABEL_STR, 10, &label_dim), NC_LABEL_STR ); + if (vector_dim[3] < 0) + NCERRX( ncmpi_def_dim(ncid, NC_SPATIAL_STR, 3, &vector_dim[3]), NC_SPATIAL_STR ); + if (vector_dim[6] < 0) + NCERRX( ncmpi_def_dim(ncid, NC_VOIGT_STR, 6, &vector_dim[6]), NC_VOIGT_STR ); + for (int i = 0; i < n_perat; i++) { int dim = perat[i].dims; if (vector_dim[dim] < 0) { @@ -384,7 +390,6 @@ void DumpNetCDFMPIIO::openfile() dims[0] = vector_dim[3]; dims[1] = label_dim; NCERRX( ncmpi_def_var(ncid, NC_CELL_ANGULAR_STR, NC_CHAR, 2, dims, &cell_angular_var), NC_CELL_ANGULAR_STR ); - dims[0] = frame_dim; NCERRX( ncmpi_def_var(ncid, NC_TIME_STR, type_nc_real, 1, dims, &time_var), NC_TIME_STR); dims[0] = frame_dim; @@ -731,8 +736,7 @@ void DumpNetCDFMPIIO::write_time_and_cell() void DumpNetCDFMPIIO::write_data(int n, double *mybuf) { - MPI_Offset start[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS]; - MPI_Offset stride[NC_MAX_VAR_DIMS]; + MPI_Offset start[LMP_MAX_VAR_DIMS], count[LMP_MAX_VAR_DIMS], stride[LMP_MAX_VAR_DIMS]; if (!int_buffer) { n_buffer = std::max(1, n); diff --git a/src/NETCDF/netcdf_units.h b/src/NETCDF/netcdf_units.h index abb48965ef..85f9b05888 100644 --- a/src/NETCDF/netcdf_units.h +++ b/src/NETCDF/netcdf_units.h @@ -36,6 +36,9 @@ namespace NetCDFUnits { DIPOLE_MOMENT, }; + // for compatibility with older NetCDF versions + static constexpr int LMP_MAX_VAR_DIMS = 1024; + // get the name of the unit for the given `quantity` in the given LAMMPS // `unit_style` any error will be reported through `error` std::string get_unit_for(const char *unit_style, int quantity, Error *error); From 091f6164c81d72b81d5ce5d58ed2a2655a16972c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 26 Dec 2021 23:22:53 -0500 Subject: [PATCH 076/193] add minimal unit test for netcdf dumps --- unittest/formats/CMakeLists.txt | 8 ++ unittest/formats/test_dump_netcdf.cpp | 158 ++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 unittest/formats/test_dump_netcdf.cpp diff --git a/unittest/formats/CMakeLists.txt b/unittest/formats/CMakeLists.txt index a17707fdf1..18bd7d1195 100644 --- a/unittest/formats/CMakeLists.txt +++ b/unittest/formats/CMakeLists.txt @@ -116,6 +116,14 @@ target_link_libraries(test_dump_local PRIVATE lammps GTest::GMock) add_test(NAME DumpLocal COMMAND test_dump_local WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) set_tests_properties(DumpLocal PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}") +if(PKG_NETCDF) + find_program(NCDUMP NAMES ncdump REQUIRED) + add_executable(test_dump_netcdf test_dump_netcdf.cpp) + target_link_libraries(test_dump_netcdf PRIVATE lammps GTest::GMock) + add_test(NAME DumpNetCDF COMMAND test_dump_netcdf WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + set_tests_properties(DumpNetCDF PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR};NCDUMP_BINARY=${NCDUMP}") +endif() + if(BUILD_TOOLS) set_tests_properties(DumpAtom PROPERTIES ENVIRONMENT "BINARY2TXT_BINARY=$") set_tests_properties(DumpCustom PROPERTIES ENVIRONMENT "BINARY2TXT_BINARY=$") diff --git a/unittest/formats/test_dump_netcdf.cpp b/unittest/formats/test_dump_netcdf.cpp new file mode 100644 index 0000000000..3aa65fa112 --- /dev/null +++ b/unittest/formats/test_dump_netcdf.cpp @@ -0,0 +1,158 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#include "../testing/core.h" +#include "../testing/systems/melt.h" +#include "../testing/utils.h" +#include "fmt/format.h" +#include "library.h" +#include "output.h" +#include "thermo.h" +#include "utils.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include + +using ::testing::Eq; + +char *NCDUMP_BINARY = nullptr; +bool verbose = false; + +class DumpNetCDFTest : public MeltTest { + std::string dump_style = "netcdf"; + +public: + void set_style(const std::string &new_style) { dump_style = new_style; } + + void enable_triclinic() + { + BEGIN_HIDE_OUTPUT(); + command("change_box all triclinic"); + END_HIDE_OUTPUT(); + } + + std::string dump_filename(std::string ident) + { + return fmt::format("dump_{}_{}.nc", dump_style, ident); + } + + void generate_dump(std::string dump_file, std::string fields, std::string dump_modify_options, + int ntimesteps) + { + BEGIN_HIDE_OUTPUT(); + command(fmt::format("dump id all {} 1 {} {}", dump_style, dump_file, fields)); + + if (!dump_modify_options.empty()) { + command(fmt::format("dump_modify id {}", dump_modify_options)); + } + + command(fmt::format("run {} post no", ntimesteps)); + END_HIDE_OUTPUT(); + } + + void continue_dump(int ntimesteps) + { + BEGIN_HIDE_OUTPUT(); + command(fmt::format("run {} pre no post no", ntimesteps)); + END_HIDE_OUTPUT(); + } + + void close_dump() + { + BEGIN_HIDE_OUTPUT(); + command("undump id"); + END_HIDE_OUTPUT(); + } + + std::string convert_binary_to_text(std::string binary_file) + { + BEGIN_HIDE_OUTPUT(); + std::string cmdline = fmt::format("{0} {1} > {1}.txt", NCDUMP_BINARY, binary_file); + system(cmdline.c_str()); + END_HIDE_OUTPUT(); + return fmt::format("{}.txt", binary_file); + } +}; + +TEST_F(DumpNetCDFTest, run0_plain) +{ + if (!lammps_has_style(lmp, "dump", "netcdf")) GTEST_SKIP(); + auto dump_file = dump_filename("run0"); + auto fields = "id type proc procp1 mass x y z ix iy iz xu yu zu vx vy vz fx fy fz"; + set_style("netcdf"); + generate_dump(dump_file, fields, "", 0); + + ASSERT_FILE_EXISTS(dump_file); + if (NCDUMP_BINARY) { + auto converted_file = convert_binary_to_text(dump_file); + auto lines = read_lines(converted_file); + auto words = utils::split_words(lines[0]); + ASSERT_EQ(lines.size(), 233); + ASSERT_THAT(words[0], Eq("netcdf")); + ASSERT_THAT(words[1]+".nc", Eq(dump_file)); + words = utils::split_words(lines[3]); + ASSERT_THAT(words[0], Eq("atom")); + ASSERT_THAT(words[2], Eq("32")); + delete_file(converted_file); + } + delete_file(dump_file); +} + +TEST_F(DumpNetCDFTest, run0_mpi) +{ + if (!lammps_has_style(lmp, "dump", "netcdf/mpiio")) GTEST_SKIP(); + auto dump_file = dump_filename("run0"); + auto fields = "id type proc procp1 mass x y z ix iy iz xu yu zu vx vy vz fx fy fz"; + set_style("netcdf/mpiio"); + generate_dump(dump_file, fields, "", 0); + + ASSERT_FILE_EXISTS(dump_file); + if (NCDUMP_BINARY) { + auto converted_file = convert_binary_to_text(dump_file); + auto lines = read_lines(converted_file); + auto words = utils::split_words(lines[0]); + ASSERT_EQ(lines.size(), 234); + ASSERT_THAT(words[0], Eq("netcdf")); + ASSERT_THAT(words[1]+".nc", Eq(dump_file)); + words = utils::split_words(lines[3]); + ASSERT_THAT(words[0], Eq("atom")); + ASSERT_THAT(words[2], Eq("32")); + delete_file(converted_file); + } + delete_file(dump_file); +} + +int main(int argc, char **argv) +{ + MPI_Init(&argc, &argv); + ::testing::InitGoogleMock(&argc, argv); + + // handle arguments passed via environment variable + if (const char *var = getenv("TEST_ARGS")) { + std::vector env = utils::split_words(var); + for (auto arg : env) { + if (arg == "-v") { + verbose = true; + } + } + } + + NCDUMP_BINARY = getenv("NCDUMP_BINARY"); + + if ((argc > 1) && (strcmp(argv[1], "-v") == 0)) verbose = true; + + int rv = RUN_ALL_TESTS(); + MPI_Finalize(); + return rv; +} From 6357f19260179b7a054df4f8aa82e83c5f88f964 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Mon, 27 Dec 2021 00:14:04 -0600 Subject: [PATCH 077/193] Added back Makefile.mpi in lib/gpu/ to be consistent with documentation; updated Makefile.*; and removed the unnecessary Makefile.turing --- lib/gpu/Makefile.cuda_mps | 2 +- lib/gpu/Makefile.linux | 2 +- lib/gpu/Makefile.linux_multi | 4 +-- lib/gpu/Makefile.mpi | 59 ++++++++++++++++++++++++++++++++++++ lib/gpu/Makefile.serial | 26 ++++------------ lib/gpu/Makefile.turing | 23 -------------- 6 files changed, 69 insertions(+), 47 deletions(-) create mode 100644 lib/gpu/Makefile.mpi delete mode 100644 lib/gpu/Makefile.turing diff --git a/lib/gpu/Makefile.cuda_mps b/lib/gpu/Makefile.cuda_mps index f52bd07fcf..d7820e4c34 100644 --- a/lib/gpu/Makefile.cuda_mps +++ b/lib/gpu/Makefile.cuda_mps @@ -1,5 +1,5 @@ # /* ---------------------------------------------------------------------- -# Generic Linux Makefile for CUDA +# Generic Linux Makefile for CUDA with the Multi-Process Service (MPS) # - change CUDA_ARCH for your GPU # ------------------------------------------------------------------------- */ diff --git a/lib/gpu/Makefile.linux b/lib/gpu/Makefile.linux index 0b3084cbe9..fe4e57ac77 100644 --- a/lib/gpu/Makefile.linux +++ b/lib/gpu/Makefile.linux @@ -1,5 +1,5 @@ # /* ---------------------------------------------------------------------- -# Generic Linux Makefile for CUDA +# Generic Linux Makefile for CUDA # - Change CUDA_ARCH for your GPU # ------------------------------------------------------------------------- */ diff --git a/lib/gpu/Makefile.linux_multi b/lib/gpu/Makefile.linux_multi index 05b869879e..f3d89fd9f0 100644 --- a/lib/gpu/Makefile.linux_multi +++ b/lib/gpu/Makefile.linux_multi @@ -1,6 +1,6 @@ # /* ---------------------------------------------------------------------- -# Generic Linux Makefile for CUDA -# - Change CUDA_ARCH for your GPU +# Generic Linux Makefile for CUDA complied for multiple compute capabilities +# - Add your GPU to CUDA_CODE # ------------------------------------------------------------------------- */ # which file will be copied to Makefile.lammps diff --git a/lib/gpu/Makefile.mpi b/lib/gpu/Makefile.mpi new file mode 100644 index 0000000000..be3c582632 --- /dev/null +++ b/lib/gpu/Makefile.mpi @@ -0,0 +1,59 @@ +# /* ---------------------------------------------------------------------- +# Generic Linux Makefile for CUDA +# - Change CUDA_ARCH for your GPU +# ------------------------------------------------------------------------- */ + +# which file will be copied to Makefile.lammps + +EXTRAMAKE = Makefile.lammps.standard + +ifeq ($(CUDA_HOME),) +CUDA_HOME = /usr/local/cuda +endif + +NVCC = nvcc + +# Pascal hardware +CUDA_ARCH = -arch=sm_60 +#CUDA_ARCH = -arch=sm_61 + +# Volta hardware +#CUDA_ARCH = -arch=sm_70 + +# Turing hardware +#CUDA_ARCH = -arch=sm_75 + +# Ampere hardware +#CUDA_ARCH = -arch=sm_80 +#CUDA_ARCH = -arch=sm_86 + +# this setting should match LAMMPS Makefile +# one of LAMMPS_SMALLBIG (default), LAMMPS_BIGBIG and LAMMPS_SMALLSMALL + +LMP_INC = -DLAMMPS_SMALLBIG + +# precision for GPU calculations +# -D_SINGLE_SINGLE # Single precision for all calculations +# -D_DOUBLE_DOUBLE # Double precision for all calculations +# -D_SINGLE_DOUBLE # Accumulation of forces, etc. in double + +CUDA_PRECISION = -D_SINGLE_DOUBLE + +CUDA_INCLUDE = -I$(CUDA_HOME)/include +CUDA_LIB = -L$(CUDA_HOME)/lib64 -L$(CUDA_HOME)/lib64/stubs +CUDA_OPTS = -DUNIX -O3 --use_fast_math $(LMP_INC) -Xcompiler -fPIC + +CUDR_CPP = mpicxx -DMPI_GERYON -DUCL_NO_EXIT -DMPICH_IGNORE_CXX_SEEK -DOMPI_SKIP_MPICXX=1 -fPIC -std=c++11 +CUDR_OPTS = -O2 $(LMP_INC) # -xHost -no-prec-div -ansi-alias + +BIN_DIR = ./ +OBJ_DIR = ./ +LIB_DIR = ./ +AR = ar +BSH = /bin/sh + +# GPU binning not recommended for most modern GPUs +CUDPP_OPT = #-DUSE_CUDPP -Icudpp_mini + +include Nvidia.makefile + diff --git a/lib/gpu/Makefile.serial b/lib/gpu/Makefile.serial index d24b03f8d6..a1339fffec 100644 --- a/lib/gpu/Makefile.serial +++ b/lib/gpu/Makefile.serial @@ -1,5 +1,5 @@ # /* ---------------------------------------------------------------------- -# Generic Linux Makefile for CUDA +# Generic Linux Makefile for CUDA without MPI libraries # - Change CUDA_ARCH for your GPU # ------------------------------------------------------------------------- */ @@ -13,26 +13,8 @@ endif NVCC = nvcc -# obsolete hardware. not supported by current drivers anymore. -#CUDA_ARCH = -arch=sm_13 -#CUDA_ARCH = -arch=sm_10 -DCUDA_PRE_THREE - -# Fermi hardware -#CUDA_ARCH = -arch=sm_20 -#CUDA_ARCH = -arch=sm_21 - -# Kepler hardware -#CUDA_ARCH = -arch=sm_30 -#CUDA_ARCH = -arch=sm_32 -#CUDA_ARCH = -arch=sm_35 -#CUDA_ARCH = -arch=sm_37 - -# Maxwell hardware -CUDA_ARCH = -arch=sm_50 -#CUDA_ARCH = -arch=sm_52 - # Pascal hardware -#CUDA_ARCH = -arch=sm_60 +CUDA_ARCH = -arch=sm_60 #CUDA_ARCH = -arch=sm_61 # Volta hardware @@ -41,6 +23,10 @@ CUDA_ARCH = -arch=sm_50 # Turing hardware #CUDA_ARCH = -arch=sm_75 +# Ampere hardware +#CUDA_ARCH = -arch=sm_80 +#CUDA_ARCH = -arch=sm_86 + # this setting should match LAMMPS Makefile # one of LAMMPS_SMALLBIG (default), LAMMPS_BIGBIG and LAMMPS_SMALLSMALL diff --git a/lib/gpu/Makefile.turing b/lib/gpu/Makefile.turing deleted file mode 100644 index 390de9c558..0000000000 --- a/lib/gpu/Makefile.turing +++ /dev/null @@ -1,23 +0,0 @@ -NVCC = $(CUDA_HOME)/bin/nvcc -EXTRAMAKE = Makefile.lammps.standard - -CUDA_ARCH = -arch=sm_75 -CUDA_PRECISION = -D_SINGLE_DOUBLE -CUDA_INCLUDE = -I$(CUDA_HOME)/include -CUDA_LIB = -L$(CUDA_HOME)/lib64 -Xlinker -rpath -Xlinker $(CUDA_HOME)/lib64 -lcudart -CUDA_OPTS = -DUNIX -O3 --use_fast_math --ftz=true - -CUDR_CPP = mpic++ -DMPI_GERYON -DUCL_NO_EXIT -I$(CUDA_HOME)/include -CUDR_OPTS = -O3 -ffast-math -funroll-loops -DMPI_GERYON -DLAMMPS_SMALLBIG - -BIN_DIR = . -OBJ_DIR = obj -LIB_DIR = . -AR = ar -BSH = /bin/sh - -# GPU binning not recommended with most modern GPUs -CUDPP_OPT = #-DUSE_CUDPP -Icudpp_mini - -include Nvidia.makefile - From 3262140b65f84509f0586d684a13948f7a8d9485 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 27 Dec 2021 10:35:38 -0500 Subject: [PATCH 078/193] more detailed unit tests. do not fail if ncdump is missing. --- unittest/formats/CMakeLists.txt | 6 +- unittest/formats/test_dump_netcdf.cpp | 280 ++++++++++++++++++++++++-- 2 files changed, 271 insertions(+), 15 deletions(-) diff --git a/unittest/formats/CMakeLists.txt b/unittest/formats/CMakeLists.txt index 18bd7d1195..be8e055adb 100644 --- a/unittest/formats/CMakeLists.txt +++ b/unittest/formats/CMakeLists.txt @@ -117,11 +117,13 @@ add_test(NAME DumpLocal COMMAND test_dump_local WORKING_DIRECTORY ${CMAKE_CURREN set_tests_properties(DumpLocal PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}") if(PKG_NETCDF) - find_program(NCDUMP NAMES ncdump REQUIRED) + find_program(NCDUMP NAMES ncdump ncdump.exe) add_executable(test_dump_netcdf test_dump_netcdf.cpp) target_link_libraries(test_dump_netcdf PRIVATE lammps GTest::GMock) add_test(NAME DumpNetCDF COMMAND test_dump_netcdf WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - set_tests_properties(DumpNetCDF PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR};NCDUMP_BINARY=${NCDUMP}") + if(NOT (NCDUMP STREQUAL "NCDUMP-NOTFOUND")) + set_tests_properties(DumpNetCDF PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR};NCDUMP_BINARY=${NCDUMP}") + endif() endif() if(BUILD_TOOLS) diff --git a/unittest/formats/test_dump_netcdf.cpp b/unittest/formats/test_dump_netcdf.cpp index 3aa65fa112..8b4110b352 100644 --- a/unittest/formats/test_dump_netcdf.cpp +++ b/unittest/formats/test_dump_netcdf.cpp @@ -19,9 +19,11 @@ #include "output.h" #include "thermo.h" #include "utils.h" +#include "version.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include #include using ::testing::Eq; @@ -97,13 +99,139 @@ TEST_F(DumpNetCDFTest, run0_plain) if (NCDUMP_BINARY) { auto converted_file = convert_binary_to_text(dump_file); auto lines = read_lines(converted_file); - auto words = utils::split_words(lines[0]); + auto header = utils::split_words(lines[0]); ASSERT_EQ(lines.size(), 233); - ASSERT_THAT(words[0], Eq("netcdf")); - ASSERT_THAT(words[1]+".nc", Eq(dump_file)); - words = utils::split_words(lines[3]); - ASSERT_THAT(words[0], Eq("atom")); - ASSERT_THAT(words[2], Eq("32")); + ASSERT_THAT(header[0], Eq("netcdf")); + ASSERT_THAT(header[1] + ".nc", Eq(dump_file)); + + // check dimensions section + auto section = std::find(lines.begin(), lines.end(), "dimensions:"); + for (auto line = ++section; line < lines.end(); ++line) { + auto words = utils::split_words(*line); + if ((words.size() < 1) || (words[0] == "variables:")) break; + if (words[0] == "atom") ASSERT_THAT(words[2], Eq("32")); + if (words[0] == "label") ASSERT_THAT(words[2], Eq("10")); + if (words[0] == "Voigt") ASSERT_THAT(words[2], Eq("6")); + if (words[0] == "spatial") ASSERT_THAT(words[2], Eq("3")); + } + + // check variables section + section = std::find(lines.begin(), lines.end(), "variables:"); + for (auto line = ++section; line < lines.end(); ++line) { + auto words = utils::split_words(*line); + if ((words.size() < 2) || (words[0] == "data:")) break; + if (words[0] == "time:units") ASSERT_THAT(words[2], Eq("lj")); + if (words[0] == "time:scale_factor") ASSERT_THAT(words[2], Eq("0.005f")); + if (words[0] == "cell_origin:units") ASSERT_THAT(words[2], Eq("lj")); + if (words[0] == "cell_angles:units") ASSERT_THAT(words[2], Eq("degree")); + if (words[1] == "id(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[1] == "type(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[1] == "proc(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[1] == "procp1(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[1] == "mass(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[1] == "ix(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[1] == "iy(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[1] == "iz(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[0] == ":Conventions") ASSERT_THAT(words[2], Eq("AMBER")); + if (words[0] == ":ConventionVersion") ASSERT_THAT(words[2], Eq("1.0")); + if (words[0] == ":program") ASSERT_THAT(words[2], Eq("LAMMPS")); + if (words[0] == ":programVersion") ASSERT_THAT(words[2], Eq(LAMMPS_VERSION)); + } + + // check data section + section = std::find(lines.begin(), lines.end(), "data:"); + for (auto line = ++section; line < lines.end(); ++line) { + auto words = utils::split_words(*line); + if (words.size() > 0) { + if (words[0] == "spatial") ASSERT_THAT(words[2], Eq("xyz")); + if (words[0] == "cell_spatial") ASSERT_THAT(words[2], Eq("abc")); + if (words[0] == "cell_origin") { + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("0,")); + ASSERT_THAT(words[1], Eq("0,")); + ASSERT_THAT(words[2], Eq("0")); + } + if (words[0] == "cell_lengths") { + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("3.359192,")); + ASSERT_THAT(words[1], Eq("3.359192,")); + ASSERT_THAT(words[2], Eq("3.359192")); + } + if (words[0] == "cell_angles") { + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("90,")); + ASSERT_THAT(words[1], Eq("90,")); + ASSERT_THAT(words[2], Eq("90")); + } + if (words[0] == "id") { + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("1,")); + ASSERT_THAT(words[1], Eq("2,")); + ASSERT_THAT(words[2], Eq("3,")); + ASSERT_THAT(words[3], Eq("4,")); + ASSERT_THAT(words[4], Eq("5,")); + ASSERT_THAT(words[5], Eq("6,")); + ASSERT_THAT(words[6], Eq("7,")); + ASSERT_THAT(words[7], Eq("8,")); + ASSERT_THAT(words[8], Eq("9,")); + ASSERT_THAT(words[9], Eq("10,")); + } + if (words[0] == "mass") { + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("1,")); + ASSERT_THAT(words[1], Eq("1,")); + ASSERT_THAT(words[2], Eq("1,")); + ASSERT_THAT(words[3], Eq("1,")); + ASSERT_THAT(words[4], Eq("1,")); + ASSERT_THAT(words[5], Eq("1,")); + ASSERT_THAT(words[6], Eq("1,")); + ASSERT_THAT(words[7], Eq("1,")); + ASSERT_THAT(words[8], Eq("1,")); + ASSERT_THAT(words[9], Eq("1,")); + } + if (words[0] == "coordinates") { + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("0,")); + ASSERT_THAT(words[1], Eq("0,")); + ASSERT_THAT(words[2], Eq("0,")); + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("0.8397981,")); + ASSERT_THAT(words[1], Eq("0.8397981,")); + ASSERT_THAT(words[2], Eq("0,")); + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("0.8397981,")); + ASSERT_THAT(words[1], Eq("0,")); + ASSERT_THAT(words[2], Eq("0.8397981,")); + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("0,")); + ASSERT_THAT(words[1], Eq("0.8397981,")); + ASSERT_THAT(words[2], Eq("0.8397981,")); + } + if (words[0] == "ix") { + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("0,")); + ASSERT_THAT(words[1], Eq("0,")); + ASSERT_THAT(words[2], Eq("0,")); + ASSERT_THAT(words[3], Eq("0,")); + ASSERT_THAT(words[4], Eq("0,")); + ASSERT_THAT(words[5], Eq("0,")); + ASSERT_THAT(words[6], Eq("0,")); + ASSERT_THAT(words[7], Eq("0,")); + ASSERT_THAT(words[8], Eq("0,")); + ASSERT_THAT(words[9], Eq("0,")); + } + } + } delete_file(converted_file); } delete_file(dump_file); @@ -112,7 +240,7 @@ TEST_F(DumpNetCDFTest, run0_plain) TEST_F(DumpNetCDFTest, run0_mpi) { if (!lammps_has_style(lmp, "dump", "netcdf/mpiio")) GTEST_SKIP(); - auto dump_file = dump_filename("run0"); + auto dump_file = dump_filename("mpi0"); auto fields = "id type proc procp1 mass x y z ix iy iz xu yu zu vx vy vz fx fy fz"; set_style("netcdf/mpiio"); generate_dump(dump_file, fields, "", 0); @@ -121,13 +249,139 @@ TEST_F(DumpNetCDFTest, run0_mpi) if (NCDUMP_BINARY) { auto converted_file = convert_binary_to_text(dump_file); auto lines = read_lines(converted_file); - auto words = utils::split_words(lines[0]); + auto header = utils::split_words(lines[0]); ASSERT_EQ(lines.size(), 234); - ASSERT_THAT(words[0], Eq("netcdf")); - ASSERT_THAT(words[1]+".nc", Eq(dump_file)); - words = utils::split_words(lines[3]); - ASSERT_THAT(words[0], Eq("atom")); - ASSERT_THAT(words[2], Eq("32")); + ASSERT_THAT(header[0], Eq("netcdf")); + ASSERT_THAT(header[1] + ".nc", Eq(dump_file)); + + // check dimensions section + auto section = std::find(lines.begin(), lines.end(), "dimensions:"); + for (auto line = ++section; line < lines.end(); ++line) { + auto words = utils::split_words(*line); + if ((words.size() < 1) || (words[0] == "variables:")) break; + if (words[0] == "atom") ASSERT_THAT(words[2], Eq("32")); + if (words[0] == "label") ASSERT_THAT(words[2], Eq("10")); + if (words[0] == "Voigt") ASSERT_THAT(words[2], Eq("6")); + if (words[0] == "spatial") ASSERT_THAT(words[2], Eq("3")); + } + + // check variables section + section = std::find(lines.begin(), lines.end(), "variables:"); + for (auto line = ++section; line < lines.end(); ++line) { + auto words = utils::split_words(*line); + if ((words.size() < 2) || (words[0] == "data:")) break; + if (words[0] == "time:units") ASSERT_THAT(words[2], Eq("lj")); + if (words[0] == "time:scale_factor") ASSERT_THAT(words[2], Eq("0.005f")); + if (words[0] == "cell_origin:units") ASSERT_THAT(words[2], Eq("lj")); + if (words[0] == "cell_angles:units") ASSERT_THAT(words[2], Eq("degree")); + if (words[1] == "id(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[1] == "type(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[1] == "proc(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[1] == "procp1(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[1] == "mass(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[1] == "ix(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[1] == "iy(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[1] == "iz(frame,") ASSERT_THAT(words[2], Eq("atom)")); + if (words[0] == ":Conventions") ASSERT_THAT(words[2], Eq("AMBER")); + if (words[0] == ":ConventionVersion") ASSERT_THAT(words[2], Eq("1.0")); + if (words[0] == ":program") ASSERT_THAT(words[2], Eq("LAMMPS")); + if (words[0] == ":programVersion") ASSERT_THAT(words[2], Eq(LAMMPS_VERSION)); + } + + // check data section + section = std::find(lines.begin(), lines.end(), "data:"); + for (auto line = ++section; line < lines.end(); ++line) { + auto words = utils::split_words(*line); + if (words.size() > 0) { + if (words[0] == "spatial") ASSERT_THAT(words[2], Eq("xyz")); + if (words[0] == "cell_spatial") ASSERT_THAT(words[2], Eq("abc")); + if (words[0] == "cell_origin") { + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("0,")); + ASSERT_THAT(words[1], Eq("0,")); + ASSERT_THAT(words[2], Eq("0")); + } + if (words[0] == "cell_lengths") { + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("3.359192,")); + ASSERT_THAT(words[1], Eq("3.359192,")); + ASSERT_THAT(words[2], Eq("3.359192")); + } + if (words[0] == "cell_angles") { + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("90,")); + ASSERT_THAT(words[1], Eq("90,")); + ASSERT_THAT(words[2], Eq("90")); + } + if (words[0] == "id") { + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("1,")); + ASSERT_THAT(words[1], Eq("2,")); + ASSERT_THAT(words[2], Eq("3,")); + ASSERT_THAT(words[3], Eq("4,")); + ASSERT_THAT(words[4], Eq("5,")); + ASSERT_THAT(words[5], Eq("6,")); + ASSERT_THAT(words[6], Eq("7,")); + ASSERT_THAT(words[7], Eq("8,")); + ASSERT_THAT(words[8], Eq("9,")); + ASSERT_THAT(words[9], Eq("10,")); + } + if (words[0] == "mass") { + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("1,")); + ASSERT_THAT(words[1], Eq("1,")); + ASSERT_THAT(words[2], Eq("1,")); + ASSERT_THAT(words[3], Eq("1,")); + ASSERT_THAT(words[4], Eq("1,")); + ASSERT_THAT(words[5], Eq("1,")); + ASSERT_THAT(words[6], Eq("1,")); + ASSERT_THAT(words[7], Eq("1,")); + ASSERT_THAT(words[8], Eq("1,")); + ASSERT_THAT(words[9], Eq("1,")); + } + if (words[0] == "coordinates") { + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("0,")); + ASSERT_THAT(words[1], Eq("0,")); + ASSERT_THAT(words[2], Eq("0,")); + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("0.8397981,")); + ASSERT_THAT(words[1], Eq("0.8397981,")); + ASSERT_THAT(words[2], Eq("0,")); + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("0.8397981,")); + ASSERT_THAT(words[1], Eq("0,")); + ASSERT_THAT(words[2], Eq("0.8397981,")); + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("0,")); + ASSERT_THAT(words[1], Eq("0.8397981,")); + ASSERT_THAT(words[2], Eq("0.8397981,")); + } + if (words[0] == "ix") { + ++line; + words = utils::split_words(*line); + ASSERT_THAT(words[0], Eq("0,")); + ASSERT_THAT(words[1], Eq("0,")); + ASSERT_THAT(words[2], Eq("0,")); + ASSERT_THAT(words[3], Eq("0,")); + ASSERT_THAT(words[4], Eq("0,")); + ASSERT_THAT(words[5], Eq("0,")); + ASSERT_THAT(words[6], Eq("0,")); + ASSERT_THAT(words[7], Eq("0,")); + ASSERT_THAT(words[8], Eq("0,")); + ASSERT_THAT(words[9], Eq("0,")); + } + } + } delete_file(converted_file); } delete_file(dump_file); From 5594a38bb7bc4f834f7bd35b5ed95e07aade83a7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 27 Dec 2021 10:47:23 -0500 Subject: [PATCH 079/193] replace explicit Makefile.mpi with symbolic link --- lib/gpu/Makefile.linux | 8 +++--- lib/gpu/Makefile.mpi | 60 +----------------------------------------- 2 files changed, 5 insertions(+), 63 deletions(-) mode change 100644 => 120000 lib/gpu/Makefile.mpi diff --git a/lib/gpu/Makefile.linux b/lib/gpu/Makefile.linux index fe4e57ac77..bed6848980 100644 --- a/lib/gpu/Makefile.linux +++ b/lib/gpu/Makefile.linux @@ -13,7 +13,7 @@ endif NVCC = nvcc -# obsolete hardware. not supported by current drivers anymore. +# obsolete hardware. not supported by current drivers and toolkits anymore. #CUDA_ARCH = -arch=sm_13 #CUDA_ARCH = -arch=sm_10 -DCUDA_PRE_THREE @@ -28,11 +28,11 @@ NVCC = nvcc #CUDA_ARCH = -arch=sm_37 # Maxwell hardware -CUDA_ARCH = -arch=sm_50 +#CUDA_ARCH = -arch=sm_50 #CUDA_ARCH = -arch=sm_52 # Pascal hardware -#CUDA_ARCH = -arch=sm_60 +CUDA_ARCH = -arch=sm_60 #CUDA_ARCH = -arch=sm_61 # Volta hardware @@ -70,7 +70,7 @@ LIB_DIR = ./ AR = ar BSH = /bin/sh -# GPU binning not recommended with modern GPUs +# GPU binning not recommended for most modern GPUs CUDPP_OPT = #-DUSE_CUDPP -Icudpp_mini include Nvidia.makefile diff --git a/lib/gpu/Makefile.mpi b/lib/gpu/Makefile.mpi deleted file mode 100644 index be3c582632..0000000000 --- a/lib/gpu/Makefile.mpi +++ /dev/null @@ -1,59 +0,0 @@ -# /* ---------------------------------------------------------------------- -# Generic Linux Makefile for CUDA -# - Change CUDA_ARCH for your GPU -# ------------------------------------------------------------------------- */ - -# which file will be copied to Makefile.lammps - -EXTRAMAKE = Makefile.lammps.standard - -ifeq ($(CUDA_HOME),) -CUDA_HOME = /usr/local/cuda -endif - -NVCC = nvcc - -# Pascal hardware -CUDA_ARCH = -arch=sm_60 -#CUDA_ARCH = -arch=sm_61 - -# Volta hardware -#CUDA_ARCH = -arch=sm_70 - -# Turing hardware -#CUDA_ARCH = -arch=sm_75 - -# Ampere hardware -#CUDA_ARCH = -arch=sm_80 -#CUDA_ARCH = -arch=sm_86 - -# this setting should match LAMMPS Makefile -# one of LAMMPS_SMALLBIG (default), LAMMPS_BIGBIG and LAMMPS_SMALLSMALL - -LMP_INC = -DLAMMPS_SMALLBIG - -# precision for GPU calculations -# -D_SINGLE_SINGLE # Single precision for all calculations -# -D_DOUBLE_DOUBLE # Double precision for all calculations -# -D_SINGLE_DOUBLE # Accumulation of forces, etc. in double - -CUDA_PRECISION = -D_SINGLE_DOUBLE - -CUDA_INCLUDE = -I$(CUDA_HOME)/include -CUDA_LIB = -L$(CUDA_HOME)/lib64 -L$(CUDA_HOME)/lib64/stubs -CUDA_OPTS = -DUNIX -O3 --use_fast_math $(LMP_INC) -Xcompiler -fPIC - -CUDR_CPP = mpicxx -DMPI_GERYON -DUCL_NO_EXIT -DMPICH_IGNORE_CXX_SEEK -DOMPI_SKIP_MPICXX=1 -fPIC -std=c++11 -CUDR_OPTS = -O2 $(LMP_INC) # -xHost -no-prec-div -ansi-alias - -BIN_DIR = ./ -OBJ_DIR = ./ -LIB_DIR = ./ -AR = ar -BSH = /bin/sh - -# GPU binning not recommended for most modern GPUs -CUDPP_OPT = #-DUSE_CUDPP -Icudpp_mini - -include Nvidia.makefile - diff --git a/lib/gpu/Makefile.mpi b/lib/gpu/Makefile.mpi new file mode 120000 index 0000000000..8bad27d081 --- /dev/null +++ b/lib/gpu/Makefile.mpi @@ -0,0 +1 @@ +Makefile.linux \ No newline at end of file From 47b0c8b33edf14cf60f95bbb8fe2959b0653a6ba Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 27 Dec 2021 11:31:01 -0500 Subject: [PATCH 080/193] whitespace --- src/NETCDF/dump_netcdf.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/NETCDF/dump_netcdf.h b/src/NETCDF/dump_netcdf.h index 8e468692c5..f3a4e81d9c 100644 --- a/src/NETCDF/dump_netcdf.h +++ b/src/NETCDF/dump_netcdf.h @@ -37,16 +37,16 @@ class DumpNetCDF : public DumpCustom { virtual void write(); private: - static constexpr int NC_FIELD_NAME_MAX = 100; - static constexpr int DUMP_NC_MAX_DIMS = 100; + static constexpr int NC_FIELD_NAME_MAX = 100; + static constexpr int DUMP_NC_MAX_DIMS = 100; // per-atoms quantities (positions, velocities, etc.) struct nc_perat_t { - int dims; // number of dimensions - int field[DUMP_NC_MAX_DIMS]; // field indices corresponding to the dim. - char name[NC_FIELD_NAME_MAX]; // field name - int var; // NetCDF variable - int quantity; // type of the quantity + int dims; // number of dimensions + int field[DUMP_NC_MAX_DIMS]; // field indices corresponding to the dim. + char name[NC_FIELD_NAME_MAX]; // field name + int var; // NetCDF variable + int quantity; // type of the quantity bool constant; // is this property per file (not per frame) int ndumped; // number of enties written for this prop. From b781410f924cf1005e269667c179cb2befd93798 Mon Sep 17 00:00:00 2001 From: Vsevak Date: Tue, 28 Dec 2021 03:11:02 +0300 Subject: [PATCH 081/193] Delete fast-math flag from Makefile.hip for AMD platforms --- lib/gpu/Makefile.hip | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/gpu/Makefile.hip b/lib/gpu/Makefile.hip index a736988596..d5391f7d6b 100644 --- a/lib/gpu/Makefile.hip +++ b/lib/gpu/Makefile.hip @@ -39,11 +39,9 @@ HIP_PLATFORM=$(shell $(HIP_PATH)/bin/hipconfig --platform) HIP_COMPILER=$(shell $(HIP_PATH)/bin/hipconfig --compiler) ifeq (hcc,$(HIP_PLATFORM)) - HIP_OPTS += -ffast-math # possible values: gfx803,gfx900,gfx906 HIP_ARCH = gfx906 else ifeq (amd,$(HIP_PLATFORM)) - HIP_OPTS += -ffast-math # possible values: gfx803,gfx900,gfx906 HIP_ARCH = gfx906 else ifeq (nvcc,$(HIP_PLATFORM)) From 053d915fc407b956c8d3ce0fd2b7529e0e86ff4f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 27 Dec 2021 20:14:30 -0500 Subject: [PATCH 082/193] drop -ffast-math for HIP also when compiling with CMake --- cmake/Modules/Packages/GPU.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/Modules/Packages/GPU.cmake b/cmake/Modules/Packages/GPU.cmake index a57715d294..048c0ed473 100644 --- a/cmake/Modules/Packages/GPU.cmake +++ b/cmake/Modules/Packages/GPU.cmake @@ -306,12 +306,12 @@ elseif(GPU_API STREQUAL "HIP") if(HIP_COMPILER STREQUAL "clang") add_custom_command(OUTPUT ${CUBIN_FILE} - VERBATIM COMMAND ${HIP_HIPCC_EXECUTABLE} --genco --offload-arch=${HIP_ARCH} -O3 -ffast-math -DUSE_HIP -D_${GPU_PREC_SETTING} -DLAMMPS_${LAMMPS_SIZES} -I${LAMMPS_LIB_SOURCE_DIR}/gpu -o ${CUBIN_FILE} ${CU_CPP_FILE} + VERBATIM COMMAND ${HIP_HIPCC_EXECUTABLE} --genco --offload-arch=${HIP_ARCH} -O3 -DUSE_HIP -D_${GPU_PREC_SETTING} -DLAMMPS_${LAMMPS_SIZES} -I${LAMMPS_LIB_SOURCE_DIR}/gpu -o ${CUBIN_FILE} ${CU_CPP_FILE} DEPENDS ${CU_CPP_FILE} COMMENT "Generating ${CU_NAME}.cubin") else() add_custom_command(OUTPUT ${CUBIN_FILE} - VERBATIM COMMAND ${HIP_HIPCC_EXECUTABLE} --genco -t="${HIP_ARCH}" -f=\"-O3 -ffast-math -DUSE_HIP -D_${GPU_PREC_SETTING} -DLAMMPS_${LAMMPS_SIZES} -I${LAMMPS_LIB_SOURCE_DIR}/gpu\" -o ${CUBIN_FILE} ${CU_CPP_FILE} + VERBATIM COMMAND ${HIP_HIPCC_EXECUTABLE} --genco -t="${HIP_ARCH}" -f=\"-O3 -DUSE_HIP -D_${GPU_PREC_SETTING} -DLAMMPS_${LAMMPS_SIZES} -I${LAMMPS_LIB_SOURCE_DIR}/gpu\" -o ${CUBIN_FILE} ${CU_CPP_FILE} DEPENDS ${CU_CPP_FILE} COMMENT "Generating ${CU_NAME}.cubin") endif() From 14e5474174492254fd0889044f34062d67b24932 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 27 Dec 2021 20:31:42 -0500 Subject: [PATCH 083/193] restore obsolete compilation settings similar to parallel makefile --- lib/gpu/Makefile.serial | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/gpu/Makefile.serial b/lib/gpu/Makefile.serial index a1339fffec..6c94911f32 100644 --- a/lib/gpu/Makefile.serial +++ b/lib/gpu/Makefile.serial @@ -13,6 +13,24 @@ endif NVCC = nvcc +# obsolete hardware. not supported by current drivers anymore. +#CUDA_ARCH = -arch=sm_13 +#CUDA_ARCH = -arch=sm_10 -DCUDA_PRE_THREE + +# Fermi hardware +#CUDA_ARCH = -arch=sm_20 +#CUDA_ARCH = -arch=sm_21 + +# Kepler hardware +#CUDA_ARCH = -arch=sm_30 +#CUDA_ARCH = -arch=sm_32 +#CUDA_ARCH = -arch=sm_35 +#CUDA_ARCH = -arch=sm_37 + +# Maxwell hardware +#CUDA_ARCH = -arch=sm_50 +#CUDA_ARCH = -arch=sm_52 + # Pascal hardware CUDA_ARCH = -arch=sm_60 #CUDA_ARCH = -arch=sm_61 From 88b42503f96013def50a5c159b8d846a175d8c8c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 29 Dec 2021 14:06:22 -0500 Subject: [PATCH 084/193] address segfault issue with fix nve/gpu when group is not "all" --- src/GPU/fix_nve_gpu.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/GPU/fix_nve_gpu.cpp b/src/GPU/fix_nve_gpu.cpp index 6612b8f65d..9392953398 100644 --- a/src/GPU/fix_nve_gpu.cpp +++ b/src/GPU/fix_nve_gpu.cpp @@ -37,7 +37,7 @@ using namespace FixConst; FixNVEGPU::FixNVEGPU(LAMMPS *lmp, int narg, char **arg) : FixNVE(lmp, narg, arg) { - _dtfm = 0; + _dtfm = nullptr; _nlocal_max = 0; } @@ -57,7 +57,11 @@ void FixNVEGPU::setup(int vflag) _respa_on = 1; else _respa_on = 0; - if (atom->ntypes > 1) reset_dt(); + + // ensure that _dtfm array is initialized if the group is not "all" + // or there is more than one atom type as that re-ordeted array is used for + // per-type/per-atom masses and group membership detection. + if ((igroup != 0) || (atom->ntypes > 1)) reset_dt(); } /* ---------------------------------------------------------------------- From 27a6c63aeb33f9a054cc924bc8b0aaf9bc709e09 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 29 Dec 2021 16:18:48 -0500 Subject: [PATCH 085/193] correct format string for Error::one() --- src/error.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/error.cpp b/src/error.cpp index 5338f41cca..e2162cf661 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -196,7 +196,7 @@ void Error::one(const std::string &file, int line, const std::string &str) MPI_Comm_rank(world,&me); if (input && input->line) lastcmd = input->line; - std::string mesg = fmt::format("ERROR on proc {}: {} ({}:{})\n", + std::string mesg = fmt::format("ERROR on proc {}: {} ({}:{})\nLast command: {}\n", me,str,truncpath(file),line,lastcmd); utils::logmesg(lmp,mesg); From 78df5c2258612e56984b6faead921123e4528c56 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 29 Dec 2021 19:18:42 -0500 Subject: [PATCH 086/193] modernize parsing of Bonds/Angles/Dihedrals/Impropers section of data files --- src/atom.cpp | 94 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 32 deletions(-) diff --git a/src/atom.cpp b/src/atom.cpp index d4a2a431ca..a76dfa22ef 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -29,6 +29,7 @@ #include "modify.h" #include "molecule.h" #include "neighbor.h" +#include "tokenizer.h" #include "update.h" #include "variable.h" @@ -1252,18 +1253,25 @@ void Atom::data_vels(int n, char *buf, tagint id_offset) void Atom::data_bonds(int n, char *buf, int *count, tagint id_offset, int type_offset) { - int m,tmp,itype,rv; + int m,itype; tagint atom1,atom2; char *next; int newton_bond = force->newton_bond; + const std::string errtxt = "Bonds section of data file: "; for (int i = 0; i < n; i++) { next = strchr(buf,'\n'); *next = '\0'; - rv = sscanf(buf,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT, - &tmp,&itype,&atom1,&atom2); - if (rv != 4) - error->one(FLERR,"Incorrect format of Bonds section in data file"); + try { + ValueTokenizer values(utils::trim_comment(buf)); + values.next_int(); + itype = values.next_int(); + atom1 = values.next_tagint(); + atom2 = values.next_tagint(); + if (values.has_next()) throw TokenizerException("Too many tokens",""); + } catch (TokenizerException &e) { + error->one(FLERR,e.what() + std::string(" in ") + errtxt + utils::trim(buf)); + } if (id_offset) { atom1 += id_offset; atom2 += id_offset; @@ -1272,9 +1280,9 @@ void Atom::data_bonds(int n, char *buf, int *count, tagint id_offset, if ((atom1 <= 0) || (atom1 > map_tag_max) || (atom2 <= 0) || (atom2 > map_tag_max) || (atom1 == atom2)) - error->one(FLERR,"Invalid atom ID in Bonds section of data file"); + error->one(FLERR,"Invalid atom ID in " + errtxt + utils::trim(buf)); if (itype <= 0 || itype > nbondtypes) - error->one(FLERR,"Invalid bond type in Bonds section of data file"); + error->one(FLERR,"Invalid bond type in " + errtxt + utils::trim(buf)); if ((m = map(atom1)) >= 0) { if (count) count[m]++; else { @@ -1309,18 +1317,26 @@ void Atom::data_bonds(int n, char *buf, int *count, tagint id_offset, void Atom::data_angles(int n, char *buf, int *count, tagint id_offset, int type_offset) { - int m,tmp,itype,rv; + int m,itype; tagint atom1,atom2,atom3; char *next; int newton_bond = force->newton_bond; + const std::string errtxt = "Angles section of data file: "; for (int i = 0; i < n; i++) { next = strchr(buf,'\n'); *next = '\0'; - rv = sscanf(buf,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, - &tmp,&itype,&atom1,&atom2,&atom3); - if (rv != 5) - error->one(FLERR,"Incorrect format of Angles section in data file"); + try { + ValueTokenizer values(utils::trim_comment(buf)); + values.next_int(); + itype = values.next_int(); + atom1 = values.next_tagint(); + atom2 = values.next_tagint(); + atom3 = values.next_tagint(); + if (values.has_next()) throw TokenizerException("Too many tokens",""); + } catch (TokenizerException &e) { + error->one(FLERR,e.what() + std::string(" in ") + errtxt + utils::trim(buf)); + } if (id_offset) { atom1 += id_offset; atom2 += id_offset; @@ -1332,9 +1348,9 @@ void Atom::data_angles(int n, char *buf, int *count, tagint id_offset, (atom2 <= 0) || (atom2 > map_tag_max) || (atom3 <= 0) || (atom3 > map_tag_max) || (atom1 == atom2) || (atom1 == atom3) || (atom2 == atom3)) - error->one(FLERR,"Invalid atom ID in Angles section of data file"); + error->one(FLERR,"Invalid atom ID in " + errtxt + utils::trim(buf)); if (itype <= 0 || itype > nangletypes) - error->one(FLERR,"Invalid angle type in Angles section of data file"); + error->one(FLERR,"Invalid angle type in " + errtxt + utils::trim(buf)); if ((m = map(atom2)) >= 0) { if (count) count[m]++; else { @@ -1381,19 +1397,27 @@ void Atom::data_angles(int n, char *buf, int *count, tagint id_offset, void Atom::data_dihedrals(int n, char *buf, int *count, tagint id_offset, int type_offset) { - int m,tmp,itype,rv; + int m,itype; tagint atom1,atom2,atom3,atom4; char *next; int newton_bond = force->newton_bond; + const std::string errtxt = "Dihedrals section of data file: "; for (int i = 0; i < n; i++) { next = strchr(buf,'\n'); *next = '\0'; - rv = sscanf(buf,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT - " " TAGINT_FORMAT " " TAGINT_FORMAT, - &tmp,&itype,&atom1,&atom2,&atom3,&atom4); - if (rv != 6) - error->one(FLERR,"Incorrect format of Dihedrals section in data file"); + try { + ValueTokenizer values(utils::trim_comment(buf)); + values.next_int(); + itype = values.next_int(); + atom1 = values.next_tagint(); + atom2 = values.next_tagint(); + atom3 = values.next_tagint(); + atom4 = values.next_tagint(); + if (values.has_next()) throw TokenizerException("Too many tokens",""); + } catch (TokenizerException &e) { + error->one(FLERR,e.what() + std::string(" in ") + errtxt + utils::trim(buf)); + } if (id_offset) { atom1 += id_offset; atom2 += id_offset; @@ -1408,10 +1432,9 @@ void Atom::data_dihedrals(int n, char *buf, int *count, tagint id_offset, (atom4 <= 0) || (atom4 > map_tag_max) || (atom1 == atom2) || (atom1 == atom3) || (atom1 == atom4) || (atom2 == atom3) || (atom2 == atom4) || (atom3 == atom4)) - error->one(FLERR,"Invalid atom ID in Dihedrals section of data file"); + error->one(FLERR, "Invalid atom ID in " + errtxt + utils::trim(buf)); if (itype <= 0 || itype > ndihedraltypes) - error->one(FLERR, - "Invalid dihedral type in Dihedrals section of data file"); + error->one(FLERR, "Invalid dihedral type in " + errtxt + utils::trim(buf)); if ((m = map(atom2)) >= 0) { if (count) count[m]++; else { @@ -1472,19 +1495,27 @@ void Atom::data_dihedrals(int n, char *buf, int *count, tagint id_offset, void Atom::data_impropers(int n, char *buf, int *count, tagint id_offset, int type_offset) { - int m,tmp,itype,rv; + int m,itype; tagint atom1,atom2,atom3,atom4; char *next; int newton_bond = force->newton_bond; + const std::string errtxt = "Impropers section of data file: "; for (int i = 0; i < n; i++) { next = strchr(buf,'\n'); *next = '\0'; - rv = sscanf(buf,"%d %d " - TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, - &tmp,&itype,&atom1,&atom2,&atom3,&atom4); - if (rv != 6) - error->one(FLERR,"Incorrect format of Impropers section in data file"); + try { + ValueTokenizer values(utils::trim_comment(buf)); + values.next_int(); + itype = values.next_int(); + atom1 = values.next_tagint(); + atom2 = values.next_tagint(); + atom3 = values.next_tagint(); + atom4 = values.next_tagint(); + if (values.has_next()) throw TokenizerException("Too many tokens",""); + } catch (TokenizerException &e) { + error->one(FLERR,e.what() + std::string(" in ") + errtxt + utils::trim(buf)); + } if (id_offset) { atom1 += id_offset; atom2 += id_offset; @@ -1499,10 +1530,9 @@ void Atom::data_impropers(int n, char *buf, int *count, tagint id_offset, (atom4 <= 0) || (atom4 > map_tag_max) || (atom1 == atom2) || (atom1 == atom3) || (atom1 == atom4) || (atom2 == atom3) || (atom2 == atom4) || (atom3 == atom4)) - error->one(FLERR,"Invalid atom ID in Impropers section of data file"); + error->one(FLERR, "Invalid atom ID in " + errtxt + utils::trim(buf)); if (itype <= 0 || itype > nimpropertypes) - error->one(FLERR, - "Invalid improper type in Impropers section of data file"); + error->one(FLERR, "Invalid improper type in " + errtxt + utils::trim(buf)); if ((m = map(atom2)) >= 0) { if (count) count[m]++; else { From c97483c46f5a6c1c0133520119c0b3cfa62d61d1 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 29 Dec 2021 19:36:18 -0500 Subject: [PATCH 087/193] modernize parsing of the Masses section in data files --- src/atom.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/atom.cpp b/src/atom.cpp index a76dfa22ef..9ab5da5992 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -1773,17 +1773,20 @@ void Atom::set_mass(const char *file, int line, const char *str, int type_offset int itype; double mass_one; - int n = sscanf(str,"%d %lg",&itype,&mass_one); - if (n != 2) error->all(file,line,"Invalid mass line in data file"); - itype += type_offset; + try { + ValueTokenizer values(utils::trim_comment(str)); + itype = values.next_int() + type_offset; + mass_one = values.next_double(); + if (values.has_next()) throw TokenizerException("Too many tokens", ""); - if (itype < 1 || itype > ntypes) - error->all(file,line,"Invalid type for mass set"); + if (itype < 1 || itype > ntypes) throw TokenizerException("Invalid atom type", ""); + if (mass_one <= 0.0) throw TokenizerException("Invalid mass value", ""); + } catch (TokenizerException &e) { + error->all(file,line,"{} in Masses section of data file: {}", e.what(), utils::trim(str)); + } mass[itype] = mass_one; mass_setflag[itype] = 1; - - if (mass[itype] <= 0.0) error->all(file,line,"Invalid mass value"); } /* ---------------------------------------------------------------------- From 64d6a2fd1f48a4707c19086a64c37f2e554d3849 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 29 Dec 2021 20:24:27 -0500 Subject: [PATCH 088/193] modernize parsing of the Atoms section --- src/atom.cpp | 29 +++++++++++------------------ src/atom_vec.cpp | 14 +++++++------- src/atom_vec.h | 2 +- 3 files changed, 19 insertions(+), 26 deletions(-) diff --git a/src/atom.cpp b/src/atom.cpp index 9ab5da5992..bf791b8c35 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -1058,6 +1058,7 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset, double *coord; char *next; + // use the first line to detect and validate the number of words/tokens per line next = strchr(buf,'\n'); *next = '\0'; int nwords = utils::trim_and_count_words(buf); @@ -1066,8 +1067,6 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset, if (nwords != avec->size_data_atom && nwords != avec->size_data_atom + 3) error->all(FLERR,"Incorrect atom format in data file"); - char **values = new char*[nwords]; - // set bounds for my proc // if periodic and I am lo/hi proc, adjust bounds by EPSILON // insures all data atoms will be owned even with round-off @@ -1138,21 +1137,16 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset, for (int i = 0; i < n; i++) { next = strchr(buf,'\n'); - - for (m = 0; m < nwords; m++) { - buf += strspn(buf," \t\n\r\f"); - buf[strcspn(buf," \t\n\r\f")] = '\0'; - if (strlen(buf) == 0) - error->all(FLERR,"Incorrect atom format in data file"); - values[m] = buf; - buf += strlen(buf)+1; - } + *next = '\0'; + auto values = Tokenizer(utils::trim_comment(buf)).as_vector(); + if (values.size() != nwords) + error->all(FLERR, "Incorrect atom format in data file: {}", utils::trim(buf)); int imx = 0, imy = 0, imz = 0; if (imageflag) { - imx = utils::inumeric(FLERR,values[iptr],false,lmp); - imy = utils::inumeric(FLERR,values[iptr+1],false,lmp); - imz = utils::inumeric(FLERR,values[iptr+2],false,lmp); + imx = utils::inumeric(FLERR,values[iptr].c_str(),false,lmp); + imy = utils::inumeric(FLERR,values[iptr+1].c_str(),false,lmp); + imz = utils::inumeric(FLERR,values[iptr+2].c_str(),false,lmp); if ((domain->dimension == 2) && (imz != 0)) error->all(FLERR,"Z-direction image flag must be 0 for 2d-systems"); if ((!domain->xperiodic) && (imx != 0)) { reset_image_flag[0] = true; imx = 0; } @@ -1163,9 +1157,9 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset, (((imageint) (imy + IMGMAX) & IMGMASK) << IMGBITS) | (((imageint) (imz + IMGMAX) & IMGMASK) << IMG2BITS); - xdata[0] = utils::numeric(FLERR,values[xptr],false,lmp); - xdata[1] = utils::numeric(FLERR,values[xptr+1],false,lmp); - xdata[2] = utils::numeric(FLERR,values[xptr+2],false,lmp); + xdata[0] = utils::numeric(FLERR,values[xptr].c_str(),false,lmp); + xdata[1] = utils::numeric(FLERR,values[xptr+1].c_str(),false,lmp); + xdata[2] = utils::numeric(FLERR,values[xptr+2].c_str(),false,lmp); if (shiftflag) { xdata[0] += shift[0]; xdata[1] += shift[1]; @@ -1193,7 +1187,6 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset, buf = next + 1; } - delete [] values; } /* ---------------------------------------------------------------------- diff --git a/src/atom_vec.cpp b/src/atom_vec.cpp index 5ebaf41ebb..cfecfa4d48 100644 --- a/src/atom_vec.cpp +++ b/src/atom_vec.cpp @@ -1707,7 +1707,7 @@ void AtomVec::create_atom(int itype, double *coord) initialize other peratom quantities ------------------------------------------------------------------------- */ -void AtomVec::data_atom(double *coord, imageint imagetmp, char **values) +void AtomVec::data_atom(double *coord, imageint imagetmp, const std::vector &values) { int m,n,datatype,cols; void *pdata; @@ -1732,7 +1732,7 @@ void AtomVec::data_atom(double *coord, imageint imagetmp, char **values) if (datatype == Atom::DOUBLE) { if (cols == 0) { double *vec = *((double **) pdata); - vec[nlocal] = utils::numeric(FLERR,values[ivalue++],true,lmp); + vec[nlocal] = utils::numeric(FLERR,values[ivalue++].c_str(),true,lmp); } else { double **array = *((double ***) pdata); if (array == atom->x) { // x was already set by coord arg @@ -1740,25 +1740,25 @@ void AtomVec::data_atom(double *coord, imageint imagetmp, char **values) continue; } for (m = 0; m < cols; m++) - array[nlocal][m] = utils::numeric(FLERR,values[ivalue++],true,lmp); + array[nlocal][m] = utils::numeric(FLERR,values[ivalue++].c_str(),true,lmp); } } else if (datatype == Atom::INT) { if (cols == 0) { int *vec = *((int **) pdata); - vec[nlocal] = utils::inumeric(FLERR,values[ivalue++],true,lmp); + vec[nlocal] = utils::inumeric(FLERR,values[ivalue++].c_str(),true,lmp); } else { int **array = *((int ***) pdata); for (m = 0; m < cols; m++) - array[nlocal][m] = utils::inumeric(FLERR,values[ivalue++],true,lmp); + array[nlocal][m] = utils::inumeric(FLERR,values[ivalue++].c_str(),true,lmp); } } else if (datatype == Atom::BIGINT) { if (cols == 0) { bigint *vec = *((bigint **) pdata); - vec[nlocal] = utils::bnumeric(FLERR,values[ivalue++],true,lmp); + vec[nlocal] = utils::bnumeric(FLERR,values[ivalue++].c_str(),true,lmp); } else { bigint **array = *((bigint ***) pdata); for (m = 0; m < cols; m++) - array[nlocal][m] = utils::bnumeric(FLERR,values[ivalue++],true,lmp); + array[nlocal][m] = utils::bnumeric(FLERR,values[ivalue++].c_str(),true,lmp); } } } diff --git a/src/atom_vec.h b/src/atom_vec.h index 0a86d1122c..cbc270aefe 100644 --- a/src/atom_vec.h +++ b/src/atom_vec.h @@ -124,7 +124,7 @@ class AtomVec : protected Pointers { virtual void create_atom(int, double *); virtual void create_atom_post(int) {} - virtual void data_atom(double *, imageint, char **); + virtual void data_atom(double *, imageint, const std::vector &); virtual void data_atom_post(int) {} virtual void data_atom_bonus(int, char **) {} virtual void data_body(int, int, int, int *, double *) {} From cf9429dc68f719ea4c442c43c898a445a2a9d1e4 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 30 Dec 2021 10:43:33 -0500 Subject: [PATCH 089/193] implement overloads so that utils::*numeric() functions can be safely used with std::string() --- doc/src/Developer_utils.rst | 31 ++++++-- doc/src/Developer_write.rst | 2 +- src/utils.cpp | 98 ++++++++++++++++++------- src/utils.h | 61 ++++++++++++++- unittest/formats/test_input_convert.cpp | 39 ++++++++++ 5 files changed, 194 insertions(+), 37 deletions(-) diff --git a/doc/src/Developer_utils.rst b/doc/src/Developer_utils.rst index db47a9e3c3..a9969b7543 100644 --- a/doc/src/Developer_utils.rst +++ b/doc/src/Developer_utils.rst @@ -56,11 +56,11 @@ String to number conversions with validity check These functions should be used to convert strings to numbers. They are are strongly preferred over C library calls like ``atoi()`` or -``atof()`` since they check if the **entire** provided string is a valid +``atof()`` since they check if the **entire** string is a valid (floating-point or integer) number, and will error out instead of silently returning the result of a partial conversion or zero in cases -where the string is not a valid number. This behavior allows to more -easily detect typos or issues when processing input files. +where the string is not a valid number. This behavior improves +detecting typos or issues when processing input files. Similarly the :cpp:func:`logical() ` function will convert a string into a boolean and will only accept certain words. @@ -76,19 +76,34 @@ strings for compliance without conversion. ---------- -.. doxygenfunction:: numeric +.. doxygenfunction:: numeric(const char *file, int line, const std::string &str, bool do_abort, LAMMPS *lmp) :project: progguide -.. doxygenfunction:: inumeric +.. doxygenfunction:: numeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) :project: progguide -.. doxygenfunction:: bnumeric +.. doxygenfunction:: inumeric(const char *file, int line, const std::string &str, bool do_abort, LAMMPS *lmp) :project: progguide -.. doxygenfunction:: tnumeric +.. doxygenfunction:: inumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) :project: progguide -.. doxygenfunction:: logical +.. doxygenfunction:: bnumeric(const char *file, int line, const std::string &str, bool do_abort, LAMMPS *lmp) + :project: progguide + +.. doxygenfunction:: bnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) + :project: progguide + +.. doxygenfunction:: tnumeric(const char *file, int line, const std::string &str, bool do_abort, LAMMPS *lmp) + :project: progguide + +.. doxygenfunction:: tnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) + :project: progguide + +.. doxygenfunction:: logical(const char *file, int line, const std::string &str, bool do_abort, LAMMPS *lmp) + :project: progguide + +.. doxygenfunction:: logical(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) :project: progguide diff --git a/doc/src/Developer_write.rst b/doc/src/Developer_write.rst index c3df6ad6bb..bdb51540c7 100644 --- a/doc/src/Developer_write.rst +++ b/doc/src/Developer_write.rst @@ -55,7 +55,7 @@ of each timestep. First of all, implement a constructor: if (narg < 4) error->all(FLERR,"Illegal fix print/vel command"); - nevery = force->inumeric(FLERR,arg[3]); + nevery = utils::inumeric(FLERR,arg[3]); if (nevery <= 0) error->all(FLERR,"Illegal fix print/vel command"); } diff --git a/src/utils.cpp b/src/utils.cpp index f70a60da7c..81d886f3ed 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -298,12 +298,9 @@ std::string utils::check_packages_for_style(const std::string &style, const std: called by various commands to check validity of their arguments ------------------------------------------------------------------------- */ -int utils::logical(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) +int utils::logical(const char *file, int line, const std::string &str, bool do_abort, LAMMPS *lmp) { - int n = 0; - - if (str) n = strlen(str); - if (n == 0) { + if (str.empty()) { const char msg[] = "Expected boolean parameter instead of NULL or empty string " "in input script or data file"; if (do_abort) @@ -332,18 +329,28 @@ int utils::logical(const char *file, int line, const char *str, bool do_abort, L return rv; } +/* ---------------------------------------------------------------------- + wrapper for logical() that accepts a char pointer instead of a string +------------------------------------------------------------------------- */ + +int utils::logical(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) +{ + if (str) + return logical(file, line, std::string(str), do_abort, lmp); + else + return logical(file, line, std::string(""), do_abort, lmp); +} + /* ---------------------------------------------------------------------- read a floating point value from a string generate an error if not a legitimate floating point value called by various commands to check validity of their arguments ------------------------------------------------------------------------- */ -double utils::numeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) +double utils::numeric(const char *file, int line, const std::string &str, bool do_abort, + LAMMPS *lmp) { - int n = 0; - - if (str) n = strlen(str); - if (n == 0) { + if (str.empty()) { const char msg[] = "Expected floating point parameter instead of" " NULL or empty string in input script or data file"; if (do_abort) @@ -367,18 +374,27 @@ double utils::numeric(const char *file, int line, const char *str, bool do_abort return atof(buf.c_str()); } +/* ---------------------------------------------------------------------- + wrapper for numeric() that accepts a char pointer instead of a string +------------------------------------------------------------------------- */ + +double utils::numeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) +{ + if (str) + return numeric(file, line, std::string(str), do_abort, lmp); + else + return numeric(file, line, std::string(""), do_abort, lmp); +} + /* ---------------------------------------------------------------------- read an integer value from a string generate an error if not a legitimate integer value called by various commands to check validity of their arguments ------------------------------------------------------------------------- */ -int utils::inumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) +int utils::inumeric(const char *file, int line, const std::string &str, bool do_abort, LAMMPS *lmp) { - int n = 0; - - if (str) n = strlen(str); - if (n == 0) { + if (str.empty()) { const char msg[] = "Expected integer parameter instead of" " NULL or empty string in input script or data file"; if (do_abort) @@ -402,18 +418,28 @@ int utils::inumeric(const char *file, int line, const char *str, bool do_abort, return atoi(buf.c_str()); } +/* ---------------------------------------------------------------------- + wrapper for inumeric() that accepts a char pointer instead of a string +------------------------------------------------------------------------- */ + +double utils::inumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) +{ + if (str) + return inumeric(file, line, std::string(str), do_abort, lmp); + else + return inumeric(file, line, std::string(""), do_abort, lmp); +} + /* ---------------------------------------------------------------------- read a big integer value from a string generate an error if not a legitimate integer value called by various commands to check validity of their arguments ------------------------------------------------------------------------- */ -bigint utils::bnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) +bigint utils::bnumeric(const char *file, int line, const std::string &str, bool do_abort, + LAMMPS *lmp) { - int n = 0; - - if (str) n = strlen(str); - if (n == 0) { + if (str.empty()) { const char msg[] = "Expected integer parameter instead of" " NULL or empty string in input script or data file"; if (do_abort) @@ -437,18 +463,28 @@ bigint utils::bnumeric(const char *file, int line, const char *str, bool do_abor return ATOBIGINT(buf.c_str()); } +/* ---------------------------------------------------------------------- + wrapper for bnumeric() that accepts a char pointer instead of a string +------------------------------------------------------------------------- */ + +double utils::bnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) +{ + if (str) + return bnumeric(file, line, std::string(str), do_abort, lmp); + else + return bnumeric(file, line, std::string(""), do_abort, lmp); +} + /* ---------------------------------------------------------------------- read a tag integer value from a string generate an error if not a legitimate integer value called by various commands to check validity of their arguments ------------------------------------------------------------------------- */ -tagint utils::tnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) +tagint utils::tnumeric(const char *file, int line, const std::string &str, bool do_abort, + LAMMPS *lmp) { - int n = 0; - - if (str) n = strlen(str); - if (n == 0) { + if (str.empty()) { const char msg[] = "Expected integer parameter instead of" " NULL or empty string in input script or data file"; if (do_abort) @@ -472,6 +508,18 @@ tagint utils::tnumeric(const char *file, int line, const char *str, bool do_abor return ATOTAGINT(buf.c_str()); } +/* ---------------------------------------------------------------------- + wrapper for tnumeric() that accepts a char pointer instead of a string +------------------------------------------------------------------------- */ + +double utils::tnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) +{ + if (str) + return tnumeric(file, line, std::string(str), do_abort, lmp); + else + return tnumeric(file, line, std::string(""), do_abort, lmp); +} + /* ---------------------------------------------------------------------- compute bounds implied by numeric str with a possible wildcard asterisk ------------------------------------------------------------------------- */ diff --git a/src/utils.h b/src/utils.h index 1feee26f27..4a8080e2ba 100644 --- a/src/utils.h +++ b/src/utils.h @@ -169,6 +169,17 @@ namespace utils { * \param lmp pointer to top-level LAMMPS class instance * \return 1 if string resolves to "true", otherwise 0 */ + int logical(const char *file, int line, const std::string &str, bool do_abort, LAMMPS *lmp); + + /*! \overload + * + * \param file name of source file for error message + * \param line line number in source file for error message + * \param str string to be converted to logical + * \param do_abort determines whether to call Error::one() or Error::all() + * \param lmp pointer to top-level LAMMPS class instance + * \return 1 if string resolves to "true", otherwise 0 */ + int logical(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp); /*! Convert a string to a floating point number while checking @@ -181,6 +192,17 @@ namespace utils { * \param lmp pointer to top-level LAMMPS class instance * \return double precision floating point number */ + double numeric(const char *file, int line, const std::string &str, bool do_abort, LAMMPS *lmp); + + /*! \overload + * + * \param file name of source file for error message + * \param line line number in source file for error message + * \param str string to be converted to number + * \param do_abort determines whether to call Error::one() or Error::all() + * \param lmp pointer to top-level LAMMPS class instance + * \return double precision floating point number */ + double numeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp); /*! Convert a string to an integer number while checking @@ -193,7 +215,18 @@ namespace utils { * \param lmp pointer to top-level LAMMPS class instance * \return integer number (regular int) */ - int inumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp); + int inumeric(const char *file, int line, const std::string &str, bool do_abort, LAMMPS *lmp); + + /*! \overload + * + * \param file name of source file for error message + * \param line line number in source file for error message + * \param str string to be converted to number + * \param do_abort determines whether to call Error::one() or Error::all() + * \param lmp pointer to top-level LAMMPS class instance + * \return double precision floating point number */ + + double inumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp); /*! Convert a string to an integer number while checking * if it is a valid integer number (bigint) @@ -205,7 +238,18 @@ namespace utils { * \param lmp pointer to top-level LAMMPS class instance * \return integer number (bigint) */ - bigint bnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp); + bigint bnumeric(const char *file, int line, const std::string &str, bool do_abort, LAMMPS *lmp); + + /*! \overload + * + * \param file name of source file for error message + * \param line line number in source file for error message + * \param str string to be converted to number + * \param do_abort determines whether to call Error::one() or Error::all() + * \param lmp pointer to top-level LAMMPS class instance + * \return double precision floating point number */ + + double bnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp); /*! Convert a string to an integer number while checking * if it is a valid integer number (tagint) @@ -217,7 +261,18 @@ namespace utils { * \param lmp pointer to top-level LAMMPS class instance * \return integer number (tagint) */ - tagint tnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp); + tagint tnumeric(const char *file, int line, const std::string &str, bool do_abort, LAMMPS *lmp); + + /*! \overload + * + * \param file name of source file for error message + * \param line line number in source file for error message + * \param str string to be converted to number + * \param do_abort determines whether to call Error::one() or Error::all() + * \param lmp pointer to top-level LAMMPS class instance + * \return double precision floating point number */ + + double tnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp); /*! Compute index bounds derived from a string with a possible wildcard * diff --git a/unittest/formats/test_input_convert.cpp b/unittest/formats/test_input_convert.cpp index 0ff6878b13..5930824735 100644 --- a/unittest/formats/test_input_convert.cpp +++ b/unittest/formats/test_input_convert.cpp @@ -49,6 +49,15 @@ TEST_F(InputConvertTest, logical) EXPECT_EQ(utils::logical(FLERR, "off", false, lmp), 0); EXPECT_EQ(utils::logical(FLERR, "0", false, lmp), 0); + EXPECT_EQ(utils::logical(FLERR, std::string("yes"), false, lmp), 1); + EXPECT_EQ(utils::logical(FLERR, std::string("true"), false, lmp), 1); + EXPECT_EQ(utils::logical(FLERR, std::string("on"), false, lmp), 1); + EXPECT_EQ(utils::logical(FLERR, std::string("1"), false, lmp), 1); + EXPECT_EQ(utils::logical(FLERR, std::string("no"), false, lmp), 0); + EXPECT_EQ(utils::logical(FLERR, std::string("false"), false, lmp), 0); + EXPECT_EQ(utils::logical(FLERR, std::string("off"), false, lmp), 0); + EXPECT_EQ(utils::logical(FLERR, std::string("0"), false, lmp), 0); + TEST_FAILURE(".*ERROR: Expected boolean parameter instead of.*", utils::logical(FLERR, "YES", false, lmp);); TEST_FAILURE(".*ERROR: Expected boolean parameter instead of.*", @@ -94,6 +103,15 @@ TEST_F(InputConvertTest, numeric) EXPECT_DOUBLE_EQ(utils::numeric(FLERR, "10000000000", false, lmp), 1e10); EXPECT_DOUBLE_EQ(utils::numeric(FLERR, "2.56E+3", false, lmp), 2560); + EXPECT_DOUBLE_EQ(utils::numeric(FLERR, std::string("0"), false, lmp), 0); + EXPECT_DOUBLE_EQ(utils::numeric(FLERR, std::string("0.1"), false, lmp), 0.1); + EXPECT_DOUBLE_EQ(utils::numeric(FLERR, std::string("-.232"), false, lmp), -0.232); + EXPECT_DOUBLE_EQ(utils::numeric(FLERR, std::string(".2e5"), false, lmp), 20000.0); + EXPECT_DOUBLE_EQ(utils::numeric(FLERR, std::string("2.5e-10"), false, lmp), 2.5e-10); + EXPECT_DOUBLE_EQ(utils::numeric(FLERR, std::string("+0.3"), false, lmp), 0.3); + EXPECT_DOUBLE_EQ(utils::numeric(FLERR, std::string("10000000000"), false, lmp), 1e10); + EXPECT_DOUBLE_EQ(utils::numeric(FLERR, std::string("2.56E+3"), false, lmp), 2560); + TEST_FAILURE(".*ERROR: Expected floating point.*", utils::numeric(FLERR, "yay", false, lmp);); TEST_FAILURE(".*ERROR: Expected floating point.*", utils::numeric(FLERR, "", false, lmp);); TEST_FAILURE(".*ERROR: Expected floating point.*", utils::numeric(FLERR, nullptr, false, lmp);); @@ -110,6 +128,13 @@ TEST_F(InputConvertTest, inumeric) EXPECT_EQ(utils::inumeric(FLERR, "-0", false, lmp), 0); EXPECT_EQ(utils::inumeric(FLERR, "0100", false, lmp), 100); + EXPECT_EQ(utils::inumeric(FLERR, std::string("0"), false, lmp), 0); + EXPECT_EQ(utils::inumeric(FLERR, std::string("-1"), false, lmp), -1); + EXPECT_EQ(utils::inumeric(FLERR, std::string("10000"), false, lmp), 10000); + EXPECT_EQ(utils::inumeric(FLERR, std::string("-532410"), false, lmp), -532410); + EXPECT_EQ(utils::inumeric(FLERR, std::string("-0"), false, lmp), 0); + EXPECT_EQ(utils::inumeric(FLERR, std::string("0100"), false, lmp), 100); + TEST_FAILURE(".*ERROR: Expected integer.*", utils::inumeric(FLERR, "yay", false, lmp);); TEST_FAILURE(".*ERROR: Expected integer.*", utils::inumeric(FLERR, "0.1", false, lmp);); TEST_FAILURE(".*ERROR: Expected integer.*", utils::inumeric(FLERR, "1.1", false, lmp);); @@ -128,6 +153,13 @@ TEST_F(InputConvertTest, bnumeric) EXPECT_EQ(utils::bnumeric(FLERR, "-0", false, lmp), 0); EXPECT_EQ(utils::bnumeric(FLERR, "0100", false, lmp), 100); + EXPECT_EQ(utils::bnumeric(FLERR, std::string("0"), false, lmp), 0); + EXPECT_EQ(utils::bnumeric(FLERR, std::string("-1"), false, lmp), -1); + EXPECT_EQ(utils::bnumeric(FLERR, std::string("10000"), false, lmp), 10000); + EXPECT_EQ(utils::bnumeric(FLERR, std::string("-532410"), false, lmp), -532410); + EXPECT_EQ(utils::bnumeric(FLERR, std::string("-0"), false, lmp), 0); + EXPECT_EQ(utils::bnumeric(FLERR, std::string("0100"), false, lmp), 100); + TEST_FAILURE(".*ERROR: Expected integer.*", utils::bnumeric(FLERR, "yay", false, lmp);); TEST_FAILURE(".*ERROR: Expected integer.*", utils::bnumeric(FLERR, "0.1", false, lmp);); TEST_FAILURE(".*ERROR: Expected integer.*", utils::bnumeric(FLERR, "1.1", false, lmp);); @@ -146,6 +178,13 @@ TEST_F(InputConvertTest, tnumeric) EXPECT_EQ(utils::tnumeric(FLERR, "-0", false, lmp), 0); EXPECT_EQ(utils::tnumeric(FLERR, "0100", false, lmp), 100); + EXPECT_EQ(utils::tnumeric(FLERR, std::string("0"), false, lmp), 0); + EXPECT_EQ(utils::tnumeric(FLERR, std::string("-1"), false, lmp), -1); + EXPECT_EQ(utils::tnumeric(FLERR, std::string("10000"), false, lmp), 10000); + EXPECT_EQ(utils::tnumeric(FLERR, std::string("-532410"), false, lmp), -532410); + EXPECT_EQ(utils::tnumeric(FLERR, std::string("-0"), false, lmp), 0); + EXPECT_EQ(utils::tnumeric(FLERR, std::string("0100"), false, lmp), 100); + TEST_FAILURE(".*ERROR: Expected integer.*", utils::tnumeric(FLERR, "yay", false, lmp);); TEST_FAILURE(".*ERROR: Expected integer.*", utils::tnumeric(FLERR, "0.1", false, lmp);); TEST_FAILURE(".*ERROR: Expected integer.*", utils::tnumeric(FLERR, "1.1", false, lmp);); From 7f2b505df35f6bc3f304cdda6c9f7b3cd5c7fd04 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 30 Dec 2021 11:14:48 -0500 Subject: [PATCH 090/193] apply utils overloads --- src/ML-IAP/mliap_descriptor_so3.cpp | 33 ++++++++++++++--------------- src/ML-RANN/pair_rann.cpp | 30 +++++++++++++------------- src/ML-SNAP/pair_snap.cpp | 31 +++++++++++++-------------- src/atom.cpp | 12 +++++------ src/atom_vec.cpp | 12 +++++------ 5 files changed, 58 insertions(+), 60 deletions(-) diff --git a/src/ML-IAP/mliap_descriptor_so3.cpp b/src/ML-IAP/mliap_descriptor_so3.cpp index e8bedea377..48748d8565 100644 --- a/src/ML-IAP/mliap_descriptor_so3.cpp +++ b/src/ML-IAP/mliap_descriptor_so3.cpp @@ -125,28 +125,27 @@ void MLIAPDescriptorSO3::read_paramfile(char *paramfilename) // check for keywords with one value per element - if (strcmp(skeywd.c_str(), "elems") == 0 || strcmp(skeywd.c_str(), "radelems") == 0 || - strcmp(skeywd.c_str(), "welems") == 0) { + if ((skeywd == "elems") || (skeywd == "radelems") || (skeywd == "welems")) { if (nelementsflag == 0 || nwords != nelements + 1) error->all(FLERR, "Incorrect SO3 parameter file"); - if (strcmp(skeywd.c_str(), "elems") == 0) { + if (skeywd == "elems") { for (int ielem = 0; ielem < nelements; ielem++) { elements[ielem] = utils::strdup(skeyval); if (ielem < nelements - 1) skeyval = p.next(); } elementsflag = 1; - } else if (strcmp(skeywd.c_str(), "radelems") == 0) { + } else if (skeywd == "radelems") { for (int ielem = 0; ielem < nelements; ielem++) { - radelem[ielem] = utils::numeric(FLERR, skeyval.c_str(), false, lmp); + radelem[ielem] = utils::numeric(FLERR, skeyval, false, lmp); if (ielem < nelements - 1) skeyval = p.next(); } radelemflag = 1; - } else if (strcmp(skeywd.c_str(), "welems") == 0) { + } else if (skeywd == "welems") { for (int ielem = 0; ielem < nelements; ielem++) { - wjelem[ielem] = utils::numeric(FLERR, skeyval.c_str(), false, lmp); + wjelem[ielem] = utils::numeric(FLERR, skeyval, false, lmp); if (ielem < nelements - 1) skeyval = p.next(); } wjelemflag = 1; @@ -158,23 +157,23 @@ void MLIAPDescriptorSO3::read_paramfile(char *paramfilename) if (nwords != 2) error->all(FLERR, "Incorrect SO3 parameter file"); - if (strcmp(skeywd.c_str(), "nelems") == 0) { - nelements = utils::inumeric(FLERR, skeyval.c_str(), false, lmp); + if (skeywd == "nelems") { + nelements = utils::inumeric(FLERR, skeyval, false, lmp); elements = new char *[nelements]; memory->create(radelem, nelements, "mliap_so3_descriptor:radelem"); memory->create(wjelem, nelements, "mliap_so3_descriptor:wjelem"); nelementsflag = 1; - } else if (strcmp(skeywd.c_str(), "rcutfac") == 0) { - rcutfac = utils::numeric(FLERR, skeyval.c_str(), false, lmp); + } else if (skeywd == "rcutfac") { + rcutfac = utils::numeric(FLERR, skeyval, false, lmp); rcutfacflag = 1; - } else if (strcmp(skeywd.c_str(), "nmax") == 0) { - nmax = utils::inumeric(FLERR, skeyval.c_str(), false, lmp); + } else if (skeywd == "nmax") { + nmax = utils::inumeric(FLERR, skeyval, false, lmp); nmaxflag = 1; - } else if (strcmp(skeywd.c_str(), "lmax") == 0) { - lmax = utils::inumeric(FLERR, skeyval.c_str(), false, lmp); + } else if (skeywd == "lmax") { + lmax = utils::inumeric(FLERR, skeyval, false, lmp); lmaxflag = 1; - } else if (strcmp(skeywd.c_str(), "alpha") == 0) { - alpha = utils::numeric(FLERR, skeyval.c_str(), false, lmp); + } else if (skeywd == "alpha") { + alpha = utils::numeric(FLERR, skeyval, false, lmp); alphaflag = 1; } else error->all(FLERR, "Incorrect SO3 parameter file"); diff --git a/src/ML-RANN/pair_rann.cpp b/src/ML-RANN/pair_rann.cpp index 3e97b638dc..97a3478332 100644 --- a/src/ML-RANN/pair_rann.cpp +++ b/src/ML-RANN/pair_rann.cpp @@ -440,7 +440,7 @@ void PairRANN::read_mass(const std::vector &line1, const std::vecto if (nelements == -1)error->one(filename,linenum-1,"atom types must be defined before mass in potential file."); for (int i=0;i line,std::vector l if (nelements == -1)error->one(filename,linenum-1,"atom types must be defined before fingerprints per element in potential file."); for (i=0;i line,std::vectorn_body_type!=nwords-1) {error->one(filename,linenum,"invalid fingerprint for element combination");} k++; - fingerprints[i][i1]->init(atomtypes,utils::inumeric(filename,linenum,line1[k++].c_str(),true,lmp)); + fingerprints[i][i1]->init(atomtypes,utils::inumeric(filename,linenum,line1[k++],true,lmp)); fingerprintcount[i]++; } delete[] atomtypes; @@ -523,7 +523,7 @@ void PairRANN::read_fingerprint_constants(std::vector line,std::vec for (j=0;jatomtypes[j]!=atomtypes[j]) {break;} if (j==n_body_type-1) { - if (line[nwords-3].compare(fingerprints[i][k]->style)==0 && utils::inumeric(filename,linenum,line[nwords-2].c_str(),true,lmp)==fingerprints[i][k]->id) { + if (line[nwords-3].compare(fingerprints[i][k]->style)==0 && utils::inumeric(filename,linenum,line[nwords-2],true,lmp)==fingerprints[i][k]->id) { found=true; i1 = k; break; @@ -542,7 +542,7 @@ void PairRANN::read_network_layers(std::vector line,std::vectorone(filename,linenum-1,"atom types must be defined before network layers in potential file."); for (i=0;ione(filename,linenum,"invalid number of network layers"); delete[] net[i].dimensions; weightdefined[i] = new bool [net[i].layers]; @@ -570,9 +570,9 @@ void PairRANN::read_layer_size(std::vector line,std::vectorone(filename,linenum-1,"networklayers for each atom type must be defined before the corresponding layer sizes."); - int j = utils::inumeric(filename,linenum,line[2].c_str(),true,lmp); + int j = utils::inumeric(filename,linenum,line[2],true,lmp); if (j>=net[i].layers || j<0) {error->one(filename,linenum,"invalid layer in layer size definition");}; - net[i].dimensions[j]= utils::inumeric(filename,linenum,line1[0].c_str(),true,lmp); + net[i].dimensions[j]= utils::inumeric(filename,linenum,line1[0],true,lmp); return; } } @@ -587,7 +587,7 @@ void PairRANN::read_weight(std::vector line,std::vectorone(filename,*linenum-1,"networklayers must be defined before weights."); - i=utils::inumeric(filename,*linenum,line[2].c_str(),true,lmp); + i=utils::inumeric(filename,*linenum,line[2],true,lmp); if (i>=net[l].layers || i<0)error->one(filename,*linenum-1,"invalid weight layer"); if (net[l].dimensions[i]==0 || net[l].dimensions[i+1]==0) error->one(filename,*linenum-1,"network layer sizes must be defined before corresponding weight"); net[l].Weights[i] = new double[net[l].dimensions[i]*net[l].dimensions[i+1]]; @@ -595,7 +595,7 @@ void PairRANN::read_weight(std::vector line,std::vectorone(filename,*linenum,"invalid weights per line"); for (k=0;k line,std::vectorone(filename,*linenum,"invalid weights per line"); for (k=0;k line,std::vector for (l=0;lone(filename,*linenum-1,"networklayers must be defined before biases."); - i=utils::inumeric(filename,*linenum,line[2].c_str(),true,lmp); + i=utils::inumeric(filename,*linenum,line[2],true,lmp); if (i>=net[l].layers || i<0)error->one(filename,*linenum-1,"invalid bias layer"); if (net[l].dimensions[i]==0) error->one(filename,*linenum-1,"network layer sizes must be defined before corresponding bias"); biasdefined[l][i] = true; net[l].Biases[i] = new double[net[l].dimensions[i+1]]; - net[l].Biases[i][0] = utils::numeric(filename,*linenum,line1[0].c_str(),true,lmp); + net[l].Biases[i][0] = utils::numeric(filename,*linenum,line1[0],true,lmp); for (j=1;jone(filename,*linenum,"unexpected end of potential file!"); (*linenum)++; Tokenizer values1 = Tokenizer(linetemp,": ,\t_\n"); line1 = values1.as_vector(); - net[l].Biases[i][j] = utils::numeric(filename,*linenum,line1[0].c_str(),true,lmp); + net[l].Biases[i][j] = utils::numeric(filename,*linenum,line1[0],true,lmp); } return; } @@ -680,10 +680,10 @@ void PairRANN::read_screening(std::vector line,std::vectorone(filename,linenum-1,"unrecognized screening keyword"); delete[] atomtypes; diff --git a/src/ML-SNAP/pair_snap.cpp b/src/ML-SNAP/pair_snap.cpp index 1eb078bc61..eafb27f5ba 100644 --- a/src/ML-SNAP/pair_snap.cpp +++ b/src/ML-SNAP/pair_snap.cpp @@ -570,8 +570,8 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) else elementflags[jelem] = 1; - radelem[jelem] = utils::numeric(FLERR,words[1].c_str(),false,lmp); - wjelem[jelem] = utils::numeric(FLERR,words[2].c_str(),false,lmp); + radelem[jelem] = utils::numeric(FLERR,words[1],false,lmp); + wjelem[jelem] = utils::numeric(FLERR,words[2],false,lmp); if (comm->me == 0) utils::logmesg(lmp,"SNAP Element = {}, Radius {}, Weight {}\n", @@ -672,34 +672,33 @@ void PairSNAP::read_files(char *coefffilename, char *paramfilename) utils::logmesg(lmp,"SNAP keyword {} {}\n",keywd,keyval); if (keywd == "rcutfac") { - rcutfac = utils::numeric(FLERR,keyval.c_str(),false,lmp); + rcutfac = utils::numeric(FLERR,keyval,false,lmp); rcutfacflag = 1; } else if (keywd == "twojmax") { - twojmax = utils::inumeric(FLERR,keyval.c_str(),false,lmp); + twojmax = utils::inumeric(FLERR,keyval,false,lmp); twojmaxflag = 1; } else if (keywd == "rfac0") - rfac0 = utils::numeric(FLERR,keyval.c_str(),false,lmp); + rfac0 = utils::numeric(FLERR,keyval,false,lmp); else if (keywd == "rmin0") - rmin0 = utils::numeric(FLERR,keyval.c_str(),false,lmp); + rmin0 = utils::numeric(FLERR,keyval,false,lmp); else if (keywd == "switchflag") - switchflag = utils::inumeric(FLERR,keyval.c_str(),false,lmp); + switchflag = utils::inumeric(FLERR,keyval,false,lmp); else if (keywd == "bzeroflag") - bzeroflag = utils::inumeric(FLERR,keyval.c_str(),false,lmp); + bzeroflag = utils::inumeric(FLERR,keyval,false,lmp); else if (keywd == "quadraticflag") - quadraticflag = utils::inumeric(FLERR,keyval.c_str(),false,lmp); + quadraticflag = utils::inumeric(FLERR,keyval,false,lmp); else if (keywd == "chemflag") - chemflag = utils::inumeric(FLERR,keyval.c_str(),false,lmp); + chemflag = utils::inumeric(FLERR,keyval,false,lmp); else if (keywd == "bnormflag") - bnormflag = utils::inumeric(FLERR,keyval.c_str(),false,lmp); + bnormflag = utils::inumeric(FLERR,keyval,false,lmp); else if (keywd == "wselfallflag") - wselfallflag = utils::inumeric(FLERR,keyval.c_str(),false,lmp); + wselfallflag = utils::inumeric(FLERR,keyval,false,lmp); else if (keywd == "chunksize") - chunksize = utils::inumeric(FLERR,keyval.c_str(),false,lmp); + chunksize = utils::inumeric(FLERR,keyval,false,lmp); else if (keywd == "parallelthresh") - parallel_thresh = utils::inumeric(FLERR,keyval.c_str(),false,lmp); + parallel_thresh = utils::inumeric(FLERR,keyval,false,lmp); else - error->all(FLERR,"Unknown parameter '{}' in SNAP " - "parameter file", keywd); + error->all(FLERR,"Unknown parameter '{}' in SNAP parameter file", keywd); } if (rcutfacflag == 0 || twojmaxflag == 0) diff --git a/src/atom.cpp b/src/atom.cpp index bf791b8c35..438dcd4870 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -1144,9 +1144,9 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset, int imx = 0, imy = 0, imz = 0; if (imageflag) { - imx = utils::inumeric(FLERR,values[iptr].c_str(),false,lmp); - imy = utils::inumeric(FLERR,values[iptr+1].c_str(),false,lmp); - imz = utils::inumeric(FLERR,values[iptr+2].c_str(),false,lmp); + imx = utils::inumeric(FLERR,values[iptr],false,lmp); + imy = utils::inumeric(FLERR,values[iptr+1],false,lmp); + imz = utils::inumeric(FLERR,values[iptr+2],false,lmp); if ((domain->dimension == 2) && (imz != 0)) error->all(FLERR,"Z-direction image flag must be 0 for 2d-systems"); if ((!domain->xperiodic) && (imx != 0)) { reset_image_flag[0] = true; imx = 0; } @@ -1157,9 +1157,9 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset, (((imageint) (imy + IMGMAX) & IMGMASK) << IMGBITS) | (((imageint) (imz + IMGMAX) & IMGMASK) << IMG2BITS); - xdata[0] = utils::numeric(FLERR,values[xptr].c_str(),false,lmp); - xdata[1] = utils::numeric(FLERR,values[xptr+1].c_str(),false,lmp); - xdata[2] = utils::numeric(FLERR,values[xptr+2].c_str(),false,lmp); + xdata[0] = utils::numeric(FLERR,values[xptr],false,lmp); + xdata[1] = utils::numeric(FLERR,values[xptr+1],false,lmp); + xdata[2] = utils::numeric(FLERR,values[xptr+2],false,lmp); if (shiftflag) { xdata[0] += shift[0]; xdata[1] += shift[1]; diff --git a/src/atom_vec.cpp b/src/atom_vec.cpp index cfecfa4d48..f80d25b706 100644 --- a/src/atom_vec.cpp +++ b/src/atom_vec.cpp @@ -1732,7 +1732,7 @@ void AtomVec::data_atom(double *coord, imageint imagetmp, const std::vectorx) { // x was already set by coord arg @@ -1740,25 +1740,25 @@ void AtomVec::data_atom(double *coord, imageint imagetmp, const std::vector Date: Thu, 30 Dec 2021 18:31:15 -0500 Subject: [PATCH 091/193] port data_atom() changes to KOKKOS --- src/KOKKOS/atom_vec_angle_kokkos.cpp | 7 ++++--- src/KOKKOS/atom_vec_angle_kokkos.h | 4 ++-- src/KOKKOS/atom_vec_atomic_kokkos.cpp | 4 ++-- src/KOKKOS/atom_vec_atomic_kokkos.h | 2 +- src/KOKKOS/atom_vec_bond_kokkos.cpp | 7 ++++--- src/KOKKOS/atom_vec_bond_kokkos.h | 4 ++-- src/KOKKOS/atom_vec_charge_kokkos.cpp | 7 ++++--- src/KOKKOS/atom_vec_charge_kokkos.h | 4 ++-- src/KOKKOS/atom_vec_dpd_kokkos.cpp | 9 +++++---- src/KOKKOS/atom_vec_dpd_kokkos.h | 4 ++-- src/KOKKOS/atom_vec_full_kokkos.cpp | 9 +++++---- src/KOKKOS/atom_vec_full_kokkos.h | 4 ++-- src/KOKKOS/atom_vec_hybrid_kokkos.cpp | 5 +++-- src/KOKKOS/atom_vec_hybrid_kokkos.h | 4 ++-- src/KOKKOS/atom_vec_molecular_kokkos.cpp | 7 ++++--- src/KOKKOS/atom_vec_molecular_kokkos.h | 4 ++-- src/KOKKOS/atom_vec_sphere_kokkos.cpp | 10 ++++++---- src/KOKKOS/atom_vec_sphere_kokkos.h | 4 ++-- src/KOKKOS/atom_vec_spin_kokkos.cpp | 13 +++++++------ src/KOKKOS/atom_vec_spin_kokkos.h | 4 ++-- src/atom_vec.h | 2 +- 21 files changed, 64 insertions(+), 54 deletions(-) diff --git a/src/KOKKOS/atom_vec_angle_kokkos.cpp b/src/KOKKOS/atom_vec_angle_kokkos.cpp index c713427aa7..18de4d46cb 100644 --- a/src/KOKKOS/atom_vec_angle_kokkos.cpp +++ b/src/KOKKOS/atom_vec_angle_kokkos.cpp @@ -1630,7 +1630,7 @@ void AtomVecAngleKokkos::create_atom(int itype, double *coord) ------------------------------------------------------------------------- */ void AtomVecAngleKokkos::data_atom(double *coord, imageint imagetmp, - char **values) + const std::vector &values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); @@ -1663,9 +1663,10 @@ void AtomVecAngleKokkos::data_atom(double *coord, imageint imagetmp, initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ -int AtomVecAngleKokkos::data_atom_hybrid(int nlocal, char **values) +int AtomVecAngleKokkos::data_atom_hybrid(int nlocal, const std::vector &values, + int offset) { - h_molecule(nlocal) = utils::inumeric(FLERR,values[0],true,lmp); + h_molecule(nlocal) = utils::inumeric(FLERR,values[offset],true,lmp); h_num_bond(nlocal) = 0; h_num_angle(nlocal) = 0; return 1; diff --git a/src/KOKKOS/atom_vec_angle_kokkos.h b/src/KOKKOS/atom_vec_angle_kokkos.h index 9de0c043eb..9bc7753889 100644 --- a/src/KOKKOS/atom_vec_angle_kokkos.h +++ b/src/KOKKOS/atom_vec_angle_kokkos.h @@ -51,8 +51,8 @@ class AtomVecAngleKokkos : public AtomVecKokkos { int pack_restart(int, double *); int unpack_restart(double *); void create_atom(int, double *); - void data_atom(double *, tagint, char **); - int data_atom_hybrid(int, char **); + void data_atom(double *, imageint, const std::vector &); + int data_atom_hybrid(int, const std::vector &, int); void pack_data(double **); int pack_data_hybrid(int, double *); void write_data(FILE *, int, double **); diff --git a/src/KOKKOS/atom_vec_atomic_kokkos.cpp b/src/KOKKOS/atom_vec_atomic_kokkos.cpp index eec2486763..891ebb51c2 100644 --- a/src/KOKKOS/atom_vec_atomic_kokkos.cpp +++ b/src/KOKKOS/atom_vec_atomic_kokkos.cpp @@ -821,8 +821,8 @@ void AtomVecAtomicKokkos::create_atom(int itype, double *coord) initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecAtomicKokkos::data_atom(double *coord, tagint imagetmp, - char **values) +void AtomVecAtomicKokkos::data_atom(double *coord, imageint imagetmp, + const std::vector &values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); diff --git a/src/KOKKOS/atom_vec_atomic_kokkos.h b/src/KOKKOS/atom_vec_atomic_kokkos.h index 231c95cd3b..1197bc04e7 100644 --- a/src/KOKKOS/atom_vec_atomic_kokkos.h +++ b/src/KOKKOS/atom_vec_atomic_kokkos.h @@ -44,7 +44,7 @@ class AtomVecAtomicKokkos : public AtomVecKokkos { int pack_restart(int, double *); int unpack_restart(double *); void create_atom(int, double *); - void data_atom(double *, tagint, char **); + void data_atom(double *, imageint, const std::vector &); void pack_data(double **); void write_data(FILE *, int, double **); double memory_usage(); diff --git a/src/KOKKOS/atom_vec_bond_kokkos.cpp b/src/KOKKOS/atom_vec_bond_kokkos.cpp index 7582a01730..3655d894c9 100644 --- a/src/KOKKOS/atom_vec_bond_kokkos.cpp +++ b/src/KOKKOS/atom_vec_bond_kokkos.cpp @@ -1056,7 +1056,7 @@ void AtomVecBondKokkos::create_atom(int itype, double *coord) ------------------------------------------------------------------------- */ void AtomVecBondKokkos::data_atom(double *coord, imageint imagetmp, - char **values) + const std::vector &values) { int nlocal = atomKK->nlocal; if (nlocal == nmax) grow(0); @@ -1088,9 +1088,10 @@ void AtomVecBondKokkos::data_atom(double *coord, imageint imagetmp, initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ -int AtomVecBondKokkos::data_atom_hybrid(int nlocal, char **values) +int AtomVecBondKokkos::data_atom_hybrid(int nlocal, const std::vector &values, + int offset) { - h_molecule(nlocal) = utils::inumeric(FLERR,values[0],true,lmp); + h_molecule(nlocal) = utils::inumeric(FLERR,values[offset],true,lmp); h_num_bond(nlocal) = 0; return 1; } diff --git a/src/KOKKOS/atom_vec_bond_kokkos.h b/src/KOKKOS/atom_vec_bond_kokkos.h index 350aeef2d7..a9bc5a1092 100644 --- a/src/KOKKOS/atom_vec_bond_kokkos.h +++ b/src/KOKKOS/atom_vec_bond_kokkos.h @@ -45,8 +45,8 @@ class AtomVecBondKokkos : public AtomVecKokkos { int pack_restart(int, double *); int unpack_restart(double *); void create_atom(int, double *); - void data_atom(double *, tagint, char **); - int data_atom_hybrid(int, char **); + void data_atom(double *, imageint, const std::vector &); + int data_atom_hybrid(int, const std::vector &, int); void pack_data(double **); int pack_data_hybrid(int, double *); void write_data(FILE *, int, double **); diff --git a/src/KOKKOS/atom_vec_charge_kokkos.cpp b/src/KOKKOS/atom_vec_charge_kokkos.cpp index 3bb0985afe..7de36ffd5d 100644 --- a/src/KOKKOS/atom_vec_charge_kokkos.cpp +++ b/src/KOKKOS/atom_vec_charge_kokkos.cpp @@ -955,7 +955,7 @@ void AtomVecChargeKokkos::create_atom(int itype, double *coord) ------------------------------------------------------------------------- */ void AtomVecChargeKokkos::data_atom(double *coord, imageint imagetmp, - char **values) + const std::vector &values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); @@ -987,9 +987,10 @@ void AtomVecChargeKokkos::data_atom(double *coord, imageint imagetmp, initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ -int AtomVecChargeKokkos::data_atom_hybrid(int nlocal, char **values) +int AtomVecChargeKokkos::data_atom_hybrid(int nlocal, const std::vector &values, + int offset) { - h_q[nlocal] = utils::numeric(FLERR,values[0],true,lmp); + h_q[nlocal] = utils::numeric(FLERR,values[offset],true,lmp); return 1; } diff --git a/src/KOKKOS/atom_vec_charge_kokkos.h b/src/KOKKOS/atom_vec_charge_kokkos.h index 2e1ba97e8d..866b836350 100644 --- a/src/KOKKOS/atom_vec_charge_kokkos.h +++ b/src/KOKKOS/atom_vec_charge_kokkos.h @@ -46,8 +46,8 @@ class AtomVecChargeKokkos : public AtomVecKokkos { int pack_restart(int, double *); int unpack_restart(double *); void create_atom(int, double *); - void data_atom(double *, tagint, char **); - int data_atom_hybrid(int , char **); + void data_atom(double *, imageint, const std::vector &); + int data_atom_hybrid(int , const std::vector &, int); void pack_data(double **); int pack_data_hybrid(int, double *); void write_data(FILE *, int, double **); diff --git a/src/KOKKOS/atom_vec_dpd_kokkos.cpp b/src/KOKKOS/atom_vec_dpd_kokkos.cpp index e02631f89e..cf7ad9d533 100644 --- a/src/KOKKOS/atom_vec_dpd_kokkos.cpp +++ b/src/KOKKOS/atom_vec_dpd_kokkos.cpp @@ -1716,8 +1716,8 @@ void AtomVecDPDKokkos::create_atom(int itype, double *coord) initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecDPDKokkos::data_atom(double *coord, tagint imagetmp, - char **values) +void AtomVecDPDKokkos::data_atom(double *coord, imageint imagetmp, + const std::vector &values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); @@ -1759,9 +1759,10 @@ void AtomVecDPDKokkos::data_atom(double *coord, tagint imagetmp, initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ -int AtomVecDPDKokkos::data_atom_hybrid(int nlocal, char **values) +int AtomVecDPDKokkos::data_atom_hybrid(int nlocal, const std::vector &values, + int offset) { - h_dpdTheta(nlocal) = utils::numeric(FLERR,values[0],true,lmp); + h_dpdTheta(nlocal) = utils::numeric(FLERR,values[offset],true,lmp); atomKK->modified(Host,DPDTHETA_MASK); diff --git a/src/KOKKOS/atom_vec_dpd_kokkos.h b/src/KOKKOS/atom_vec_dpd_kokkos.h index c7d523cb34..2168fa630c 100644 --- a/src/KOKKOS/atom_vec_dpd_kokkos.h +++ b/src/KOKKOS/atom_vec_dpd_kokkos.h @@ -54,8 +54,8 @@ class AtomVecDPDKokkos : public AtomVecKokkos { int pack_restart(int, double *); int unpack_restart(double *); void create_atom(int, double *); - void data_atom(double *, tagint, char **); - int data_atom_hybrid(int, char **); + void data_atom(double *, imageint, const std::vector &); + int data_atom_hybrid(int, const std::vector &, int); void pack_data(double **); int pack_data_hybrid(int, double *); void write_data(FILE *, int, double **); diff --git a/src/KOKKOS/atom_vec_full_kokkos.cpp b/src/KOKKOS/atom_vec_full_kokkos.cpp index cd5316cc73..b75c33e046 100644 --- a/src/KOKKOS/atom_vec_full_kokkos.cpp +++ b/src/KOKKOS/atom_vec_full_kokkos.cpp @@ -1488,7 +1488,7 @@ void AtomVecFullKokkos::create_atom(int itype, double *coord) ------------------------------------------------------------------------- */ void AtomVecFullKokkos::data_atom(double *coord, imageint imagetmp, - char **values) + const std::vector &values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); @@ -1525,10 +1525,11 @@ void AtomVecFullKokkos::data_atom(double *coord, imageint imagetmp, initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ -int AtomVecFullKokkos::data_atom_hybrid(int nlocal, char **values) +int AtomVecFullKokkos::data_atom_hybrid(int nlocal, const std::vector &values, + int offset) { - h_molecule(nlocal) = utils::inumeric(FLERR,values[0],true,lmp); - h_q(nlocal) = utils::numeric(FLERR,values[1],true,lmp); + h_molecule(nlocal) = utils::inumeric(FLERR,values[offset],true,lmp); + h_q(nlocal) = utils::numeric(FLERR,values[offset+1],true,lmp); h_num_bond(nlocal) = 0; h_num_angle(nlocal) = 0; h_num_dihedral(nlocal) = 0; diff --git a/src/KOKKOS/atom_vec_full_kokkos.h b/src/KOKKOS/atom_vec_full_kokkos.h index c751eb840d..b5ce032c4f 100644 --- a/src/KOKKOS/atom_vec_full_kokkos.h +++ b/src/KOKKOS/atom_vec_full_kokkos.h @@ -45,8 +45,8 @@ class AtomVecFullKokkos : public AtomVecKokkos { int pack_restart(int, double *); int unpack_restart(double *); void create_atom(int, double *); - void data_atom(double *, tagint, char **); - int data_atom_hybrid(int, char **); + void data_atom(double *, imageint, const std::vector &); + int data_atom_hybrid(int, const std::vector &, int); void pack_data(double **); int pack_data_hybrid(int, double *); void write_data(FILE *, int, double **); diff --git a/src/KOKKOS/atom_vec_hybrid_kokkos.cpp b/src/KOKKOS/atom_vec_hybrid_kokkos.cpp index 6b9f6852ad..60ee9cc04c 100644 --- a/src/KOKKOS/atom_vec_hybrid_kokkos.cpp +++ b/src/KOKKOS/atom_vec_hybrid_kokkos.cpp @@ -970,7 +970,8 @@ void AtomVecHybridKokkos::create_atom(int itype, double *coord) grow() occurs here so arrays for all sub-styles are grown ------------------------------------------------------------------------- */ -void AtomVecHybridKokkos::data_atom(double *coord, imageint imagetmp, char **values) +void AtomVecHybridKokkos::data_atom(double *coord, imageint imagetmp, + const std::vector &values) { atomKK->sync(Host,X_MASK|TAG_MASK|TYPE_MASK|IMAGE_MASK|MASK_MASK|V_MASK|OMEGA_MASK/*|ANGMOM_MASK*/); @@ -1009,7 +1010,7 @@ void AtomVecHybridKokkos::data_atom(double *coord, imageint imagetmp, char **val int m = 5; for (int k = 0; k < nstyles; k++) - m += styles[k]->data_atom_hybrid(nlocal,&values[m]); + m += styles[k]->data_atom_hybrid(nlocal,values,m); atom->nlocal++; } diff --git a/src/KOKKOS/atom_vec_hybrid_kokkos.h b/src/KOKKOS/atom_vec_hybrid_kokkos.h index 4c1907ddc6..17e27ca0b6 100644 --- a/src/KOKKOS/atom_vec_hybrid_kokkos.h +++ b/src/KOKKOS/atom_vec_hybrid_kokkos.h @@ -57,8 +57,8 @@ class AtomVecHybridKokkos : public AtomVecKokkos { int pack_restart(int, double *); int unpack_restart(double *); void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **) {return 0;} + void data_atom(double *, imageint, const std::vector &); + int data_atom_hybrid(int, const std::vector &, int) {return 0;} void data_vel(int, char **); void pack_data(double **); void write_data(FILE *, int, double **); diff --git a/src/KOKKOS/atom_vec_molecular_kokkos.cpp b/src/KOKKOS/atom_vec_molecular_kokkos.cpp index 016e3f80e3..c4e75c1da7 100644 --- a/src/KOKKOS/atom_vec_molecular_kokkos.cpp +++ b/src/KOKKOS/atom_vec_molecular_kokkos.cpp @@ -1889,7 +1889,7 @@ void AtomVecMolecularKokkos::create_atom(int itype, double *coord) ------------------------------------------------------------------------- */ void AtomVecMolecularKokkos::data_atom(double *coord, imageint imagetmp, - char **values) + const std::vector &values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); @@ -1924,9 +1924,10 @@ void AtomVecMolecularKokkos::data_atom(double *coord, imageint imagetmp, initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ -int AtomVecMolecularKokkos::data_atom_hybrid(int nlocal, char **values) +int AtomVecMolecularKokkos::data_atom_hybrid(int nlocal, const std::vector &values, + int offset) { - h_molecule(nlocal) = utils::inumeric(FLERR,values[0],true,lmp); + h_molecule(nlocal) = utils::inumeric(FLERR,values[offset],true,lmp); h_num_bond(nlocal) = 0; h_num_angle(nlocal) = 0; h_num_dihedral(nlocal) = 0; diff --git a/src/KOKKOS/atom_vec_molecular_kokkos.h b/src/KOKKOS/atom_vec_molecular_kokkos.h index fab833469c..abd04f905b 100644 --- a/src/KOKKOS/atom_vec_molecular_kokkos.h +++ b/src/KOKKOS/atom_vec_molecular_kokkos.h @@ -51,8 +51,8 @@ class AtomVecMolecularKokkos : public AtomVecKokkos { int pack_restart(int, double *); int unpack_restart(double *); void create_atom(int, double *); - void data_atom(double *, tagint, char **); - int data_atom_hybrid(int, char **); + void data_atom(double *, imageint, const std::vector &); + int data_atom_hybrid(int, const std::vector &, int); void pack_data(double **); int pack_data_hybrid(int, double *); void write_data(FILE *, int, double **); diff --git a/src/KOKKOS/atom_vec_sphere_kokkos.cpp b/src/KOKKOS/atom_vec_sphere_kokkos.cpp index 6b29af824a..61a33d99ae 100644 --- a/src/KOKKOS/atom_vec_sphere_kokkos.cpp +++ b/src/KOKKOS/atom_vec_sphere_kokkos.cpp @@ -2543,7 +2543,8 @@ void AtomVecSphereKokkos::create_atom(int itype, double *coord) initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecSphereKokkos::data_atom(double *coord, imageint imagetmp, char **values) +void AtomVecSphereKokkos::data_atom(double *coord, imageint imagetmp, + const std::vector &values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); @@ -2590,13 +2591,14 @@ void AtomVecSphereKokkos::data_atom(double *coord, imageint imagetmp, char **val initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ -int AtomVecSphereKokkos::data_atom_hybrid(int nlocal, char **values) +int AtomVecSphereKokkos::data_atom_hybrid(int nlocal, const std::vector &values, + int offset) { - radius[nlocal] = 0.5 * utils::numeric(FLERR,values[0],true,lmp); + radius[nlocal] = 0.5 * utils::numeric(FLERR,values[offset],true,lmp); if (radius[nlocal] < 0.0) error->one(FLERR,"Invalid radius in Atoms section of data file"); - double density = utils::numeric(FLERR,values[1],true,lmp); + double density = utils::numeric(FLERR,values[offset+1],true,lmp); if (density <= 0.0) error->one(FLERR,"Invalid density in Atoms section of data file"); diff --git a/src/KOKKOS/atom_vec_sphere_kokkos.h b/src/KOKKOS/atom_vec_sphere_kokkos.h index 72eb7a665e..79ece5ca83 100644 --- a/src/KOKKOS/atom_vec_sphere_kokkos.h +++ b/src/KOKKOS/atom_vec_sphere_kokkos.h @@ -58,8 +58,8 @@ class AtomVecSphereKokkos : public AtomVecKokkos { int pack_restart(int, double *); int unpack_restart(double *); void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); + void data_atom(double *, imageint, const std::vector &); + int data_atom_hybrid(int, const std::vector &, int); void data_vel(int, char **); int data_vel_hybrid(int, char **); void pack_data(double **); diff --git a/src/KOKKOS/atom_vec_spin_kokkos.cpp b/src/KOKKOS/atom_vec_spin_kokkos.cpp index c8f0663806..039c08f31c 100644 --- a/src/KOKKOS/atom_vec_spin_kokkos.cpp +++ b/src/KOKKOS/atom_vec_spin_kokkos.cpp @@ -1056,7 +1056,7 @@ void AtomVecSpinKokkos::create_atom(int itype, double *coord) ------------------------------------------------------------------------- */ void AtomVecSpinKokkos::data_atom(double *coord, imageint imagetmp, - char **values) + const std::vector &values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); @@ -1098,12 +1098,13 @@ void AtomVecSpinKokkos::data_atom(double *coord, imageint imagetmp, initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ -int AtomVecSpinKokkos::data_atom_hybrid(int nlocal, char **values) +int AtomVecSpinKokkos::data_atom_hybrid(int nlocal, const std::vector &values, + int offset) { - h_sp(nlocal,3) = utils::numeric(FLERR,values[0],true,lmp); - h_sp(nlocal,0) = utils::numeric(FLERR,values[1],true,lmp); - h_sp(nlocal,1) = utils::numeric(FLERR,values[2],true,lmp); - h_sp(nlocal,2) = utils::numeric(FLERR,values[3],true,lmp); + h_sp(nlocal,3) = utils::numeric(FLERR,values[offset],true,lmp); + h_sp(nlocal,0) = utils::numeric(FLERR,values[offset+1],true,lmp); + h_sp(nlocal,1) = utils::numeric(FLERR,values[offset+2],true,lmp); + h_sp(nlocal,2) = utils::numeric(FLERR,values[offset+3],true,lmp); double inorm = 1.0/sqrt(sp[nlocal][0]*sp[nlocal][0] + sp[nlocal][1]*sp[nlocal][1] + sp[nlocal][2]*sp[nlocal][2]); diff --git a/src/KOKKOS/atom_vec_spin_kokkos.h b/src/KOKKOS/atom_vec_spin_kokkos.h index 6438da9eaa..38d206c007 100644 --- a/src/KOKKOS/atom_vec_spin_kokkos.h +++ b/src/KOKKOS/atom_vec_spin_kokkos.h @@ -45,8 +45,8 @@ class AtomVecSpinKokkos : public AtomVecKokkos { int pack_restart(int, double *); int unpack_restart(double *); void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); + void data_atom(double *, imageint, const std::vector &); + int data_atom_hybrid(int, const std::vector &, int); void pack_data(double **); int pack_data_hybrid(int, double *); void write_data(FILE *, int, double **); diff --git a/src/atom_vec.h b/src/atom_vec.h index cbc270aefe..cb27a11519 100644 --- a/src/atom_vec.h +++ b/src/atom_vec.h @@ -166,7 +166,7 @@ class AtomVec : protected Pointers { virtual int unpack_reverse_hybrid(int, int *, double *) { return 0; } virtual int pack_border_hybrid(int, int *, double *) { return 0; } virtual int unpack_border_hybrid(int, int, double *) { return 0; } - virtual int data_atom_hybrid(int, char **) { return 0; } + virtual int data_atom_hybrid(int, const std::vector &, int) { return 0; } virtual int data_vel_hybrid(int, char **) { return 0; } virtual int pack_data_hybrid(int, double *) { return 0; } virtual int write_data_hybrid(FILE *, double *) { return 0; } From 8d53cd1e5d1538deb0597f2010e5ce267c67e35c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 30 Dec 2021 19:02:52 -0500 Subject: [PATCH 092/193] modernize parsing of Velocities section of data files --- src/KOKKOS/atom_vec_hybrid_kokkos.cpp | 12 ++++++------ src/KOKKOS/atom_vec_hybrid_kokkos.h | 2 +- src/KOKKOS/atom_vec_kokkos.cpp | 9 +++++---- src/KOKKOS/atom_vec_kokkos.h | 2 +- src/KOKKOS/atom_vec_sphere_kokkos.cpp | 24 +++++++++++++----------- src/KOKKOS/atom_vec_sphere_kokkos.h | 4 ++-- src/atom.cpp | 19 ++++++------------- src/atom_vec.cpp | 10 +++++----- src/atom_vec.h | 4 ++-- 9 files changed, 41 insertions(+), 45 deletions(-) diff --git a/src/KOKKOS/atom_vec_hybrid_kokkos.cpp b/src/KOKKOS/atom_vec_hybrid_kokkos.cpp index 60ee9cc04c..22ce80478c 100644 --- a/src/KOKKOS/atom_vec_hybrid_kokkos.cpp +++ b/src/KOKKOS/atom_vec_hybrid_kokkos.cpp @@ -1019,21 +1019,21 @@ void AtomVecHybridKokkos::data_atom(double *coord, imageint imagetmp, unpack one line from Velocities section of data file ------------------------------------------------------------------------- */ -void AtomVecHybridKokkos::data_vel(int m, char **values) +void AtomVecHybridKokkos::data_vel(int m, const std::vector &values) { atomKK->sync(Host,V_MASK); - h_v(m,0) = utils::numeric(FLERR,values[0],true,lmp); - h_v(m,1) = utils::numeric(FLERR,values[1],true,lmp); - h_v(m,2) = utils::numeric(FLERR,values[2],true,lmp); + int ivalue = 1; + h_v(m,0) = utils::numeric(FLERR,values[ivalue++],true,lmp); + h_v(m,1) = utils::numeric(FLERR,values[ivalue++],true,lmp); + h_v(m,2) = utils::numeric(FLERR,values[ivalue++],true,lmp); atomKK->modified(Host,V_MASK); // each sub-style parses sub-style specific values - int n = 3; for (int k = 0; k < nstyles; k++) - n += styles[k]->data_vel_hybrid(m,&values[n]); + ivalue += styles[k]->data_vel_hybrid(m,values,ivalue); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/atom_vec_hybrid_kokkos.h b/src/KOKKOS/atom_vec_hybrid_kokkos.h index 17e27ca0b6..567b98695f 100644 --- a/src/KOKKOS/atom_vec_hybrid_kokkos.h +++ b/src/KOKKOS/atom_vec_hybrid_kokkos.h @@ -59,7 +59,7 @@ class AtomVecHybridKokkos : public AtomVecKokkos { void create_atom(int, double *); void data_atom(double *, imageint, const std::vector &); int data_atom_hybrid(int, const std::vector &, int) {return 0;} - void data_vel(int, char **); + void data_vel(int, const std::vector &); void pack_data(double **); void write_data(FILE *, int, double **); void pack_vel(double **); diff --git a/src/KOKKOS/atom_vec_kokkos.cpp b/src/KOKKOS/atom_vec_kokkos.cpp index 1255712a21..931cd8d8f4 100644 --- a/src/KOKKOS/atom_vec_kokkos.cpp +++ b/src/KOKKOS/atom_vec_kokkos.cpp @@ -1016,12 +1016,13 @@ void AtomVecKokkos::unpack_reverse(int n, int *list, double *buf) * unpack one line from Velocities section of data file * ------------------------------------------------------------------------- */ -void AtomVecKokkos::data_vel(int m, char **values) +void AtomVecKokkos::data_vel(int m, const std::vector &values) { double **v = atom->v; - v[m][0] = utils::numeric(FLERR,values[0],true,lmp); - v[m][1] = utils::numeric(FLERR,values[1],true,lmp); - v[m][2] = utils::numeric(FLERR,values[2],true,lmp); + int ivalue = 1; + v[m][0] = utils::numeric(FLERR,values[ivalue++],true,lmp); + v[m][1] = utils::numeric(FLERR,values[ivalue++],true,lmp); + v[m][2] = utils::numeric(FLERR,values[ivalue++],true,lmp); atomKK->modified(Host,V_MASK); } diff --git a/src/KOKKOS/atom_vec_kokkos.h b/src/KOKKOS/atom_vec_kokkos.h index c596d80e94..20dd41dd75 100644 --- a/src/KOKKOS/atom_vec_kokkos.h +++ b/src/KOKKOS/atom_vec_kokkos.h @@ -44,7 +44,7 @@ class AtomVecKokkos : public AtomVec { virtual void unpack_comm_vel(int, int, double *); virtual int pack_reverse(int, int, double *); virtual void unpack_reverse(int, int *, double *); - virtual void data_vel(int, char **); + virtual void data_vel(int, const std::vector &); virtual void pack_vel(double **); virtual void write_vel(FILE *, int, double **); diff --git a/src/KOKKOS/atom_vec_sphere_kokkos.cpp b/src/KOKKOS/atom_vec_sphere_kokkos.cpp index 61a33d99ae..0b722e8563 100644 --- a/src/KOKKOS/atom_vec_sphere_kokkos.cpp +++ b/src/KOKKOS/atom_vec_sphere_kokkos.cpp @@ -2617,15 +2617,16 @@ int AtomVecSphereKokkos::data_atom_hybrid(int nlocal, const std::vector &values) { + int ivalue = 1; atomKK->sync(Host,V_MASK|OMEGA_MASK); - h_v(m,0) = utils::numeric(FLERR,values[0],true,lmp); - h_v(m,1) = utils::numeric(FLERR,values[1],true,lmp); - h_v(m,2) = utils::numeric(FLERR,values[2],true,lmp); - h_omega(m,0) = utils::numeric(FLERR,values[3],true,lmp); - h_omega(m,1) = utils::numeric(FLERR,values[4],true,lmp); - h_omega(m,2) = utils::numeric(FLERR,values[5],true,lmp); + h_v(m,0) = utils::numeric(FLERR,values[ivalue++],true,lmp); + h_v(m,1) = utils::numeric(FLERR,values[ivalue++],true,lmp); + h_v(m,2) = utils::numeric(FLERR,values[ivalue++],true,lmp); + h_omega(m,0) = utils::numeric(FLERR,values[ivalue++],true,lmp); + h_omega(m,1) = utils::numeric(FLERR,values[ivalue++],true,lmp); + h_omega(m,2) = utils::numeric(FLERR,values[ivalue++],true,lmp); atomKK->modified(Host,V_MASK|OMEGA_MASK); } @@ -2633,12 +2634,13 @@ void AtomVecSphereKokkos::data_vel(int m, char **values) unpack hybrid quantities from one line in Velocities section of data file ------------------------------------------------------------------------- */ -int AtomVecSphereKokkos::data_vel_hybrid(int m, char **values) +int AtomVecSphereKokkos::data_vel_hybrid(int m, const std::vector &values, + int offset) { atomKK->sync(Host,OMEGA_MASK); - omega[m][0] = utils::numeric(FLERR,values[0],true,lmp); - omega[m][1] = utils::numeric(FLERR,values[1],true,lmp); - omega[m][2] = utils::numeric(FLERR,values[2],true,lmp); + omega[m][0] = utils::numeric(FLERR,values[offset],true,lmp); + omega[m][1] = utils::numeric(FLERR,values[offset+1],true,lmp); + omega[m][2] = utils::numeric(FLERR,values[offset+2],true,lmp); atomKK->modified(Host,OMEGA_MASK); return 3; } diff --git a/src/KOKKOS/atom_vec_sphere_kokkos.h b/src/KOKKOS/atom_vec_sphere_kokkos.h index 79ece5ca83..a9ba4baa24 100644 --- a/src/KOKKOS/atom_vec_sphere_kokkos.h +++ b/src/KOKKOS/atom_vec_sphere_kokkos.h @@ -60,8 +60,8 @@ class AtomVecSphereKokkos : public AtomVecKokkos { void create_atom(int, double *); void data_atom(double *, imageint, const std::vector &); int data_atom_hybrid(int, const std::vector &, int); - void data_vel(int, char **); - int data_vel_hybrid(int, char **); + void data_vel(int, const std::vector &); + int data_vel_hybrid(int, const std::vector &, int); void pack_data(double **); int pack_data_hybrid(int, double *); void write_data(FILE *, int, double **); diff --git a/src/atom.cpp b/src/atom.cpp index 438dcd4870..ae0968aa61 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -1209,31 +1209,24 @@ void Atom::data_vels(int n, char *buf, tagint id_offset) if (nwords != avec->size_data_vel) error->all(FLERR,"Incorrect velocity format in data file"); - char **values = new char*[nwords]; - // loop over lines of atom velocities // tokenize the line into values // if I own atom tag, unpack its values for (int i = 0; i < n; i++) { next = strchr(buf,'\n'); + *next = '\0'; + auto values = Tokenizer(utils::trim_comment(buf)).as_vector(); + if (values.size() != nwords) + error->all(FLERR, "Incorrect atom format in data file: {}", utils::trim(buf)); - for (j = 0; j < nwords; j++) { - buf += strspn(buf," \t\n\r\f"); - buf[strcspn(buf," \t\n\r\f")] = '\0'; - values[j] = buf; - buf += strlen(buf)+1; - } - - tagdata = ATOTAGINT(values[0]) + id_offset; + tagdata = utils::tnumeric(FLERR,values[0],false,lmp) + id_offset; if (tagdata <= 0 || tagdata > map_tag_max) error->one(FLERR,"Invalid atom ID in Velocities section of data file"); - if ((m = map(tagdata)) >= 0) avec->data_vel(m,&values[1]); + if ((m = map(tagdata)) >= 0) avec->data_vel(m,values); buf = next + 1; } - - delete [] values; } /* ---------------------------------------------------------------------- diff --git a/src/atom_vec.cpp b/src/atom_vec.cpp index f80d25b706..aa646ecabb 100644 --- a/src/atom_vec.cpp +++ b/src/atom_vec.cpp @@ -1890,18 +1890,18 @@ void AtomVec::write_data(FILE *fp, int n, double **buf) unpack one line from Velocities section of data file ------------------------------------------------------------------------- */ -void AtomVec::data_vel(int ilocal, char **values) +void AtomVec::data_vel(int ilocal, const std::vector &values) { int m,n,datatype,cols; void *pdata; double **v = atom->v; - v[ilocal][0] = utils::numeric(FLERR,values[0],true,lmp); - v[ilocal][1] = utils::numeric(FLERR,values[1],true,lmp); - v[ilocal][2] = utils::numeric(FLERR,values[2],true,lmp); + int ivalue = 1; + v[ilocal][0] = utils::numeric(FLERR,values[ivalue++],true,lmp); + v[ilocal][1] = utils::numeric(FLERR,values[ivalue++],true,lmp); + v[ilocal][2] = utils::numeric(FLERR,values[ivalue++],true,lmp); if (ndata_vel > 2) { - int ivalue = 3; for (n = 2; n < ndata_vel; n++) { pdata = mdata_vel.pdata[n]; datatype = mdata_vel.datatype[n]; diff --git a/src/atom_vec.h b/src/atom_vec.h index cb27a11519..57ca96e6e4 100644 --- a/src/atom_vec.h +++ b/src/atom_vec.h @@ -136,7 +136,7 @@ class AtomVec : protected Pointers { virtual void pack_data_pre(int) {} virtual void pack_data_post(int) {} - virtual void data_vel(int, char **); + virtual void data_vel(int, const std::vector &); virtual void pack_vel(double **); virtual void write_vel(FILE *, int, double **); @@ -167,7 +167,7 @@ class AtomVec : protected Pointers { virtual int pack_border_hybrid(int, int *, double *) { return 0; } virtual int unpack_border_hybrid(int, int, double *) { return 0; } virtual int data_atom_hybrid(int, const std::vector &, int) { return 0; } - virtual int data_vel_hybrid(int, char **) { return 0; } + virtual int data_vel_hybrid(int, const std::vector &, int) { return 0; } virtual int pack_data_hybrid(int, double *) { return 0; } virtual int write_data_hybrid(FILE *, double *) { return 0; } virtual int pack_vel_hybrid(int, double *) { return 0; } From e6e9aed38559ff508c9ef7f161c92527520fc6f8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 30 Dec 2021 22:58:14 -0500 Subject: [PATCH 093/193] modernize/correct parsing for Bonus and Bodies sections --- src/atom.cpp | 63 +++++++++++++++++--------------------- src/atom_vec.h | 2 +- src/atom_vec_ellipsoid.cpp | 17 +++++----- src/atom_vec_ellipsoid.h | 2 +- src/atom_vec_line.cpp | 11 ++++--- src/atom_vec_line.h | 2 +- src/atom_vec_tri.cpp | 21 +++++++------ src/atom_vec_tri.h | 2 +- 8 files changed, 58 insertions(+), 62 deletions(-) diff --git a/src/atom.cpp b/src/atom.cpp index ae0968aa61..292583da87 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -1198,7 +1198,6 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset, void Atom::data_vels(int n, char *buf, tagint id_offset) { int j,m; - tagint tagdata; char *next; next = strchr(buf,'\n'); @@ -1220,7 +1219,7 @@ void Atom::data_vels(int n, char *buf, tagint id_offset) if (values.size() != nwords) error->all(FLERR, "Incorrect atom format in data file: {}", utils::trim(buf)); - tagdata = utils::tnumeric(FLERR,values[0],false,lmp) + id_offset; + tagint tagdata = utils::tnumeric(FLERR,values[0],false,lmp) + id_offset; if (tagdata <= 0 || tagdata > map_tag_max) error->one(FLERR,"Invalid atom ID in Velocities section of data file"); if ((m = map(tagdata)) >= 0) avec->data_vel(m,values); @@ -1577,7 +1576,7 @@ void Atom::data_impropers(int n, char *buf, int *count, tagint id_offset, void Atom::data_bonus(int n, char *buf, AtomVec *avec_bonus, tagint id_offset) { - int j,m,tagdata; + int j,m; char *next; next = strchr(buf,'\n'); @@ -1588,35 +1587,28 @@ void Atom::data_bonus(int n, char *buf, AtomVec *avec_bonus, tagint id_offset) if (nwords != avec_bonus->size_data_bonus) error->all(FLERR,"Incorrect bonus data format in data file"); - char **values = new char*[nwords]; - // loop over lines of bonus atom data // tokenize the line into values // if I own atom tag, unpack its values for (int i = 0; i < n; i++) { next = strchr(buf,'\n'); + *next = '\0'; + auto values = Tokenizer(utils::trim_comment(buf)).as_vector(); + if (values.size() != nwords) + error->all(FLERR, "Incorrect atom format in data file: {}", utils::trim(buf)); - for (j = 0; j < nwords; j++) { - buf += strspn(buf," \t\n\r\f"); - buf[strcspn(buf," \t\n\r\f")] = '\0'; - values[j] = buf; - buf += strlen(buf)+1; - } - - tagdata = ATOTAGINT(values[0]) + id_offset; + tagint tagdata = utils::tnumeric(FLERR,values[0],false,lmp) + id_offset; if (tagdata <= 0 || tagdata > map_tag_max) error->one(FLERR,"Invalid atom ID in Bonus section of data file"); // ok to call child's data_atom_bonus() method thru parent avec_bonus, // since data_bonus() was called with child ptr, and method is virtual - if ((m = map(tagdata)) >= 0) avec_bonus->data_atom_bonus(m,&values[1]); + if ((m = map(tagdata)) >= 0) avec_bonus->data_atom_bonus(m,values); buf = next + 1; } - - delete [] values; } /* ---------------------------------------------------------------------- @@ -1628,12 +1620,13 @@ void Atom::data_bonus(int n, char *buf, AtomVec *avec_bonus, tagint id_offset) void Atom::data_bodies(int n, char *buf, AtomVec *avec_body, tagint id_offset) { - int j,m,nvalues,tagdata,ninteger,ndouble; + int j,m,nvalues,ninteger,ndouble; int maxint = 0; int maxdouble = 0; int *ivalues = nullptr; double *dvalues = nullptr; + char *next; if (!unique_tags) unique_tags = new std::set; @@ -1642,10 +1635,13 @@ void Atom::data_bodies(int n, char *buf, AtomVec *avec_body, tagint id_offset) // else skip values for (int i = 0; i < n; i++) { - buf += strspn(buf," \t\n\r\f"); - buf[strcspn(buf," \t\n\r\f")] = '\0'; - tagdata = utils::tnumeric(FLERR,buf,false,lmp) + id_offset; - buf += strlen(buf)+1; + next = strchr(buf,'\n'); + *next = '\0'; + + auto values = Tokenizer(utils::trim_comment(buf)).as_vector(); + tagint tagdata = utils::tnumeric(FLERR,values[0],false,lmp) + id_offset; + ninteger = utils::inumeric(FLERR,values[1],false,lmp); + ndouble = utils::inumeric(FLERR,values[2],false,lmp); if (tagdata <= 0 || tagdata > map_tag_max) error->one(FLERR,"Invalid atom ID in Bodies section of data file"); @@ -1655,24 +1651,21 @@ void Atom::data_bodies(int n, char *buf, AtomVec *avec_body, tagint id_offset) else error->one(FLERR,"Duplicate atom ID in Bodies section of data file"); - buf += strspn(buf," \t\n\r\f"); - buf[strcspn(buf," \t\n\r\f")] = '\0'; - ninteger = utils::inumeric(FLERR,buf,false,lmp); - buf += strlen(buf)+1; + if (ninteger < 0) + error->one(FLERR,"Invalid number of integers in Bodies section of data file"); + if (ndouble < 0) + error->one(FLERR,"Invalid number of doubles in Bodies section of data file"); - buf += strspn(buf," \t\n\r\f"); - buf[strcspn(buf," \t\n\r\f")] = '\0'; - ndouble = utils::inumeric(FLERR,buf,false,lmp); - buf += strlen(buf)+1; - - if ((m = map(tagdata)) >= 0) { + buf = next + 1; + m = map(tagdata); + if (m >= 0) { if (ninteger > maxint) { - delete [] ivalues; + delete[] ivalues; maxint = ninteger; ivalues = new int[maxint]; } if (ndouble > maxdouble) { - delete [] dvalues; + delete[] dvalues; maxdouble = ndouble; dvalues = new double[maxdouble]; } @@ -1703,8 +1696,8 @@ void Atom::data_bodies(int n, char *buf, AtomVec *avec_body, tagint id_offset) } } - delete [] ivalues; - delete [] dvalues; + delete[] ivalues; + delete[] dvalues; } /* ---------------------------------------------------------------------- diff --git a/src/atom_vec.h b/src/atom_vec.h index 57ca96e6e4..6bc7f23532 100644 --- a/src/atom_vec.h +++ b/src/atom_vec.h @@ -126,7 +126,7 @@ class AtomVec : protected Pointers { virtual void data_atom(double *, imageint, const std::vector &); virtual void data_atom_post(int) {} - virtual void data_atom_bonus(int, char **) {} + virtual void data_atom_bonus(int, const std::vector &) {} virtual void data_body(int, int, int, int *, double *) {} virtual void data_bonds_post(int, int, tagint, tagint, tagint) {} diff --git a/src/atom_vec_ellipsoid.cpp b/src/atom_vec_ellipsoid.cpp index 38c4893f61..6c39e4cfaf 100644 --- a/src/atom_vec_ellipsoid.cpp +++ b/src/atom_vec_ellipsoid.cpp @@ -381,7 +381,7 @@ int AtomVecEllipsoid::unpack_restart_bonus(int ilocal, double *buf) unpack one line from Ellipsoids section of data file ------------------------------------------------------------------------- */ -void AtomVecEllipsoid::data_atom_bonus(int m, char **values) +void AtomVecEllipsoid::data_atom_bonus(int m, const std::vector & values) { if (ellipsoid[m]) error->one(FLERR,"Assigning ellipsoid parameters to non-ellipsoid atom"); @@ -389,17 +389,18 @@ void AtomVecEllipsoid::data_atom_bonus(int m, char **values) if (nlocal_bonus == nmax_bonus) grow_bonus(); double *shape = bonus[nlocal_bonus].shape; - shape[0] = 0.5 * utils::numeric(FLERR,values[0],true,lmp); - shape[1] = 0.5 * utils::numeric(FLERR,values[1],true,lmp); - shape[2] = 0.5 * utils::numeric(FLERR,values[2],true,lmp); + int ivalue = 1; + shape[0] = 0.5 * utils::numeric(FLERR,values[ivalue++],true,lmp); + shape[1] = 0.5 * utils::numeric(FLERR,values[ivalue++],true,lmp); + shape[2] = 0.5 * utils::numeric(FLERR,values[ivalue++],true,lmp); if (shape[0] <= 0.0 || shape[1] <= 0.0 || shape[2] <= 0.0) error->one(FLERR,"Invalid shape in Ellipsoids section of data file"); double *quat = bonus[nlocal_bonus].quat; - quat[0] = utils::numeric(FLERR,values[3],true,lmp); - quat[1] = utils::numeric(FLERR,values[4],true,lmp); - quat[2] = utils::numeric(FLERR,values[5],true,lmp); - quat[3] = utils::numeric(FLERR,values[6],true,lmp); + quat[0] = utils::numeric(FLERR,values[ivalue++],true,lmp); + quat[1] = utils::numeric(FLERR,values[ivalue++],true,lmp); + quat[2] = utils::numeric(FLERR,values[ivalue++],true,lmp); + quat[3] = utils::numeric(FLERR,values[ivalue++],true,lmp); MathExtra::qnormalize(quat); // reset ellipsoid mass diff --git a/src/atom_vec_ellipsoid.h b/src/atom_vec_ellipsoid.h index 6a77d9886c..bb50944f30 100644 --- a/src/atom_vec_ellipsoid.h +++ b/src/atom_vec_ellipsoid.h @@ -48,7 +48,7 @@ class AtomVecEllipsoid : public AtomVec { int size_restart_bonus(); int pack_restart_bonus(int, double *); int unpack_restart_bonus(int, double *); - void data_atom_bonus(int, char **); + void data_atom_bonus(int, const std::vector &); double memory_usage_bonus(); void create_atom_post(int); diff --git a/src/atom_vec_line.cpp b/src/atom_vec_line.cpp index bfc6c7e6d7..e15bc61f2f 100644 --- a/src/atom_vec_line.cpp +++ b/src/atom_vec_line.cpp @@ -337,16 +337,17 @@ int AtomVecLine::unpack_restart_bonus(int ilocal, double *buf) unpack one line from Lines section of data file ------------------------------------------------------------------------- */ -void AtomVecLine::data_atom_bonus(int m, char **values) +void AtomVecLine::data_atom_bonus(int m, const std::vector &values) { if (line[m]) error->one(FLERR,"Assigning line parameters to non-line atom"); if (nlocal_bonus == nmax_bonus) grow_bonus(); - double x1 = utils::numeric(FLERR,values[0],true,lmp); - double y1 = utils::numeric(FLERR,values[1],true,lmp); - double x2 = utils::numeric(FLERR,values[2],true,lmp); - double y2 = utils::numeric(FLERR,values[3],true,lmp); + int ivalue = 1; + double x1 = utils::numeric(FLERR,values[ivalue++],true,lmp); + double y1 = utils::numeric(FLERR,values[ivalue++],true,lmp); + double x2 = utils::numeric(FLERR,values[ivalue++],true,lmp); + double y2 = utils::numeric(FLERR,values[ivalue++],true,lmp); double dx = x2 - x1; double dy = y2 - y1; double length = sqrt(dx*dx + dy*dy); diff --git a/src/atom_vec_line.h b/src/atom_vec_line.h index 176cfc0dd9..5903349700 100644 --- a/src/atom_vec_line.h +++ b/src/atom_vec_line.h @@ -48,7 +48,7 @@ class AtomVecLine : public AtomVec { int size_restart_bonus(); int pack_restart_bonus(int, double *); int unpack_restart_bonus(int, double *); - void data_atom_bonus(int, char **); + void data_atom_bonus(int, const std::vector &); double memory_usage_bonus(); void create_atom_post(int); diff --git a/src/atom_vec_tri.cpp b/src/atom_vec_tri.cpp index 6a1cad5f5c..4b1ee0d921 100644 --- a/src/atom_vec_tri.cpp +++ b/src/atom_vec_tri.cpp @@ -470,22 +470,23 @@ int AtomVecTri::unpack_restart_bonus(int ilocal, double *buf) unpack one line from Tris section of data file ------------------------------------------------------------------------- */ -void AtomVecTri::data_atom_bonus(int m, char **values) +void AtomVecTri::data_atom_bonus(int m, const std::vector &values) { if (tri[m]) error->one(FLERR,"Assigning tri parameters to non-tri atom"); if (nlocal_bonus == nmax_bonus) grow_bonus(); double c1[3],c2[3],c3[3]; - c1[0] = utils::numeric(FLERR,values[0],true,lmp); - c1[1] = utils::numeric(FLERR,values[1],true,lmp); - c1[2] = utils::numeric(FLERR,values[2],true,lmp); - c2[0] = utils::numeric(FLERR,values[3],true,lmp); - c2[1] = utils::numeric(FLERR,values[4],true,lmp); - c2[2] = utils::numeric(FLERR,values[5],true,lmp); - c3[0] = utils::numeric(FLERR,values[6],true,lmp); - c3[1] = utils::numeric(FLERR,values[7],true,lmp); - c3[2] = utils::numeric(FLERR,values[8],true,lmp); + int ivalue = 1; + c1[0] = utils::numeric(FLERR,values[ivalue++],true,lmp); + c1[1] = utils::numeric(FLERR,values[ivalue++],true,lmp); + c1[2] = utils::numeric(FLERR,values[ivalue++],true,lmp); + c2[0] = utils::numeric(FLERR,values[ivalue++],true,lmp); + c2[1] = utils::numeric(FLERR,values[ivalue++],true,lmp); + c2[2] = utils::numeric(FLERR,values[ivalue++],true,lmp); + c3[0] = utils::numeric(FLERR,values[ivalue++],true,lmp); + c3[1] = utils::numeric(FLERR,values[ivalue++],true,lmp); + c3[2] = utils::numeric(FLERR,values[ivalue++],true,lmp); // check for duplicate points diff --git a/src/atom_vec_tri.h b/src/atom_vec_tri.h index 36ec8d6948..f9f0bae386 100644 --- a/src/atom_vec_tri.h +++ b/src/atom_vec_tri.h @@ -50,7 +50,7 @@ class AtomVecTri : public AtomVec { int size_restart_bonus(); int pack_restart_bonus(int, double *); int unpack_restart_bonus(int, double *); - void data_atom_bonus(int, char **); + void data_atom_bonus(int, const std::vector &); double memory_usage_bonus(); void create_atom_post(int); From ca3be99e77d8c1a30c9891e8b62791278f4f0402 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 30 Dec 2021 23:48:42 -0500 Subject: [PATCH 094/193] correct function prototypes --- src/utils.cpp | 6 +++--- src/utils.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/utils.cpp b/src/utils.cpp index 81d886f3ed..eabe86adbc 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -422,7 +422,7 @@ int utils::inumeric(const char *file, int line, const std::string &str, bool do_ wrapper for inumeric() that accepts a char pointer instead of a string ------------------------------------------------------------------------- */ -double utils::inumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) +int utils::inumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) { if (str) return inumeric(file, line, std::string(str), do_abort, lmp); @@ -467,7 +467,7 @@ bigint utils::bnumeric(const char *file, int line, const std::string &str, bool wrapper for bnumeric() that accepts a char pointer instead of a string ------------------------------------------------------------------------- */ -double utils::bnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) +bigint utils::bnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) { if (str) return bnumeric(file, line, std::string(str), do_abort, lmp); @@ -512,7 +512,7 @@ tagint utils::tnumeric(const char *file, int line, const std::string &str, bool wrapper for tnumeric() that accepts a char pointer instead of a string ------------------------------------------------------------------------- */ -double utils::tnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) +tagint utils::tnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp) { if (str) return tnumeric(file, line, std::string(str), do_abort, lmp); diff --git a/src/utils.h b/src/utils.h index 4a8080e2ba..47a4ace5f9 100644 --- a/src/utils.h +++ b/src/utils.h @@ -226,7 +226,7 @@ namespace utils { * \param lmp pointer to top-level LAMMPS class instance * \return double precision floating point number */ - double inumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp); + int inumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp); /*! Convert a string to an integer number while checking * if it is a valid integer number (bigint) @@ -249,7 +249,7 @@ namespace utils { * \param lmp pointer to top-level LAMMPS class instance * \return double precision floating point number */ - double bnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp); + bigint bnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp); /*! Convert a string to an integer number while checking * if it is a valid integer number (tagint) @@ -272,7 +272,7 @@ namespace utils { * \param lmp pointer to top-level LAMMPS class instance * \return double precision floating point number */ - double tnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp); + tagint tnumeric(const char *file, int line, const char *str, bool do_abort, LAMMPS *lmp); /*! Compute index bounds derived from a string with a possible wildcard * From 6d9764e1401d3ea1945917e1e9c9fbb086e4a340 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 31 Dec 2021 00:14:52 -0500 Subject: [PATCH 095/193] add missing advance of buffer pointer --- src/atom.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/atom.cpp b/src/atom.cpp index 292583da87..145c744a06 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -1694,6 +1694,7 @@ void Atom::data_bodies(int n, char *buf, AtomVec *avec_body, tagint id_offset) buf += strlen(buf)+1; } } + buf += strspn(buf," \t\n\r\f"); } delete[] ivalues; From 863de683eef7230479fe45bde7a3c26132d8348a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 31 Dec 2021 13:43:56 -0500 Subject: [PATCH 096/193] do not shadow "natoms" class member --- src/read_data.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/read_data.cpp b/src/read_data.cpp index 7e5d49e65c..67eadc313c 100644 --- a/src/read_data.cpp +++ b/src/read_data.cpp @@ -1677,11 +1677,11 @@ void ReadData::bodies(int firstpass, AtomVec *ptr) // nchunk = actual # read bigint nread = 0; - bigint natoms = nbodies; + bigint nblocks = nbodies; - while (nread < natoms) { - if (natoms-nread > CHUNK) nmax = CHUNK; - else nmax = natoms-nread; + while (nread < nblocks) { + if (nblocks-nread > CHUNK) nmax = CHUNK; + else nmax = nblocks-nread; if (me == 0) { nchunk = 0; @@ -1754,7 +1754,7 @@ void ReadData::bodies(int firstpass, AtomVec *ptr) } if (me == 0 && firstpass) - utils::logmesg(lmp," {} bodies\n",natoms); + utils::logmesg(lmp," {} bodies\n",nblocks); } /* ---------------------------------------------------------------------- */ From c17a183816ce1b1137ea81979dc04dc08ef45489 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 31 Dec 2021 14:34:09 -0500 Subject: [PATCH 097/193] do error checking already in read_data code --- src/atom.cpp | 8 -------- src/read_data.cpp | 27 +++++++++++++++++++++------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/atom.cpp b/src/atom.cpp index 145c744a06..2dc6819978 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -1643,19 +1643,11 @@ void Atom::data_bodies(int n, char *buf, AtomVec *avec_body, tagint id_offset) ninteger = utils::inumeric(FLERR,values[1],false,lmp); ndouble = utils::inumeric(FLERR,values[2],false,lmp); - if (tagdata <= 0 || tagdata > map_tag_max) - error->one(FLERR,"Invalid atom ID in Bodies section of data file"); - if (unique_tags->find(tagdata) == unique_tags->end()) unique_tags->insert(tagdata); else error->one(FLERR,"Duplicate atom ID in Bodies section of data file"); - if (ninteger < 0) - error->one(FLERR,"Invalid number of integers in Bodies section of data file"); - if (ndouble < 0) - error->one(FLERR,"Invalid number of doubles in Bodies section of data file"); - buf = next + 1; m = map(tagdata); if (m >= 0) { diff --git a/src/read_data.cpp b/src/read_data.cpp index 67eadc313c..d789d205f8 100644 --- a/src/read_data.cpp +++ b/src/read_data.cpp @@ -35,6 +35,7 @@ #include "molecule.h" #include "pair.h" #include "special.h" +#include "tokenizer.h" #include "update.h" #include @@ -1658,12 +1659,12 @@ void ReadData::bonus(bigint nbonus, AtomVec *ptr, const char *type) read all body data variable amount of info per body, described by ninteger and ndouble to find atoms, must build atom map if not a molecular system - if not firstpass, just read past data, but no processing of data + if not firstpass, just read past body data and only process body header ------------------------------------------------------------------------- */ void ReadData::bodies(int firstpass, AtomVec *ptr) { - int m,nchunk,nline,nmax,ninteger,ndouble,nword,ncount,onebody,tmp,rv; + int m,nchunk,nline,nmax,ninteger,ndouble,nword,ncount,onebody; char *eof; int mapflag = 0; @@ -1690,11 +1691,25 @@ void ReadData::bodies(int firstpass, AtomVec *ptr) while (nchunk < nmax && nline <= CHUNK-MAXBODY) { eof = utils::fgets_trunc(&buffer[m],MAXLINE,fp); + const char *buf = &buffer[m]; if (eof == nullptr) error->one(FLERR,"Unexpected end of data file"); - rv = sscanf(&buffer[m],"%d %d %d",&tmp,&ninteger,&ndouble); - if (rv != 3) - error->one(FLERR,"Incorrect format in Bodies section of data file"); - m += strlen(&buffer[m]); + try { + auto values = ValueTokenizer(utils::trim_comment(buf)); + tagint tagdata = values.next_tagint() + id_offset; + ninteger = values.next_int(); + ndouble = values.next_double(); + if (tagdata <= 0 || tagdata > atom->map_tag_max) + throw TokenizerException("Invalid atom ID in body header", utils::trim(buf)); + if (ninteger < 0) + throw TokenizerException("Invalid number of integers", utils::trim(buf)); + if (ndouble < 0) + throw TokenizerException("Invalid number of doubles", utils::trim(buf)); + if (values.has_next()) + throw TokenizerException("Too many tokens in body header", utils::trim(buf)); + } catch (TokenizerException &e) { + error->one(FLERR,std::string(e.what()) + " while reading Bodies section of data file"); + } + m += strlen(buf); // read lines one at a time into buffer and count words // count to ninteger and ndouble until have enough lines From 9efa2369dd0675deaf3725381aff8f05f3eaca2c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 31 Dec 2021 14:34:24 -0500 Subject: [PATCH 098/193] join wrapped strings --- src/read_data.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/read_data.cpp b/src/read_data.cpp index d789d205f8..89b3ecadec 100644 --- a/src/read_data.cpp +++ b/src/read_data.cpp @@ -1089,37 +1089,32 @@ void ReadData::header(int firstpass) } else if (utils::strmatch(line,"^\\s*\\d+\\s+atom\\s+types\\s")) { rv = sscanf(line,"%d",&ntypes); if (rv != 1) - error->all(FLERR,"Could not parse 'atom types' line " - "in data file header"); + error->all(FLERR,"Could not parse 'atom types' line in data file header"); if (addflag == NONE) atom->ntypes = ntypes + extra_atom_types; } else if (utils::strmatch(line,"\\s*\\d+\\s+bond\\s+types\\s")) { rv = sscanf(line,"%d",&nbondtypes); if (rv != 1) - error->all(FLERR,"Could not parse 'bond types' line " - "in data file header"); + error->all(FLERR,"Could not parse 'bond types' line in data file header"); if (addflag == NONE) atom->nbondtypes = nbondtypes + extra_bond_types; } else if (utils::strmatch(line,"^\\s*\\d+\\s+angle\\s+types\\s")) { rv = sscanf(line,"%d",&nangletypes); if (rv != 1) - error->all(FLERR,"Could not parse 'angle types' line " - "in data file header"); + error->all(FLERR,"Could not parse 'angle types' line in data file header"); if (addflag == NONE) atom->nangletypes = nangletypes + extra_angle_types; } else if (utils::strmatch(line,"^\\s*\\d+\\s+dihedral\\s+types\\s")) { rv = sscanf(line,"%d",&ndihedraltypes); if (rv != 1) - error->all(FLERR,"Could not parse 'dihedral types' line " - "in data file header"); + error->all(FLERR,"Could not parse 'dihedral types' line in data file header"); if (addflag == NONE) atom->ndihedraltypes = ndihedraltypes + extra_dihedral_types; } else if (utils::strmatch(line,"^\\s*\\d+\\s+improper\\s+types\\s")) { rv = sscanf(line,"%d",&nimpropertypes); if (rv != 1) - error->all(FLERR,"Could not parse 'improper types' line " - "in data file header"); + error->all(FLERR,"Could not parse 'improper types' line in data file header"); if (addflag == NONE) atom->nimpropertypes = nimpropertypes + extra_improper_types; From e5c517c8d8098fd857dda15d6f1f5bff00646998 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 31 Dec 2021 23:46:33 -0500 Subject: [PATCH 099/193] silence compiler warnings --- src/EXTRA-MOLECULE/bond_fene_nm.cpp | 2 +- src/MOLFILE/molfile_interface.cpp | 76 ++++++++++++++--------------- src/output.cpp | 2 - 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/src/EXTRA-MOLECULE/bond_fene_nm.cpp b/src/EXTRA-MOLECULE/bond_fene_nm.cpp index f9280f4a82..147a63512a 100644 --- a/src/EXTRA-MOLECULE/bond_fene_nm.cpp +++ b/src/EXTRA-MOLECULE/bond_fene_nm.cpp @@ -47,7 +47,7 @@ void BondFENENM::compute(int eflag, int vflag) { int i1, i2, n, type; double delx, dely, delz, ebond, fbond; - double rsq, r0sq, rlogarg, sr2, sr6; + double rsq, r0sq, rlogarg, sr6; double r; ebond = sr6 = 0.0; diff --git a/src/MOLFILE/molfile_interface.cpp b/src/MOLFILE/molfile_interface.cpp index 9ce3822082..5fd398570e 100644 --- a/src/MOLFILE/molfile_interface.cpp +++ b/src/MOLFILE/molfile_interface.cpp @@ -75,25 +75,25 @@ extern "C" { /* corresponding table of masses. */ static const float pte_mass[] = { - /* X */ 0.00000, 1.00794, 4.00260, 6.941, 9.012182, 10.811, - /* C */ 12.0107, 14.0067, 15.9994, 18.9984032, 20.1797, - /* Na */ 22.989770, 24.3050, 26.981538, 28.0855, 30.973761, - /* S */ 32.065, 35.453, 39.948, 39.0983, 40.078, 44.955910, - /* Ti */ 47.867, 50.9415, 51.9961, 54.938049, 55.845, 58.9332, - /* Ni */ 58.6934, 63.546, 65.409, 69.723, 72.64, 74.92160, - /* Se */ 78.96, 79.904, 83.798, 85.4678, 87.62, 88.90585, - /* Zr */ 91.224, 92.90638, 95.94, 98.0, 101.07, 102.90550, - /* Pd */ 106.42, 107.8682, 112.411, 114.818, 118.710, 121.760, - /* Te */ 127.60, 126.90447, 131.293, 132.90545, 137.327, - /* La */ 138.9055, 140.116, 140.90765, 144.24, 145.0, 150.36, - /* Eu */ 151.964, 157.25, 158.92534, 162.500, 164.93032, - /* Er */ 167.259, 168.93421, 173.04, 174.967, 178.49, 180.9479, - /* W */ 183.84, 186.207, 190.23, 192.217, 195.078, 196.96655, - /* Hg */ 200.59, 204.3833, 207.2, 208.98038, 209.0, 210.0, 222.0, - /* Fr */ 223.0, 226.0, 227.0, 232.0381, 231.03588, 238.02891, - /* Np */ 237.0, 244.0, 243.0, 247.0, 247.0, 251.0, 252.0, 257.0, - /* Md */ 258.0, 259.0, 262.0, 261.0, 262.0, 266.0, 264.0, 269.0, - /* Mt */ 268.0, 271.0, 272.0 + /* X */ 0.00000f, 1.00794f, 4.00260f, 6.941f, 9.012182f, 10.811f, + /* C */ 12.0107f, 14.0067f, 15.9994f, 18.9984032f, 20.1797f, + /* Na */ 22.989770f, 24.3050f, 26.981538f, 28.0855f, 30.973761f, + /* S */ 32.065f, 35.453f, 39.948f, 39.0983f, 40.078f, 44.955910f, + /* Ti */ 47.867f, 50.9415f, 51.9961f, 54.938049f, 55.845f, 58.9332f, + /* Ni */ 58.6934f, 63.546f, 65.409f, 69.723f, 72.64f, 74.92160f, + /* Se */ 78.96f, 79.904f, 83.798f, 85.4678f, 87.62f, 88.90585f, + /* Zr */ 91.224f, 92.90638f, 95.94f, 98.0f, 101.07f, 102.90550f, + /* Pd */ 106.42f, 107.8682f, 112.411f, 114.818f, 118.710f, 121.760f, + /* Te */ 127.60f, 126.90447f, 131.293f, 132.90545f, 137.327f, + /* La */ 138.9055f, 140.116f, 140.90765f, 144.24f, 145.0f, 150.36f, + /* Eu */ 151.964f, 157.25f, 158.92534f, 162.500f, 164.93032f, + /* Er */ 167.259f, 168.93421f, 173.04f, 174.967f, 178.49f, 180.9479f, + /* W */ 183.84f, 186.207f, 190.23f, 192.217f, 195.078f, 196.96655f, + /* Hg */ 200.59f, 204.3833f, 207.2f, 208.98038f, 209.0f, 210.0f, 222.0f, + /* Fr */ 223.0f, 226.0f, 227.0f, 232.0381f, 231.03588f, 238.02891f, + /* Np */ 237.0f, 244.0f, 243.0f, 247.0f, 247.0f, 251.0f, 252.0f, 257.0f, + /* Md */ 258.0f, 259.0f, 262.0f, 261.0f, 262.0f, 266.0f, 264.0f, 269.0f, + /* Mt */ 268.0f, 271.0f, 272.0f }; /* @@ -107,25 +107,25 @@ extern "C" { * Rmin/2 parameters for (SOD, POT, CLA, CAL, MG, CES) by default. */ static const float pte_vdw_radius[] = { - /* X */ 1.5, 1.2, 1.4, 1.82, 2.0, 2.0, - /* C */ 1.7, 1.55, 1.52, 1.47, 1.54, - /* Na */ 1.36, 1.18, 2.0, 2.1, 1.8, - /* S */ 1.8, 2.27, 1.88, 1.76, 1.37, 2.0, - /* Ti */ 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, - /* Ni */ 1.63, 1.4, 1.39, 1.07, 2.0, 1.85, - /* Se */ 1.9, 1.85, 2.02, 2.0, 2.0, 2.0, - /* Zr */ 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, - /* Pd */ 1.63, 1.72, 1.58, 1.93, 2.17, 2.0, - /* Te */ 2.06, 1.98, 2.16, 2.1, 2.0, - /* La */ 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, - /* Eu */ 2.0, 2.0, 2.0, 2.0, 2.0, - /* Er */ 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, - /* W */ 2.0, 2.0, 2.0, 2.0, 1.72, 1.66, - /* Hg */ 1.55, 1.96, 2.02, 2.0, 2.0, 2.0, 2.0, - /* Fr */ 2.0, 2.0, 2.0, 2.0, 2.0, 1.86, - /* Np */ 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, - /* Md */ 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, - /* Mt */ 2.0, 2.0, 2.0 + /* X */ 1.5f, 1.2f, 1.4f, 1.82f, 2.0f, 2.0f, + /* C */ 1.7f, 1.55f, 1.52f, 1.47f, 1.54f, + /* Na */ 1.36f, 1.18f, 2.0f, 2.1f, 1.8f, + /* S */ 1.8f, 2.27f, 1.88f, 1.76f, 1.37f, 2.0f, + /* Ti */ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, + /* Ni */ 1.63f, 1.4f, 1.39f, 1.07f, 2.0f, 1.85f, + /* Se */ 1.9f, 1.85f, 2.02f, 2.0f, 2.0f, 2.0f, + /* Zr */ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, + /* Pd */ 1.63f, 1.72f, 1.58f, 1.93f, 2.17f, 2.0f, + /* Te */ 2.06f, 1.98f, 2.16f, 2.1f, 2.0f, + /* La */ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, + /* Eu */ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, + /* Er */ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, + /* W */ 2.0f, 2.0f, 2.0f, 2.0f, 1.72f, 1.66f, + /* Hg */ 1.55f, 1.96f, 2.02f, 2.0f, 2.0f, 2.0f, 2.0f, + /* Fr */ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.86f, + /* Np */ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, + /* Md */ 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, + /* Mt */ 2.0f, 2.0f, 2.0f }; /* lookup functions */ diff --git a/src/output.cpp b/src/output.cpp index 4cea582283..a8fda4173d 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -344,8 +344,6 @@ void Output::setup(int memflag) // can't remove an uneeded addstep from a compute, b/c don't know // what other command may have added it - int writeflag; - if (next_dump_any == ntimestep) { for (int idump = 0; idump < ndump; idump++) { From f3c5593c50b7fea04cb75ab10895d4f3ecaf9ccc Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 1 Jan 2022 16:40:54 -0500 Subject: [PATCH 100/193] correct code example --- doc/src/Developer_write.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/Developer_write.rst b/doc/src/Developer_write.rst index bdb51540c7..bdc6559060 100644 --- a/doc/src/Developer_write.rst +++ b/doc/src/Developer_write.rst @@ -55,7 +55,7 @@ of each timestep. First of all, implement a constructor: if (narg < 4) error->all(FLERR,"Illegal fix print/vel command"); - nevery = utils::inumeric(FLERR,arg[3]); + nevery = utils::inumeric(FLERR,arg[3],false,lmp); if (nevery <= 0) error->all(FLERR,"Illegal fix print/vel command"); } From bb1c12d22b71710e15aca3d0c45bbc8f88d607a0 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 2 Jan 2022 13:31:55 -0500 Subject: [PATCH 101/193] import fmtlib v8.1.0 --- src/fmt/args.h | 2 + src/fmt/chrono.h | 1173 +++++++++++++++++++++++++++++++++-------- src/fmt/color.h | 35 +- src/fmt/compile.h | 25 +- src/fmt/core.h | 745 +++++++++++++++++--------- src/fmt/format-inl.h | 587 +++++++++++---------- src/fmt/format.h | 882 ++++++++++++++++++++----------- src/fmt/os.h | 48 +- src/fmt/ostream.h | 108 ++-- src/fmt/printf.h | 19 +- src/fmt/ranges.h | 547 +++++++++++++++---- src/fmt/xchar.h | 10 +- src/fmtlib_format.cpp | 46 ++ src/fmtlib_os.cpp | 17 +- 14 files changed, 2938 insertions(+), 1306 deletions(-) diff --git a/src/fmt/args.h b/src/fmt/args.h index 562e8ab111..9a8e4ed2ce 100644 --- a/src/fmt/args.h +++ b/src/fmt/args.h @@ -143,6 +143,8 @@ class dynamic_format_arg_store } public: + constexpr dynamic_format_arg_store() = default; + /** \rst Adds an argument into the dynamic store for later passing to a formatting diff --git a/src/fmt/chrono.h b/src/fmt/chrono.h index c024fd710c..31fee070af 100644 --- a/src/fmt/chrono.h +++ b/src/fmt/chrono.h @@ -11,13 +11,29 @@ #include #include #include +#include #include -#include +#include +#include #include "format.h" FMT_BEGIN_NAMESPACE +// Enable tzset. +#ifndef FMT_USE_TZSET +// UWP doesn't provide _tzset. +# if FMT_HAS_INCLUDE("winapifamily.h") +# include +# endif +# if defined(_WIN32) && (!defined(WINAPI_FAMILY) || \ + (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) +# define FMT_USE_TZSET 1 +# else +# define FMT_USE_TZSET 0 +# endif +#endif + // Enable safe chrono durations, unless explicitly disabled. #ifndef FMT_SAFE_DURATION_CAST # define FMT_SAFE_DURATION_CAST 1 @@ -44,7 +60,7 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { static_assert(T::is_integer, "To must be integral"); // A and B are both signed, or both unsigned. - if (F::digits <= T::digits) { + if (detail::const_check(F::digits <= T::digits)) { // From fits in To without any problem. } else { // From does not always fit in To, resort to a dynamic check. @@ -79,14 +95,15 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { return {}; } // From is positive. Can it always fit in To? - if (F::digits > T::digits && + if (detail::const_check(F::digits > T::digits) && from > static_cast(detail::max_value())) { ec = 1; return {}; } } - if (!F::is_signed && T::is_signed && F::digits >= T::digits && + if (detail::const_check(!F::is_signed && T::is_signed && + F::digits >= T::digits) && from > static_cast(detail::max_value())) { ec = 1; return {}; @@ -243,7 +260,7 @@ To safe_duration_cast(std::chrono::duration from, } // multiply with Factor::num without overflow or underflow - if (Factor::num != 1) { + if (detail::const_check(Factor::num != 1)) { constexpr auto max1 = detail::max_value() / static_cast(Factor::num); if (count > max1) { @@ -260,7 +277,7 @@ To safe_duration_cast(std::chrono::duration from, } // this can't go wrong, right? den>0 is checked earlier. - if (Factor::den != 1) { + if (detail::const_check(Factor::den != 1)) { using common_t = typename std::common_type::type; count /= static_cast(Factor::den); } @@ -288,74 +305,139 @@ inline null<> localtime_s(...) { return null<>(); } inline null<> gmtime_r(...) { return null<>(); } inline null<> gmtime_s(...) { return null<>(); } -inline auto do_write(const std::tm& time, const std::locale& loc, char format, - char modifier) -> std::string { - auto&& os = std::ostringstream(); - os.imbue(loc); - using iterator = std::ostreambuf_iterator; - const auto& facet = std::use_facet>(loc); - auto end = facet.put(os, os, ' ', &time, format, modifier); - if (end.failed()) FMT_THROW(format_error("failed to format time")); - auto str = os.str(); - if (!detail::is_utf8() || loc == std::locale::classic()) return str; +inline const std::locale& get_classic_locale() { + static const auto& locale = std::locale::classic(); + return locale; +} + +template struct codecvt_result { + static constexpr const size_t max_size = 32; + CodeUnit buf[max_size]; + CodeUnit* end; +}; +template +constexpr const size_t codecvt_result::max_size; + +template +void write_codecvt(codecvt_result& out, string_view in_buf, + const std::locale& loc) { + using codecvt = std::codecvt; +#if FMT_CLANG_VERSION +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated" + auto& f = std::use_facet(loc); +# pragma clang diagnostic pop +#else + auto& f = std::use_facet(loc); +#endif + auto mb = std::mbstate_t(); + const char* from_next = nullptr; + auto result = f.in(mb, in_buf.begin(), in_buf.end(), from_next, + std::begin(out.buf), std::end(out.buf), out.end); + if (result != std::codecvt_base::ok) + FMT_THROW(format_error("failed to format time")); +} + +template +auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc) + -> OutputIt { + if (detail::is_utf8() && loc != get_classic_locale()) { // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and // gcc-4. #if FMT_MSC_VER != 0 || \ (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI)) - // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5 - // and newer. - using code_unit = wchar_t; + // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5 + // and newer. + using code_unit = wchar_t; #else - using code_unit = char32_t; + using code_unit = char32_t; #endif - auto& f = std::use_facet>(loc); - auto mb = std::mbstate_t(); - const char* from_next = nullptr; - code_unit* to_next = nullptr; - constexpr size_t buf_size = 32; - code_unit buf[buf_size] = {}; - auto result = f.in(mb, str.data(), str.data() + str.size(), from_next, buf, - buf + buf_size, to_next); - if (result != std::codecvt_base::ok) - FMT_THROW(format_error("failed to format time")); - str.clear(); - for (code_unit* p = buf; p != to_next; ++p) { - uint32_t c = static_cast(*p); - if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) { - // surrogate pair - ++p; - if (p == to_next || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) { + + using unit_t = codecvt_result; + unit_t unit; + write_codecvt(unit, in, loc); + // In UTF-8 is used one to four one-byte code units. + auto&& buf = basic_memory_buffer(); + for (code_unit* p = unit.buf; p != unit.end; ++p) { + uint32_t c = static_cast(*p); + if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) { + // surrogate pair + ++p; + if (p == unit.end || (c & 0xfc00) != 0xd800 || + (*p & 0xfc00) != 0xdc00) { + FMT_THROW(format_error("failed to format time")); + } + c = (c << 10) + static_cast(*p) - 0x35fdc00; + } + if (c < 0x80) { + buf.push_back(static_cast(c)); + } else if (c < 0x800) { + buf.push_back(static_cast(0xc0 | (c >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) { + buf.push_back(static_cast(0xe0 | (c >> 12))); + buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else if (c >= 0x10000 && c <= 0x10ffff) { + buf.push_back(static_cast(0xf0 | (c >> 18))); + buf.push_back(static_cast(0x80 | ((c & 0x3ffff) >> 12))); + buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else { FMT_THROW(format_error("failed to format time")); } - c = (c << 10) + static_cast(*p) - 0x35fdc00; - } - if (c < 0x80) { - str.push_back(static_cast(c)); - } else if (c < 0x800) { - str.push_back(static_cast(0xc0 | (c >> 6))); - str.push_back(static_cast(0x80 | (c & 0x3f))); - } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) { - str.push_back(static_cast(0xe0 | (c >> 12))); - str.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); - str.push_back(static_cast(0x80 | (c & 0x3f))); - } else if (c >= 0x10000 && c <= 0x10ffff) { - str.push_back(static_cast(0xf0 | (c >> 18))); - str.push_back(static_cast(0x80 | ((c & 0x3ffff) >> 12))); - str.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); - str.push_back(static_cast(0x80 | (c & 0x3f))); - } else { - FMT_THROW(format_error("failed to format time")); } + return copy_str(buf.data(), buf.data() + buf.size(), out); } - return str; + return copy_str(in.data(), in.data() + in.size(), out); } -template +template ::value)> +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { + codecvt_result unit; + write_codecvt(unit, sv, loc); + return copy_str(unit.buf, unit.end, out); +} + +template ::value)> +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { + return write_encoded_tm_str(out, sv, loc); +} + +template +inline void do_write(buffer& buf, const std::tm& time, + const std::locale& loc, char format, char modifier) { + auto&& format_buf = formatbuf>(buf); + auto&& os = std::basic_ostream(&format_buf); + os.imbue(loc); + using iterator = std::ostreambuf_iterator; + const auto& facet = std::use_facet>(loc); + auto end = facet.put(os, os, Char(' '), &time, format, modifier); + if (end.failed()) FMT_THROW(format_error("failed to format time")); +} + +template ::value)> auto write(OutputIt out, const std::tm& time, const std::locale& loc, char format, char modifier = 0) -> OutputIt { - auto str = do_write(time, loc, format, modifier); - return std::copy(str.begin(), str.end(), out); + auto&& buf = get_buffer(out); + do_write(buf, time, loc, format, modifier); + return buf.out(); } + +template ::value)> +auto write(OutputIt out, const std::tm& time, const std::locale& loc, + char format, char modifier = 0) -> OutputIt { + auto&& buf = basic_memory_buffer(); + do_write(buf, time, loc, format, modifier); + return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc); +} + } // namespace detail FMT_MODULE_EXPORT_BEGIN @@ -453,103 +535,32 @@ inline std::tm gmtime( FMT_BEGIN_DETAIL_NAMESPACE -inline size_t strftime(char* str, size_t count, const char* format, - const std::tm* time) { - // Assign to a pointer to suppress GCCs -Wformat-nonliteral - // First assign the nullptr to suppress -Wsuggest-attribute=format - std::size_t (*strftime)(char*, std::size_t, const char*, const std::tm*) = - nullptr; - strftime = std::strftime; - return strftime(str, count, format, time); +// Writes two-digit numbers a, b and c separated by sep to buf. +// The method by Pavel Novikov based on +// https://johnnylee-sde.github.io/Fast-unsigned-integer-to-time-string/. +inline void write_digit2_separated(char* buf, unsigned a, unsigned b, + unsigned c, char sep) { + unsigned long long digits = + a | (b << 24) | (static_cast(c) << 48); + // Convert each value to BCD. + // We have x = a * 10 + b and we want to convert it to BCD y = a * 16 + b. + // The difference is + // y - x = a * 6 + // a can be found from x: + // a = floor(x / 10) + // then + // y = x + a * 6 = x + floor(x / 10) * 6 + // floor(x / 10) is (x * 205) >> 11 (needs 16 bits). + digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6; + // Put low nibbles to high bytes and high nibbles to low bytes. + digits = ((digits & 0x00f00000f00000f0) >> 4) | + ((digits & 0x000f00000f00000f) << 8); + auto usep = static_cast(sep); + // Add ASCII '0' to each digit byte and insert separators. + digits |= 0x3030003030003030 | (usep << 16) | (usep << 40); + memcpy(buf, &digits, 8); } -inline size_t strftime(wchar_t* str, size_t count, const wchar_t* format, - const std::tm* time) { - // See above - std::size_t (*wcsftime)(wchar_t*, std::size_t, const wchar_t*, - const std::tm*) = nullptr; - wcsftime = std::wcsftime; - return wcsftime(str, count, format, time); -} - -FMT_END_DETAIL_NAMESPACE - -template -struct formatter, - Char> : formatter { - FMT_CONSTEXPR formatter() { - this->specs = {default_specs, sizeof(default_specs) / sizeof(Char)}; - } - - template - FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - auto it = ctx.begin(); - if (it != ctx.end() && *it == ':') ++it; - auto end = it; - while (end != ctx.end() && *end != '}') ++end; - if (end != it) this->specs = {it, detail::to_unsigned(end - it)}; - return end; - } - - template - auto format(std::chrono::time_point val, - FormatContext& ctx) -> decltype(ctx.out()) { - std::tm time = localtime(val); - return formatter::format(time, ctx); - } - - static constexpr Char default_specs[] = {'%', 'Y', '-', '%', 'm', '-', - '%', 'd', ' ', '%', 'H', ':', - '%', 'M', ':', '%', 'S'}; -}; - -template -constexpr Char - formatter, - Char>::default_specs[]; - -template struct formatter { - template - FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - auto it = ctx.begin(); - if (it != ctx.end() && *it == ':') ++it; - auto end = it; - while (end != ctx.end() && *end != '}') ++end; - specs = {it, detail::to_unsigned(end - it)}; - return end; - } - - template - auto format(const std::tm& tm, FormatContext& ctx) const - -> decltype(ctx.out()) { - basic_memory_buffer tm_format; - tm_format.append(specs.begin(), specs.end()); - // By appending an extra space we can distinguish an empty result that - // indicates insufficient buffer size from a guaranteed non-empty result - // https://github.com/fmtlib/fmt/issues/2238 - tm_format.push_back(' '); - tm_format.push_back('\0'); - basic_memory_buffer buf; - size_t start = buf.size(); - for (;;) { - size_t size = buf.capacity() - start; - size_t count = detail::strftime(&buf[start], size, &tm_format[0], &tm); - if (count != 0) { - buf.resize(start + count); - break; - } - const size_t MIN_GROWTH = 10; - buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); - } - // Remove the extra space. - return std::copy(buf.begin(), buf.end() - 1, ctx.out()); - } - - basic_string_view specs; -}; - -FMT_BEGIN_DETAIL_NAMESPACE - template FMT_CONSTEXPR inline const char* get_units() { if (std::is_same::value) return "as"; if (std::is_same::value) return "fs"; @@ -610,6 +621,22 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, handler.on_text(tab, tab + 1); break; } + // Year: + case 'Y': + handler.on_year(numeric_system::standard); + break; + case 'y': + handler.on_short_year(numeric_system::standard); + break; + case 'C': + handler.on_century(numeric_system::standard); + break; + case 'G': + handler.on_iso_week_based_year(); + break; + case 'g': + handler.on_iso_week_based_short_year(); + break; // Day of the week: case 'a': handler.on_abbr_weekday(); @@ -625,11 +652,34 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, break; // Month: case 'b': + case 'h': handler.on_abbr_month(); break; case 'B': handler.on_full_month(); break; + case 'm': + handler.on_dec_month(numeric_system::standard); + break; + // Day of the year/month: + case 'U': + handler.on_dec0_week_of_year(numeric_system::standard); + break; + case 'W': + handler.on_dec1_week_of_year(numeric_system::standard); + break; + case 'V': + handler.on_iso_week_of_year(numeric_system::standard); + break; + case 'j': + handler.on_day_of_year(); + break; + case 'd': + handler.on_day_of_month(numeric_system::standard); + break; + case 'e': + handler.on_day_of_month_space(numeric_system::standard); + break; // Hour, minute, second: case 'H': handler.on_24_hour(numeric_system::standard); @@ -688,6 +738,15 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, if (ptr == end) FMT_THROW(format_error("invalid format")); c = *ptr++; switch (c) { + case 'Y': + handler.on_year(numeric_system::alternative); + break; + case 'y': + handler.on_offset_year(); + break; + case 'C': + handler.on_century(numeric_system::alternative); + break; case 'c': handler.on_datetime(numeric_system::alternative); break; @@ -706,6 +765,27 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, if (ptr == end) FMT_THROW(format_error("invalid format")); c = *ptr++; switch (c) { + case 'y': + handler.on_short_year(numeric_system::alternative); + break; + case 'm': + handler.on_dec_month(numeric_system::alternative); + break; + case 'U': + handler.on_dec0_week_of_year(numeric_system::alternative); + break; + case 'W': + handler.on_dec1_week_of_year(numeric_system::alternative); + break; + case 'V': + handler.on_iso_week_of_year(numeric_system::alternative); + break; + case 'd': + handler.on_day_of_month(numeric_system::alternative); + break; + case 'e': + handler.on_day_of_month_space(numeric_system::alternative); + break; case 'w': handler.on_dec0_weekday(numeric_system::alternative); break; @@ -741,12 +821,25 @@ template struct null_chrono_spec_handler { FMT_CONSTEXPR void unsupported() { static_cast(this)->unsupported(); } + FMT_CONSTEXPR void on_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_short_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_offset_year() { unsupported(); } + FMT_CONSTEXPR void on_century(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_iso_week_based_year() { unsupported(); } + FMT_CONSTEXPR void on_iso_week_based_short_year() { unsupported(); } FMT_CONSTEXPR void on_abbr_weekday() { unsupported(); } FMT_CONSTEXPR void on_full_weekday() { unsupported(); } FMT_CONSTEXPR void on_dec0_weekday(numeric_system) { unsupported(); } FMT_CONSTEXPR void on_dec1_weekday(numeric_system) { unsupported(); } FMT_CONSTEXPR void on_abbr_month() { unsupported(); } FMT_CONSTEXPR void on_full_month() { unsupported(); } + FMT_CONSTEXPR void on_dec_month(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_day_of_year() { unsupported(); } + FMT_CONSTEXPR void on_day_of_month(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_day_of_month_space(numeric_system) { unsupported(); } FMT_CONSTEXPR void on_24_hour(numeric_system) { unsupported(); } FMT_CONSTEXPR void on_12_hour(numeric_system) { unsupported(); } FMT_CONSTEXPR void on_minute(numeric_system) { unsupported(); } @@ -766,6 +859,509 @@ template struct null_chrono_spec_handler { FMT_CONSTEXPR void on_tz_name() { unsupported(); } }; +struct tm_format_checker : null_chrono_spec_handler { + FMT_NORETURN void unsupported() { FMT_THROW(format_error("no format")); } + + template + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + FMT_CONSTEXPR void on_year(numeric_system) {} + FMT_CONSTEXPR void on_short_year(numeric_system) {} + FMT_CONSTEXPR void on_offset_year() {} + FMT_CONSTEXPR void on_century(numeric_system) {} + FMT_CONSTEXPR void on_iso_week_based_year() {} + FMT_CONSTEXPR void on_iso_week_based_short_year() {} + FMT_CONSTEXPR void on_abbr_weekday() {} + FMT_CONSTEXPR void on_full_weekday() {} + FMT_CONSTEXPR void on_dec0_weekday(numeric_system) {} + FMT_CONSTEXPR void on_dec1_weekday(numeric_system) {} + FMT_CONSTEXPR void on_abbr_month() {} + FMT_CONSTEXPR void on_full_month() {} + FMT_CONSTEXPR void on_dec_month(numeric_system) {} + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system) {} + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system) {} + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system) {} + FMT_CONSTEXPR void on_day_of_year() {} + FMT_CONSTEXPR void on_day_of_month(numeric_system) {} + FMT_CONSTEXPR void on_day_of_month_space(numeric_system) {} + FMT_CONSTEXPR void on_24_hour(numeric_system) {} + FMT_CONSTEXPR void on_12_hour(numeric_system) {} + FMT_CONSTEXPR void on_minute(numeric_system) {} + FMT_CONSTEXPR void on_second(numeric_system) {} + FMT_CONSTEXPR void on_datetime(numeric_system) {} + FMT_CONSTEXPR void on_loc_date(numeric_system) {} + FMT_CONSTEXPR void on_loc_time(numeric_system) {} + FMT_CONSTEXPR void on_us_date() {} + FMT_CONSTEXPR void on_iso_date() {} + FMT_CONSTEXPR void on_12_hour_time() {} + FMT_CONSTEXPR void on_24_hour_time() {} + FMT_CONSTEXPR void on_iso_time() {} + FMT_CONSTEXPR void on_am_pm() {} + FMT_CONSTEXPR void on_utc_offset() {} + FMT_CONSTEXPR void on_tz_name() {} +}; + +inline const char* tm_wday_full_name(int wday) { + static constexpr const char* full_name_list[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday"}; + return wday >= 0 && wday <= 6 ? full_name_list[wday] : "?"; +} +inline const char* tm_wday_short_name(int wday) { + static constexpr const char* short_name_list[] = {"Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat"}; + return wday >= 0 && wday <= 6 ? short_name_list[wday] : "???"; +} + +inline const char* tm_mon_full_name(int mon) { + static constexpr const char* full_name_list[] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"}; + return mon >= 0 && mon <= 11 ? full_name_list[mon] : "?"; +} +inline const char* tm_mon_short_name(int mon) { + static constexpr const char* short_name_list[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + }; + return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???"; +} + +template +struct has_member_data_tm_gmtoff : std::false_type {}; +template +struct has_member_data_tm_gmtoff> + : std::true_type {}; + +template +struct has_member_data_tm_zone : std::false_type {}; +template +struct has_member_data_tm_zone> + : std::true_type {}; + +#if FMT_USE_TZSET +inline void tzset_once() { + static bool init = []() -> bool { + _tzset(); + return true; + }(); + ignore_unused(init); +} +#endif + +template class tm_writer { + private: + static constexpr int days_per_week = 7; + + const std::locale& loc_; + const bool is_classic_; + OutputIt out_; + const std::tm& tm_; + + auto tm_sec() const noexcept -> int { + FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61, ""); + return tm_.tm_sec; + } + auto tm_min() const noexcept -> int { + FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59, ""); + return tm_.tm_min; + } + auto tm_hour() const noexcept -> int { + FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23, ""); + return tm_.tm_hour; + } + auto tm_mday() const noexcept -> int { + FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31, ""); + return tm_.tm_mday; + } + auto tm_mon() const noexcept -> int { + FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11, ""); + return tm_.tm_mon; + } + auto tm_year() const noexcept -> long long { return 1900ll + tm_.tm_year; } + auto tm_wday() const noexcept -> int { + FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6, ""); + return tm_.tm_wday; + } + auto tm_yday() const noexcept -> int { + FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365, ""); + return tm_.tm_yday; + } + + auto tm_hour12() const noexcept -> int { + const auto h = tm_hour(); + const auto z = h < 12 ? h : h - 12; + return z == 0 ? 12 : z; + } + + // POSIX and the C Standard are unclear or inconsistent about what %C and %y + // do if the year is negative or exceeds 9999. Use the convention that %C + // concatenated with %y yields the same output as %Y, and that %Y contains at + // least 4 characters, with more only if necessary. + auto split_year_lower(long long year) const noexcept -> int { + auto l = year % 100; + if (l < 0) l = -l; // l in [0, 99] + return static_cast(l); + } + + // Algorithm: + // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_from_a_month_and_day_of_the_month_or_ordinal_date + auto iso_year_weeks(long long curr_year) const noexcept -> int { + const auto prev_year = curr_year - 1; + const auto curr_p = + (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) % + days_per_week; + const auto prev_p = + (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) % + days_per_week; + return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0); + } + auto iso_week_num(int tm_yday, int tm_wday) const noexcept -> int { + return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) / + days_per_week; + } + auto tm_iso_week_year() const noexcept -> long long { + const auto year = tm_year(); + const auto w = iso_week_num(tm_yday(), tm_wday()); + if (w < 1) return year - 1; + if (w > iso_year_weeks(year)) return year + 1; + return year; + } + auto tm_iso_week_of_year() const noexcept -> int { + const auto year = tm_year(); + const auto w = iso_week_num(tm_yday(), tm_wday()); + if (w < 1) return iso_year_weeks(year - 1); + if (w > iso_year_weeks(year)) return 1; + return w; + } + + void write1(int value) { + *out_++ = static_cast('0' + to_unsigned(value) % 10); + } + void write2(int value) { + const char* d = digits2(to_unsigned(value) % 100); + *out_++ = *d++; + *out_++ = *d; + } + + void write_year_extended(long long year) { + // At least 4 characters. + int width = 4; + if (year < 0) { + *out_++ = '-'; + year = 0 - year; + --width; + } + uint32_or_64_or_128_t n = to_unsigned(year); + const int num_digits = count_digits(n); + if (width > num_digits) out_ = std::fill_n(out_, width - num_digits, '0'); + out_ = format_decimal(out_, n, num_digits).end; + } + void write_year(long long year) { + if (year >= 0 && year < 10000) { + write2(static_cast(year / 100)); + write2(static_cast(year % 100)); + } else { + write_year_extended(year); + } + } + + void write_utc_offset(long offset) { + if (offset < 0) { + *out_++ = '-'; + offset = -offset; + } else { + *out_++ = '+'; + } + offset /= 60; + write2(static_cast(offset / 60)); + write2(static_cast(offset % 60)); + } + template ::value)> + void format_utc_offset_impl(const T& tm) { + write_utc_offset(tm.tm_gmtoff); + } + template ::value)> + void format_utc_offset_impl(const T& tm) { +#if defined(_WIN32) +# if FMT_USE_TZSET + tzset_once(); +# endif + long offset = 0; + _get_timezone(&offset); + if (tm.tm_isdst) { + long dstbias = 0; + _get_dstbias(&dstbias); + offset += dstbias; + } + write_utc_offset(-offset); +#else + ignore_unused(tm); + format_localized('z'); +#endif + } + + template ::value)> + void format_tz_name_impl(const T& tm) { + if (is_classic_) + out_ = write_tm_str(out_, tm.tm_zone, loc_); + else + format_localized('Z'); + } + template ::value)> + void format_tz_name_impl(const T&) { + format_localized('Z'); + } + + void format_localized(char format, char modifier = 0) { + out_ = write(out_, tm_, loc_, format, modifier); + } + + public: + tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm) + : loc_(loc), + is_classic_(loc_ == get_classic_locale()), + out_(out), + tm_(tm) {} + + OutputIt out() const { return out_; } + + FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { + out_ = copy_str(begin, end, out_); + } + + void on_abbr_weekday() { + if (is_classic_) + out_ = write(out_, tm_wday_short_name(tm_wday())); + else + format_localized('a'); + } + void on_full_weekday() { + if (is_classic_) + out_ = write(out_, tm_wday_full_name(tm_wday())); + else + format_localized('A'); + } + void on_dec0_weekday(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write1(tm_wday()); + format_localized('w', 'O'); + } + void on_dec1_weekday(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto wday = tm_wday(); + write1(wday == 0 ? days_per_week : wday); + } else { + format_localized('u', 'O'); + } + } + + void on_abbr_month() { + if (is_classic_) + out_ = write(out_, tm_mon_short_name(tm_mon())); + else + format_localized('b'); + } + void on_full_month() { + if (is_classic_) + out_ = write(out_, tm_mon_full_name(tm_mon())); + else + format_localized('B'); + } + + void on_datetime(numeric_system ns) { + if (is_classic_) { + on_abbr_weekday(); + *out_++ = ' '; + on_abbr_month(); + *out_++ = ' '; + on_day_of_month_space(numeric_system::standard); + *out_++ = ' '; + on_iso_time(); + *out_++ = ' '; + on_year(numeric_system::standard); + } else { + format_localized('c', ns == numeric_system::standard ? '\0' : 'E'); + } + } + void on_loc_date(numeric_system ns) { + if (is_classic_) + on_us_date(); + else + format_localized('x', ns == numeric_system::standard ? '\0' : 'E'); + } + void on_loc_time(numeric_system ns) { + if (is_classic_) + on_iso_time(); + else + format_localized('X', ns == numeric_system::standard ? '\0' : 'E'); + } + void on_us_date() { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_mon() + 1), + to_unsigned(tm_mday()), + to_unsigned(split_year_lower(tm_year())), '/'); + out_ = copy_str(std::begin(buf), std::end(buf), out_); + } + void on_iso_date() { + auto year = tm_year(); + char buf[10]; + size_t offset = 0; + if (year >= 0 && year < 10000) { + copy2(buf, digits2(to_unsigned(year / 100))); + } else { + offset = 4; + write_year_extended(year); + year = 0; + } + write_digit2_separated(buf + 2, static_cast(year % 100), + to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()), + '-'); + out_ = copy_str(std::begin(buf) + offset, std::end(buf), out_); + } + + void on_utc_offset() { format_utc_offset_impl(tm_); } + void on_tz_name() { format_tz_name_impl(tm_); } + + void on_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write_year(tm_year()); + format_localized('Y', 'E'); + } + void on_short_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(split_year_lower(tm_year())); + format_localized('y', 'O'); + } + void on_offset_year() { + if (is_classic_) return write2(split_year_lower(tm_year())); + format_localized('y', 'E'); + } + + void on_century(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto year = tm_year(); + auto upper = year / 100; + if (year >= -99 && year < 0) { + // Zero upper on negative year. + *out_++ = '-'; + *out_++ = '0'; + } else if (upper >= 0 && upper < 100) { + write2(static_cast(upper)); + } else { + out_ = write(out_, upper); + } + } else { + format_localized('C', 'E'); + } + } + + void on_dec_month(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_mon() + 1); + format_localized('m', 'O'); + } + + void on_dec0_week_of_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week); + format_localized('U', 'O'); + } + void on_dec1_week_of_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto wday = tm_wday(); + write2((tm_yday() + days_per_week - + (wday == 0 ? (days_per_week - 1) : (wday - 1))) / + days_per_week); + } else { + format_localized('W', 'O'); + } + } + void on_iso_week_of_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_iso_week_of_year()); + format_localized('V', 'O'); + } + + void on_iso_week_based_year() { write_year(tm_iso_week_year()); } + void on_iso_week_based_short_year() { + write2(split_year_lower(tm_iso_week_year())); + } + + void on_day_of_year() { + auto yday = tm_yday() + 1; + write1(yday / 100); + write2(yday % 100); + } + void on_day_of_month(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write2(tm_mday()); + format_localized('d', 'O'); + } + void on_day_of_month_space(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto mday = to_unsigned(tm_mday()) % 100; + const char* d2 = digits2(mday); + *out_++ = mday < 10 ? ' ' : d2[0]; + *out_++ = d2[1]; + } else { + format_localized('e', 'O'); + } + } + + void on_24_hour(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write2(tm_hour()); + format_localized('H', 'O'); + } + void on_12_hour(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_hour12()); + format_localized('I', 'O'); + } + void on_minute(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write2(tm_min()); + format_localized('M', 'O'); + } + void on_second(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write2(tm_sec()); + format_localized('S', 'O'); + } + + void on_12_hour_time() { + if (is_classic_) { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_hour12()), + to_unsigned(tm_min()), to_unsigned(tm_sec()), ':'); + out_ = copy_str(std::begin(buf), std::end(buf), out_); + *out_++ = ' '; + on_am_pm(); + } else { + format_localized('r'); + } + } + void on_24_hour_time() { + write2(tm_hour()); + *out_++ = ':'; + write2(tm_min()); + } + void on_iso_time() { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_hour()), to_unsigned(tm_min()), + to_unsigned(tm_sec()), ':'); + out_ = copy_str(std::begin(buf), std::end(buf), out_); + } + + void on_am_pm() { + if (is_classic_) { + *out_++ = tm_hour() < 12 ? 'A' : 'P'; + *out_++ = 'M'; + } else { + format_localized('p'); + } + } + + // These apply to chrono durations but not tm. + void on_duration_value() {} + void on_duration_unit() {} +}; + struct chrono_format_checker : null_chrono_spec_handler { FMT_NORETURN void unsupported() { FMT_THROW(format_error("no date")); } @@ -796,26 +1392,20 @@ template ::value)> inline bool isfinite(T) { return true; } -template ::value)> -inline bool isfinite(T value) { - return std::isfinite(value); -} -// Converts value to int and checks that it's in the range [0, upper). -template ::value)> -inline int to_nonnegative_int(T value, int upper) { +// Converts value to Int and checks that it's in the range [0, upper). +template ::value)> +inline Int to_nonnegative_int(T value, Int upper) { FMT_ASSERT(value >= 0 && to_unsigned(value) <= to_unsigned(upper), "invalid value"); (void)upper; - return static_cast(value); + return static_cast(value); } -template ::value)> -inline int to_nonnegative_int(T value, int upper) { - FMT_ASSERT( - std::isnan(value) || (value >= 0 && value <= static_cast(upper)), - "invalid value"); - (void)upper; - return static_cast(value); +template ::value)> +inline Int to_nonnegative_int(T value, Int upper) { + if (value < 0 || value > static_cast(upper)) + FMT_THROW(format_error("invalid value")); + return static_cast(value); } template ::value)> @@ -872,15 +1462,37 @@ inline std::chrono::duration get_milliseconds( #endif } -template ::value)> -inline std::chrono::duration get_milliseconds( +// Returns the number of fractional digits in the range [0, 18] according to the +// C++20 spec. If more than 18 fractional digits are required then returns 6 for +// microseconds precision. +constexpr int count_fractional_digits(long long num, long long den, int n = 0) { + return num % den == 0 + ? n + : (n > 18 ? 6 : count_fractional_digits(num * 10, den, n + 1)); +} + +constexpr long long pow10(std::uint32_t n) { + return n == 0 ? 1 : 10 * pow10(n - 1); +} + +template ::is_signed)> +constexpr std::chrono::duration abs( std::chrono::duration d) { - using common_type = typename std::common_type::type; - auto ms = mod(d.count() * static_cast(Period::num) / - static_cast(Period::den) * 1000, - 1000); - return std::chrono::duration(static_cast(ms)); + // We need to compare the duration using the count() method directly + // due to a compiler bug in clang-11 regarding the spaceship operator, + // when -Wzero-as-null-pointer-constant is enabled. + // In clang-12 the bug has been fixed. See + // https://bugs.llvm.org/show_bug.cgi?id=46235 and the reproducible example: + // https://www.godbolt.org/z/Knbb5joYx. + return d.count() >= d.zero().count() ? d : -d; +} + +template ::is_signed)> +constexpr std::chrono::duration abs( + std::chrono::duration d) { + return d; } template (); specs.precision = precision; - specs.type = precision > 0 ? 'f' : 'g'; + specs.type = precision >= 0 ? presentation_type::fixed_lower + : presentation_type::general_lower; return write(out, val, specs); } @@ -926,6 +1539,26 @@ OutputIt format_duration_unit(OutputIt out) { return out; } +class get_locale { + private: + union { + std::locale locale_; + }; + bool has_locale_ = false; + + public: + get_locale(bool localized, locale_ref loc) : has_locale_(localized) { + if (localized) + ::new (&locale_) std::locale(loc.template get()); + } + ~get_locale() { + if (has_locale_) locale_.~locale(); + } + operator const std::locale&() const { + return has_locale_ ? locale_ : get_classic_locale(); + } +}; + template struct chrono_formatter { @@ -944,9 +1577,10 @@ struct chrono_formatter { bool negative; using char_type = typename FormatContext::char_type; + using tm_writer_type = tm_writer; - explicit chrono_formatter(FormatContext& ctx, OutputIt o, - std::chrono::duration d) + chrono_formatter(FormatContext& ctx, OutputIt o, + std::chrono::duration d) : context(ctx), out(o), val(static_cast(d.count())), @@ -1021,15 +1655,48 @@ struct chrono_formatter { out = format_decimal(out, n, num_digits).end; } + template void write_fractional_seconds(Duration d) { + constexpr auto num_fractional_digits = + count_fractional_digits(Duration::period::num, Duration::period::den); + + using subsecond_precision = std::chrono::duration< + typename std::common_type::type, + std::ratio<1, detail::pow10(num_fractional_digits)>>; + if (std::ratio_less::value) { + *out++ = '.'; + // Don't convert long double to integer seconds to avoid overflow. + using sec = conditional_t< + std::is_same::value, + std::chrono::duration, std::chrono::seconds>; + auto fractional = detail::abs(d) - std::chrono::duration_cast(d); + const auto subseconds = + std::chrono::treat_as_floating_point< + typename subsecond_precision::rep>::value + ? fractional.count() + : std::chrono::duration_cast(fractional) + .count(); + uint32_or_64_or_128_t n = + to_unsigned(to_nonnegative_int(subseconds, max_value())); + int num_digits = detail::count_digits(n); + if (num_fractional_digits > num_digits) + out = std::fill_n(out, num_fractional_digits - num_digits, '0'); + out = format_decimal(out, n, num_digits).end; + } + } + void write_nan() { std::copy_n("nan", 3, out); } void write_pinf() { std::copy_n("inf", 3, out); } void write_ninf() { std::copy_n("-inf", 4, out); } - void format_localized(const tm& time, char format, char modifier = 0) { + template + void format_tm(const tm& time, Callback cb, Args... args) { if (isnan(val)) return write_nan(); - const auto& loc = localized ? context.locale().template get() - : std::locale::classic(); - out = detail::write(out, time, loc, format, modifier); + get_locale loc(localized, context.locale()); + auto w = tm_writer_type(loc, out, time); + (w.*cb)(args...); + out = w.out(); } void on_text(const char_type* begin, const char_type* end) { @@ -1050,6 +1717,19 @@ struct chrono_formatter { void on_iso_date() {} void on_utc_offset() {} void on_tz_name() {} + void on_year(numeric_system) {} + void on_short_year(numeric_system) {} + void on_offset_year() {} + void on_century(numeric_system) {} + void on_iso_week_based_year() {} + void on_iso_week_based_short_year() {} + void on_dec_month(numeric_system) {} + void on_dec0_week_of_year(numeric_system) {} + void on_dec1_week_of_year(numeric_system) {} + void on_iso_week_of_year(numeric_system) {} + void on_day_of_year() {} + void on_day_of_month(numeric_system) {} + void on_day_of_month_space(numeric_system) {} void on_24_hour(numeric_system ns) { if (handle_nan_inf()) return; @@ -1057,7 +1737,7 @@ struct chrono_formatter { if (ns == numeric_system::standard) return write(hour(), 2); auto time = tm(); time.tm_hour = to_nonnegative_int(hour(), 24); - format_localized(time, 'H', 'O'); + format_tm(time, &tm_writer_type::on_24_hour, ns); } void on_12_hour(numeric_system ns) { @@ -1066,7 +1746,7 @@ struct chrono_formatter { if (ns == numeric_system::standard) return write(hour12(), 2); auto time = tm(); time.tm_hour = to_nonnegative_int(hour12(), 12); - format_localized(time, 'I', 'O'); + format_tm(time, &tm_writer_type::on_12_hour, ns); } void on_minute(numeric_system ns) { @@ -1075,7 +1755,7 @@ struct chrono_formatter { if (ns == numeric_system::standard) return write(minute(), 2); auto time = tm(); time.tm_min = to_nonnegative_int(minute(), 60); - format_localized(time, 'M', 'O'); + format_tm(time, &tm_writer_type::on_minute, ns); } void on_second(numeric_system ns) { @@ -1083,29 +1763,17 @@ struct chrono_formatter { if (ns == numeric_system::standard) { write(second(), 2); -#if FMT_SAFE_DURATION_CAST - // convert rep->Rep - using duration_rep = std::chrono::duration; - using duration_Rep = std::chrono::duration; - auto tmpval = fmt_safe_duration_cast(duration_rep{val}); -#else - auto tmpval = std::chrono::duration(val); -#endif - auto ms = get_milliseconds(tmpval); - if (ms != std::chrono::milliseconds(0)) { - *out++ = '.'; - write(ms.count(), 3); - } + write_fractional_seconds(std::chrono::duration{val}); return; } auto time = tm(); time.tm_sec = to_nonnegative_int(second(), 60); - format_localized(time, 'S', 'O'); + format_tm(time, &tm_writer_type::on_second, ns); } void on_12_hour_time() { if (handle_nan_inf()) return; - format_localized(time(), 'r'); + format_tm(time(), &tm_writer_type::on_12_hour_time); } void on_24_hour_time() { @@ -1124,12 +1792,12 @@ struct chrono_formatter { on_24_hour_time(); *out++ = ':'; if (handle_nan_inf()) return; - write(second(), 2); + on_second(numeric_system::standard); } void on_am_pm() { if (handle_nan_inf()) return; - format_localized(time(), 'p'); + format_tm(time(), &tm_writer_type::on_am_pm); } void on_duration_value() { @@ -1159,15 +1827,18 @@ class weekday { : value(static_cast(wd != 7 ? wd : 0)) {} constexpr unsigned c_encoding() const noexcept { return value; } }; + +class year_month_day {}; #endif // A rudimentary weekday formatter. -template <> struct formatter { +template struct formatter { private: bool localized = false; public: - FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { auto begin = ctx.begin(), end = ctx.end(); if (begin != end && *begin == 'L') { ++begin; @@ -1176,12 +1847,14 @@ template <> struct formatter { return begin; } - auto format(weekday wd, format_context& ctx) -> decltype(ctx.out()) { + template + auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) { auto time = std::tm(); time.tm_wday = static_cast(wd.c_encoding()); - const auto& loc = localized ? ctx.locale().template get() - : std::locale::classic(); - return detail::write(ctx.out(), time, loc, 'a'); + detail::get_locale loc(localized, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_abbr_weekday(); + return w.out(); } }; @@ -1260,7 +1933,8 @@ struct formatter, Char> { ++begin; localized = true; } - end = parse_chrono_format(begin, end, detail::chrono_format_checker()); + end = detail::parse_chrono_format(begin, end, + detail::chrono_format_checker()); return {begin, end}; } @@ -1302,6 +1976,83 @@ struct formatter, Char> { } }; +template +struct formatter, + Char> : formatter { + FMT_CONSTEXPR formatter() { + this->do_parse(default_specs, + default_specs + sizeof(default_specs) / sizeof(Char)); + } + + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return this->do_parse(ctx.begin(), ctx.end(), true); + } + + template + auto format(std::chrono::time_point val, + FormatContext& ctx) const -> decltype(ctx.out()) { + return formatter::format(localtime(val), ctx); + } + + static constexpr const Char default_specs[] = {'%', 'F', ' ', '%', 'T'}; +}; + +template +constexpr const Char + formatter, + Char>::default_specs[]; + +template struct formatter { + private: + enum class spec { + unknown, + year_month_day, + hh_mm_ss, + }; + spec spec_ = spec::unknown; + basic_string_view specs; + + protected: + template + FMT_CONSTEXPR auto do_parse(It begin, It end, bool with_default = false) + -> It { + if (begin != end && *begin == ':') ++begin; + end = detail::parse_chrono_format(begin, end, detail::tm_format_checker()); + if (!with_default || end != begin) + specs = {begin, detail::to_unsigned(end - begin)}; + // basic_string_view<>::compare isn't constexpr before C++17. + if (specs.size() == 2 && specs[0] == Char('%')) { + if (specs[1] == Char('F')) + spec_ = spec::year_month_day; + else if (specs[1] == Char('T')) + spec_ = spec::hh_mm_ss; + } + return end; + } + + public: + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return this->do_parse(ctx.begin(), ctx.end()); + } + + template + auto format(const std::tm& tm, FormatContext& ctx) const + -> decltype(ctx.out()) { + const auto loc_ref = ctx.locale(); + detail::get_locale loc(static_cast(loc_ref), loc_ref); + auto w = detail::tm_writer(loc, ctx.out(), tm); + if (spec_ == spec::year_month_day) + w.on_iso_date(); + else if (spec_ == spec::hh_mm_ss) + w.on_iso_time(); + else + detail::parse_chrono_format(specs.begin(), specs.end(), w); + return w.out(); + } +}; + FMT_MODULE_EXPORT_END FMT_END_NAMESPACE diff --git a/src/fmt/color.h b/src/fmt/color.h index 3d5490e87f..dfbe482938 100644 --- a/src/fmt/color.h +++ b/src/fmt/color.h @@ -185,9 +185,13 @@ enum class terminal_color : uint8_t { enum class emphasis : uint8_t { bold = 1, - italic = 1 << 1, - underline = 1 << 2, - strikethrough = 1 << 3 + faint = 1 << 1, + italic = 1 << 2, + underline = 1 << 3, + blink = 1 << 4, + reverse = 1 << 5, + conceal = 1 << 6, + strikethrough = 1 << 7, }; // rgb is a struct for red, green and blue colors. @@ -409,16 +413,18 @@ template struct ansi_color_escape { buffer[19] = static_cast(0); } FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT { - uint8_t em_codes[4] = {}; - uint8_t em_bits = static_cast(em); - if (em_bits & static_cast(emphasis::bold)) em_codes[0] = 1; - if (em_bits & static_cast(emphasis::italic)) em_codes[1] = 3; - if (em_bits & static_cast(emphasis::underline)) em_codes[2] = 4; - if (em_bits & static_cast(emphasis::strikethrough)) - em_codes[3] = 9; + uint8_t em_codes[num_emphases] = {}; + if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1; + if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2; + if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3; + if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4; + if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5; + if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7; + if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8; + if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9; size_t index = 0; - for (int i = 0; i < 4; ++i) { + for (size_t i = 0; i < num_emphases; ++i) { if (!em_codes[i]) continue; buffer[index++] = static_cast('\x1b'); buffer[index++] = static_cast('['); @@ -435,7 +441,8 @@ template struct ansi_color_escape { } private: - Char buffer[7u + 3u * 4u + 1u]; + static constexpr size_t num_emphases = 8; + Char buffer[7u + 3u * num_emphases + 1u]; static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, char delimiter) FMT_NOEXCEPT { @@ -444,6 +451,10 @@ template struct ansi_color_escape { out[2] = static_cast('0' + c % 10); out[3] = static_cast(delimiter); } + static FMT_CONSTEXPR bool has_emphasis(emphasis em, + emphasis mask) FMT_NOEXCEPT { + return static_cast(em) & static_cast(mask); + } }; template diff --git a/src/fmt/compile.h b/src/fmt/compile.h index 00000c92e3..1dba3ddb52 100644 --- a/src/fmt/compile.h +++ b/src/fmt/compile.h @@ -156,7 +156,7 @@ struct is_compiled_string : std::is_base_of {}; std::string s = fmt::format(FMT_COMPILE("{}"), 42); \endrst */ -#ifdef __cpp_if_constexpr +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) # define FMT_COMPILE(s) \ FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit) #else @@ -179,7 +179,7 @@ const T& first(const T& value, const Tail&...) { return value; } -#ifdef __cpp_if_constexpr +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) template struct type_list {}; // Returns a reference to the argument at index N from [first, rest...]. @@ -190,7 +190,7 @@ constexpr const auto& get([[maybe_unused]] const T& first, if constexpr (N == 0) return first; else - return get(rest...); + return detail::get(rest...); } template @@ -202,7 +202,8 @@ constexpr int get_arg_index_by_name(basic_string_view name, template struct get_type_impl; template struct get_type_impl> { - using type = remove_cvref_t(std::declval()...))>; + using type = + remove_cvref_t(std::declval()...))>; }; template @@ -242,7 +243,7 @@ template struct code_unit { // This ensures that the argument type is convertible to `const T&`. template constexpr const T& get_arg_checked(const Args&... args) { - const auto& arg = get(args...); + const auto& arg = detail::get(args...); if constexpr (detail::is_named_arg>()) { return arg.value; } else { @@ -289,7 +290,7 @@ template struct runtime_named_field { constexpr OutputIt format(OutputIt out, const Args&... args) const { bool found = (try_format_argument(out, name, args) || ...); if (!found) { - throw format_error("argument with specified name is not found"); + FMT_THROW(format_error("argument with specified name is not found")); } return out; } @@ -399,7 +400,9 @@ template struct arg_id_handler { return 0; } - constexpr void on_error(const char* message) { throw format_error(message); } + constexpr void on_error(const char* message) { + FMT_THROW(format_error(message)); + } }; template struct parse_arg_id_result { @@ -451,7 +454,7 @@ constexpr auto compile_format_string(S format_str) { constexpr auto str = basic_string_view(format_str); if constexpr (str[POS] == '{') { if constexpr (POS + 1 == str.size()) - throw format_error("unmatched '{' in format string"); + FMT_THROW(format_error("unmatched '{' in format string")); if constexpr (str[POS + 1] == '{') { return parse_tail(make_text(str, POS, 1), format_str); } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { @@ -500,7 +503,7 @@ constexpr auto compile_format_string(S format_str) { } } else if constexpr (str[POS] == '}') { if constexpr (POS + 1 == str.size()) - throw format_error("unmatched '}' in format string"); + FMT_THROW(format_error("unmatched '}' in format string")); return parse_tail(make_text(str, POS, 1), format_str); } else { constexpr auto end = parse_text(str, POS + 1); @@ -527,12 +530,12 @@ constexpr auto compile(S format_str) { return result; } } -#endif // __cpp_if_constexpr +#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) } // namespace detail FMT_MODULE_EXPORT_BEGIN -#ifdef __cpp_if_constexpr +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) template // std::FILE +#include // std::byte +#include // std::FILE #include #include #include @@ -16,29 +17,33 @@ #include // The fmt library version in the form major * 10000 + minor * 100 + patch. -#define FMT_VERSION 80001 +#define FMT_VERSION 80100 -#if defined (__clang__ ) && !defined(__ibmxl__) +#if defined(__clang__) && !defined(__ibmxl__) # define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) #else # define FMT_CLANG_VERSION 0 #endif -#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && \ + !defined(__NVCOMPILER) # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FMT_GCC_PRAGMA(arg) _Pragma(arg) #else # define FMT_GCC_VERSION 0 -# define FMT_GCC_PRAGMA(arg) #endif -#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) -# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION -#else -# define FMT_HAS_GXX_CXX11 0 +#ifndef FMT_GCC_PRAGMA +// Workaround _Pragma bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59884. +# if FMT_GCC_VERSION >= 504 +# define FMT_GCC_PRAGMA(arg) _Pragma(arg) +# else +# define FMT_GCC_PRAGMA(arg) +# endif #endif -#if defined(__INTEL_COMPILER) +#ifdef __ICL +# define FMT_ICC_VERSION __ICL +#elif defined(__INTEL_COMPILER) # define FMT_ICC_VERSION __INTEL_COMPILER #else # define FMT_ICC_VERSION 0 @@ -78,17 +83,23 @@ # define FMT_HAS_CPP_ATTRIBUTE(x) 0 #endif +#ifdef _MSVC_LANG +# define FMT_CPLUSPLUS _MSVC_LANG +#else +# define FMT_CPLUSPLUS __cplusplus +#endif + #define FMT_HAS_CPP14_ATTRIBUTE(attribute) \ - (__cplusplus >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) #define FMT_HAS_CPP17_ATTRIBUTE(attribute) \ - (__cplusplus >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) // Check if relaxed C++14 constexpr is supported. // GCC doesn't allow throw in constexpr until version 6 (bug 67371). #ifndef FMT_USE_CONSTEXPR # define FMT_USE_CONSTEXPR \ - (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \ + (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1912 || \ (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \ !FMT_NVCC && !FMT_ICC_VERSION #endif @@ -100,6 +111,14 @@ # define FMT_CONSTEXPR_DECL #endif +#if ((__cplusplus >= 202002L) && \ + (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE > 9)) || \ + (__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002) +# define FMT_CONSTEXPR20 constexpr +#else +# define FMT_CONSTEXPR20 +#endif + // Check if constexpr std::char_traits<>::compare,length is supported. #if defined(__GLIBCXX__) # if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \ @@ -116,15 +135,6 @@ # define FMT_CONSTEXPR_CHAR_TRAITS #endif -#ifndef FMT_OVERRIDE -# if FMT_HAS_FEATURE(cxx_override_control) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 -# define FMT_OVERRIDE override -# else -# define FMT_OVERRIDE -# endif -#endif - // Check if exceptions are disabled. #ifndef FMT_EXCEPTIONS # if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ @@ -141,7 +151,7 @@ #endif #if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 + FMT_GCC_VERSION >= 408 || FMT_MSC_VER >= 1900 # define FMT_DETECTED_NOEXCEPT noexcept # define FMT_HAS_CXX11_NOEXCEPT 1 #else @@ -166,14 +176,6 @@ # define FMT_NORETURN #endif -#ifndef FMT_MAYBE_UNUSED -# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) -# define FMT_MAYBE_UNUSED [[maybe_unused]] -# else -# define FMT_MAYBE_UNUSED -# endif -#endif - #if __cplusplus == 201103L || __cplusplus == 201402L # if defined(__INTEL_COMPILER) || defined(__PGI) # define FMT_FALLTHROUGH @@ -185,13 +187,20 @@ # else # define FMT_FALLTHROUGH # endif -#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) || \ - (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) # define FMT_FALLTHROUGH [[fallthrough]] #else # define FMT_FALLTHROUGH #endif +#ifndef FMT_NODISCARD +# if FMT_HAS_CPP17_ATTRIBUTE(nodiscard) +# define FMT_NODISCARD [[nodiscard]] +# else +# define FMT_NODISCARD +# endif +#endif + #ifndef FMT_USE_FLOAT # define FMT_USE_FLOAT 1 #endif @@ -210,15 +219,6 @@ # endif #endif -#ifndef FMT_USE_INLINE_NAMESPACES -# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \ - (FMT_MSC_VER >= 1900 && (!defined(_MANAGED) || !_MANAGED)) -# define FMT_USE_INLINE_NAMESPACES 1 -# else -# define FMT_USE_INLINE_NAMESPACES 0 -# endif -#endif - // LAMMPS customization // use 'v8_lmp' namespace instead of 'v8' so that our // bundled copy does not collide with linking other code @@ -226,21 +226,12 @@ // a different version. #ifndef FMT_BEGIN_NAMESPACE -# if FMT_USE_INLINE_NAMESPACES -# define FMT_INLINE_NAMESPACE inline namespace -# define FMT_END_NAMESPACE \ - } \ - } -# else -# define FMT_INLINE_NAMESPACE namespace -# define FMT_END_NAMESPACE \ - } \ - using namespace v8_lmp; \ - } -# endif # define FMT_BEGIN_NAMESPACE \ namespace fmt { \ - FMT_INLINE_NAMESPACE v8_lmp { + inline namespace v8_lmp { +# define FMT_END_NAMESPACE \ + } \ + } #endif #ifndef FMT_MODULE_EXPORT @@ -270,12 +261,6 @@ # define FMT_API #endif -#if FMT_GCC_VERSION -# define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) -#else -# define FMT_GCC_VISIBILITY_HIDDEN -#endif - // libc++ supports string_view in pre-c++17. #if (FMT_HAS_INCLUDE() && \ (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \ @@ -292,10 +277,11 @@ #endif #ifndef FMT_CONSTEVAL -# if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \ - __cplusplus > 201703L) || \ - (defined(__cpp_consteval) && \ - !FMT_MSC_VER) // consteval is broken in MSVC. +# if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \ + __cplusplus > 201703L && !defined(__apple_build_version__)) || \ + (defined(__cpp_consteval) && \ + (!FMT_MSC_VER || _MSC_FULL_VER >= 193030704)) +// consteval is broken in MSVC before VS2022 and Apple clang 13. # define FMT_CONSTEVAL consteval # define FMT_HAS_CONSTEVAL # else @@ -331,6 +317,8 @@ template using bool_constant = std::integral_constant; template using remove_reference_t = typename std::remove_reference::type; template +using remove_const_t = typename std::remove_const::type; +template using remove_cvref_t = typename std::remove_cv>::type; template struct type_identity { using type = T; }; template using type_identity_t = typename type_identity::type; @@ -339,11 +327,6 @@ struct monostate { constexpr monostate() {} }; -// Suppress "unused variable" warnings with the method described in -// https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/. -// (void)var does not work on many Intel compilers. -template FMT_CONSTEXPR void ignore_unused(const T&...) {} - // An enable_if helper to be used in template parameters which results in much // shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed // to workaround a bug in MSVC 2019 (see #1140 and #1186). @@ -355,16 +338,25 @@ template FMT_CONSTEXPR void ignore_unused(const T&...) {} FMT_BEGIN_DETAIL_NAMESPACE -constexpr FMT_INLINE auto is_constant_evaluated() FMT_NOEXCEPT -> bool { +// Suppress "unused variable" warnings with the method described in +// https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/. +// (void)var does not work on many Intel compilers. +template FMT_CONSTEXPR void ignore_unused(const T&...) {} + +constexpr FMT_INLINE auto is_constant_evaluated(bool default_value = false) + FMT_NOEXCEPT -> bool { #ifdef __cpp_lib_is_constant_evaluated + ignore_unused(default_value); return std::is_constant_evaluated(); #else - return false; + return default_value; #endif } // A function to suppress "conditional expression is constant" warnings. -template constexpr auto const_check(T value) -> T { return value; } +template constexpr FMT_INLINE auto const_check(T value) -> T { + return value; +} FMT_NORETURN FMT_API void assert_fail(const char* file, int line, const char* message); @@ -373,7 +365,7 @@ FMT_NORETURN FMT_API void assert_fail(const char* file, int line, # ifdef NDEBUG // FMT_ASSERT is not empty to avoid -Werror=empty-body. # define FMT_ASSERT(condition, message) \ - ::fmt::ignore_unused((condition), (message)) + ::fmt::detail::ignore_unused((condition), (message)) # else # define FMT_ASSERT(condition, message) \ ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \ @@ -382,6 +374,12 @@ FMT_NORETURN FMT_API void assert_fail(const char* file, int line, # endif #endif +#ifdef __cpp_lib_byte +using byte = std::byte; +#else +enum class byte : unsigned char {}; +#endif + #if defined(FMT_USE_STRING_VIEW) template using std_string_view = std::basic_string_view; #elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) @@ -463,13 +461,12 @@ template class basic_string_view { */ FMT_CONSTEXPR_CHAR_TRAITS FMT_INLINE - basic_string_view(const Char* s) : data_(s) { - if (detail::const_check(std::is_same::value && - !detail::is_constant_evaluated())) - size_ = std::strlen(reinterpret_cast(s)); - else - size_ = std::char_traits::length(s); - } + basic_string_view(const Char* s) + : data_(s), + size_(detail::const_check(std::is_same::value && + !detail::is_constant_evaluated(true)) + ? std::strlen(reinterpret_cast(s)) + : std::char_traits::length(s)) {} /** Constructs a string reference from a ``std::basic_string`` object. */ template @@ -484,19 +481,19 @@ template class basic_string_view { size_(s.size()) {} /** Returns a pointer to the string data. */ - constexpr auto data() const -> const Char* { return data_; } + constexpr auto data() const FMT_NOEXCEPT -> const Char* { return data_; } /** Returns the string size. */ - constexpr auto size() const -> size_t { return size_; } + constexpr auto size() const FMT_NOEXCEPT -> size_t { return size_; } - constexpr auto begin() const -> iterator { return data_; } - constexpr auto end() const -> iterator { return data_ + size_; } + constexpr auto begin() const FMT_NOEXCEPT -> iterator { return data_; } + constexpr auto end() const FMT_NOEXCEPT -> iterator { return data_ + size_; } - constexpr auto operator[](size_t pos) const -> const Char& { + constexpr auto operator[](size_t pos) const FMT_NOEXCEPT -> const Char& { return data_[pos]; } - FMT_CONSTEXPR void remove_prefix(size_t n) { + FMT_CONSTEXPR void remove_prefix(size_t n) FMT_NOEXCEPT { data_ += n; size_ -= n; } @@ -573,11 +570,9 @@ constexpr auto to_string_view(const S& s) return basic_string_view(s); } -// LAMMPS customization using 'v8_lmp' instead of 'v8' - FMT_BEGIN_DETAIL_NAMESPACE void to_string_view(...); -using fmt::v8_lmp::to_string_view; +using fmt::to_string_view; // Specifies whether S is a string type convertible to fmt::basic_string_view. // It should be a constexpr function but MSVC 2017 fails to compile it in @@ -604,12 +599,14 @@ FMT_INLINE void check_format_string(const S&) { template ::value)> void check_format_string(S); +FMT_NORETURN FMT_API void throw_format_error(const char* message); + struct error_handler { constexpr error_handler() = default; constexpr error_handler(const error_handler&) = default; // This function is intentionally not constexpr to give a compile-time error. - FMT_NORETURN FMT_API void on_error(const char* message); + void on_error(const char* message) { throw_format_error(message); } }; FMT_END_DETAIL_NAMESPACE @@ -718,6 +715,22 @@ class appender; FMT_BEGIN_DETAIL_NAMESPACE +template +constexpr auto has_const_formatter_impl(T*) + -> decltype(typename Context::template formatter_type().format( + std::declval(), std::declval()), + true) { + return true; +} +template +constexpr auto has_const_formatter_impl(...) -> bool { + return false; +} +template +constexpr auto has_const_formatter() -> bool { + return has_const_formatter_impl(static_cast(nullptr)); +} + // Extracts a reference to the container from back_insert_iterator. template inline auto get_container(std::back_insert_iterator it) @@ -737,13 +750,13 @@ FMT_CONSTEXPR auto copy_str(InputIt begin, InputIt end, OutputIt out) return out; } -template ::value)> -FMT_CONSTEXPR auto copy_str(const Char* begin, const Char* end, Char* out) - -> Char* { - if (is_constant_evaluated()) - return copy_str(begin, end, out); +template , U>::value&& is_char::value)> +FMT_CONSTEXPR auto copy_str(T* begin, T* end, U* out) -> U* { + if (is_constant_evaluated()) return copy_str(begin, end, out); auto size = to_unsigned(end - begin); - memcpy(out, begin, size); + memcpy(out, begin, size * sizeof(U)); return out + size; } @@ -764,22 +777,22 @@ template class buffer { FMT_MSC_WARNING(suppress : 26495) buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {} - buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) FMT_NOEXCEPT - : ptr_(p), - size_(sz), - capacity_(cap) {} + FMT_CONSTEXPR20 buffer(T* p = nullptr, size_t sz = 0, + size_t cap = 0) FMT_NOEXCEPT : ptr_(p), + size_(sz), + capacity_(cap) {} - ~buffer() = default; + FMT_CONSTEXPR20 ~buffer() = default; buffer(buffer&&) = default; /** Sets the buffer data and capacity. */ - void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT { + FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT { ptr_ = buf_data; capacity_ = buf_capacity; } /** Increases the buffer capacity to hold at least *capacity* elements. */ - virtual void grow(size_t capacity) = 0; + virtual FMT_CONSTEXPR20 void grow(size_t capacity) = 0; public: using value_type = T; @@ -795,23 +808,23 @@ template class buffer { auto end() const FMT_NOEXCEPT -> const T* { return ptr_ + size_; } /** Returns the size of this buffer. */ - auto size() const FMT_NOEXCEPT -> size_t { return size_; } + constexpr auto size() const FMT_NOEXCEPT -> size_t { return size_; } /** Returns the capacity of this buffer. */ - auto capacity() const FMT_NOEXCEPT -> size_t { return capacity_; } + constexpr auto capacity() const FMT_NOEXCEPT -> size_t { return capacity_; } /** Returns a pointer to the buffer data. */ - auto data() FMT_NOEXCEPT -> T* { return ptr_; } + FMT_CONSTEXPR auto data() FMT_NOEXCEPT -> T* { return ptr_; } /** Returns a pointer to the buffer data. */ - auto data() const FMT_NOEXCEPT -> const T* { return ptr_; } + FMT_CONSTEXPR auto data() const FMT_NOEXCEPT -> const T* { return ptr_; } /** Clears this buffer. */ void clear() { size_ = 0; } // Tries resizing the buffer to contain *count* elements. If T is a POD type // the new elements may not be initialized. - void try_resize(size_t count) { + FMT_CONSTEXPR20 void try_resize(size_t count) { try_reserve(count); size_ = count <= capacity_ ? count : capacity_; } @@ -820,11 +833,11 @@ template class buffer { // capacity by a smaller amount than requested but guarantees there is space // for at least one additional element either by increasing the capacity or by // flushing the buffer if it is full. - void try_reserve(size_t new_capacity) { + FMT_CONSTEXPR20 void try_reserve(size_t new_capacity) { if (new_capacity > capacity_) grow(new_capacity); } - void push_back(const T& value) { + FMT_CONSTEXPR20 void push_back(const T& value) { try_reserve(size_ + 1); ptr_[size_++] = value; } @@ -832,8 +845,11 @@ template class buffer { /** Appends data to the end of the buffer. */ template void append(const U* begin, const U* end); - template auto operator[](I index) -> T& { return ptr_[index]; } - template auto operator[](I index) const -> const T& { + template FMT_CONSTEXPR auto operator[](I index) -> T& { + return ptr_[index]; + } + template + FMT_CONSTEXPR auto operator[](I index) const -> const T& { return ptr_[index]; } }; @@ -868,7 +884,7 @@ class iterator_buffer final : public Traits, public buffer { T data_[buffer_size]; protected: - void grow(size_t) final FMT_OVERRIDE { + FMT_CONSTEXPR20 void grow(size_t) override { if (this->size() == buffer_size) flush(); } @@ -892,9 +908,55 @@ class iterator_buffer final : public Traits, public buffer { auto count() const -> size_t { return Traits::count() + this->size(); } }; +template +class iterator_buffer final + : public fixed_buffer_traits, + public buffer { + private: + T* out_; + enum { buffer_size = 256 }; + T data_[buffer_size]; + + protected: + FMT_CONSTEXPR20 void grow(size_t) override { + if (this->size() == this->capacity()) flush(); + } + + void flush() { + size_t n = this->limit(this->size()); + if (this->data() == out_) { + out_ += n; + this->set(data_, buffer_size); + } + this->clear(); + } + + public: + explicit iterator_buffer(T* out, size_t n = buffer_size) + : fixed_buffer_traits(n), buffer(out, 0, n), out_(out) {} + iterator_buffer(iterator_buffer&& other) + : fixed_buffer_traits(other), + buffer(std::move(other)), + out_(other.out_) { + if (this->data() != out_) { + this->set(data_, buffer_size); + this->clear(); + } + } + ~iterator_buffer() { flush(); } + + auto out() -> T* { + flush(); + return out_; + } + auto count() const -> size_t { + return fixed_buffer_traits::count() + this->size(); + } +}; + template class iterator_buffer final : public buffer { protected: - void grow(size_t) final FMT_OVERRIDE {} + FMT_CONSTEXPR20 void grow(size_t) override {} public: explicit iterator_buffer(T* out, size_t = 0) : buffer(out, 0, ~size_t()) {} @@ -912,7 +974,7 @@ class iterator_buffer, Container& container_; protected: - void grow(size_t capacity) final FMT_OVERRIDE { + FMT_CONSTEXPR20 void grow(size_t capacity) override { container_.resize(capacity); this->set(&container_[0], capacity); } @@ -935,7 +997,7 @@ template class counting_buffer final : public buffer { size_t count_ = 0; protected: - void grow(size_t) final FMT_OVERRIDE { + FMT_CONSTEXPR20 void grow(size_t) override { if (this->size() != buffer_size) return; count_ += this->size(); this->clear(); @@ -1052,6 +1114,11 @@ template constexpr auto count_named_args() -> size_t { return count::value...>(); } +template +constexpr auto count_statically_named_args() -> size_t { + return count::value...>(); +} + enum class type { none_type, // Integer types should go first, @@ -1107,6 +1174,11 @@ constexpr bool is_arithmetic_type(type t) { return t > type::none_type && t <= type::last_numeric_type; } +struct unformattable {}; +struct unformattable_char : unformattable {}; +struct unformattable_const : unformattable {}; +struct unformattable_pointer : unformattable {}; + template struct string_value { const Char* data; size_t size; @@ -1119,8 +1191,8 @@ template struct named_arg_value { template struct custom_value { using parse_context = typename Context::parse_context_type; - const void* value; - void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx); + void* value; + void (*format)(void* arg, parse_context& parse_ctx, Context& ctx); }; // A formatting argument value. @@ -1154,8 +1226,8 @@ template class value { constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {} FMT_INLINE value(int128_t val) : int128_value(val) {} FMT_INLINE value(uint128_t val) : uint128_value(val) {} - FMT_INLINE value(float val) : float_value(val) {} - FMT_INLINE value(double val) : double_value(val) {} + constexpr FMT_INLINE value(float val) : float_value(val) {} + constexpr FMT_INLINE value(double val) : double_value(val) {} FMT_INLINE value(long double val) : long_double_value(val) {} constexpr FMT_INLINE value(bool val) : bool_value(val) {} constexpr FMT_INLINE value(char_type val) : char_value(val) {} @@ -1171,26 +1243,34 @@ template class value { FMT_INLINE value(const named_arg_info* args, size_t size) : named_args{args, size} {} - template FMT_CONSTEXPR FMT_INLINE value(const T& val) { - custom.value = &val; + template FMT_CONSTEXPR FMT_INLINE value(T& val) { + using value_type = remove_cvref_t; + custom.value = const_cast(&val); // Get the formatter type through the context to allow different contexts // have different extension points, e.g. `formatter` for `format` and // `printf_formatter` for `printf`. custom.format = format_custom_arg< - T, conditional_t::value, - typename Context::template formatter_type, - fallback_formatter>>; + value_type, + conditional_t::value, + typename Context::template formatter_type, + fallback_formatter>>; } + value(unformattable); + value(unformattable_char); + value(unformattable_const); + value(unformattable_pointer); private: // Formats an argument of a custom type, such as a user-defined class. template - static void format_custom_arg(const void* arg, + static void format_custom_arg(void* arg, typename Context::parse_context_type& parse_ctx, Context& ctx) { - Formatter f; + auto f = Formatter(); parse_ctx.advance_to(f.parse(parse_ctx)); - ctx.advance_to(f.format(*static_cast(arg), ctx)); + using qualified_type = + conditional_t(), const T, T>; + ctx.advance_to(f.format(*static_cast(arg), ctx)); } }; @@ -1203,9 +1283,9 @@ enum { long_short = sizeof(long) == sizeof(int) }; using long_type = conditional_t; using ulong_type = conditional_t; -struct unformattable {}; - // Maps formatting arguments to core types. +// arg_mapper reports errors by returning unformattable instead of using +// static_assert because it's used in the is_formattable trait. template struct arg_mapper { using char_type = typename Context::char_type; @@ -1232,13 +1312,22 @@ template struct arg_mapper { FMT_CONSTEXPR FMT_INLINE auto map(uint128_t val) -> uint128_t { return val; } FMT_CONSTEXPR FMT_INLINE auto map(bool val) -> bool { return val; } - template ::value)> + template ::value || + std::is_same::value)> FMT_CONSTEXPR FMT_INLINE auto map(T val) -> char_type { - static_assert( - std::is_same::value || std::is_same::value, - "mixing character types is disallowed"); return val; } + template ::value || +#ifdef __cpp_char8_t + std::is_same::value || +#endif + std::is_same::value || + std::is_same::value) && + !std::is_same::value, + int> = 0> + FMT_CONSTEXPR FMT_INLINE auto map(T) -> unformattable_char { + return {}; + } FMT_CONSTEXPR FMT_INLINE auto map(float val) -> float { return val; } FMT_CONSTEXPR FMT_INLINE auto map(double val) -> double { return val; } @@ -1252,13 +1341,19 @@ template struct arg_mapper { FMT_CONSTEXPR FMT_INLINE auto map(const char_type* val) -> const char_type* { return val; } - template ::value)> + template ::value && !std::is_pointer::value && + std::is_same>::value)> FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> basic_string_view { - static_assert(std::is_same>::value, - "mixing character types is disallowed"); return to_string_view(val); } + template ::value && !std::is_pointer::value && + !std::is_same>::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T&) -> unformattable_char { + return {}; + } template , T>::value && @@ -1279,21 +1374,26 @@ template struct arg_mapper { -> basic_string_view { return std_string_view(val); } - FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val) -> const char* { - static_assert(std::is_same::value, "invalid string type"); - return reinterpret_cast(val); + + using cstring_result = conditional_t::value, + const char*, unformattable_pointer>; + + // DEPRECATED! + FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val) -> cstring_result { + return map(reinterpret_cast(val)); } - FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val) -> const char* { - static_assert(std::is_same::value, "invalid string type"); - return reinterpret_cast(val); + // DEPRECATED! + FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val) + -> cstring_result { + return map(reinterpret_cast(val)); } - FMT_CONSTEXPR FMT_INLINE auto map(signed char* val) -> const char* { - const auto* const_val = val; - return map(const_val); + // DEPRECATED! + FMT_CONSTEXPR FMT_INLINE auto map(signed char* val) -> cstring_result { + return map(reinterpret_cast(val)); } - FMT_CONSTEXPR FMT_INLINE auto map(unsigned char* val) -> const char* { - const auto* const_val = val; - return map(const_val); + // DEPRECATED! + FMT_CONSTEXPR FMT_INLINE auto map(unsigned char* val) -> cstring_result { + return map(reinterpret_cast(val)); } FMT_CONSTEXPR FMT_INLINE auto map(void* val) -> const void* { return val; } @@ -1306,37 +1406,69 @@ template struct arg_mapper { // We use SFINAE instead of a const T* parameter to avoid conflicting with // the C array overload. - template - FMT_CONSTEXPR auto map(T) -> enable_if_t::value, int> { - // Formatting of arbitrary pointers is disallowed. If you want to output - // a pointer cast it to "void *" or "const void *". In particular, this - // forbids formatting of "[const] volatile char *" which is printed as bool - // by iostreams. - static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); - return 0; + template < + typename T, + FMT_ENABLE_IF( + std::is_member_pointer::value || + std::is_function::type>::value || + (std::is_convertible::value && + !std::is_convertible::value))> + FMT_CONSTEXPR auto map(const T&) -> unformattable_pointer { + return {}; } - template + template ::value)> FMT_CONSTEXPR FMT_INLINE auto map(const T (&values)[N]) -> const T (&)[N] { return values; } template ::value && - !has_formatter::value && - !has_fallback_formatter::value)> + FMT_ENABLE_IF( + std::is_enum::value&& std::is_convertible::value && + !has_formatter::value && + !has_fallback_formatter::value)> FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> decltype(std::declval().map( static_cast::type>(val))) { return map(static_cast::type>(val)); } - template ::value && !is_char::value && - (has_formatter::value || - has_fallback_formatter::value))> - FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> const T& { + + FMT_CONSTEXPR FMT_INLINE auto map(detail::byte val) -> unsigned { + return map(static_cast(val)); + } + + template > + struct formattable + : bool_constant() || + !std::is_const>::value || + has_fallback_formatter::value> {}; + +#if FMT_MSC_VER != 0 && FMT_MSC_VER < 1910 + // Workaround a bug in MSVC. + template FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& { return val; } +#else + template ::value)> + FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& { + return val; + } + template ::value)> + FMT_CONSTEXPR FMT_INLINE auto do_map(T&&) -> unformattable_const { + return {}; + } +#endif + + template , + FMT_ENABLE_IF(!is_string::value && !is_char::value && + !std::is_array::value && + (has_formatter::value || + has_fallback_formatter::value))> + FMT_CONSTEXPR FMT_INLINE auto map(T&& val) + -> decltype(this->do_map(std::forward(val))) { + return do_map(std::forward(val)); + } template ::value)> FMT_CONSTEXPR FMT_INLINE auto map(const T& named_arg) @@ -1373,19 +1505,12 @@ class appender : public std::back_insert_iterator> { public: using std::back_insert_iterator>::back_insert_iterator; - appender(base it) : base(it) {} + appender(base it) FMT_NOEXCEPT : base(it) {} using _Unchecked_type = appender; // Mark iterator as checked. - auto operator++() -> appender& { - base::operator++(); - return *this; - } + auto operator++() FMT_NOEXCEPT -> appender& { return *this; } - auto operator++(int) -> appender { - auto tmp = *this; - ++*this; - return tmp; - } + auto operator++(int) FMT_NOEXCEPT -> appender { return *this; } }; // A formatting argument. It is a trivially copyable/constructible type to @@ -1569,10 +1694,30 @@ FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg { // another (not recommended). template -FMT_CONSTEXPR FMT_INLINE auto make_arg(const T& val) -> value { - const auto& arg = arg_mapper().map(val); +FMT_CONSTEXPR FMT_INLINE auto make_arg(T&& val) -> value { + const auto& arg = arg_mapper().map(std::forward(val)); + + constexpr bool formattable_char = + !std::is_same::value; + static_assert(formattable_char, "Mixing character types is disallowed."); + + constexpr bool formattable_const = + !std::is_same::value; + static_assert(formattable_const, "Cannot format a const argument."); + + // Formatting of arbitrary pointers is disallowed. If you want to output + // a pointer cast it to "void *" or "const void *". In particular, this + // forbids formatting of "[const] volatile char *" which is printed as bool + // by iostreams. + constexpr bool formattable_pointer = + !std::is_same::value; + static_assert(formattable_pointer, + "Formatting of non-void pointers is disallowed."); + + constexpr bool formattable = + !std::is_same::value; static_assert( - !std::is_same::value, + formattable, "Cannot format an argument. To make type T formattable provide a " "formatter specialization: https://fmt.dev/latest/api.html#udt"); return {arg}; @@ -1650,9 +1795,9 @@ using format_context = buffer_context; template using is_formattable = bool_constant< - !std::is_same>().map( - std::declval())), - detail::unformattable>::value && + !std::is_base_of>().map( + std::declval()))>::value && !detail::has_fallback_formatter::value>; /** @@ -1691,14 +1836,16 @@ class format_arg_store : 0); public: - FMT_CONSTEXPR FMT_INLINE format_arg_store(const Args&... args) + template + FMT_CONSTEXPR FMT_INLINE format_arg_store(T&&... args) : #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 basic_format_args(*this), #endif data_{detail::make_arg< is_packed, Context, - detail::mapped_type_constant::value>(args)...} { + detail::mapped_type_constant, Context>::value>( + std::forward(args))...} { detail::init_named_args(data_.named_args(), 0, 0, args...); } }; @@ -1712,9 +1859,9 @@ class format_arg_store \endrst */ template -constexpr auto make_format_args(const Args&... args) - -> format_arg_store { - return {args...}; +constexpr auto make_format_args(Args&&... args) + -> format_arg_store...> { + return {std::forward(args)...}; } /** @@ -1873,8 +2020,6 @@ using sign_t = sign::type; FMT_BEGIN_DETAIL_NAMESPACE -void throw_format_error(const char* message); - // Workaround an array initialization issue in gcc 4.8. template struct fill_t { private: @@ -1900,11 +2045,33 @@ template struct fill_t { }; FMT_END_DETAIL_NAMESPACE +enum class presentation_type : unsigned char { + none, + // Integer types should go first, + dec, // 'd' + oct, // 'o' + hex_lower, // 'x' + hex_upper, // 'X' + bin_lower, // 'b' + bin_upper, // 'B' + hexfloat_lower, // 'a' + hexfloat_upper, // 'A' + exp_lower, // 'e' + exp_upper, // 'E' + fixed_lower, // 'f' + fixed_upper, // 'F' + general_lower, // 'g' + general_upper, // 'G' + chr, // 'c' + string, // 's' + pointer // 'p' +}; + // Format specifiers for built-in and string types. template struct basic_format_specs { int width; int precision; - char type; + presentation_type type; align_t align : 4; sign_t sign : 3; bool alt : 1; // Alternate form ('#'). @@ -1914,7 +2081,7 @@ template struct basic_format_specs { constexpr basic_format_specs() : width(0), precision(-1), - type(0), + type(presentation_type::none), align(align::none), sign(sign::none), alt(false), @@ -1994,9 +2161,7 @@ template class specs_setter { } FMT_CONSTEXPR void end_precision() {} - FMT_CONSTEXPR void on_type(Char type) { - specs_.type = static_cast(type); - } + FMT_CONSTEXPR void on_type(presentation_type type) { specs_.type = type; } }; // Format spec handler that saves references to arguments representing dynamic @@ -2070,8 +2235,8 @@ constexpr auto to_ascii(Char value) -> template FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int { if (const_check(sizeof(Char) != 1)) return 1; - constexpr char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0}; + auto lengths = + "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4"; int len = lengths[static_cast(*begin) >> 3]; // Compute the pointer to the next character early so that the next @@ -2278,6 +2443,48 @@ FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end, return begin; } +template +FMT_CONSTEXPR auto parse_presentation_type(Char type) -> presentation_type { + switch (to_ascii(type)) { + case 'd': + return presentation_type::dec; + case 'o': + return presentation_type::oct; + case 'x': + return presentation_type::hex_lower; + case 'X': + return presentation_type::hex_upper; + case 'b': + return presentation_type::bin_lower; + case 'B': + return presentation_type::bin_upper; + case 'a': + return presentation_type::hexfloat_lower; + case 'A': + return presentation_type::hexfloat_upper; + case 'e': + return presentation_type::exp_lower; + case 'E': + return presentation_type::exp_upper; + case 'f': + return presentation_type::fixed_lower; + case 'F': + return presentation_type::fixed_upper; + case 'g': + return presentation_type::general_lower; + case 'G': + return presentation_type::general_upper; + case 'c': + return presentation_type::chr; + case 's': + return presentation_type::string; + case 'p': + return presentation_type::pointer; + default: + return presentation_type::none; + } +} + // Parses standard format specifiers and sends notifications about parsed // components to handler. template @@ -2285,9 +2492,12 @@ FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(const Char* begin, const Char* end, SpecHandler&& handler) -> const Char* { - if (begin + 1 < end && begin[1] == '}' && is_ascii_letter(*begin) && + if (1 < end - begin && begin[1] == '}' && is_ascii_letter(*begin) && *begin != 'L') { - handler.on_type(*begin++); + presentation_type type = parse_presentation_type(*begin++); + if (type == presentation_type::none) + handler.on_error("invalid type specifier"); + handler.on_type(type); return begin; } @@ -2341,7 +2551,12 @@ FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(const Char* begin, } // Parse type. - if (begin != end && *begin != '}') handler.on_type(*begin++); + if (begin != end && *begin != '}') { + presentation_type type = parse_presentation_type(*begin++); + if (type == presentation_type::none) + handler.on_error("invalid type specifier"); + handler.on_type(type); + } return begin; } @@ -2388,7 +2603,7 @@ FMT_CONSTEXPR auto parse_replacement_field(const Char* begin, const Char* end, template FMT_CONSTEXPR FMT_INLINE void parse_format_string( basic_string_view format_str, Handler&& handler) { - // this is most likely a name-lookup defect in msvc's modules implementation + // Workaround a name-lookup bug in MSVC's modules implementation. using detail::find; auto begin = format_str.data(); @@ -2483,28 +2698,18 @@ class compile_parse_context }; template -FMT_CONSTEXPR void check_int_type_spec(char spec, ErrorHandler&& eh) { - switch (spec) { - case 0: - case 'd': - case 'x': - case 'X': - case 'b': - case 'B': - case 'o': - case 'c': - break; - default: +FMT_CONSTEXPR void check_int_type_spec(presentation_type type, + ErrorHandler&& eh) { + if (type > presentation_type::bin_upper && type != presentation_type::chr) eh.on_error("invalid type specifier"); - break; - } } // Checks char specs and returns true if the type spec is char (and not int). template FMT_CONSTEXPR auto check_char_specs(const basic_format_specs& specs, ErrorHandler&& eh = {}) -> bool { - if (specs.type && specs.type != 'c') { + if (specs.type != presentation_type::none && + specs.type != presentation_type::chr) { check_int_type_spec(specs.type, eh); return false; } @@ -2528,7 +2733,7 @@ struct float_specs { bool upper : 1; bool locale : 1; bool binary32 : 1; - bool use_grisu : 1; + bool fallback : 1; bool showpoint : 1; }; @@ -2540,33 +2745,33 @@ FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs& specs, result.showpoint = specs.alt; result.locale = specs.localized; switch (specs.type) { - case 0: + case presentation_type::none: result.format = float_format::general; break; - case 'G': + case presentation_type::general_upper: result.upper = true; FMT_FALLTHROUGH; - case 'g': + case presentation_type::general_lower: result.format = float_format::general; break; - case 'E': + case presentation_type::exp_upper: result.upper = true; FMT_FALLTHROUGH; - case 'e': + case presentation_type::exp_lower: result.format = float_format::exp; result.showpoint |= specs.precision != 0; break; - case 'F': + case presentation_type::fixed_upper: result.upper = true; FMT_FALLTHROUGH; - case 'f': + case presentation_type::fixed_lower: result.format = float_format::fixed; result.showpoint |= specs.precision != 0; break; - case 'A': + case presentation_type::hexfloat_upper: result.upper = true; FMT_FALLTHROUGH; - case 'a': + case presentation_type::hexfloat_lower: result.format = float_format::hex; break; default: @@ -2576,22 +2781,27 @@ FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs& specs, return result; } -template -FMT_CONSTEXPR auto check_cstring_type_spec(Char spec, ErrorHandler&& eh = {}) - -> bool { - if (spec == 0 || spec == 's') return true; - if (spec != 'p') eh.on_error("invalid type specifier"); +template +FMT_CONSTEXPR auto check_cstring_type_spec(presentation_type type, + ErrorHandler&& eh = {}) -> bool { + if (type == presentation_type::none || type == presentation_type::string) + return true; + if (type != presentation_type::pointer) eh.on_error("invalid type specifier"); return false; } -template -FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler&& eh = {}) { - if (spec != 0 && spec != 's') eh.on_error("invalid type specifier"); +template +FMT_CONSTEXPR void check_string_type_spec(presentation_type type, + ErrorHandler&& eh = {}) { + if (type != presentation_type::none && type != presentation_type::string) + eh.on_error("invalid type specifier"); } -template -FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler&& eh) { - if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier"); +template +FMT_CONSTEXPR void check_pointer_type_spec(presentation_type type, + ErrorHandler&& eh) { + if (type != presentation_type::none && type != presentation_type::pointer) + eh.on_error("invalid type specifier"); } // A parse_format_specs handler that checks if specifiers are consistent with @@ -2652,28 +2862,21 @@ constexpr auto get_arg_index_by_name(basic_string_view name) -> int { if constexpr (detail::is_statically_named_arg()) { if (name == T::name) return N; } - if constexpr (sizeof...(Args) > 0) { + if constexpr (sizeof...(Args) > 0) return get_arg_index_by_name(name); - } else { - (void)name; // Workaround an MSVC bug about "unused" parameter. - return invalid_arg_index; - } + (void)name; // Workaround an MSVC bug about "unused" parameter. + return invalid_arg_index; } #endif template FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view name) -> int { #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS - if constexpr (sizeof...(Args) > 0) { + if constexpr (sizeof...(Args) > 0) return get_arg_index_by_name<0, Args...>(name); - } else { - (void)name; - return invalid_arg_index; - } -#else +#endif (void)name; return invalid_arg_index; -#endif } template @@ -2776,7 +2979,10 @@ struct formatter struct basic_runtime { basic_string_view str; }; +/** A compile-time format string. */ template class basic_format_string { private: basic_string_view str_; @@ -2839,14 +3046,15 @@ template class basic_format_string { template >::value)> - FMT_CONSTEVAL basic_format_string(const S& s) : str_(s) { + FMT_CONSTEVAL FMT_INLINE basic_format_string(const S& s) : str_(s) { static_assert( detail::count< (std::is_base_of>::value && std::is_reference::value)...>() == 0, "passing views as lvalues is disallowed"); #ifdef FMT_HAS_CONSTEVAL - if constexpr (detail::count_named_args() == 0) { + if constexpr (detail::count_named_args() == + detail::count_statically_named_args()) { using checker = detail::format_string_checker...>; detail::parse_format_string(str_, checker(s, {})); @@ -2869,7 +3077,16 @@ template auto runtime(const S& s) -> basic_string_view> { #else template using format_string = basic_format_string...>; -// Creates a runtime format string. +/** + \rst + Creates a runtime format string. + + **Example**:: + + // Check format string at runtime instead of compile-time. + fmt::print(fmt::runtime("{:d}"), "I am not a number"); + \endrst + */ template auto runtime(const S& s) -> basic_runtime> { return {{s}}; } @@ -2885,11 +3102,12 @@ FMT_API auto vformat(string_view fmt, format_args args) -> std::string; **Example**:: #include - std::string message = fmt::format("The answer is {}", 42); + std::string message = fmt::format("The answer is {}.", 42); \endrst */ template -FMT_INLINE auto format(format_string fmt, T&&... args) -> std::string { +FMT_NODISCARD FMT_INLINE auto format(format_string fmt, T&&... args) + -> std::string { return vformat(fmt, fmt::make_format_args(args...)); } @@ -2899,7 +3117,7 @@ template OutputIt { using detail::get_buffer; auto&& buf = get_buffer(out); - detail::vformat_to(buf, string_view(fmt), args, {}); + detail::vformat_to(buf, fmt, args, {}); return detail::get_iterator(buf); } @@ -2907,7 +3125,7 @@ auto vformat_to(OutputIt out, string_view fmt, format_args args) -> OutputIt { \rst Formats ``args`` according to specifications in ``fmt``, writes the result to the output iterator ``out`` and returns the iterator past the end of the output - range. + range. `format_to` does not append a terminating null character. **Example**:: @@ -2933,9 +3151,8 @@ template ::value)> auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args) -> format_to_n_result { - using buffer = - detail::iterator_buffer; - auto buf = buffer(out, n); + using traits = detail::fixed_buffer_traits; + auto buf = detail::iterator_buffer(out, n); detail::vformat_to(buf, fmt, args, {}); return {buf.out(), buf.count()}; } @@ -2945,18 +3162,20 @@ auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args) Formats ``args`` according to specifications in ``fmt``, writes up to ``n`` characters of the result to the output iterator ``out`` and returns the total (not truncated) output size and the iterator past the end of the output range. + `format_to_n` does not append a terminating null character. \endrst */ template ::value)> FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string fmt, - const T&... args) -> format_to_n_result { + T&&... args) -> format_to_n_result { return vformat_to_n(out, n, fmt, fmt::make_format_args(args...)); } /** Returns the number of chars in the output of ``format(fmt, args...)``. */ template -FMT_INLINE auto formatted_size(format_string fmt, T&&... args) -> size_t { +FMT_NODISCARD FMT_INLINE auto formatted_size(format_string fmt, + T&&... args) -> size_t { auto buf = detail::counting_buffer<>(); detail::vformat_to(buf, string_view(fmt), fmt::make_format_args(args...), {}); return buf.count(); diff --git a/src/fmt/format-inl.h b/src/fmt/format-inl.h index b01aa30813..0c277956f1 100644 --- a/src/fmt/format-inl.h +++ b/src/fmt/format-inl.h @@ -40,6 +40,10 @@ FMT_FUNC void assert_fail(const char* file, int line, const char* message) { std::terminate(); } +FMT_FUNC void throw_format_error(const char* message) { + FMT_THROW(format_error(message)); +} + #ifndef _MSC_VER # define FMT_SNPRINTF snprintf #else // _MSC_VER @@ -145,141 +149,13 @@ template <> FMT_FUNC int count_digits<4>(detail::fallback_uintptr n) { return i >= 0 ? i * char_digits + count_digits<4, unsigned>(n.value[i]) : 1; } -#if __cplusplus < 201703L -template constexpr const char basic_data::digits[][2]; -template constexpr const char basic_data::hex_digits[]; -template constexpr const char basic_data::signs[]; -template constexpr const unsigned basic_data::prefixes[]; -template constexpr const char basic_data::left_padding_shifts[]; -template -constexpr const char basic_data::right_padding_shifts[]; -#endif +// log10(2) = 0x0.4d104d427de7fbcc... +static constexpr uint64_t log10_2_significand = 0x4d104d427de7fbcc; -template struct bits { - static FMT_CONSTEXPR_DECL const int value = - static_cast(sizeof(T) * std::numeric_limits::digits); -}; - -class fp; -template fp normalize(fp value); - -// Lower (upper) boundary is a value half way between a floating-point value -// and its predecessor (successor). Boundaries have the same exponent as the -// value so only significands are stored. -struct boundaries { - uint64_t lower; - uint64_t upper; -}; - -// A handmade floating-point number f * pow(2, e). -class fp { - private: - using significand_type = uint64_t; - - template - using is_supported_float = bool_constant; - - public: - significand_type f; - int e; - - // All sizes are in bits. - // Subtract 1 to account for an implicit most significant bit in the - // normalized form. - static FMT_CONSTEXPR_DECL const int double_significand_size = - std::numeric_limits::digits - 1; - static FMT_CONSTEXPR_DECL const uint64_t implicit_bit = - 1ULL << double_significand_size; - static FMT_CONSTEXPR_DECL const int significand_size = - bits::value; - - fp() : f(0), e(0) {} - fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} - - // Constructs fp from an IEEE754 double. It is a template to prevent compile - // errors on platforms where double is not IEEE754. - template explicit fp(Double d) { assign(d); } - - // Assigns d to this and return true iff predecessor is closer than successor. - template ::value)> - bool assign(Float d) { - // Assume float is in the format [sign][exponent][significand]. - using limits = std::numeric_limits; - const int float_significand_size = limits::digits - 1; - const int exponent_size = - bits::value - float_significand_size - 1; // -1 for sign - const uint64_t float_implicit_bit = 1ULL << float_significand_size; - const uint64_t significand_mask = float_implicit_bit - 1; - const uint64_t exponent_mask = (~0ULL >> 1) & ~significand_mask; - const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1; - constexpr bool is_double = sizeof(Float) == sizeof(uint64_t); - auto u = bit_cast>(d); - f = u & significand_mask; - int biased_e = - static_cast((u & exponent_mask) >> float_significand_size); - // Predecessor is closer if d is a normalized power of 2 (f == 0) other than - // the smallest normalized number (biased_e > 1). - bool is_predecessor_closer = f == 0 && biased_e > 1; - if (biased_e != 0) - f += float_implicit_bit; - else - biased_e = 1; // Subnormals use biased exponent 1 (min exponent). - e = biased_e - exponent_bias - float_significand_size; - return is_predecessor_closer; - } - - template ::value)> - bool assign(Float) { - *this = fp(); - return false; - } -}; - -// Normalizes the value converted from double and multiplied by (1 << SHIFT). -template fp normalize(fp value) { - // Handle subnormals. - const auto shifted_implicit_bit = fp::implicit_bit << SHIFT; - while ((value.f & shifted_implicit_bit) == 0) { - value.f <<= 1; - --value.e; - } - // Subtract 1 to account for hidden bit. - const auto offset = - fp::significand_size - fp::double_significand_size - SHIFT - 1; - value.f <<= offset; - value.e -= offset; - return value; -} - -inline bool operator==(fp x, fp y) { return x.f == y.f && x.e == y.e; } - -// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking. -inline uint64_t multiply(uint64_t lhs, uint64_t rhs) { -#if FMT_USE_INT128 - auto product = static_cast<__uint128_t>(lhs) * rhs; - auto f = static_cast(product >> 64); - return (static_cast(product) & (1ULL << 63)) != 0 ? f + 1 : f; -#else - // Multiply 32-bit parts of significands. - uint64_t mask = (1ULL << 32) - 1; - uint64_t a = lhs >> 32, b = lhs & mask; - uint64_t c = rhs >> 32, d = rhs & mask; - uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; - // Compute mid 64-bit of result and round. - uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); - return ac + (ad >> 32) + (bc >> 32) + (mid >> 32); -#endif -} - -inline fp operator*(fp x, fp y) { return {multiply(x.f, y.f), x.e + y.e + 64}; } - -// Returns a cached power of 10 `c_k = c_k.f * pow(2, c_k.e)` such that its -// (binary) exponent satisfies `min_exponent <= c_k.e <= min_exponent + 28`. -inline fp get_cached_power(int min_exponent, int& pow10_exponent) { +template struct basic_impl_data { // Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. // These are generated by support/compute-powers.py. - static constexpr const uint64_t pow10_significands[] = { + static constexpr uint64_t pow10_significands[87] = { 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c, @@ -311,9 +187,13 @@ inline fp get_cached_power(int min_exponent, int& pow10_exponent) { 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b, }; +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnarrowing" +#endif // Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding // to significands above. - static constexpr const int16_t pow10_exponents[] = { + static constexpr int16_t pow10_exponents[87] = { -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, @@ -322,11 +202,137 @@ inline fp get_cached_power(int min_exponent, int& pow10_exponent) { 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066}; +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +# pragma GCC diagnostic pop +#endif + static constexpr uint64_t power_of_10_64[20] = { + 1, FMT_POWERS_OF_10(1ULL), FMT_POWERS_OF_10(1000000000ULL), + 10000000000000000000ULL}; +}; + +// This is a struct rather than an alias to avoid shadowing warnings in gcc. +struct impl_data : basic_impl_data<> {}; + +#if __cplusplus < 201703L +template +constexpr uint64_t basic_impl_data::pow10_significands[]; +template constexpr int16_t basic_impl_data::pow10_exponents[]; +template constexpr uint64_t basic_impl_data::power_of_10_64[]; +#endif + +template struct bits { + static FMT_CONSTEXPR_DECL const int value = + static_cast(sizeof(T) * std::numeric_limits::digits); +}; + +// Returns the number of significand bits in Float excluding the implicit bit. +template constexpr int num_significand_bits() { + // Subtract 1 to account for an implicit most significant bit in the + // normalized form. + return std::numeric_limits::digits - 1; +} + +// A floating-point number f * pow(2, e). +struct fp { + uint64_t f; + int e; + + static constexpr const int num_significand_bits = bits::value; + + constexpr fp() : f(0), e(0) {} + constexpr fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} + + // Constructs fp from an IEEE754 floating-point number. It is a template to + // prevent compile errors on systems where n is not IEEE754. + template explicit FMT_CONSTEXPR fp(Float n) { assign(n); } + + template + using is_supported = bool_constant; + + // Assigns d to this and return true iff predecessor is closer than successor. + template ::value)> + FMT_CONSTEXPR bool assign(Float n) { + // Assume float is in the format [sign][exponent][significand]. + const int num_float_significand_bits = + detail::num_significand_bits(); + const uint64_t implicit_bit = 1ULL << num_float_significand_bits; + const uint64_t significand_mask = implicit_bit - 1; + constexpr bool is_double = sizeof(Float) == sizeof(uint64_t); + auto u = bit_cast>(n); + f = u & significand_mask; + const uint64_t exponent_mask = (~0ULL >> 1) & ~significand_mask; + int biased_e = + static_cast((u & exponent_mask) >> num_float_significand_bits); + // The predecessor is closer if n is a normalized power of 2 (f == 0) other + // than the smallest normalized number (biased_e > 1). + bool is_predecessor_closer = f == 0 && biased_e > 1; + if (biased_e != 0) + f += implicit_bit; + else + biased_e = 1; // Subnormals use biased exponent 1 (min exponent). + const int exponent_bias = std::numeric_limits::max_exponent - 1; + e = biased_e - exponent_bias - num_float_significand_bits; + return is_predecessor_closer; + } + + template ::value)> + bool assign(Float) { + FMT_ASSERT(false, ""); + return false; + } +}; + +// Normalizes the value converted from double and multiplied by (1 << SHIFT). +template FMT_CONSTEXPR fp normalize(fp value) { + // Handle subnormals. + const uint64_t implicit_bit = 1ULL << num_significand_bits(); + const auto shifted_implicit_bit = implicit_bit << SHIFT; + while ((value.f & shifted_implicit_bit) == 0) { + value.f <<= 1; + --value.e; + } + // Subtract 1 to account for hidden bit. + const auto offset = + fp::num_significand_bits - num_significand_bits() - SHIFT - 1; + value.f <<= offset; + value.e -= offset; + return value; +} + +inline bool operator==(fp x, fp y) { return x.f == y.f && x.e == y.e; } + +// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking. +FMT_CONSTEXPR inline uint64_t multiply(uint64_t lhs, uint64_t rhs) { +#if FMT_USE_INT128 + auto product = static_cast<__uint128_t>(lhs) * rhs; + auto f = static_cast(product >> 64); + return (static_cast(product) & (1ULL << 63)) != 0 ? f + 1 : f; +#else + // Multiply 32-bit parts of significands. + uint64_t mask = (1ULL << 32) - 1; + uint64_t a = lhs >> 32, b = lhs & mask; + uint64_t c = rhs >> 32, d = rhs & mask; + uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; + // Compute mid 64-bit of result and round. + uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); + return ac + (ad >> 32) + (bc >> 32) + (mid >> 32); +#endif +} + +FMT_CONSTEXPR inline fp operator*(fp x, fp y) { + return {multiply(x.f, y.f), x.e + y.e + 64}; +} + +// Returns a cached power of 10 `c_k = c_k.f * pow(2, c_k.e)` such that its +// (binary) exponent satisfies `min_exponent <= c_k.e <= min_exponent + 28`. +FMT_CONSTEXPR inline fp get_cached_power(int min_exponent, + int& pow10_exponent) { const int shift = 32; - const auto significand = static_cast(data::log10_2_significand); + const auto significand = static_cast(log10_2_significand); int index = static_cast( - ((min_exponent + fp::significand_size - 1) * (significand >> shift) + + ((min_exponent + fp::num_significand_bits - 1) * (significand >> shift) + ((int64_t(1) << shift) - 1)) // ceil >> 32 // arithmetic shift ); @@ -336,7 +342,8 @@ inline fp get_cached_power(int min_exponent, int& pow10_exponent) { const int dec_exp_step = 8; index = (index - first_dec_exp - 1) / dec_exp_step + 1; pow10_exponent = first_dec_exp + index * dec_exp_step; - return {pow10_significands[index], pow10_exponents[index]}; + return {impl_data::pow10_significands[index], + impl_data::pow10_exponents[index]}; } // A simple accumulator to hold the sums of terms in bigint::square if uint128_t @@ -345,14 +352,16 @@ struct accumulator { uint64_t lower; uint64_t upper; - accumulator() : lower(0), upper(0) {} - explicit operator uint32_t() const { return static_cast(lower); } + constexpr accumulator() : lower(0), upper(0) {} + constexpr explicit operator uint32_t() const { + return static_cast(lower); + } - void operator+=(uint64_t n) { + FMT_CONSTEXPR void operator+=(uint64_t n) { lower += n; if (lower < n) ++upper; } - void operator>>=(int shift) { + FMT_CONSTEXPR void operator>>=(int shift) { FMT_ASSERT(shift == 32, ""); (void)shift; lower = (upper << 32) | (lower >> 32); @@ -370,27 +379,31 @@ class bigint { basic_memory_buffer bigits_; int exp_; - bigit operator[](int index) const { return bigits_[to_unsigned(index)]; } - bigit& operator[](int index) { return bigits_[to_unsigned(index)]; } + FMT_CONSTEXPR20 bigit operator[](int index) const { + return bigits_[to_unsigned(index)]; + } + FMT_CONSTEXPR20 bigit& operator[](int index) { + return bigits_[to_unsigned(index)]; + } static FMT_CONSTEXPR_DECL const int bigit_bits = bits::value; friend struct formatter; - void subtract_bigits(int index, bigit other, bigit& borrow) { + FMT_CONSTEXPR20 void subtract_bigits(int index, bigit other, bigit& borrow) { auto result = static_cast((*this)[index]) - other - borrow; (*this)[index] = static_cast(result); borrow = static_cast(result >> (bigit_bits * 2 - 1)); } - void remove_leading_zeros() { + FMT_CONSTEXPR20 void remove_leading_zeros() { int num_bigits = static_cast(bigits_.size()) - 1; while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits; bigits_.resize(to_unsigned(num_bigits + 1)); } // Computes *this -= other assuming aligned bigints and *this >= other. - void subtract_aligned(const bigint& other) { + FMT_CONSTEXPR20 void subtract_aligned(const bigint& other) { FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints"); FMT_ASSERT(compare(*this, other) >= 0, ""); bigit borrow = 0; @@ -401,7 +414,7 @@ class bigint { remove_leading_zeros(); } - void multiply(uint32_t value) { + FMT_CONSTEXPR20 void multiply(uint32_t value) { const double_bigit wide_value = value; bigit carry = 0; for (size_t i = 0, n = bigits_.size(); i < n; ++i) { @@ -412,7 +425,7 @@ class bigint { if (carry != 0) bigits_.push_back(carry); } - void multiply(uint64_t value) { + FMT_CONSTEXPR20 void multiply(uint64_t value) { const bigit mask = ~bigit(0); const double_bigit lower = value & mask; const double_bigit upper = value >> bigit_bits; @@ -430,14 +443,16 @@ class bigint { } public: - bigint() : exp_(0) {} + FMT_CONSTEXPR20 bigint() : exp_(0) {} explicit bigint(uint64_t n) { assign(n); } - ~bigint() { FMT_ASSERT(bigits_.capacity() <= bigits_capacity, ""); } + FMT_CONSTEXPR20 ~bigint() { + FMT_ASSERT(bigits_.capacity() <= bigits_capacity, ""); + } bigint(const bigint&) = delete; void operator=(const bigint&) = delete; - void assign(const bigint& other) { + FMT_CONSTEXPR20 void assign(const bigint& other) { auto size = other.bigits_.size(); bigits_.resize(size); auto data = other.bigits_.data(); @@ -445,7 +460,7 @@ class bigint { exp_ = other.exp_; } - void assign(uint64_t n) { + FMT_CONSTEXPR20 void assign(uint64_t n) { size_t num_bigits = 0; do { bigits_[num_bigits++] = n & ~bigit(0); @@ -455,9 +470,11 @@ class bigint { exp_ = 0; } - int num_bigits() const { return static_cast(bigits_.size()) + exp_; } + FMT_CONSTEXPR20 int num_bigits() const { + return static_cast(bigits_.size()) + exp_; + } - FMT_NOINLINE bigint& operator<<=(int shift) { + FMT_NOINLINE FMT_CONSTEXPR20 bigint& operator<<=(int shift) { FMT_ASSERT(shift >= 0, ""); exp_ += shift / bigit_bits; shift %= bigit_bits; @@ -472,13 +489,13 @@ class bigint { return *this; } - template bigint& operator*=(Int value) { + template FMT_CONSTEXPR20 bigint& operator*=(Int value) { FMT_ASSERT(value > 0, ""); multiply(uint32_or_64_or_128_t(value)); return *this; } - friend int compare(const bigint& lhs, const bigint& rhs) { + friend FMT_CONSTEXPR20 int compare(const bigint& lhs, const bigint& rhs) { int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits(); if (num_lhs_bigits != num_rhs_bigits) return num_lhs_bigits > num_rhs_bigits ? 1 : -1; @@ -495,8 +512,8 @@ class bigint { } // Returns compare(lhs1 + lhs2, rhs). - friend int add_compare(const bigint& lhs1, const bigint& lhs2, - const bigint& rhs) { + friend FMT_CONSTEXPR20 int add_compare(const bigint& lhs1, const bigint& lhs2, + const bigint& rhs) { int max_lhs_bigits = (std::max)(lhs1.num_bigits(), lhs2.num_bigits()); int num_rhs_bigits = rhs.num_bigits(); if (max_lhs_bigits + 1 < num_rhs_bigits) return -1; @@ -519,7 +536,7 @@ class bigint { } // Assigns pow(10, exp) to this bigint. - void assign_pow10(int exp) { + FMT_CONSTEXPR20 void assign_pow10(int exp) { FMT_ASSERT(exp >= 0, ""); if (exp == 0) return assign(1); // Find the top bit. @@ -538,7 +555,7 @@ class bigint { *this <<= exp; // Multiply by pow(2, exp) by shifting. } - void square() { + FMT_CONSTEXPR20 void square() { int num_bigits = static_cast(bigits_.size()); int num_result_bigits = 2 * num_bigits; basic_memory_buffer n(std::move(bigits_)); @@ -569,7 +586,7 @@ class bigint { // If this bigint has a bigger exponent than other, adds trailing zero to make // exponents equal. This simplifies some operations such as subtraction. - void align(const bigint& other) { + FMT_CONSTEXPR20 void align(const bigint& other) { int exp_difference = exp_ - other.exp_; if (exp_difference <= 0) return; int num_bigits = static_cast(bigits_.size()); @@ -582,7 +599,7 @@ class bigint { // Divides this bignum by divisor, assigning the remainder to this and // returning the quotient. - int divmod_assign(const bigint& divisor) { + FMT_CONSTEXPR20 int divmod_assign(const bigint& divisor) { FMT_ASSERT(this != &divisor, ""); if (compare(*this, divisor) < 0) return 0; FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, ""); @@ -602,8 +619,9 @@ enum class round_direction { unknown, up, down }; // some number v and the error, returns whether v should be rounded up, down, or // whether the rounding direction can't be determined due to error. // error should be less than divisor / 2. -inline round_direction get_round_direction(uint64_t divisor, uint64_t remainder, - uint64_t error) { +FMT_CONSTEXPR inline round_direction get_round_direction(uint64_t divisor, + uint64_t remainder, + uint64_t error) { FMT_ASSERT(remainder < divisor, ""); // divisor - remainder won't overflow. FMT_ASSERT(error < divisor, ""); // divisor - error won't overflow. FMT_ASSERT(error < divisor - error, ""); // error * 2 won't overflow. @@ -626,19 +644,52 @@ enum result { }; } -inline uint64_t power_of_10_64(int exp) { - static constexpr const uint64_t data[] = {1, FMT_POWERS_OF_10(1), - FMT_POWERS_OF_10(1000000000ULL), - 10000000000000000000ULL}; - return data[exp]; -} +struct gen_digits_handler { + char* buf; + int size; + int precision; + int exp10; + bool fixed; + + FMT_CONSTEXPR digits::result on_digit(char digit, uint64_t divisor, + uint64_t remainder, uint64_t error, + bool integral) { + FMT_ASSERT(remainder < divisor, ""); + buf[size++] = digit; + if (!integral && error >= remainder) return digits::error; + if (size < precision) return digits::more; + if (!integral) { + // Check if error * 2 < divisor with overflow prevention. + // The check is not needed for the integral part because error = 1 + // and divisor > (1 << 32) there. + if (error >= divisor || error >= divisor - error) return digits::error; + } else { + FMT_ASSERT(error == 1 && divisor > 2, ""); + } + auto dir = get_round_direction(divisor, remainder, error); + if (dir != round_direction::up) + return dir == round_direction::down ? digits::done : digits::error; + ++buf[size - 1]; + for (int i = size - 1; i > 0 && buf[i] > '9'; --i) { + buf[i] = '0'; + ++buf[i - 1]; + } + if (buf[0] > '9') { + buf[0] = '1'; + if (fixed) + buf[size++] = '0'; + else + ++exp10; + } + return digits::done; + } +}; // Generates output using the Grisu digit-gen algorithm. // error: the size of the region (lower, upper) outside of which numbers // definitely do not round to value (Delta in Grisu3). -template -FMT_INLINE digits::result grisu_gen_digits(fp value, uint64_t error, int& exp, - Handler& handler) { +FMT_INLINE FMT_CONSTEXPR20 digits::result grisu_gen_digits( + fp value, uint64_t error, int& exp, gen_digits_handler& handler) { const fp one(1ULL << -value.e, value.e); // The integral part of scaled value (p1 in Grisu) = value / one. It cannot be // zero because it contains a product of two 64-bit numbers with MSB set (due @@ -649,10 +700,28 @@ FMT_INLINE digits::result grisu_gen_digits(fp value, uint64_t error, int& exp, // The fractional part of scaled value (p2 in Grisu) c = value % one. uint64_t fractional = value.f & (one.f - 1); exp = count_digits(integral); // kappa in Grisu. - // Divide by 10 to prevent overflow. - auto result = handler.on_start(power_of_10_64(exp - 1) << -one.e, - value.f / 10, error * 10, exp); - if (result != digits::more) return result; + // Non-fixed formats require at least one digit and no precision adjustment. + if (handler.fixed) { + // Adjust fixed precision by exponent because it is relative to decimal + // point. + int precision_offset = exp + handler.exp10; + if (precision_offset > 0 && + handler.precision > max_value() - precision_offset) { + FMT_THROW(format_error("number is too big")); + } + handler.precision += precision_offset; + // Check if precision is satisfied just by leading zeros, e.g. + // format("{:.2f}", 0.001) gives "0.00" without generating any digits. + if (handler.precision <= 0) { + if (handler.precision < 0) return digits::done; + // Divide by 10 to prevent overflow. + uint64_t divisor = impl_data::power_of_10_64[exp - 1] << -one.e; + auto dir = get_round_direction(divisor, value.f / 10, error * 10); + if (dir == round_direction::unknown) return digits::error; + handler.buf[handler.size++] = dir == round_direction::up ? '1' : '0'; + return digits::done; + } + } // Generate digits for the integral part. This can produce up to 10 digits. do { uint32_t digit = 0; @@ -699,9 +768,9 @@ FMT_INLINE digits::result grisu_gen_digits(fp value, uint64_t error, int& exp, } --exp; auto remainder = (static_cast(integral) << -one.e) + fractional; - result = handler.on_digit(static_cast('0' + digit), - power_of_10_64(exp) << -one.e, remainder, error, - exp, true); + auto result = handler.on_digit(static_cast('0' + digit), + impl_data::power_of_10_64[exp] << -one.e, + remainder, error, true); if (result != digits::more) return result; } while (exp > 0); // Generate digits for the fractional part. @@ -711,69 +780,11 @@ FMT_INLINE digits::result grisu_gen_digits(fp value, uint64_t error, int& exp, char digit = static_cast('0' + (fractional >> -one.e)); fractional &= one.f - 1; --exp; - result = handler.on_digit(digit, one.f, fractional, error, exp, false); + auto result = handler.on_digit(digit, one.f, fractional, error, false); if (result != digits::more) return result; } } -// The fixed precision digit handler. -struct fixed_handler { - char* buf; - int size; - int precision; - int exp10; - bool fixed; - - digits::result on_start(uint64_t divisor, uint64_t remainder, uint64_t error, - int& exp) { - // Non-fixed formats require at least one digit and no precision adjustment. - if (!fixed) return digits::more; - // Adjust fixed precision by exponent because it is relative to decimal - // point. - precision += exp + exp10; - // Check if precision is satisfied just by leading zeros, e.g. - // format("{:.2f}", 0.001) gives "0.00" without generating any digits. - if (precision > 0) return digits::more; - if (precision < 0) return digits::done; - auto dir = get_round_direction(divisor, remainder, error); - if (dir == round_direction::unknown) return digits::error; - buf[size++] = dir == round_direction::up ? '1' : '0'; - return digits::done; - } - - digits::result on_digit(char digit, uint64_t divisor, uint64_t remainder, - uint64_t error, int, bool integral) { - FMT_ASSERT(remainder < divisor, ""); - buf[size++] = digit; - if (!integral && error >= remainder) return digits::error; - if (size < precision) return digits::more; - if (!integral) { - // Check if error * 2 < divisor with overflow prevention. - // The check is not needed for the integral part because error = 1 - // and divisor > (1 << 32) there. - if (error >= divisor || error >= divisor - error) return digits::error; - } else { - FMT_ASSERT(error == 1 && divisor > 2, ""); - } - auto dir = get_round_direction(divisor, remainder, error); - if (dir != round_direction::up) - return dir == round_direction::down ? digits::done : digits::error; - ++buf[size - 1]; - for (int i = size - 1; i > 0 && buf[i] > '9'; --i) { - buf[i] = '0'; - ++buf[i - 1]; - } - if (buf[0] > '9') { - buf[0] = '1'; - if (fixed) - buf[size++] = '0'; - else - ++exp10; - } - return digits::done; - } -}; - // A 128-bit integer type used internally, struct uint128_wrapper { uint128_wrapper() = default; @@ -897,8 +908,7 @@ inline uint64_t umul96_lower64(uint32_t x, uint64_t y) FMT_NOEXCEPT { inline int floor_log10_pow2(int e) FMT_NOEXCEPT { FMT_ASSERT(e <= 1700 && e >= -1700, "too large exponent"); const int shift = 22; - return (e * static_cast(data::log10_2_significand >> (64 - shift))) >> - shift; + return (e * static_cast(log10_2_significand >> (64 - shift))) >> shift; } // Various fast log computations. @@ -916,8 +926,7 @@ inline int floor_log10_pow2_minus_log10_4_over_3(int e) FMT_NOEXCEPT { FMT_ASSERT(e <= 1700 && e >= -1700, "too large exponent"); const uint64_t log10_4_over_3_fractional_digits = 0x1ffbfc2bbc780375; const int shift_amount = 22; - return (e * static_cast(data::log10_2_significand >> - (64 - shift_amount)) - + return (e * static_cast(log10_2_significand >> (64 - shift_amount)) - static_cast(log10_4_over_3_fractional_digits >> (64 - shift_amount))) >> shift_amount; @@ -1062,7 +1071,7 @@ template <> struct cache_accessor { static uint64_t get_cached_power(int k) FMT_NOEXCEPT { FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, "k is out of range"); - constexpr const uint64_t pow10_significands[] = { + static constexpr const uint64_t pow10_significands[] = { 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3f, 0xfd87b5f28300ca0e, 0x9e74d1b791e07e49, 0xc612062576589ddb, 0xf79687aed3eec552, 0x9abe14cd44753b53, 0xc16d9a0095928a28, @@ -2230,24 +2239,21 @@ small_divisor_case_label: } } // namespace dragonbox -// Formats value using a variation of the Fixed-Precision Positive -// Floating-Point Printout ((FPP)^2) algorithm by Steele & White: +// Formats a floating-point number using a variation of the Fixed-Precision +// Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White: // https://fmt.dev/papers/p372-steele.pdf. -template -void fallback_format(Double d, int num_digits, bool binary32, buffer& buf, - int& exp10) { +FMT_CONSTEXPR20 inline void format_dragon(fp value, bool is_predecessor_closer, + int num_digits, buffer& buf, + int& exp10) { bigint numerator; // 2 * R in (FPP)^2. bigint denominator; // 2 * S in (FPP)^2. // lower and upper are differences between value and corresponding boundaries. bigint lower; // (M^- in (FPP)^2). bigint upper_store; // upper's value if different from lower. bigint* upper = nullptr; // (M^+ in (FPP)^2). - fp value; // Shift numerator and denominator by an extra bit or two (if lower boundary // is closer) to make lower and upper integers. This eliminates multiplication // by 2 during later computations. - const bool is_predecessor_closer = - binary32 ? value.assign(static_cast(d)) : value.assign(d); int shift = is_predecessor_closer ? 2 : 1; uint64_t significand = value.f << shift; if (value.e >= 0) { @@ -2317,9 +2323,9 @@ void fallback_format(Double d, int num_digits, bool binary32, buffer& buf, // Generate the given number of digits. exp10 -= num_digits - 1; if (num_digits == 0) { - buf.try_resize(1); denominator *= 10; - buf[0] = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0'; + auto digit = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0'; + buf.push_back(digit); return; } buf.try_resize(to_unsigned(num_digits)); @@ -2350,9 +2356,12 @@ void fallback_format(Double d, int num_digits, bool binary32, buffer& buf, buf[num_digits - 1] = static_cast('0' + digit); } -template -int format_float(T value, int precision, float_specs specs, buffer& buf) { - static_assert(!std::is_same::value, ""); +template +FMT_HEADER_ONLY_CONSTEXPR20 int format_float(Float value, int precision, + float_specs specs, + buffer& buf) { + // float is passed as double to reduce the number of instantiations. + static_assert(!std::is_same::value, ""); FMT_ASSERT(value >= 0, "value is negative"); const bool fixed = specs.format == float_format::fixed; @@ -2362,13 +2371,13 @@ int format_float(T value, int precision, float_specs specs, buffer& buf) { return 0; } buf.try_resize(to_unsigned(precision)); - std::uninitialized_fill_n(buf.data(), precision, '0'); + fill_n(buf.data(), precision, '0'); return -precision; } - if (!specs.use_grisu) return snprintf_float(value, precision, specs, buf); + if (specs.fallback) return snprintf_float(value, precision, specs, buf); - if (precision < 0) { + if (!is_constant_evaluated() && precision < 0) { // Use Dragonbox for the shortest format. if (specs.binary32) { auto dec = dragonbox::to_decimal(static_cast(value)); @@ -2380,26 +2389,37 @@ int format_float(T value, int precision, float_specs specs, buffer& buf) { return dec.exponent; } - // Use Grisu + Dragon4 for the given precision: - // https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf. int exp = 0; - const int min_exp = -60; // alpha in Grisu. - int cached_exp10 = 0; // K in Grisu. - fp normalized = normalize(fp(value)); - const auto cached_pow = get_cached_power( - min_exp - (normalized.e + fp::significand_size), cached_exp10); - normalized = normalized * cached_pow; - // Limit precision to the maximum possible number of significant digits in an - // IEEE754 double because we don't need to generate zeros. - const int max_double_digits = 767; - if (precision > max_double_digits) precision = max_double_digits; - fixed_handler handler{buf.data(), 0, precision, -cached_exp10, fixed}; - if (grisu_gen_digits(normalized, 1, exp, handler) == digits::error) { - exp += handler.size - cached_exp10 - 1; - fallback_format(value, handler.precision, specs.binary32, buf, exp); - } else { - exp += handler.exp10; - buf.try_resize(to_unsigned(handler.size)); + bool use_dragon = true; + if (is_fast_float()) { + // Use Grisu + Dragon4 for the given precision: + // https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf. + const int min_exp = -60; // alpha in Grisu. + int cached_exp10 = 0; // K in Grisu. + fp normalized = normalize(fp(value)); + const auto cached_pow = get_cached_power( + min_exp - (normalized.e + fp::num_significand_bits), cached_exp10); + normalized = normalized * cached_pow; + gen_digits_handler handler{buf.data(), 0, precision, -cached_exp10, fixed}; + if (grisu_gen_digits(normalized, 1, exp, handler) != digits::error && + !is_constant_evaluated()) { + exp += handler.exp10; + buf.try_resize(to_unsigned(handler.size)); + use_dragon = false; + } else { + exp += handler.size - cached_exp10 - 1; + precision = handler.precision; + } + } + if (use_dragon) { + auto f = fp(); + bool is_predecessor_closer = + specs.binary32 ? f.assign(static_cast(value)) : f.assign(value); + // Limit precision to the maximum possible number of significant digits in + // an IEEE754 double because we don't need to generate zeros. + const int max_double_digits = 767; + if (precision > max_double_digits) precision = max_double_digits; + format_dragon(f, is_predecessor_closer, precision, buf, exp); } if (!fixed && !specs.showpoint) { // Remove trailing zeros. @@ -2411,7 +2431,7 @@ int format_float(T value, int precision, float_specs specs, buffer& buf) { buf.try_resize(num_digits); } return exp; -} // namespace detail +} template int snprintf_float(T value, int precision, float_specs specs, @@ -2545,8 +2565,8 @@ template <> struct formatter { }; FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { - for_each_codepoint(s, [this](uint32_t cp, int error) { - if (error != 0) FMT_THROW(std::runtime_error("invalid utf8")); + for_each_codepoint(s, [this](uint32_t cp, string_view) { + if (cp == invalid_code_point) FMT_THROW(std::runtime_error("invalid utf8")); if (cp <= 0xFFFF) { buffer_.push_back(static_cast(cp)); } else { @@ -2554,6 +2574,7 @@ FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { buffer_.push_back(static_cast(0xD800 + (cp >> 10))); buffer_.push_back(static_cast(0xDC00 + (cp & 0x3FF))); } + return true; }); buffer_.push_back(0); } @@ -2569,10 +2590,6 @@ FMT_FUNC void format_system_error(detail::buffer& out, int error_code, format_error_code(out, error_code, message); } -FMT_FUNC void detail::error_handler::on_error(const char* message) { - FMT_THROW(format_error(message)); -} - FMT_FUNC void report_system_error(int error_code, const char* message) FMT_NOEXCEPT { report_error(format_system_error, error_code, message); diff --git a/src/fmt/format.h b/src/fmt/format.h index 5398a23a82..1a5ff23009 100644 --- a/src/fmt/format.h +++ b/src/fmt/format.h @@ -41,14 +41,16 @@ #include // std::system_error #include // std::swap +#ifdef __cpp_lib_bit_cast +# include // std::bitcast +#endif + #include "core.h" -#ifdef __INTEL_COMPILER -# define FMT_ICC_VERSION __INTEL_COMPILER -#elif defined(__ICL) -# define FMT_ICC_VERSION __ICL +#if FMT_GCC_VERSION +# define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) #else -# define FMT_ICC_VERSION 0 +# define FMT_GCC_VISIBILITY_HIDDEN #endif #ifdef __NVCC__ @@ -122,6 +124,14 @@ FMT_END_NAMESPACE # endif #endif +#ifndef FMT_MAYBE_UNUSED +# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) +# define FMT_MAYBE_UNUSED [[maybe_unused]] +# else +# define FMT_MAYBE_UNUSED +# endif +#endif + // Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers. #if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC # define FMT_DEPRECATED_ALIAS @@ -149,18 +159,25 @@ FMT_END_NAMESPACE #endif // __builtin_clz is broken in clang with Microsoft CodeGen: -// https://github.com/fmtlib/fmt/issues/519 -#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clz)) && !FMT_MSC_VER -# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +// https://github.com/fmtlib/fmt/issues/519. +#if !FMT_MSC_VER +# if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +# endif +# if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +# endif #endif -#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clzll)) && !FMT_MSC_VER -# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) -#endif -#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_ctz)) -# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) -#endif -#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_ctzll)) -# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) + +// __builtin_ctz is broken in Intel Compiler Classic on Windows: +// https://github.com/fmtlib/fmt/issues/2510. +#ifndef __ICL +# if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) +# endif +# if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) +# endif #endif #if FMT_MSC_VER @@ -175,7 +192,6 @@ FMT_BEGIN_NAMESPACE namespace detail { // Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. # if !defined(__clang__) -# pragma managed(push, off) # pragma intrinsic(_BitScanForward) # pragma intrinsic(_BitScanReverse) # if defined(_WIN64) @@ -237,40 +253,67 @@ inline auto ctzll(uint64_t x) -> int { return static_cast(r); } # define FMT_BUILTIN_CTZLL(n) detail::ctzll(n) -# if !defined(__clang__) -# pragma managed(pop) -# endif } // namespace detail FMT_END_NAMESPACE #endif +#ifdef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY_CONSTEXPR20 FMT_CONSTEXPR20 +#else +# define FMT_HEADER_ONLY_CONSTEXPR20 +#endif + FMT_BEGIN_NAMESPACE namespace detail { -#if __cplusplus >= 202002L || \ - (__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002) -# define FMT_CONSTEXPR20 constexpr -#else -# define FMT_CONSTEXPR20 -#endif +template class formatbuf : public Streambuf { + private: + using char_type = typename Streambuf::char_type; + using streamsize = decltype(std::declval().sputn(nullptr, 0)); + using int_type = typename Streambuf::int_type; + using traits_type = typename Streambuf::traits_type; -// An equivalent of `*reinterpret_cast(&source)` that doesn't have -// undefined behavior (e.g. due to type aliasing). -// Example: uint64_t d = bit_cast(2.718); -template -inline auto bit_cast(const Source& source) -> Dest { - static_assert(sizeof(Dest) == sizeof(Source), "size mismatch"); - Dest dest; - std::memcpy(&dest, &source, sizeof(dest)); - return dest; + buffer& buffer_; + + public: + explicit formatbuf(buffer& buf) : buffer_(buf) {} + + protected: + // The put area is always empty. This makes the implementation simpler and has + // the advantage that the streambuf and the buffer are always in sync and + // sputc never writes into uninitialized memory. A disadvantage is that each + // call to sputc always results in a (virtual) call to overflow. There is no + // disadvantage here for sputn since this always results in a call to xsputn. + + auto overflow(int_type ch) -> int_type override { + if (!traits_type::eq_int_type(ch, traits_type::eof())) + buffer_.push_back(static_cast(ch)); + return ch; + } + + auto xsputn(const char_type* s, streamsize count) -> streamsize override { + buffer_.append(s, s + count); + return count; + } +}; + +// Implementation of std::bit_cast for pre-C++20. +template +FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To { + static_assert(sizeof(To) == sizeof(From), "size mismatch"); +#ifdef __cpp_lib_bit_cast + if (is_constant_evaluated()) return std::bit_cast(from); +#endif + auto to = To(); + std::memcpy(&to, &from, sizeof(to)); + return to; } inline auto is_big_endian() -> bool { - const auto u = 1u; struct bytes { - char data[sizeof(u)]; + char data[sizeof(int)]; }; - return bit_cast(u).data[0] == 0; + return bit_cast(1).data[0] == 0; } // A fallback implementation of uintptr_t for systems that lack it. @@ -339,12 +382,15 @@ inline auto get_data(Container& c) -> typename Container::value_type* { #if defined(_SECURE_SCL) && _SECURE_SCL // Make a checked iterator to avoid MSVC warnings. template using checked_ptr = stdext::checked_array_iterator; -template auto make_checked(T* p, size_t size) -> checked_ptr { +template +constexpr auto make_checked(T* p, size_t size) -> checked_ptr { return {p, size}; } #else template using checked_ptr = T*; -template inline auto make_checked(T* p, size_t) -> T* { return p; } +template constexpr auto make_checked(T* p, size_t) -> T* { + return p; +} #endif // Attempts to reserve space for n extra characters in the output range. @@ -480,27 +526,38 @@ FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e) return next; } +enum { invalid_code_point = ~uint32_t() }; + +// Invokes f(cp, sv) for every code point cp in s with sv being the string view +// corresponding to the code point. cp is invalid_code_point on error. template FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) { - auto decode = [f](const char* p) { + auto decode = [f](const char* buf_ptr, const char* ptr) { auto cp = uint32_t(); auto error = 0; - p = utf8_decode(p, &cp, &error); - f(cp, error); - return p; + auto end = utf8_decode(buf_ptr, &cp, &error); + bool result = f(error ? invalid_code_point : cp, + string_view(ptr, to_unsigned(end - buf_ptr))); + return result ? end : nullptr; }; auto p = s.data(); const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars. if (s.size() >= block_size) { - for (auto end = p + s.size() - block_size + 1; p < end;) p = decode(p); + for (auto end = p + s.size() - block_size + 1; p < end;) { + p = decode(p, p); + if (!p) return; + } } if (auto num_chars_left = s.data() + s.size() - p) { char buf[2 * block_size - 1] = {}; copy_str(p, p + num_chars_left, buf); - p = buf; + const char* buf_ptr = buf; do { - p = decode(p); - } while (p - buf < num_chars_left); + auto end = decode(buf_ptr, p); + if (!end) return; + p += end - buf_ptr; + buf_ptr = end; + } while (buf_ptr - buf < num_chars_left); } } @@ -515,10 +572,10 @@ FMT_CONSTEXPR inline size_t compute_width(string_view s) { // It is not a lambda for compatibility with C++14. struct count_code_points { size_t* count; - FMT_CONSTEXPR void operator()(uint32_t cp, int error) const { + FMT_CONSTEXPR auto operator()(uint32_t cp, string_view) const -> bool { *count += detail::to_unsigned( 1 + - (error == 0 && cp >= 0x1100 && + (cp >= 0x1100 && (cp <= 0x115f || // Hangul Jamo init. consonants cp == 0x2329 || // LEFT-POINTING ANGLE BRACKET cp == 0x232a || // RIGHT-POINTING ANGLE BRACKET @@ -536,6 +593,7 @@ FMT_CONSTEXPR inline size_t compute_width(string_view s) { (cp >= 0x1f300 && cp <= 0x1f64f) || // Supplemental Symbols and Pictographs: (cp >= 0x1f900 && cp <= 0x1f9ff)))); + return true; } }; for_each_codepoint(s, count_code_points{&num_code_points}); @@ -564,9 +622,10 @@ inline auto code_point_index(basic_string_view s, size_t n) return s.size(); } -template -using is_fast_float = bool_constant::is_iec559 && - sizeof(T) <= sizeof(double)>; +template ::value> +struct is_fast_float : bool_constant::is_iec559 && + sizeof(T) <= sizeof(double)> {}; +template struct is_fast_float : std::false_type {}; #ifndef FMT_USE_FULL_CACHE_DRAGONBOX # define FMT_USE_FULL_CACHE_DRAGONBOX 0 @@ -607,8 +666,8 @@ enum { inline_buffer_size = 500 }; **Example**:: - fmt::memory_buffer out; - format_to(out, "The answer is {}.", 42); + auto out = fmt::memory_buffer(); + format_to(std::back_inserter(out), "The answer is {}.", 42); This will append the following output to the ``out`` object: @@ -629,34 +688,43 @@ class basic_memory_buffer final : public detail::buffer { Allocator alloc_; // Deallocate memory allocated by the buffer. - void deallocate() { + FMT_CONSTEXPR20 void deallocate() { T* data = this->data(); if (data != store_) alloc_.deallocate(data, this->capacity()); } protected: - void grow(size_t size) final FMT_OVERRIDE; + FMT_CONSTEXPR20 void grow(size_t size) override; public: using value_type = T; using const_reference = const T&; - explicit basic_memory_buffer(const Allocator& alloc = Allocator()) + FMT_CONSTEXPR20 explicit basic_memory_buffer( + const Allocator& alloc = Allocator()) : alloc_(alloc) { this->set(store_, SIZE); + if (detail::is_constant_evaluated()) { + detail::fill_n(store_, SIZE, T{}); + } } - ~basic_memory_buffer() { deallocate(); } + FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); } private: // Move data from other to this buffer. - void move(basic_memory_buffer& other) { + FMT_CONSTEXPR20 void move(basic_memory_buffer& other) { alloc_ = std::move(other.alloc_); T* data = other.data(); size_t size = other.size(), capacity = other.capacity(); if (data == other.store_) { this->set(store_, capacity); - std::uninitialized_copy(other.store_, other.store_ + size, - detail::make_checked(store_, capacity)); + if (detail::is_constant_evaluated()) { + detail::copy_str(other.store_, other.store_ + size, + detail::make_checked(store_, capacity)); + } else { + std::uninitialized_copy(other.store_, other.store_ + size, + detail::make_checked(store_, capacity)); + } } else { this->set(data, capacity); // Set pointer to the inline array so that delete is not called @@ -673,7 +741,10 @@ class basic_memory_buffer final : public detail::buffer { of the other object to it. \endrst */ - basic_memory_buffer(basic_memory_buffer&& other) FMT_NOEXCEPT { move(other); } + FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other) + FMT_NOEXCEPT { + move(other); + } /** \rst @@ -695,7 +766,7 @@ class basic_memory_buffer final : public detail::buffer { Resizes the buffer to contain *count* elements. If T is a POD type new elements may not be initialized. */ - void resize(size_t count) { this->try_resize(count); } + FMT_CONSTEXPR20 void resize(size_t count) { this->try_resize(count); } /** Increases the buffer capacity to *new_capacity*. */ void reserve(size_t new_capacity) { this->try_reserve(new_capacity); } @@ -709,7 +780,8 @@ class basic_memory_buffer final : public detail::buffer { }; template -void basic_memory_buffer::grow(size_t size) { +FMT_CONSTEXPR20 void basic_memory_buffer::grow( + size_t size) { #ifdef FMT_FUZZ if (size > 5000) throw std::runtime_error("fuzz mode - won't grow that much"); #endif @@ -754,7 +826,7 @@ class FMT_API format_error : public std::runtime_error { format_error& operator=(const format_error&) = default; format_error(format_error&&) = default; format_error& operator=(format_error&&) = default; - ~format_error() FMT_NOEXCEPT FMT_OVERRIDE FMT_MSC_DEFAULT; + ~format_error() FMT_NOEXCEPT override FMT_MSC_DEFAULT; }; /** @@ -807,10 +879,6 @@ constexpr auto compile_string_to_view(detail::std_string_view s) FMT_BEGIN_DETAIL_NAMESPACE -inline void throw_format_error(const char* message) { - FMT_THROW(format_error(message)); -} - template struct is_integral : std::is_integral {}; template <> struct is_integral : std::true_type {}; template <> struct is_integral : std::true_type {}; @@ -853,48 +921,23 @@ using uint64_or_128_t = conditional_t() <= 64, uint64_t, uint128_t>; (factor)*1000000, (factor)*10000000, (factor)*100000000, \ (factor)*1000000000 -// Static data is placed in this class template for the header-only config. -template struct basic_data { - // log10(2) = 0x0.4d104d427de7fbcc... - static const uint64_t log10_2_significand = 0x4d104d427de7fbcc; +// Converts value in the range [0, 100) to a string. +constexpr const char* digits2(size_t value) { + // GCC generates slightly better code when value is pointer-size. + return &"0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"[value * 2]; +} - // GCC generates slightly better code for pairs than chars. - FMT_API static constexpr const char digits[100][2] = { - {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'}, - {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'}, - {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'}, - {'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, - {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'}, - {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'}, - {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'}, - {'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'}, - {'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, - {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'}, - {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'}, - {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'}, - {'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'}, - {'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, - {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'}, - {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'}, - {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}}; - - FMT_API static constexpr const char hex_digits[] = "0123456789abcdef"; - FMT_API static constexpr const char signs[4] = {0, '-', '+', ' '}; - FMT_API static constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', - 0x1000000u | ' '}; - FMT_API static constexpr const char left_padding_shifts[5] = {31, 31, 0, 1, - 0}; - FMT_API static constexpr const char right_padding_shifts[5] = {0, 31, 0, 1, - 0}; -}; - -#ifdef FMT_SHARED -// Required for -flto, -fivisibility=hidden and -shared to work -extern template struct basic_data; +// Sign is a template parameter to workaround a bug in gcc 4.8. +template constexpr Char sign(Sign s) { +#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604 + static_assert(std::is_same::value, ""); #endif - -// This is a struct rather than an alias to avoid shadowing warnings in gcc. -struct data : basic_data<> {}; + return static_cast("\0-+ "[s]); +} template FMT_CONSTEXPR auto count_digits_fallback(T n) -> int { int count = 1; @@ -916,23 +959,33 @@ FMT_CONSTEXPR inline auto count_digits(uint128_t n) -> int { } #endif +#ifdef FMT_BUILTIN_CLZLL +// It is a separate function rather than a part of count_digits to workaround +// the lack of static constexpr in constexpr functions. +inline auto do_count_digits(uint64_t n) -> int { + // This has comparable performance to the version by Kendall Willets + // (https://github.com/fmtlib/format-benchmark/blob/master/digits10) + // but uses smaller tables. + // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). + static constexpr uint8_t bsr2log10[] = { + 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, + 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, + 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; + auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; + static constexpr const uint64_t zero_or_powers_of_10[] = { + 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL), + 10000000000000000000ULL}; + return t - (n < zero_or_powers_of_10[t]); +} +#endif + // Returns the number of decimal digits in n. Leading zeros are not counted // except for n == 0 in which case count_digits returns 1. FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int { #ifdef FMT_BUILTIN_CLZLL if (!is_constant_evaluated()) { - // https://github.com/fmtlib/format-benchmark/blob/master/digits10 - // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). - constexpr uint16_t bsr2log10[] = { - 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, - 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, - 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, - 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; - auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; - constexpr const uint64_t zero_or_powers_of_10[] = { - 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL), - 10000000000000000000ULL}; - return t - (n < zero_or_powers_of_10[t]); + return do_count_digits(n); } #endif return count_digits_fallback(n); @@ -945,21 +998,25 @@ FMT_CONSTEXPR auto count_digits(UInt n) -> int { if (num_bits() == 32) return (FMT_BUILTIN_CLZ(static_cast(n) | 1) ^ 31) / BITS + 1; #endif - int num_digits = 0; - do { - ++num_digits; - } while ((n >>= BITS) != 0); - return num_digits; + // Lambda avoids unreachable code warnings from NVHPC. + return [](UInt m) { + int num_digits = 0; + do { + ++num_digits; + } while ((m >>= BITS) != 0); + return num_digits; + }(n); } template <> auto count_digits<4>(detail::fallback_uintptr n) -> int; +#ifdef FMT_BUILTIN_CLZ // It is a separate function rather than a part of count_digits to workaround // the lack of static constexpr in constexpr functions. -FMT_INLINE uint64_t count_digits_inc(int n) { - // An optimization by Kendall Willets from https://bit.ly/3uOIQrB. - // This increments the upper 32 bits (log10(T) - 1) when >= T is added. -#define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T) +FMT_INLINE auto do_count_digits(uint32_t n) -> int { +// An optimization by Kendall Willets from https://bit.ly/3uOIQrB. +// This increments the upper 32 bits (log10(T) - 1) when >= T is added. +# define FMT_INC(T) (((sizeof(# T) - 1ull) << 32) - T) static constexpr uint64_t table[] = { FMT_INC(0), FMT_INC(0), FMT_INC(0), // 8 FMT_INC(10), FMT_INC(10), FMT_INC(10), // 64 @@ -973,15 +1030,16 @@ FMT_INLINE uint64_t count_digits_inc(int n) { FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000), // 1024M FMT_INC(1000000000), FMT_INC(1000000000) // 4B }; - return table[n]; + auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31]; + return static_cast((n + inc) >> 32); } +#endif // Optional version of count_digits for better performance on 32-bit platforms. FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int { #ifdef FMT_BUILTIN_CLZ if (!is_constant_evaluated()) { - auto inc = count_digits_inc(FMT_BUILTIN_CLZ(n | 1) ^ 31); - return static_cast((n + inc) >> 32); + return do_count_digits(n); } #endif return count_digits_fallback(n); @@ -1032,11 +1090,15 @@ inline auto equal2(const char* lhs, const char* rhs) -> bool { } // Copies two characters from src to dst. -template void copy2(Char* dst, const char* src) { +template +FMT_CONSTEXPR20 FMT_INLINE void copy2(Char* dst, const char* src) { + if (!is_constant_evaluated() && sizeof(Char) == sizeof(char)) { + memcpy(dst, src, 2); + return; + } *dst++ = static_cast(*src++); *dst = static_cast(*src); } -FMT_INLINE void copy2(char* dst, const char* src) { memcpy(dst, src, 2); } template struct format_decimal_result { Iterator begin; @@ -1052,20 +1114,12 @@ FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size) FMT_ASSERT(size >= count_digits(value), "invalid digit count"); out += size; Char* end = out; - if (is_constant_evaluated()) { - while (value >= 10) { - *--out = static_cast('0' + value % 10); - value /= 10; - } - *--out = static_cast('0' + value); - return {out, end}; - } while (value >= 100) { // Integer division is slow so do it for a group of two digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. out -= 2; - copy2(out, data::digits[value % 100]); + copy2(out, digits2(static_cast(value % 100))); value /= 100; } if (value < 10) { @@ -1073,7 +1127,7 @@ FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size) return {out, end}; } out -= 2; - copy2(out, data::digits[value]); + copy2(out, digits2(static_cast(value))); return {out, end}; } @@ -1093,7 +1147,7 @@ FMT_CONSTEXPR auto format_uint(Char* buffer, UInt value, int num_digits, buffer += num_digits; Char* end = buffer; do { - const char* digits = upper ? "0123456789ABCDEF" : data::hex_digits; + const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; unsigned digit = (value & ((1 << BASE_BITS) - 1)); *--buffer = static_cast(BASE_BITS < 4 ? static_cast('0' + digit) : digits[digit]); @@ -1116,7 +1170,7 @@ auto format_uint(Char* buffer, detail::fallback_uintptr n, int num_digits, auto p = buffer; for (int i = 0; i < char_digits; ++i) { unsigned digit = (value & ((1 << BASE_BITS) - 1)); - *--p = static_cast(data::hex_digits[digit]); + *--p = static_cast("0123456789abcdef"[digit]); value >>= BASE_BITS; } } @@ -1226,7 +1280,7 @@ constexpr auto exponent_mask() -> // Writes the exponent exp in the form "[+-]d{2,3}" to buffer. template -auto write_exponent(int exp, It it) -> It { +FMT_CONSTEXPR auto write_exponent(int exp, It it) -> It { FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range"); if (exp < 0) { *it++ = static_cast('-'); @@ -1235,28 +1289,31 @@ auto write_exponent(int exp, It it) -> It { *it++ = static_cast('+'); } if (exp >= 100) { - const char* top = data::digits[exp / 100]; + const char* top = digits2(to_unsigned(exp / 100)); if (exp >= 1000) *it++ = static_cast(top[0]); *it++ = static_cast(top[1]); exp %= 100; } - const char* d = data::digits[exp]; + const char* d = digits2(to_unsigned(exp)); *it++ = static_cast(d[0]); *it++ = static_cast(d[1]); return it; } template -auto format_float(T value, int precision, float_specs specs, buffer& buf) - -> int; +FMT_HEADER_ONLY_CONSTEXPR20 auto format_float(T value, int precision, + float_specs specs, + buffer& buf) -> int; // Formats a floating-point number with snprintf. template auto snprintf_float(T value, int precision, float_specs specs, buffer& buf) -> int; -template auto promote_float(T value) -> T { return value; } -inline auto promote_float(float value) -> double { +template constexpr auto promote_float(T value) -> T { + return value; +} +constexpr auto promote_float(float value) -> double { return static_cast(value); } @@ -1282,8 +1339,9 @@ FMT_CONSTEXPR auto write_padded(OutputIt out, static_assert(align == align::left || align == align::right, ""); unsigned spec_width = to_unsigned(specs.width); size_t padding = spec_width > width ? spec_width - width : 0; - auto* shifts = align == align::left ? data::left_padding_shifts - : data::right_padding_shifts; + // Shifts are encoded as string literals because static constexpr is not + // supported in constexpr functions. + auto* shifts = align == align::left ? "\x1f\x1f\x00\x01" : "\x00\x1f\x00\x01"; size_t left_padding = padding >> shifts[specs.align]; size_t right_padding = padding - left_padding; auto it = reserve(out, size + padding * specs.fill.size()); @@ -1393,56 +1451,91 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits, }); } +template class digit_grouping { + private: + thousands_sep_result sep_; + + struct next_state { + std::string::const_iterator group; + int pos; + }; + next_state initial_state() const { return {sep_.grouping.begin(), 0}; } + + // Returns the next digit group separator position. + int next(next_state& state) const { + if (!sep_.thousands_sep) return max_value(); + if (state.group == sep_.grouping.end()) + return state.pos += sep_.grouping.back(); + if (*state.group <= 0 || *state.group == max_value()) + return max_value(); + state.pos += *state.group++; + return state.pos; + } + + public: + explicit digit_grouping(locale_ref loc, bool localized = true) { + if (localized) + sep_ = thousands_sep(loc); + else + sep_.thousands_sep = Char(); + } + explicit digit_grouping(thousands_sep_result sep) : sep_(sep) {} + + Char separator() const { return sep_.thousands_sep; } + + int count_separators(int num_digits) const { + int count = 0; + auto state = initial_state(); + while (num_digits > next(state)) ++count; + return count; + } + + // Applies grouping to digits and write the output to out. + template + Out apply(Out out, basic_string_view digits) const { + auto num_digits = static_cast(digits.size()); + auto separators = basic_memory_buffer(); + separators.push_back(0); + auto state = initial_state(); + while (int i = next(state)) { + if (i >= num_digits) break; + separators.push_back(i); + } + for (int i = 0, sep_index = static_cast(separators.size() - 1); + i < num_digits; ++i) { + if (num_digits - i == separators[sep_index]) { + *out++ = separator(); + --sep_index; + } + *out++ = static_cast(digits[to_unsigned(i)]); + } + return out; + } +}; + +template +auto write_int_localized(OutputIt out, UInt value, unsigned prefix, + const basic_format_specs& specs, + const digit_grouping& grouping) -> OutputIt { + static_assert(std::is_same, UInt>::value, ""); + int num_digits = count_digits(value); + char digits[40]; + format_decimal(digits, value, num_digits); + unsigned size = to_unsigned((prefix != 0 ? 1 : 0) + num_digits + + grouping.count_separators(num_digits)); + return write_padded( + out, specs, size, size, [&](reserve_iterator it) { + if (prefix != 0) *it++ = static_cast(prefix); + return grouping.apply(it, string_view(digits, to_unsigned(num_digits))); + }); +} + template auto write_int_localized(OutputIt& out, UInt value, unsigned prefix, const basic_format_specs& specs, locale_ref loc) -> bool { - static_assert(std::is_same, UInt>::value, ""); - const auto sep_size = 1; - auto ts = thousands_sep(loc); - if (!ts.thousands_sep) return false; - int num_digits = count_digits(value); - int size = num_digits, n = num_digits; - const std::string& groups = ts.grouping; - std::string::const_iterator group = groups.cbegin(); - while (group != groups.cend() && n > *group && *group > 0 && - *group != max_value()) { - size += sep_size; - n -= *group; - ++group; - } - if (group == groups.cend()) size += sep_size * ((n - 1) / groups.back()); - char digits[40]; - format_decimal(digits, value, num_digits); - basic_memory_buffer buffer; - if (prefix != 0) ++size; - const auto usize = to_unsigned(size); - buffer.resize(usize); - basic_string_view s(&ts.thousands_sep, sep_size); - // Index of a decimal digit with the least significant digit having index 0. - int digit_index = 0; - group = groups.cbegin(); - auto p = buffer.data() + size - 1; - for (int i = num_digits - 1; i > 0; --i) { - *p-- = static_cast(digits[i]); - if (*group <= 0 || ++digit_index % *group != 0 || - *group == max_value()) - continue; - if (group + 1 != groups.cend()) { - digit_index = 0; - ++group; - } - std::uninitialized_copy(s.data(), s.data() + s.size(), - make_checked(p, s.size())); - p -= s.size(); - } - *p-- = static_cast(*digits); - if (prefix != 0) *p = static_cast(prefix); - auto data = buffer.data(); - out = write_padded( - out, specs, usize, usize, [=](reserve_iterator it) { - return copy_str(data, data + size, it); - }); + auto grouping = digit_grouping(loc); + out = write_int_localized(out, value, prefix, specs, grouping); return true; } @@ -1465,7 +1558,9 @@ FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign) prefix = 0x01000000 | '-'; abs_value = 0 - abs_value; } else { - prefix = data::prefixes[sign]; + constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', + 0x1000000u | ' '}; + prefix = prefixes[sign]; } return {abs_value, prefix}; } @@ -1477,10 +1572,9 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, static_assert(std::is_same>::value, ""); auto abs_value = arg.abs_value; auto prefix = arg.prefix; - auto utype = static_cast(specs.type); switch (specs.type) { - case 0: - case 'd': { + case presentation_type::none: + case presentation_type::dec: { if (specs.localized && write_int_localized(out, static_cast>(abs_value), prefix, specs, loc)) { @@ -1492,52 +1586,61 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, return format_decimal(it, abs_value, num_digits).end; }); } - case 'x': - case 'X': { - if (specs.alt) prefix_append(prefix, (utype << 8) | '0'); - bool upper = specs.type != 'x'; + case presentation_type::hex_lower: + case presentation_type::hex_upper: { + bool upper = specs.type == presentation_type::hex_upper; + if (specs.alt) + prefix_append(prefix, unsigned(upper ? 'X' : 'x') << 8 | '0'); int num_digits = count_digits<4>(abs_value); return write_int( out, num_digits, prefix, specs, [=](reserve_iterator it) { return format_uint<4, Char>(it, abs_value, num_digits, upper); }); } - case 'b': - case 'B': { - if (specs.alt) prefix_append(prefix, (utype << 8) | '0'); + case presentation_type::bin_lower: + case presentation_type::bin_upper: { + bool upper = specs.type == presentation_type::bin_upper; + if (specs.alt) + prefix_append(prefix, unsigned(upper ? 'B' : 'b') << 8 | '0'); int num_digits = count_digits<1>(abs_value); return write_int(out, num_digits, prefix, specs, [=](reserve_iterator it) { return format_uint<1, Char>(it, abs_value, num_digits); }); } - case 'o': { + case presentation_type::oct: { int num_digits = count_digits<3>(abs_value); - if (specs.alt && specs.precision <= num_digits && abs_value != 0) { - // Octal prefix '0' is counted as a digit, so only add it if precision - // is not greater than the number of digits. + // Octal prefix '0' is counted as a digit, so only add it if precision + // is not greater than the number of digits. + if (specs.alt && specs.precision <= num_digits && abs_value != 0) prefix_append(prefix, '0'); - } return write_int(out, num_digits, prefix, specs, [=](reserve_iterator it) { return format_uint<3, Char>(it, abs_value, num_digits); }); } - case 'c': + case presentation_type::chr: return write_char(out, static_cast(abs_value), specs); default: - FMT_THROW(format_error("invalid type specifier")); + throw_format_error("invalid type specifier"); } return out; } +template +FMT_CONSTEXPR FMT_NOINLINE auto write_int_noinline( + OutputIt out, write_int_arg arg, const basic_format_specs& specs, + locale_ref loc) -> OutputIt { + return write_int(out, arg, specs, loc); +} template ::value && !std::is_same::value && std::is_same>::value)> -FMT_CONSTEXPR auto write(OutputIt out, T value, - const basic_format_specs& specs, locale_ref loc) - -> OutputIt { - return write_int(out, make_write_int_arg(value, specs.sign), specs, loc); +FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, + const basic_format_specs& specs, + locale_ref loc) -> OutputIt { + return write_int_noinline(out, make_write_int_arg(value, specs.sign), specs, + loc); } // An inlined version of write used in format string compilation. template -auto write_nonfinite(OutputIt out, bool isinf, basic_format_specs specs, - const float_specs& fspecs) -> OutputIt { +FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isinf, + basic_format_specs specs, + const float_specs& fspecs) -> OutputIt { auto str = isinf ? (fspecs.upper ? "INF" : "inf") : (fspecs.upper ? "NAN" : "nan"); constexpr size_t str_size = 3; @@ -1594,7 +1698,7 @@ auto write_nonfinite(OutputIt out, bool isinf, basic_format_specs specs, specs.fill.size() == 1 && *specs.fill.data() == static_cast('0'); if (is_zero_fill) specs.fill[0] = static_cast(' '); return write_padded(out, specs, size, [=](reserve_iterator it) { - if (sign) *it++ = static_cast(data::signs[sign]); + if (sign) *it++ = detail::sign(sign); return copy_str(str, str + str_size, it); }); } @@ -1606,7 +1710,7 @@ struct big_decimal_fp { int exponent; }; -inline auto get_significand_size(const big_decimal_fp& fp) -> int { +constexpr auto get_significand_size(const big_decimal_fp& fp) -> int { return fp.significand_size; } template @@ -1615,8 +1719,8 @@ inline auto get_significand_size(const dragonbox::decimal_fp& fp) -> int { } template -inline auto write_significand(OutputIt out, const char* significand, - int& significand_size) -> OutputIt { +constexpr auto write_significand(OutputIt out, const char* significand, + int significand_size) -> OutputIt { return copy_str(significand, significand + significand_size, out); } template @@ -1624,6 +1728,19 @@ inline auto write_significand(OutputIt out, UInt significand, int significand_size) -> OutputIt { return format_decimal(out, significand, significand_size).end; } +template +FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, + int significand_size, int exponent, + const Grouping& grouping) -> OutputIt { + if (!grouping.separator()) { + out = write_significand(out, significand, significand_size); + return detail::fill_n(out, exponent, static_cast('0')); + } + auto buffer = memory_buffer(); + write_significand(appender(buffer), significand, significand_size); + detail::fill_n(appender(buffer), exponent, '0'); + return grouping.apply(out, string_view(buffer.data(), buffer.size())); +} template ::value)> @@ -1631,14 +1748,20 @@ inline auto write_significand(Char* out, UInt significand, int significand_size, int integral_size, Char decimal_point) -> Char* { if (!decimal_point) return format_decimal(out, significand, significand_size).end; - auto end = format_decimal(out + 1, significand, significand_size).end; - if (integral_size == 1) { - out[0] = out[1]; - } else { - std::uninitialized_copy_n(out + 1, integral_size, - make_checked(out, to_unsigned(integral_size))); + out += significand_size + 1; + Char* end = out; + int floating_size = significand_size - integral_size; + for (int i = floating_size / 2; i > 0; --i) { + out -= 2; + copy2(out, digits2(significand % 100)); + significand /= 100; } - out[integral_size] = decimal_point; + if (floating_size % 2 != 0) { + *--out = static_cast('0' + significand % 10); + significand /= 10; + } + *--out = decimal_point; + format_decimal(out - integral_size, significand, integral_size); return end; } @@ -1655,9 +1778,9 @@ inline auto write_significand(OutputIt out, UInt significand, } template -inline auto write_significand(OutputIt out, const char* significand, - int significand_size, int integral_size, - Char decimal_point) -> OutputIt { +FMT_CONSTEXPR auto write_significand(OutputIt out, const char* significand, + int significand_size, int integral_size, + Char decimal_point) -> OutputIt { out = detail::copy_str_noinline(significand, significand + integral_size, out); if (!decimal_point) return out; @@ -1666,17 +1789,40 @@ inline auto write_significand(OutputIt out, const char* significand, significand + significand_size, out); } -template -auto write_float(OutputIt out, const DecimalFP& fp, - const basic_format_specs& specs, float_specs fspecs, - Char decimal_point) -> OutputIt { +template +FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, + int significand_size, int integral_size, + Char decimal_point, + const Grouping& grouping) -> OutputIt { + if (!grouping.separator()) { + return write_significand(out, significand, significand_size, integral_size, + decimal_point); + } + auto buffer = basic_memory_buffer(); + write_significand(buffer_appender(buffer), significand, + significand_size, integral_size, decimal_point); + grouping.apply( + out, basic_string_view(buffer.data(), to_unsigned(integral_size))); + return detail::copy_str_noinline(buffer.data() + integral_size, + buffer.end(), out); +} + +template > +FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& fp, + const basic_format_specs& specs, + float_specs fspecs, locale_ref loc) + -> OutputIt { auto significand = fp.significand; int significand_size = get_significand_size(fp); - static const Char zero = static_cast('0'); + constexpr Char zero = static_cast('0'); auto sign = fspecs.sign; size_t size = to_unsigned(significand_size) + (sign ? 1 : 0); using iterator = reserve_iterator; + Char decimal_point = + fspecs.locale ? detail::decimal_point(loc) : static_cast('.'); + int output_exp = fp.exponent + significand_size - 1; auto use_exp_format = [=]() { if (fspecs.format == float_format::exp) return true; @@ -1703,7 +1849,7 @@ auto write_float(OutputIt out, const DecimalFP& fp, size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits); char exp_char = fspecs.upper ? 'E' : 'e'; auto write = [=](iterator it) { - if (sign) *it++ = static_cast(data::signs[sign]); + if (sign) *it++ = detail::sign(sign); // Insert a decimal point after the first digit and add an exponent. it = write_significand(it, significand, significand_size, 1, decimal_point); @@ -1728,10 +1874,12 @@ auto write_float(OutputIt out, const DecimalFP& fp, if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 1; if (num_zeros > 0) size += to_unsigned(num_zeros) + 1; } + auto grouping = Grouping(loc, fspecs.locale); + size += to_unsigned(grouping.count_separators(significand_size)); return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = static_cast(data::signs[sign]); - it = write_significand(it, significand, significand_size); - it = detail::fill_n(it, fp.exponent, zero); + if (sign) *it++ = detail::sign(sign); + it = write_significand(it, significand, significand_size, + fp.exponent, grouping); if (!fspecs.showpoint) return it; *it++ = decimal_point; return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; @@ -1740,10 +1888,12 @@ auto write_float(OutputIt out, const DecimalFP& fp, // 1234e-2 -> 12.34[0+] int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0; size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0); + auto grouping = Grouping(loc, fspecs.locale); + size += to_unsigned(grouping.count_separators(significand_size)); return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = static_cast(data::signs[sign]); + if (sign) *it++ = detail::sign(sign); it = write_significand(it, significand, significand_size, exp, - decimal_point); + decimal_point, grouping); return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; }); } @@ -1756,7 +1906,7 @@ auto write_float(OutputIt out, const DecimalFP& fp, bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint; size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros); return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = static_cast(data::signs[sign]); + if (sign) *it++ = detail::sign(sign); *it++ = zero; if (!pointy) return it; *it++ = decimal_point; @@ -1765,26 +1915,97 @@ auto write_float(OutputIt out, const DecimalFP& fp, }); } +template class fallback_digit_grouping { + public: + constexpr fallback_digit_grouping(locale_ref, bool) {} + + constexpr Char separator() const { return Char(); } + + constexpr int count_separators(int) const { return 0; } + + template + constexpr Out apply(Out out, basic_string_view) const { + return out; + } +}; + +template +FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& fp, + const basic_format_specs& specs, + float_specs fspecs, locale_ref loc) + -> OutputIt { + if (is_constant_evaluated()) { + return do_write_float>(out, fp, specs, fspecs, + loc); + } else { + return do_write_float(out, fp, specs, fspecs, loc); + } +} + +template ::value)> +FMT_CONSTEXPR20 bool isinf(T value) { + if (is_constant_evaluated()) { +#if defined(__cpp_if_constexpr) + if constexpr (std::numeric_limits::is_iec559) { + auto bits = detail::bit_cast(static_cast(value)); + constexpr auto significand_bits = + dragonbox::float_info::significand_bits; + return (bits & exponent_mask()) && + !(bits & ((uint64_t(1) << significand_bits) - 1)); + } +#endif + } + return std::isinf(value); +} + +template ::value)> +FMT_CONSTEXPR20 bool isfinite(T value) { + if (is_constant_evaluated()) { +#if defined(__cpp_if_constexpr) + if constexpr (std::numeric_limits::is_iec559) { + auto bits = detail::bit_cast(static_cast(value)); + return (bits & exponent_mask()) != exponent_mask(); + } +#endif + } + return std::isfinite(value); +} + +template ::value)> +FMT_INLINE FMT_CONSTEXPR bool signbit(T value) { + if (is_constant_evaluated()) { +#ifdef __cpp_if_constexpr + if constexpr (std::numeric_limits::is_iec559) { + auto bits = detail::bit_cast(static_cast(value)); + return (bits & (uint64_t(1) << (num_bits() - 1))) != 0; + } +#endif + } + return std::signbit(value); +} + template ::value)> -auto write(OutputIt out, T value, basic_format_specs specs, - locale_ref loc = {}) -> OutputIt { +FMT_CONSTEXPR20 auto write(OutputIt out, T value, + basic_format_specs specs, locale_ref loc = {}) + -> OutputIt { if (const_check(!is_supported_floating_point(value))) return out; float_specs fspecs = parse_float_type_spec(specs); fspecs.sign = specs.sign; - if (std::signbit(value)) { // value < 0 is false for NaN so use signbit. + if (detail::signbit(value)) { // value < 0 is false for NaN so use signbit. fspecs.sign = sign::minus; value = -value; } else if (fspecs.sign == sign::minus) { fspecs.sign = sign::none; } - if (!std::isfinite(value)) - return write_nonfinite(out, std::isinf(value), specs, fspecs); + if (!detail::isfinite(value)) + return write_nonfinite(out, detail::isinf(value), specs, fspecs); if (specs.align == align::numeric && fspecs.sign) { auto it = reserve(out, 1); - *it++ = static_cast(data::signs[fspecs.sign]); + *it++ = detail::sign(fspecs.sign); out = base_iterator(out, it); fspecs.sign = sign::none; if (specs.width != 0) --specs.width; @@ -1792,31 +2013,35 @@ auto write(OutputIt out, T value, basic_format_specs specs, memory_buffer buffer; if (fspecs.format == float_format::hex) { - if (fspecs.sign) buffer.push_back(data::signs[fspecs.sign]); + if (fspecs.sign) buffer.push_back(detail::sign(fspecs.sign)); snprintf_float(promote_float(value), specs.precision, fspecs, buffer); return write_bytes(out, {buffer.data(), buffer.size()}, specs); } - int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6; + int precision = specs.precision >= 0 || specs.type == presentation_type::none + ? specs.precision + : 6; if (fspecs.format == float_format::exp) { if (precision == max_value()) - FMT_THROW(format_error("number is too big")); + throw_format_error("number is too big"); else ++precision; } if (const_check(std::is_same())) fspecs.binary32 = true; - fspecs.use_grisu = is_fast_float(); + if (!is_fast_float()) fspecs.fallback = true; int exp = format_float(promote_float(value), precision, fspecs, buffer); fspecs.precision = precision; - Char point = - fspecs.locale ? decimal_point(loc) : static_cast('.'); auto fp = big_decimal_fp{buffer.data(), static_cast(buffer.size()), exp}; - return write_float(out, fp, specs, fspecs, point); + return write_float(out, fp, specs, fspecs, loc); } template ::value)> -auto write(OutputIt out, T value) -> OutputIt { +FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt { + if (is_constant_evaluated()) { + return write(out, value, basic_format_specs()); + } + if (const_check(!is_supported_floating_point(value))) return out; using floaty = conditional_t::value, double, T>; @@ -1824,19 +2049,18 @@ auto write(OutputIt out, T value) -> OutputIt { auto bits = bit_cast(value); auto fspecs = float_specs(); - auto sign_bit = bits & (uint(1) << (num_bits() - 1)); - if (sign_bit != 0) { + if (detail::signbit(value)) { fspecs.sign = sign::minus; value = -value; } - static const auto specs = basic_format_specs(); + constexpr auto specs = basic_format_specs(); uint mask = exponent_mask(); if ((bits & mask) == mask) return write_nonfinite(out, std::isinf(value), specs, fspecs); auto dec = dragonbox::to_decimal(static_cast(value)); - return write_float(out, dec, specs, fspecs, static_cast('.')); + return write_float(out, dec, specs, fspecs, {}); } template OutputIt { return base_iterator(out, it); } -// FMT_ENABLE_IF() condition separated to workaround MSVC bug +// FMT_ENABLE_IF() condition separated to workaround an MSVC bug. template < typename Char, typename OutputIt, typename T, bool check = @@ -1907,7 +2131,8 @@ template & specs = {}, locale_ref = {}) -> OutputIt { - return specs.type && specs.type != 's' + return specs.type != presentation_type::none && + specs.type != presentation_type::string ? write(out, value ? 1 : 0, specs, {}) : write_bytes(out, value ? "true" : "false", specs); } @@ -1923,10 +2148,9 @@ template FMT_CONSTEXPR_CHAR_TRAITS auto write(OutputIt out, const Char* value) -> OutputIt { if (!value) { - FMT_THROW(format_error("string pointer is null")); + throw_format_error("string pointer is null"); } else { - auto length = std::char_traits::length(value); - out = write(out, basic_string_view(value, length)); + out = write(out, basic_string_view(value)); } return out; } @@ -1940,18 +2164,28 @@ auto write(OutputIt out, const T* value, return write_ptr(out, to_uintptr(value), &specs); } -template -FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> - typename std::enable_if< - mapped_type_constant>::value == - type::custom_type, - OutputIt>::type { - using context_type = basic_format_context; +// A write overload that handles implicit conversions. +template > +FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> enable_if_t< + std::is_class::value && !is_string::value && + !std::is_same::value && + !std::is_same().map(value))>::value, + OutputIt> { + return write(out, arg_mapper().map(value)); +} + +template > +FMT_CONSTEXPR auto write(OutputIt out, const T& value) + -> enable_if_t::value == type::custom_type, + OutputIt> { using formatter_type = - conditional_t::value, - typename context_type::template formatter_type, + conditional_t::value, + typename Context::template formatter_type, fallback_formatter>; - context_type ctx(out, {}, {}); + auto ctx = Context(out, {}, {}); return formatter_type().format(value, ctx); } @@ -2368,6 +2602,7 @@ FMT_FORMAT_AS(unsigned long, unsigned long long); FMT_FORMAT_AS(Char*, const Char*); FMT_FORMAT_AS(std::basic_string, basic_string_view); FMT_FORMAT_AS(std::nullptr_t, const void*); +FMT_FORMAT_AS(detail::byte, unsigned char); FMT_FORMAT_AS(detail::std_string_view, basic_string_view); template @@ -2493,6 +2728,52 @@ template <> struct formatter { } }; +// group_digits_view is not derived from view because it copies the argument. +template struct group_digits_view { T value; }; + +/** + \rst + Returns a view that formats an integer value using ',' as a locale-independent + thousands separator. + + **Example**:: + + fmt::print("{}", fmt::group_digits(12345)); + // Output: "12,345" + \endrst + */ +template auto group_digits(T value) -> group_digits_view { + return {value}; +} + +template struct formatter> : formatter { + private: + detail::dynamic_format_specs specs_; + + public: + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + using handler_type = detail::dynamic_specs_handler; + detail::specs_checker handler(handler_type(specs_, ctx), + detail::type::int_type); + auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); + detail::check_string_type_spec(specs_.type, ctx.error_handler()); + return it; + } + + template + auto format(group_digits_view t, FormatContext& ctx) + -> decltype(ctx.out()) { + detail::handle_dynamic_spec(specs_.width, + specs_.width_ref, ctx); + detail::handle_dynamic_spec( + specs_.precision, specs_.precision_ref, ctx); + return detail::write_int_localized( + ctx.out(), static_cast>(t.value), 0, specs_, + detail::digit_grouping({"\3", ','})); + } +}; + template struct join_view : detail::view { It begin; @@ -2509,7 +2790,12 @@ using arg_join FMT_DEPRECATED_ALIAS = join_view; template struct formatter, Char> { private: - using value_type = typename std::iterator_traits::value_type; + using value_type = +#ifdef __cpp_lib_ranges + std::iter_value_t; +#else + typename std::iterator_traits::value_type; +#endif using context = buffer_context; using mapper = detail::arg_mapper; @@ -2543,11 +2829,13 @@ struct formatter, Char> { auto it = value.begin; auto out = ctx.out(); if (it != value.end) { - out = value_formatter_.format(map(*it++), ctx); + out = value_formatter_.format(map(*it), ctx); + ++it; while (it != value.end) { out = detail::copy_str(value.sep.begin(), value.sep.end(), out); ctx.advance_to(out); - out = value_formatter_.format(map(*it++), ctx); + out = value_formatter_.format(map(*it), ctx); + ++it; } } return out; @@ -2555,8 +2843,8 @@ struct formatter, Char> { }; /** - Returns an object that formats the iterator range `[begin, end)` with - elements separated by `sep`. + Returns a view that formats the iterator range `[begin, end)` with elements + separated by `sep`. */ template auto join(It begin, Sentinel end, string_view sep) -> join_view { @@ -2565,7 +2853,7 @@ auto join(It begin, Sentinel end, string_view sep) -> join_view { /** \rst - Returns an object that formats `range` with elements separated by `sep`. + Returns a view that formats `range` with elements separated by `sep`. **Example**:: @@ -2604,7 +2892,7 @@ inline auto to_string(const T& value) -> std::string { } template ::value)> -inline auto to_string(T value) -> std::string { +FMT_NODISCARD inline auto to_string(T value) -> std::string { // The buffer should be large enough to store the number including the sign // or "false" for bool. constexpr int max_size = detail::digits10() + 2; @@ -2614,7 +2902,7 @@ inline auto to_string(T value) -> std::string { } template -auto to_string(const basic_memory_buffer& buf) +FMT_NODISCARD auto to_string(const basic_memory_buffer& buf) -> std::basic_string { auto size = buf.size(); detail::assume(size < std::basic_string().max_size()); @@ -2757,16 +3045,14 @@ constexpr auto operator"" _a(const char* s, size_t) -> detail::udl_arg { # endif /** - \rst - User-defined literal equivalent of :func:`fmt::format`. + DEPRECATED! User-defined literal equivalent of fmt::format. **Example**:: using namespace fmt::literals; std::string message = "The answer is {}"_format(42); - \endrst */ -constexpr auto operator"" _format(const char* s, size_t n) +FMT_DEPRECATED constexpr auto operator"" _format(const char* s, size_t n) -> detail::udl_formatter { return {{s, n}}; } diff --git a/src/fmt/os.h b/src/fmt/os.h index f6c0f32985..b64f8bbfa5 100644 --- a/src/fmt/os.h +++ b/src/fmt/os.h @@ -21,17 +21,20 @@ #include "format.h" +#ifndef FMT_USE_FCNTL // UWP doesn't provide _pipe. -#if FMT_HAS_INCLUDE("winapifamily.h") -# include -#endif -#if (FMT_HAS_INCLUDE() || defined(__APPLE__) || \ - defined(__linux__)) && \ - (!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) -# include // for O_RDONLY -# define FMT_USE_FCNTL 1 -#else -# define FMT_USE_FCNTL 0 +# if FMT_HAS_INCLUDE("winapifamily.h") +# include +# endif +# if (FMT_HAS_INCLUDE() || defined(__APPLE__) || \ + defined(__linux__)) && \ + (!defined(WINAPI_FAMILY) || \ + (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) +# include // for O_RDONLY +# define FMT_USE_FCNTL 1 +# else +# define FMT_USE_FCNTL 0 +# endif #endif #ifndef FMT_POSIX @@ -390,23 +393,26 @@ struct ostream_params { : ostream_params(params...) { this->buffer_size = bs.value; } + +// Intel has a bug that results in failure to deduce a constructor +// for empty parameter packs. +# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000 + ostream_params(int new_oflag) : oflag(new_oflag) {} + ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {} +# endif }; FMT_END_DETAIL_NAMESPACE -constexpr detail::buffer_size buffer_size; +// Added {} below to work around default constructor error known to +// occur in Xcode versions 7.2.1 and 8.2.1. +constexpr detail::buffer_size buffer_size{}; /** A fast output stream which is not thread-safe. */ class FMT_API ostream final : private detail::buffer { private: file file_; - void flush() { - if (size() == 0) return; - file_.write(data(), size()); - clear(); - } - void grow(size_t) override; ostream(cstring_view path, const detail::ostream_params& params) @@ -426,6 +432,12 @@ class FMT_API ostream final : private detail::buffer { delete[] data(); } + void flush() { + if (size() == 0) return; + file_.write(data(), size()); + clear(); + } + template friend ostream output_file(cstring_view path, T... params); @@ -500,7 +512,7 @@ class locale { // Converts string to floating-point number and advances str past the end // of the parsed input. - double strtod(const char*& str) const { + FMT_DEPRECATED double strtod(const char*& str) const { char* end = nullptr; double result = strtod_l(str, &end, locale_); str = end; diff --git a/src/fmt/ostream.h b/src/fmt/ostream.h index d66248a601..3d716ece84 100644 --- a/src/fmt/ostream.h +++ b/src/fmt/ostream.h @@ -14,73 +14,20 @@ FMT_BEGIN_NAMESPACE -template class basic_printf_parse_context; template class basic_printf_context; namespace detail { -template class formatbuf : public std::basic_streambuf { - private: - using int_type = typename std::basic_streambuf::int_type; - using traits_type = typename std::basic_streambuf::traits_type; - - buffer& buffer_; - - public: - formatbuf(buffer& buf) : buffer_(buf) {} - - protected: - // The put-area is actually always empty. This makes the implementation - // simpler and has the advantage that the streambuf and the buffer are always - // in sync and sputc never writes into uninitialized memory. The obvious - // disadvantage is that each call to sputc always results in a (virtual) call - // to overflow. There is no disadvantage here for sputn since this always - // results in a call to xsputn. - - int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE { - if (!traits_type::eq_int_type(ch, traits_type::eof())) - buffer_.push_back(static_cast(ch)); - return ch; - } - - std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE { - buffer_.append(s, s + count); - return count; - } -}; - -struct converter { - template ::value)> converter(T); -}; - -template struct test_stream : std::basic_ostream { - private: - void_t<> operator<<(converter); -}; - -// Hide insertion operators for built-in types. -template -void_t<> operator<<(std::basic_ostream&, Char); -template -void_t<> operator<<(std::basic_ostream&, char); -template -void_t<> operator<<(std::basic_ostream&, char); -template -void_t<> operator<<(std::basic_ostream&, signed char); -template -void_t<> operator<<(std::basic_ostream&, unsigned char); - -// Checks if T has a user-defined operator<< (e.g. not a member of -// std::ostream). -template class is_streamable { +// Checks if T has a user-defined operator<<. +template +class is_streamable { private: template - static bool_constant&>() - << std::declval()), - void_t<>>::value> - test(int); + static auto test(int) + -> bool_constant&>() + << std::declval()) != 0>; - template static std::false_type test(...); + template static auto test(...) -> std::false_type; using result = decltype(test(0)); @@ -90,7 +37,21 @@ template class is_streamable { static const bool value = result::value; }; +// Formatting of built-in types and arrays is intentionally disabled because +// it's handled by standard (non-ostream) formatters. +template +struct is_streamable< + T, Char, + enable_if_t< + std::is_arithmetic::value || std::is_array::value || + std::is_pointer::value || std::is_same::value || + std::is_same>::value || + std::is_same>::value || + (std::is_convertible::value && !std::is_enum::value)>> + : std::false_type {}; + // Write the content of buf to os. +// It is a separate function rather than a part of vprint to simplify testing. template void write_buffer(std::basic_ostream& os, buffer& buf) { const Char* buf_data = buf.data(); @@ -108,8 +69,8 @@ void write_buffer(std::basic_ostream& os, buffer& buf) { template void format_value(buffer& buf, const T& value, locale_ref loc = locale_ref()) { - formatbuf format_buf(buf); - std::basic_ostream output(&format_buf); + auto&& format_buf = formatbuf>(buf); + auto&& output = std::basic_ostream(&format_buf); #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) if (loc) output.imbue(loc.get()); #endif @@ -122,29 +83,22 @@ void format_value(buffer& buf, const T& value, template struct fallback_formatter::value>> : private formatter, Char> { - FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) - -> decltype(ctx.begin()) { - return formatter, Char>::parse(ctx); - } - template >::value)> - auto parse(ParseCtx& ctx) -> decltype(ctx.begin()) { - return ctx.begin(); - } + using formatter, Char>::parse; template auto format(const T& value, basic_format_context& ctx) -> OutputIt { - basic_memory_buffer buffer; + auto buffer = basic_memory_buffer(); format_value(buffer, value, ctx.locale()); - basic_string_view str(buffer.data(), buffer.size()); - return formatter, Char>::format(str, ctx); + return formatter, Char>::format( + {buffer.data(), buffer.size()}, ctx); } + + // DEPRECATED! template auto format(const T& value, basic_printf_context& ctx) -> OutputIt { - basic_memory_buffer buffer; + auto buffer = basic_memory_buffer(); format_value(buffer, value, ctx.locale()); return std::copy(buffer.begin(), buffer.end(), ctx.out()); } @@ -155,7 +109,7 @@ FMT_MODULE_EXPORT template void vprint(std::basic_ostream& os, basic_string_view format_str, basic_format_args>> args) { - basic_memory_buffer buffer; + auto buffer = basic_memory_buffer(); detail::vformat_to(buffer, format_str, args); detail::write_buffer(os, buffer); } diff --git a/src/fmt/printf.h b/src/fmt/printf.h index 3a3cd15283..19d550f6cf 100644 --- a/src/fmt/printf.h +++ b/src/fmt/printf.h @@ -233,7 +233,7 @@ class printf_arg_formatter : public arg_formatter { OutputIt write_null_pointer(bool is_string = false) { auto s = this->specs; - s.type = 0; + s.type = presentation_type::none; return write_bytes(this->out, is_string ? "(null)" : "(nil)", s); } @@ -249,8 +249,10 @@ class printf_arg_formatter : public arg_formatter { // std::is_same instead. if (std::is_same::value) { format_specs fmt_specs = this->specs; - if (fmt_specs.type && fmt_specs.type != 'c') + if (fmt_specs.type != presentation_type::none && + fmt_specs.type != presentation_type::chr) { return (*this)(static_cast(value)); + } fmt_specs.sign = sign::none; fmt_specs.alt = false; fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types. @@ -271,13 +273,13 @@ class printf_arg_formatter : public arg_formatter { /** Formats a null-terminated C string. */ OutputIt operator()(const char* value) { if (value) return base::operator()(value); - return write_null_pointer(this->specs.type != 'p'); + return write_null_pointer(this->specs.type != presentation_type::pointer); } /** Formats a null-terminated wide C string. */ OutputIt operator()(const wchar_t* value) { if (value) return base::operator()(value); - return write_null_pointer(this->specs.type != 'p'); + return write_null_pointer(this->specs.type != presentation_type::pointer); } OutputIt operator()(basic_string_view value) { @@ -490,13 +492,13 @@ void vprintf(buffer& buf, basic_string_view format, // Parse type. if (it == end) FMT_THROW(format_error("invalid format string")); - specs.type = static_cast(*it++); + char type = static_cast(*it++); if (arg.is_integral()) { // Normalize type. - switch (specs.type) { + switch (type) { case 'i': case 'u': - specs.type = 'd'; + type = 'd'; break; case 'c': visit_format_arg( @@ -505,6 +507,9 @@ void vprintf(buffer& buf, basic_string_view format, break; } } + specs.type = parse_presentation_type(type); + if (specs.type == presentation_type::none) + parse_ctx.on_error("invalid type specifier"); start = it; diff --git a/src/fmt/ranges.h b/src/fmt/ranges.h index f0390df211..eb9fb8a92d 100644 --- a/src/fmt/ranges.h +++ b/src/fmt/ranges.h @@ -13,37 +13,13 @@ #define FMT_RANGES_H_ #include +#include #include #include "format.h" FMT_BEGIN_NAMESPACE -template struct formatting_range { -#ifdef FMT_DEPRECATED_BRACED_RANGES - Char prefix = '{'; - Char postfix = '}'; -#else - Char prefix = '['; - Char postfix = ']'; -#endif - - template - FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - return ctx.begin(); - } -}; - -template struct formatting_tuple { - Char prefix = '('; - Char postfix = ')'; - - template - FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - return ctx.begin(); - } -}; - namespace detail { template @@ -71,7 +47,7 @@ OutputIterator copy(wchar_t ch, OutputIterator out) { return out; } -/// Return true value if T has std::string interface, like std::string_view. +// Returns true if T has a std::string-like interface, like std::string_view. template class is_std_string_like { template static auto check(U* p) @@ -80,12 +56,40 @@ template class is_std_string_like { public: static FMT_CONSTEXPR_DECL const bool value = - is_string::value || !std::is_void(nullptr))>::value; + is_string::value || + std::is_convertible>::value || + !std::is_void(nullptr))>::value; }; template struct is_std_string_like> : std::true_type {}; +template class is_map { + template static auto check(U*) -> typename U::mapped_type; + template static void check(...); + + public: +#ifdef FMT_FORMAT_MAP_AS_LIST + static FMT_CONSTEXPR_DECL const bool value = false; +#else + static FMT_CONSTEXPR_DECL const bool value = + !std::is_void(nullptr))>::value; +#endif +}; + +template class is_set { + template static auto check(U*) -> typename U::key_type; + template static void check(...); + + public: +#ifdef FMT_FORMAT_SET_AS_LIST + static FMT_CONSTEXPR_DECL const bool value = false; +#else + static FMT_CONSTEXPR_DECL const bool value = + !std::is_void(nullptr))>::value && !is_map::value; +#endif +}; + template struct conditional_helper {}; template struct is_range_ : std::false_type {}; @@ -143,16 +147,16 @@ struct has_mutable_begin_end : std::false_type {}; template struct has_const_begin_end< - T, void_t&>())), - decltype(detail::range_begin( - std::declval&>()))>> + T, + void_t< + decltype(detail::range_begin(std::declval&>())), + decltype(detail::range_end(std::declval&>()))>> : std::true_type {}; template struct has_mutable_begin_end< T, void_t())), - decltype(detail::range_begin(std::declval())), + decltype(detail::range_end(std::declval())), enable_if_t::value>>> : std::true_type {}; @@ -160,34 +164,10 @@ template struct is_range_ : std::integral_constant::value || has_mutable_begin_end::value)> {}; - -template struct range_to_view; -template -struct range_to_view::value>> { - struct view_t { - const T* m_range_ptr; - - auto begin() const FMT_DECLTYPE_RETURN(detail::range_begin(*m_range_ptr)); - auto end() const FMT_DECLTYPE_RETURN(detail::range_end(*m_range_ptr)); - }; - static auto view(const T& range) -> view_t { return {&range}; } -}; - -template -struct range_to_view::value && - has_mutable_begin_end::value>> { - struct view_t { - T m_range_copy; - - auto begin() FMT_DECLTYPE_RETURN(detail::range_begin(m_range_copy)); - auto end() FMT_DECLTYPE_RETURN(detail::range_end(m_range_copy)); - }; - static auto view(const T& range) -> view_t { return {range}; } -}; # undef FMT_DECLTYPE_RETURN #endif -/// tuple_size and tuple_element check. +// tuple_size and tuple_element check. template class is_tuple_like_ { template static auto check(U* p) -> decltype(std::tuple_size::value, int()); @@ -251,16 +231,295 @@ template OutputIt write_delimiter(OutputIt out) { return out; } -template < - typename Char, typename OutputIt, typename Arg, - FMT_ENABLE_IF(is_std_string_like::type>::value)> -OutputIt write_range_entry(OutputIt out, const Arg& v) { +struct singleton { + unsigned char upper; + unsigned char lower_count; +}; + +inline auto is_printable(uint16_t x, const singleton* singletons, + size_t singletons_size, + const unsigned char* singleton_lowers, + const unsigned char* normal, size_t normal_size) + -> bool { + auto upper = x >> 8; + auto lower_start = 0; + for (size_t i = 0; i < singletons_size; ++i) { + auto s = singletons[i]; + auto lower_end = lower_start + s.lower_count; + if (upper < s.upper) break; + if (upper == s.upper) { + for (auto j = lower_start; j < lower_end; ++j) { + if (singleton_lowers[j] == (x & 0xff)) return false; + } + } + lower_start = lower_end; + } + + auto xsigned = static_cast(x); + auto current = true; + for (size_t i = 0; i < normal_size; ++i) { + auto v = static_cast(normal[i]); + auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[++i] : v; + xsigned -= len; + if (xsigned < 0) break; + current = !current; + } + return current; +} + +// Returns true iff the code point cp is printable. +// This code is generated by support/printable.py. +inline auto is_printable(uint32_t cp) -> bool { + static constexpr singleton singletons0[] = { + {0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8}, + {0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13}, + {0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5}, + {0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22}, + {0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3}, + {0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8}, + {0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9}, + }; + static constexpr unsigned char singletons0_lower[] = { + 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90, + 0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f, + 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1, + 0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04, + 0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d, + 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, + 0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, + 0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d, + 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d, + 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, + 0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7, + 0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, + 0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7, + 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, + 0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e, + 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16, + 0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e, + 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f, + 0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, + 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0, + 0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, + 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91, + 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, + 0xfe, 0xff, + }; + static constexpr singleton singletons1[] = { + {0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2}, + {0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5}, + {0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5}, + {0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2}, + {0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5}, + {0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2}, + {0xfa, 2}, {0xfb, 1}, + }; + static constexpr unsigned char singletons1_lower[] = { + 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07, + 0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36, + 0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87, + 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b, + 0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9, + 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66, + 0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, + 0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc, + 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, + 0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6, + 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c, + 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, + 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, + 0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93, + }; + static constexpr unsigned char normal0[] = { + 0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04, + 0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0, + 0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01, + 0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03, + 0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03, + 0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a, + 0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15, + 0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f, + 0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80, + 0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07, + 0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06, + 0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04, + 0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac, + 0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c, + 0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11, + 0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c, + 0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b, + 0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6, + 0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03, + 0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80, + 0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06, + 0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c, + 0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17, + 0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80, + 0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80, + 0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d, + }; + static constexpr unsigned char normal1[] = { + 0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f, + 0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e, + 0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04, + 0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09, + 0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16, + 0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f, + 0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36, + 0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33, + 0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08, + 0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e, + 0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41, + 0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03, + 0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22, + 0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04, + 0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45, + 0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03, + 0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81, + 0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75, + 0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1, + 0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a, + 0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11, + 0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09, + 0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89, + 0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6, + 0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09, + 0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50, + 0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05, + 0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83, + 0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05, + 0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80, + 0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80, + 0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07, + 0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e, + 0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07, + 0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06, + }; + auto lower = static_cast(cp); + if (cp < 0x10000) { + return is_printable(lower, singletons0, + sizeof(singletons0) / sizeof(*singletons0), + singletons0_lower, normal0, sizeof(normal0)); + } + if (cp < 0x20000) { + return is_printable(lower, singletons1, + sizeof(singletons1) / sizeof(*singletons1), + singletons1_lower, normal1, sizeof(normal1)); + } + if (0x2a6de <= cp && cp < 0x2a700) return false; + if (0x2b735 <= cp && cp < 0x2b740) return false; + if (0x2b81e <= cp && cp < 0x2b820) return false; + if (0x2cea2 <= cp && cp < 0x2ceb0) return false; + if (0x2ebe1 <= cp && cp < 0x2f800) return false; + if (0x2fa1e <= cp && cp < 0x30000) return false; + if (0x3134b <= cp && cp < 0xe0100) return false; + if (0xe01f0 <= cp && cp < 0x110000) return false; + return cp < 0x110000; +} + +inline auto needs_escape(uint32_t cp) -> bool { + return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' || + !is_printable(cp); +} + +template struct find_escape_result { + const Char* begin; + const Char* end; + uint32_t cp; +}; + +template +auto find_escape(const Char* begin, const Char* end) + -> find_escape_result { + for (; begin != end; ++begin) { + auto cp = static_cast::type>(*begin); + if (sizeof(Char) == 1 && cp >= 0x80) continue; + if (needs_escape(cp)) return {begin, begin + 1, cp}; + } + return {begin, nullptr, 0}; +} + +inline auto find_escape(const char* begin, const char* end) + -> find_escape_result { + if (!is_utf8()) return find_escape(begin, end); + auto result = find_escape_result{end, nullptr, 0}; + for_each_codepoint(string_view(begin, to_unsigned(end - begin)), + [&](uint32_t cp, string_view sv) { + if (needs_escape(cp)) { + result = {sv.begin(), sv.end(), cp}; + return false; + } + return true; + }); + return result; +} + +template +auto write_range_entry(OutputIt out, basic_string_view str) -> OutputIt { *out++ = '"'; - out = write(out, v); + auto begin = str.begin(), end = str.end(); + do { + auto escape = find_escape(begin, end); + out = copy_str(begin, escape.begin, out); + begin = escape.end; + if (!begin) break; + auto c = static_cast(escape.cp); + switch (escape.cp) { + case '\n': + *out++ = '\\'; + c = 'n'; + break; + case '\r': + *out++ = '\\'; + c = 'r'; + break; + case '\t': + *out++ = '\\'; + c = 't'; + break; + case '"': + FMT_FALLTHROUGH; + case '\\': + *out++ = '\\'; + break; + default: + if (is_utf8()) { + if (escape.cp < 0x100) { + out = format_to(out, "\\x{:02x}", escape.cp); + continue; + } + if (escape.cp < 0x10000) { + out = format_to(out, "\\u{:04x}", escape.cp); + continue; + } + if (escape.cp < 0x110000) { + out = format_to(out, "\\U{:08x}", escape.cp); + continue; + } + } + for (Char escape_char : basic_string_view( + escape.begin, to_unsigned(escape.end - escape.begin))) { + out = format_to( + out, "\\x{:02x}", + static_cast::type>(escape_char)); + } + continue; + } + *out++ = c; + } while (begin != end); *out++ = '"'; return out; } +template >::value)> +inline auto write_range_entry(OutputIt out, const T& str) -> OutputIt { + auto sv = std_string_view(str); + return write_range_entry(out, basic_string_view(sv)); +} + template ::value)> OutputIt write_range_entry(OutputIt out, const Arg v) { @@ -288,43 +547,37 @@ template struct is_tuple_like { template struct formatter::value>> { private: - // C++11 generic lambda for format() + // C++11 generic lambda for format(). template struct format_each { template void operator()(const T& v) { if (i > 0) out = detail::write_delimiter(out); out = detail::write_range_entry(out, v); ++i; } - formatting_tuple& formatting; - size_t& i; - typename std::add_lvalue_reference< - decltype(std::declval().out())>::type out; + int i; + typename FormatContext::iterator& out; }; public: - formatting_tuple formatting; - template FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - return formatting.parse(ctx); + return ctx.begin(); } template auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) { auto out = ctx.out(); - size_t i = 0; - - detail::copy(formatting.prefix, out); - detail::for_each(values, format_each{formatting, i, out}); - detail::copy(formatting.postfix, out); - - return ctx.out(); + *out++ = '('; + detail::for_each(values, format_each{0, out}); + *out++ = ')'; + return out; } }; template struct is_range { static FMT_CONSTEXPR_DECL const bool value = detail::is_range_::value && !detail::is_std_string_like::value && + !detail::is_map::value && !std::is_convertible>::value && !std::is_constructible, T>::value; }; @@ -334,32 +587,80 @@ struct formatter< T, Char, enable_if_t< fmt::is_range::value -// Workaround a bug in MSVC 2017 and earlier. -#if !FMT_MSC_VER || FMT_MSC_VER >= 1927 - && (has_formatter, format_context>::value || +// Workaround a bug in MSVC 2019 and earlier. +#if !FMT_MSC_VER + && (is_formattable, Char>::value || detail::has_fallback_formatter, Char>::value) #endif >> { - formatting_range formatting; - template FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - return formatting.parse(ctx); + return ctx.begin(); } - template - typename FormatContext::iterator format(const T& values, FormatContext& ctx) { - auto out = detail::copy(formatting.prefix, ctx.out()); - size_t i = 0; - auto view = detail::range_to_view::view(values); - auto it = view.begin(); - auto end = view.end(); + template < + typename FormatContext, typename U, + FMT_ENABLE_IF( + std::is_same::value, + const T, T>>::value)> + auto format(U& range, FormatContext& ctx) -> decltype(ctx.out()) { +#ifdef FMT_DEPRECATED_BRACED_RANGES + Char prefix = '{'; + Char postfix = '}'; +#else + Char prefix = detail::is_set::value ? '{' : '['; + Char postfix = detail::is_set::value ? '}' : ']'; +#endif + auto out = ctx.out(); + *out++ = prefix; + int i = 0; + auto it = std::begin(range); + auto end = std::end(range); for (; it != end; ++it) { if (i > 0) out = detail::write_delimiter(out); out = detail::write_range_entry(out, *it); ++i; } - return detail::copy(formatting.postfix, out); + *out++ = postfix; + return out; + } +}; + +template +struct formatter< + T, Char, + enable_if_t< + detail::is_map::value +// Workaround a bug in MSVC 2019 and earlier. +#if !FMT_MSC_VER + && (is_formattable, Char>::value || + detail::has_fallback_formatter, Char>::value) +#endif + >> { + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template < + typename FormatContext, typename U, + FMT_ENABLE_IF( + std::is_same::value, + const T, T>>::value)> + auto format(U& map, FormatContext& ctx) -> decltype(ctx.out()) { + auto out = ctx.out(); + *out++ = '{'; + int i = 0; + for (const auto& item : map) { + if (i > 0) out = detail::write_delimiter(out); + out = detail::write_range_entry(out, item.first); + *out++ = ':'; + *out++ = ' '; + out = detail::write_range_entry(out, item.second); + ++i; + } + *out++ = '}'; + return out; } }; @@ -374,46 +675,70 @@ template struct tuple_join_view : detail::view { template using tuple_arg_join = tuple_join_view; +// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers +// support in tuple_join. It is disabled by default because of issues with +// the dynamic width and precision. +#ifndef FMT_TUPLE_JOIN_SPECIFIERS +# define FMT_TUPLE_JOIN_SPECIFIERS 0 +#endif + template struct formatter, Char> { template FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - return ctx.begin(); + return do_parse(ctx, std::integral_constant()); } template - auto format(const tuple_join_view& value, FormatContext& ctx) -> - typename FormatContext::iterator { - return format(value, ctx, detail::make_index_sequence{}); + auto format(const tuple_join_view& value, + FormatContext& ctx) const -> typename FormatContext::iterator { + return do_format(value, ctx, + std::integral_constant()); } private: - template - auto format(const tuple_join_view& value, FormatContext& ctx, - detail::index_sequence) -> - typename FormatContext::iterator { - using std::get; - return format_args(value, ctx, get(value.tuple)...); + std::tuple::type, Char>...> formatters_; + + template + FMT_CONSTEXPR auto do_parse(ParseContext& ctx, + std::integral_constant) + -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + FMT_CONSTEXPR auto do_parse(ParseContext& ctx, + std::integral_constant) + -> decltype(ctx.begin()) { + auto end = ctx.begin(); +#if FMT_TUPLE_JOIN_SPECIFIERS + end = std::get(formatters_).parse(ctx); + if (N > 1) { + auto end1 = do_parse(ctx, std::integral_constant()); + if (end != end1) + FMT_THROW(format_error("incompatible format specs for tuple elements")); + } +#endif + return end; } template - auto format_args(const tuple_join_view&, FormatContext& ctx) -> + auto do_format(const tuple_join_view&, FormatContext& ctx, + std::integral_constant) const -> typename FormatContext::iterator { - // NOTE: for compilers that support C++17, this empty function instantiation - // can be replaced with a constexpr branch in the variadic overload. return ctx.out(); } - template - auto format_args(const tuple_join_view& value, FormatContext& ctx, - const Arg& arg, const Args&... args) -> + template + auto do_format(const tuple_join_view& value, FormatContext& ctx, + std::integral_constant) const -> typename FormatContext::iterator { - using base = formatter::type, Char>; - auto out = base().format(arg, ctx); - if (sizeof...(Args) > 0) { + auto out = std::get(formatters_) + .format(std::get(value.tuple), ctx); + if (N > 1) { out = std::copy(value.sep.begin(), value.sep.end(), out); ctx.advance_to(out); - return format_args(value, ctx, args...); + return do_format(value, ctx, std::integral_constant()); } return out; } diff --git a/src/fmt/xchar.h b/src/fmt/xchar.h index a0dd032f16..55825077f8 100644 --- a/src/fmt/xchar.h +++ b/src/fmt/xchar.h @@ -5,8 +5,8 @@ // // For the license information refer to format.h. -#ifndef FMT_WCHAR_H_ -#define FMT_WCHAR_H_ +#ifndef FMT_XCHAR_H_ +#define FMT_XCHAR_H_ #include #include @@ -217,11 +217,11 @@ inline void vprint(wstring_view fmt, wformat_args args) { template void print(std::FILE* f, wformat_string fmt, T&&... args) { - return vprint(f, wstring_view(fmt), make_wformat_args(args...)); + return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); } template void print(wformat_string fmt, T&&... args) { - return vprint(wstring_view(fmt), make_wformat_args(args...)); + return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); } /** @@ -233,4 +233,4 @@ template inline auto to_wstring(const T& value) -> std::wstring { FMT_MODULE_EXPORT_END FMT_END_NAMESPACE -#endif // FMT_WCHAR_H_ +#endif // FMT_XCHAR_H_ diff --git a/src/fmtlib_format.cpp b/src/fmtlib_format.cpp index f55efc6a42..8978dab8bc 100644 --- a/src/fmtlib_format.cpp +++ b/src/fmtlib_format.cpp @@ -11,6 +11,52 @@ FMT_BEGIN_NAMESPACE namespace detail { +// DEPRECATED! +template struct basic_data { + FMT_API static constexpr const char digits[100][2] = { + {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'}, + {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'}, + {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'}, + {'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, + {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'}, + {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'}, + {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'}, + {'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'}, + {'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, + {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'}, + {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'}, + {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'}, + {'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'}, + {'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, + {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'}, + {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'}, + {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}}; + FMT_API static constexpr const char hex_digits[] = "0123456789abcdef"; + FMT_API static constexpr const char signs[4] = {0, '-', '+', ' '}; + FMT_API static constexpr const char left_padding_shifts[5] = {31, 31, 0, 1, + 0}; + FMT_API static constexpr const char right_padding_shifts[5] = {0, 31, 0, 1, + 0}; + FMT_API static constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', + 0x1000000u | ' '}; +}; + +#ifdef FMT_SHARED +// Required for -flto, -fivisibility=hidden and -shared to work +extern template struct basic_data; +#endif + +#if __cplusplus < 201703L +// DEPRECATED! These are here only for ABI compatiblity. +template constexpr const char basic_data::digits[][2]; +template constexpr const char basic_data::hex_digits[]; +template constexpr const char basic_data::signs[]; +template constexpr const char basic_data::left_padding_shifts[]; +template +constexpr const char basic_data::right_padding_shifts[]; +template constexpr const unsigned basic_data::prefixes[]; +#endif + template int format_float(char* buf, std::size_t size, const char* format, int precision, T value) { diff --git a/src/fmtlib_os.cpp b/src/fmtlib_os.cpp index 3d46a2ce1e..d227ce44ee 100644 --- a/src/fmtlib_os.cpp +++ b/src/fmtlib_os.cpp @@ -27,19 +27,17 @@ # endif # include -# define O_CREAT _O_CREAT -# define O_TRUNC _O_TRUNC - # ifndef S_IRUSR # define S_IRUSR _S_IREAD # endif - # ifndef S_IWUSR # define S_IWUSR _S_IWRITE # endif - -# ifdef __MINGW32__ -# define _SH_DENYNO 0x40 +# ifndef S_IRGRP +# define S_IRGRP 0 +# endif +# ifndef S_IROTH +# define S_IROTH 0 # endif # endif // _WIN32 #endif // FMT_USE_FCNTL @@ -214,7 +212,10 @@ int buffered_file::fileno() const { #if FMT_USE_FCNTL file::file(cstring_view path, int oflag) { - int mode = S_IRUSR | S_IWUSR; +# ifdef _WIN32 + using mode_t = int; +# endif + mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; # if defined(_WIN32) && !defined(__MINGW32__) fd_ = -1; FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode)); From c5a7f4c3ac36e6593078d5e85860341336c0847d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 2 Jan 2022 15:24:04 -0500 Subject: [PATCH 102/193] fmtlib now uses UCRT instead of MSVCRT. add library to avoid linker failure --- cmake/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 408528f6dd..60c7269b1f 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -629,7 +629,7 @@ endif() # and after everything else that is compiled locally ###################################################################### if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - target_link_libraries(lammps PRIVATE "wsock32;psapi") + target_link_libraries(lammps PRIVATE "wsock32;psapi;ucrt") endif() ###################################################### From 8c95a8db2311206509a344771b424c08a36d31fd Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 3 Jan 2022 10:11:03 -0500 Subject: [PATCH 103/193] Incorporate bugfixes from issue #3074, a few additional cleanups --- src/MANYBODY/pair_eam_cd.cpp | 54 +++++++++++------------------------- src/MANYBODY/pair_eam_cd.h | 2 ++ 2 files changed, 18 insertions(+), 38 deletions(-) diff --git a/src/MANYBODY/pair_eam_cd.cpp b/src/MANYBODY/pair_eam_cd.cpp index de40cb2568..36c89d5568 100644 --- a/src/MANYBODY/pair_eam_cd.cpp +++ b/src/MANYBODY/pair_eam_cd.cpp @@ -20,9 +20,6 @@ #include "pair_eam_cd.h" -#include - -#include #include "atom.h" #include "force.h" #include "comm.h" @@ -31,11 +28,11 @@ #include "error.h" #include "tokenizer.h" - +#include +#include using namespace LAMMPS_NS; -#define ASSERT(cond) #define MAXLINE 1024 // This sets the maximum line length in EAM input files. PairEAMCD::PairEAMCD(LAMMPS *lmp, int _cdeamVersion) @@ -298,7 +295,7 @@ void PairEAMCD::compute(int eflag, int vflag) // It will be replaced by the concentration at site i if atom i is either A or B. double x_i = -1.0; - double D_i, h_prime_i; + double D_i = 0.0, h_prime_i; // This if-clause is only required for ternary alloys. @@ -307,7 +304,6 @@ void PairEAMCD::compute(int eflag, int vflag) // Compute local concentration at site i. x_i = rhoB[i]/rho[i]; - ASSERT(x_i >= 0 && x_i<=1.0); if (cdeamVersion == 1) { @@ -317,8 +313,6 @@ void PairEAMCD::compute(int eflag, int vflag) D_i = D_values[i] * h_prime_i / (2.0 * rho[i] * rho[i]); } else if (cdeamVersion == 2) { D_i = D_values[i]; - } else { - ASSERT(false); } } @@ -354,14 +348,11 @@ void PairEAMCD::compute(int eflag, int vflag) // This code line is required for ternary alloy. - if (jtype == speciesA || jtype == speciesB) { - ASSERT(rho[i] != 0.0); - ASSERT(rho[j] != 0.0); + if ((jtype == speciesA || jtype == speciesB) && rho[j] != 0.0) { // Compute local concentration at site j. x_j = rhoB[j]/rho[j]; - ASSERT(x_j >= 0 && x_j<=1.0); double D_j=0.0; if (cdeamVersion == 1) { @@ -372,8 +363,6 @@ void PairEAMCD::compute(int eflag, int vflag) D_j = D_values[j] * h_prime_j / (2.0 * rho[j] * rho[j]); } else if (cdeamVersion == 2) { D_j = D_values[j]; - } else { - ASSERT(false); } double t2 = -rhoB[j]; if (itype == speciesB) t2 += rho[j]; @@ -422,8 +411,6 @@ void PairEAMCD::compute(int eflag, int vflag) // Calculate h(x_ij) polynomial function. h = evalH(x_ij); - } else { - ASSERT(false); } fpair += h * phip; phi *= h; @@ -460,7 +447,8 @@ void PairEAMCD::coeff(int narg, char **arg) // Make sure the EAM file is a CD-EAM binary alloy. if (setfl->nelements < 2) - error->all(FLERR,"The EAM file must contain at least 2 elements to be used with the eam/cd pair style."); + error->all(FLERR,"The EAM file must contain at least 2 elements to be " + "used with the eam/cd pair style."); // Read in the coefficients of the h polynomial from the end of the EAM file. @@ -502,22 +490,19 @@ void PairEAMCD::read_h_coeff(char *filename) // Open potential file FILE *fptr; - char line[MAXLINE]; - char nextline[MAXLINE]; - int convert_flag = unit_convert_flag; + char line[2][MAXLINE]; + int convert_flag = unit_convert_flag, toggle = 0; fptr = utils::open_potential(filename, lmp, &convert_flag); if (fptr == nullptr) - error->one(FLERR,"Cannot open EAMCD potential file {}", - filename); + error->one(FLERR,"Cannot open EAMCD potential file {}", filename); // h coefficients are stored at the end of the file. // Skip to last line of file. - while (fgets(nextline, MAXLINE, fptr) != nullptr) { - strcpy(line, nextline); - } + while (fgets(line[toggle], MAXLINE, fptr) != nullptr) + toggle = !toggle; - ValueTokenizer values(line); + ValueTokenizer values(line[!toggle]); int degree = values.next_int(); nhcoeff = degree+1; @@ -527,10 +512,8 @@ void PairEAMCD::read_h_coeff(char *filename) delete[] hcoeff; hcoeff = new double[nhcoeff]; - int i = 0; - while (values.has_next()) { - hcoeff[i++] = values.next_double(); - } + for (int i = 0; i < nhcoeff; ++i) + hcoeff[i] = values.next_double(); // Close the potential file. @@ -545,7 +528,6 @@ void PairEAMCD::read_h_coeff(char *filename) MPI_Bcast(hcoeff, nhcoeff, MPI_DOUBLE, 0, world); } - /* ---------------------------------------------------------------------- */ int PairEAMCD::pack_forward_comm(int n, int *list, double *buf, @@ -572,7 +554,7 @@ int PairEAMCD::pack_forward_comm(int n, int *list, double *buf, buf[m++] = rhoB[j]; } return m; - } else { ASSERT(false); return 0; } + } else return 0; } else if (communicationStage == 4) { for (i = 0; i < n; i++) { j = list[i]; @@ -604,8 +586,6 @@ void PairEAMCD::unpack_forward_comm(int n, int first, double *buf) rho[i] = buf[m++]; rhoB[i] = buf[m++]; } - } else { - ASSERT(false); } } else if (communicationStage == 4) { for (i = first; i < last; i++) { @@ -636,7 +616,7 @@ int PairEAMCD::pack_reverse_comm(int n, int first, double *buf) buf[m++] = rhoB[i]; } return m; - } else { ASSERT(false); return 0; } + } else return 0; } else if (communicationStage == 3) { for (i = first; i < last; i++) { buf[m++] = D_values[i]; @@ -666,8 +646,6 @@ void PairEAMCD::unpack_reverse_comm(int n, int *list, double *buf) rho[j] += buf[m++]; rhoB[j] += buf[m++]; } - } else { - ASSERT(false); } } else if (communicationStage == 3) { for (i = 0; i < n; i++) { diff --git a/src/MANYBODY/pair_eam_cd.h b/src/MANYBODY/pair_eam_cd.h index 77e909f48b..6846a6cd76 100644 --- a/src/MANYBODY/pair_eam_cd.h +++ b/src/MANYBODY/pair_eam_cd.h @@ -120,6 +120,7 @@ class PairEAMCD : public PairEAMAlloy { index.p = r * rdr + 1.0; index.m = static_cast(index.p); index.m = index.m <= (nr - 1) ? index.m : (nr - 1); + index.m = index.m > 1 ? index.m : 1; index.p -= index.m; index.p = index.p <= 1.0 ? index.p : 1.0; return index; @@ -132,6 +133,7 @@ class PairEAMCD : public PairEAMAlloy { index.p = rho * rdrho + 1.0; index.m = static_cast(index.p); index.m = index.m <= (nrho - 1) ? index.m : (nrho - 1); + index.m = index.m > 1 ? index.m : 1; index.p -= index.m; index.p = index.p <= 1.0 ? index.p : 1.0; return index; From 90726ca0888cd2eacfddaaa02aa8cfb1123a000b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 3 Jan 2022 10:12:38 -0500 Subject: [PATCH 104/193] explain that the computed force in python pair is force/r same as in Pair:single() --- doc/src/Modify_pair.rst | 38 +++++++++++++++++++------------------- doc/src/pair_python.rst | 18 +++++++++--------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/doc/src/Modify_pair.rst b/doc/src/Modify_pair.rst index 7263b8fd48..6913204504 100644 --- a/doc/src/Modify_pair.rst +++ b/doc/src/Modify_pair.rst @@ -12,24 +12,24 @@ includes some optional methods to enable its use with rRESPA. Here is a brief description of the class methods in pair.h: -+---------------------------------+-------------------------------------------------------------------+ -| compute | workhorse routine that computes pairwise interactions | -+---------------------------------+-------------------------------------------------------------------+ -| settings | reads the input script line with arguments you define | -+---------------------------------+-------------------------------------------------------------------+ -| coeff | set coefficients for one i,j type pair | -+---------------------------------+-------------------------------------------------------------------+ -| init_one | perform initialization for one i,j type pair | -+---------------------------------+-------------------------------------------------------------------+ -| init_style | initialization specific to this pair style | -+---------------------------------+-------------------------------------------------------------------+ -| write & read_restart | write/read i,j pair coeffs to restart files | -+---------------------------------+-------------------------------------------------------------------+ -| write & read_restart_settings | write/read global settings to restart files | -+---------------------------------+-------------------------------------------------------------------+ -| single | force and energy of a single pairwise interaction between 2 atoms | -+---------------------------------+-------------------------------------------------------------------+ -| compute_inner/middle/outer | versions of compute used by rRESPA | -+---------------------------------+-------------------------------------------------------------------+ ++---------------------------------+---------------------------------------------------------------------+ +| compute | workhorse routine that computes pairwise interactions | ++---------------------------------+---------------------------------------------------------------------+ +| settings | reads the input script line with arguments you define | ++---------------------------------+---------------------------------------------------------------------+ +| coeff | set coefficients for one i,j type pair | ++---------------------------------+---------------------------------------------------------------------+ +| init_one | perform initialization for one i,j type pair | ++---------------------------------+---------------------------------------------------------------------+ +| init_style | initialization specific to this pair style | ++---------------------------------+---------------------------------------------------------------------+ +| write & read_restart | write/read i,j pair coeffs to restart files | ++---------------------------------+---------------------------------------------------------------------+ +| write & read_restart_settings | write/read global settings to restart files | ++---------------------------------+---------------------------------------------------------------------+ +| single | force/r and energy of a single pairwise interaction between 2 atoms | ++---------------------------------+---------------------------------------------------------------------+ +| compute_inner/middle/outer | versions of compute used by rRESPA | ++---------------------------------+---------------------------------------------------------------------+ The inner/middle/outer routines are optional. diff --git a/doc/src/pair_python.rst b/doc/src/pair_python.rst index 3d087565be..35e07dbd11 100644 --- a/doc/src/pair_python.rst +++ b/doc/src/pair_python.rst @@ -126,11 +126,11 @@ and *compute_energy*, which both take 3 numerical arguments: * itype = the (numerical) type of the first atom * jtype = the (numerical) type of the second atom -This functions need to compute the force and the energy, respectively, -and use the result as return value. The functions need to use the -*pmap* dictionary to convert the LAMMPS atom type number to the symbolic -value of the internal potential parameter data structure. Following -the *LJCutMelt* example, here are the two functions: +This functions need to compute the (scaled) force and the energy, +respectively, and use the result as return value. The functions need +to use the *pmap* dictionary to convert the LAMMPS atom type number +to the symbolic value of the internal potential parameter data structure. +Following the *LJCutMelt* example, here are the two functions: .. code-block:: python @@ -154,10 +154,10 @@ the *LJCutMelt* example, here are the two functions: for consistency with the C++ pair styles in LAMMPS, the *compute_force* function follows the conventions of the Pair::single() - methods and does not return the full force, but the force scaled by - the distance between the two atoms, so this value only needs to be - multiplied by delta x, delta y, and delta z to conveniently obtain the - three components of the force vector between these two atoms. + methods and does not return the pairwise force directly, but the force + divided by the distance between the two atoms, so this value only needs + to be multiplied by delta x, delta y, and delta z to conveniently obtain + the three components of the force vector between these two atoms. ---------- From a9a568aefaa6191411148eb42feb35e0acb27457 Mon Sep 17 00:00:00 2001 From: jddietz Date: Mon, 3 Jan 2022 11:50:04 -1000 Subject: [PATCH 105/193] Updated references for pair_nm.rst --- doc/src/pair_nm.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/src/pair_nm.rst b/doc/src/pair_nm.rst index 09bb571da5..fb9a45dd5d 100644 --- a/doc/src/pair_nm.rst +++ b/doc/src/pair_nm.rst @@ -195,5 +195,4 @@ none .. _Dietz: -**(Dietz)** J.D. Dietz, R.S. Hoy, "Facile equilibration of well-entangled -semi-flexible bead-spring polymer melts" arXiv:2109.11001 +**(Dietz)** Dietz and Hoy, J. Chem. Phys. 156, 014103 (2022). From 49412ce0f78b851d6ebc96ef3b3eec46e7918f3a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 3 Jan 2022 18:01:33 -0500 Subject: [PATCH 106/193] implement workaround windows from https://github.com/fmtlib/fmt/issues/2691 this also reverts commit c5a7f4c3ac36e6593078d5e85860341336c0847d and thus results in consistent crt behavior on windows --- cmake/CMakeLists.txt | 2 +- src/fmt/chrono.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 60c7269b1f..408528f6dd 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -629,7 +629,7 @@ endif() # and after everything else that is compiled locally ###################################################################### if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - target_link_libraries(lammps PRIVATE "wsock32;psapi;ucrt") + target_link_libraries(lammps PRIVATE "wsock32;psapi") endif() ###################################################### diff --git a/src/fmt/chrono.h b/src/fmt/chrono.h index 31fee070af..908999ab5f 100644 --- a/src/fmt/chrono.h +++ b/src/fmt/chrono.h @@ -1082,7 +1082,7 @@ template class tm_writer { } template ::value)> void format_utc_offset_impl(const T& tm) { -#if defined(_WIN32) +#if defined(_WIN32) && defined(_UCRT) # if FMT_USE_TZSET tzset_once(); # endif From 8439f87b76a5a385260d1cd7125a5c2e8b57fa15 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 3 Jan 2022 18:26:56 -0500 Subject: [PATCH 107/193] make consistent with other reference --- doc/src/pair_nm.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/pair_nm.rst b/doc/src/pair_nm.rst index fb9a45dd5d..2256c7f220 100644 --- a/doc/src/pair_nm.rst +++ b/doc/src/pair_nm.rst @@ -195,4 +195,4 @@ none .. _Dietz: -**(Dietz)** Dietz and Hoy, J. Chem. Phys. 156, 014103 (2022). +**(Dietz)** Dietz and Hoy, J. Chem Phys, 156, 014103 (2022). From 6a73fc0472f3e489965fc802b75184f747132ce6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 3 Jan 2022 21:35:26 -0500 Subject: [PATCH 108/193] refactor reading last line of potential file code to be more efficient --- src/MANYBODY/pair_eam_cd.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/MANYBODY/pair_eam_cd.cpp b/src/MANYBODY/pair_eam_cd.cpp index 36c89d5568..46d439b879 100644 --- a/src/MANYBODY/pair_eam_cd.cpp +++ b/src/MANYBODY/pair_eam_cd.cpp @@ -490,19 +490,28 @@ void PairEAMCD::read_h_coeff(char *filename) // Open potential file FILE *fptr; - char line[2][MAXLINE]; - int convert_flag = unit_convert_flag, toggle = 0; + int convert_flag = unit_convert_flag; fptr = utils::open_potential(filename, lmp, &convert_flag); if (fptr == nullptr) error->one(FLERR,"Cannot open EAMCD potential file {}", filename); // h coefficients are stored at the end of the file. - // Skip to last line of file. + // Seek to end of file, read last part into a buffer and + // then skip over lines in buffer until reaching the end. - while (fgets(line[toggle], MAXLINE, fptr) != nullptr) - toggle = !toggle; + platform::fseek(fptr, platform::END_OF_FILE); + platform::fseek(fptr, platform::ftell(fptr) - MAXLINE); + char *buf = new char[MAXLINE+1]; + fread(buf, 1, MAXLINE, fptr); + buf[MAXLINE] = '\0'; // must 0-terminate buffer for string processing + Tokenizer lines(buf, "\n"); + delete[] buf; - ValueTokenizer values(line[!toggle]); + std::string lastline; + while (lines.has_next()) + lastline = lines.next(); + + ValueTokenizer values(lastline); int degree = values.next_int(); nhcoeff = degree+1; From 1225b609d843c4a0c37d992bf41e433d21529759 Mon Sep 17 00:00:00 2001 From: Donatas Surblys Date: Tue, 4 Jan 2022 17:43:32 +0900 Subject: [PATCH 109/193] disable centroid stress for fix rigid/small/omp --- src/OPENMP/fix_rigid_small_omp.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/OPENMP/fix_rigid_small_omp.h b/src/OPENMP/fix_rigid_small_omp.h index fcbb78534d..82b0d1b8cd 100644 --- a/src/OPENMP/fix_rigid_small_omp.h +++ b/src/OPENMP/fix_rigid_small_omp.h @@ -21,12 +21,16 @@ FixStyle(rigid/small/omp,FixRigidSmallOMP); #define LMP_FIX_RIGID_SMALL_OMP_H #include "fix_rigid_small.h" +#include "force.h" namespace LAMMPS_NS { class FixRigidSmallOMP : public FixRigidSmall { public: - FixRigidSmallOMP(class LAMMPS *lmp, int narg, char **args) : FixRigidSmall(lmp, narg, args){}; + FixRigidSmallOMP(class LAMMPS *lmp, int narg, char **args) : FixRigidSmall(lmp, narg, args) + { + centroidstressflag = CENTROID_NOTAVAIL; + } virtual ~FixRigidSmallOMP(){}; virtual void initial_integrate(int); From fd3884d7050e8e99f3ff0726be758a23abd04c33 Mon Sep 17 00:00:00 2001 From: Donatas Surblys Date: Tue, 4 Jan 2022 18:09:49 +0900 Subject: [PATCH 110/193] disable centroid stress for non-small rigid fixes --- src/RIGID/fix_rigid.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/RIGID/fix_rigid.cpp b/src/RIGID/fix_rigid.cpp index 9c39518508..41843fecf0 100644 --- a/src/RIGID/fix_rigid.cpp +++ b/src/RIGID/fix_rigid.cpp @@ -68,6 +68,7 @@ FixRigid::FixRigid(LAMMPS *lmp, int narg, char **arg) : create_attribute = 1; dof_flag = 1; enforce2d_flag = 1; + centroidstressflag = CENTROID_NOTAVAIL; MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); From f557bf6e20887289fb7478bd0433e258759199de Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 4 Jan 2022 11:37:32 -0500 Subject: [PATCH 111/193] implement suggestion by @rbberger --- src/atom.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/atom.cpp b/src/atom.cpp index 2dc6819978..a8609b34f6 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -1242,7 +1242,7 @@ void Atom::data_bonds(int n, char *buf, int *count, tagint id_offset, tagint atom1,atom2; char *next; int newton_bond = force->newton_bond; - const std::string errtxt = "Bonds section of data file: "; + auto location = "Bonds section of data file"; for (int i = 0; i < n; i++) { next = strchr(buf,'\n'); @@ -1255,7 +1255,7 @@ void Atom::data_bonds(int n, char *buf, int *count, tagint id_offset, atom2 = values.next_tagint(); if (values.has_next()) throw TokenizerException("Too many tokens",""); } catch (TokenizerException &e) { - error->one(FLERR,e.what() + std::string(" in ") + errtxt + utils::trim(buf)); + error->one(FLERR,"{} in {}: {}", e.what(), location, utils::trim(buf)); } if (id_offset) { atom1 += id_offset; @@ -1265,9 +1265,9 @@ void Atom::data_bonds(int n, char *buf, int *count, tagint id_offset, if ((atom1 <= 0) || (atom1 > map_tag_max) || (atom2 <= 0) || (atom2 > map_tag_max) || (atom1 == atom2)) - error->one(FLERR,"Invalid atom ID in " + errtxt + utils::trim(buf)); + error->one(FLERR,"Invalid atom ID in {}: {}", location, utils::trim(buf)); if (itype <= 0 || itype > nbondtypes) - error->one(FLERR,"Invalid bond type in " + errtxt + utils::trim(buf)); + error->one(FLERR,"Invalid bond type in {}: {}", location, utils::trim(buf)); if ((m = map(atom1)) >= 0) { if (count) count[m]++; else { @@ -1306,7 +1306,7 @@ void Atom::data_angles(int n, char *buf, int *count, tagint id_offset, tagint atom1,atom2,atom3; char *next; int newton_bond = force->newton_bond; - const std::string errtxt = "Angles section of data file: "; + auto location = "Angles section of data file"; for (int i = 0; i < n; i++) { next = strchr(buf,'\n'); @@ -1320,7 +1320,7 @@ void Atom::data_angles(int n, char *buf, int *count, tagint id_offset, atom3 = values.next_tagint(); if (values.has_next()) throw TokenizerException("Too many tokens",""); } catch (TokenizerException &e) { - error->one(FLERR,e.what() + std::string(" in ") + errtxt + utils::trim(buf)); + error->one(FLERR,"{} in {}: {}", e.what(), location, utils::trim(buf)); } if (id_offset) { atom1 += id_offset; @@ -1333,9 +1333,9 @@ void Atom::data_angles(int n, char *buf, int *count, tagint id_offset, (atom2 <= 0) || (atom2 > map_tag_max) || (atom3 <= 0) || (atom3 > map_tag_max) || (atom1 == atom2) || (atom1 == atom3) || (atom2 == atom3)) - error->one(FLERR,"Invalid atom ID in " + errtxt + utils::trim(buf)); + error->one(FLERR,"Invalid atom ID in {}: {}", location, utils::trim(buf)); if (itype <= 0 || itype > nangletypes) - error->one(FLERR,"Invalid angle type in " + errtxt + utils::trim(buf)); + error->one(FLERR,"Invalid angle type in {}: {}", location, utils::trim(buf)); if ((m = map(atom2)) >= 0) { if (count) count[m]++; else { @@ -1386,7 +1386,7 @@ void Atom::data_dihedrals(int n, char *buf, int *count, tagint id_offset, tagint atom1,atom2,atom3,atom4; char *next; int newton_bond = force->newton_bond; - const std::string errtxt = "Dihedrals section of data file: "; + auto location = "Dihedrals section of data file"; for (int i = 0; i < n; i++) { next = strchr(buf,'\n'); @@ -1401,7 +1401,7 @@ void Atom::data_dihedrals(int n, char *buf, int *count, tagint id_offset, atom4 = values.next_tagint(); if (values.has_next()) throw TokenizerException("Too many tokens",""); } catch (TokenizerException &e) { - error->one(FLERR,e.what() + std::string(" in ") + errtxt + utils::trim(buf)); + error->one(FLERR,"{} in {}: {}", e.what(), location, utils::trim(buf)); } if (id_offset) { atom1 += id_offset; @@ -1417,9 +1417,9 @@ void Atom::data_dihedrals(int n, char *buf, int *count, tagint id_offset, (atom4 <= 0) || (atom4 > map_tag_max) || (atom1 == atom2) || (atom1 == atom3) || (atom1 == atom4) || (atom2 == atom3) || (atom2 == atom4) || (atom3 == atom4)) - error->one(FLERR, "Invalid atom ID in " + errtxt + utils::trim(buf)); + error->one(FLERR, "Invalid atom ID in {}: {}", location, utils::trim(buf)); if (itype <= 0 || itype > ndihedraltypes) - error->one(FLERR, "Invalid dihedral type in " + errtxt + utils::trim(buf)); + error->one(FLERR, "Invalid dihedral type in {}: {}", location, utils::trim(buf)); if ((m = map(atom2)) >= 0) { if (count) count[m]++; else { @@ -1484,7 +1484,7 @@ void Atom::data_impropers(int n, char *buf, int *count, tagint id_offset, tagint atom1,atom2,atom3,atom4; char *next; int newton_bond = force->newton_bond; - const std::string errtxt = "Impropers section of data file: "; + auto location = "Impropers section of data file"; for (int i = 0; i < n; i++) { next = strchr(buf,'\n'); @@ -1499,7 +1499,7 @@ void Atom::data_impropers(int n, char *buf, int *count, tagint id_offset, atom4 = values.next_tagint(); if (values.has_next()) throw TokenizerException("Too many tokens",""); } catch (TokenizerException &e) { - error->one(FLERR,e.what() + std::string(" in ") + errtxt + utils::trim(buf)); + error->one(FLERR,"{} in {}: {}", e.what(), location, utils::trim(buf)); } if (id_offset) { atom1 += id_offset; @@ -1515,9 +1515,9 @@ void Atom::data_impropers(int n, char *buf, int *count, tagint id_offset, (atom4 <= 0) || (atom4 > map_tag_max) || (atom1 == atom2) || (atom1 == atom3) || (atom1 == atom4) || (atom2 == atom3) || (atom2 == atom4) || (atom3 == atom4)) - error->one(FLERR, "Invalid atom ID in " + errtxt + utils::trim(buf)); + error->one(FLERR, "Invalid atom ID in {}: {}", location, utils::trim(buf)); if (itype <= 0 || itype > nimpropertypes) - error->one(FLERR, "Invalid improper type in " + errtxt + utils::trim(buf)); + error->one(FLERR, "Invalid improper type in {}: {}", location, utils::trim(buf)); if ((m = map(atom2)) >= 0) { if (count) count[m]++; else { From ede778774158ba3cfa0d3bc271e2097d11ae001d Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Tue, 4 Jan 2022 11:55:41 -0500 Subject: [PATCH 112/193] Refactor Atom::data_bodies() --- src/atom.cpp | 42 +++++++++++++----------------------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/src/atom.cpp b/src/atom.cpp index a8609b34f6..aece451b9b 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -1620,13 +1620,8 @@ void Atom::data_bonus(int n, char *buf, AtomVec *avec_bonus, tagint id_offset) void Atom::data_bodies(int n, char *buf, AtomVec *avec_body, tagint id_offset) { - int j,m,nvalues,ninteger,ndouble; - - int maxint = 0; - int maxdouble = 0; - int *ivalues = nullptr; - double *dvalues = nullptr; - char *next; + std::vector ivalues; + std::vector dvalues; if (!unique_tags) unique_tags = new std::set; @@ -1635,13 +1630,13 @@ void Atom::data_bodies(int n, char *buf, AtomVec *avec_body, tagint id_offset) // else skip values for (int i = 0; i < n; i++) { - next = strchr(buf,'\n'); + char *next = strchr(buf,'\n'); *next = '\0'; auto values = Tokenizer(utils::trim_comment(buf)).as_vector(); tagint tagdata = utils::tnumeric(FLERR,values[0],false,lmp) + id_offset; - ninteger = utils::inumeric(FLERR,values[1],false,lmp); - ndouble = utils::inumeric(FLERR,values[2],false,lmp); + int ninteger = utils::inumeric(FLERR,values[1],false,lmp); + int ndouble = utils::inumeric(FLERR,values[2],false,lmp); if (unique_tags->find(tagdata) == unique_tags->end()) unique_tags->insert(tagdata); @@ -1649,38 +1644,30 @@ void Atom::data_bodies(int n, char *buf, AtomVec *avec_body, tagint id_offset) error->one(FLERR,"Duplicate atom ID in Bodies section of data file"); buf = next + 1; - m = map(tagdata); + int m = map(tagdata); if (m >= 0) { - if (ninteger > maxint) { - delete[] ivalues; - maxint = ninteger; - ivalues = new int[maxint]; - } - if (ndouble > maxdouble) { - delete[] dvalues; - maxdouble = ndouble; - dvalues = new double[maxdouble]; - } + ivalues.resize(ninteger); + dvalues.resize(ndouble); - for (j = 0; j < ninteger; j++) { + for (int j = 0; j < ninteger; j++) { buf += strspn(buf," \t\n\r\f"); buf[strcspn(buf," \t\n\r\f")] = '\0'; ivalues[j] = utils::inumeric(FLERR,buf,false,lmp); buf += strlen(buf)+1; } - for (j = 0; j < ndouble; j++) { + for (int j = 0; j < ndouble; j++) { buf += strspn(buf," \t\n\r\f"); buf[strcspn(buf," \t\n\r\f")] = '\0'; dvalues[j] = utils::numeric(FLERR,buf,false,lmp); buf += strlen(buf)+1; } - avec_body->data_body(m,ninteger,ndouble,ivalues,dvalues); + avec_body->data_body(m,ninteger,ndouble,ivalues.data(),dvalues.data()); } else { - nvalues = ninteger + ndouble; // number of values to skip - for (j = 0; j < nvalues; j++) { + int nvalues = ninteger + ndouble; // number of values to skip + for (int j = 0; j < nvalues; j++) { buf += strspn(buf," \t\n\r\f"); buf[strcspn(buf," \t\n\r\f")] = '\0'; buf += strlen(buf)+1; @@ -1688,9 +1675,6 @@ void Atom::data_bodies(int n, char *buf, AtomVec *avec_body, tagint id_offset) } buf += strspn(buf," \t\n\r\f"); } - - delete[] ivalues; - delete[] dvalues; } /* ---------------------------------------------------------------------- From d0f203127db0e53ab76214c8bea76e9c9efb0460 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 4 Jan 2022 23:01:38 -0500 Subject: [PATCH 113/193] create missing de,df table elements from linear extrapolation --- src/MOLECULE/angle_table.cpp | 7 +++++-- src/MOLECULE/bond_table.cpp | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/MOLECULE/angle_table.cpp b/src/MOLECULE/angle_table.cpp index a5ba07b779..7e1528a5f3 100644 --- a/src/MOLECULE/angle_table.cpp +++ b/src/MOLECULE/angle_table.cpp @@ -470,9 +470,9 @@ void AngleTable::compute_table(Table *tb) memory->create(tb->ang,tablength,"angle:ang"); memory->create(tb->e,tablength,"angle:e"); - memory->create(tb->de,tlm1,"angle:de"); + memory->create(tb->de,tablength,"angle:de"); memory->create(tb->f,tablength,"angle:f"); - memory->create(tb->df,tlm1,"angle:df"); + memory->create(tb->df,tablength,"angle:df"); memory->create(tb->e2,tablength,"angle:e2"); memory->create(tb->f2,tablength,"angle:f2"); @@ -488,6 +488,9 @@ void AngleTable::compute_table(Table *tb) tb->de[i] = tb->e[i+1] - tb->e[i]; tb->df[i] = tb->f[i+1] - tb->f[i]; } + // get final elements from linear extrapolation + tb->de[tlm1] = 2.0*tb->de[tlm1-1] - tb->de[tlm1-2]; + tb->df[tlm1] = 2.0*tb->df[tlm1-1] - tb->df[tlm1-2]; double ep0 = - tb->f[0]; double epn = - tb->f[tlm1]; diff --git a/src/MOLECULE/bond_table.cpp b/src/MOLECULE/bond_table.cpp index db1314c76f..0a17873f7c 100644 --- a/src/MOLECULE/bond_table.cpp +++ b/src/MOLECULE/bond_table.cpp @@ -435,9 +435,9 @@ void BondTable::compute_table(Table *tb) memory->create(tb->r,tablength,"bond:r"); memory->create(tb->e,tablength,"bond:e"); - memory->create(tb->de,tlm1,"bond:de"); + memory->create(tb->de,tablength,"bond:de"); memory->create(tb->f,tablength,"bond:f"); - memory->create(tb->df,tlm1,"bond:df"); + memory->create(tb->df,tablength,"bond:df"); memory->create(tb->e2,tablength,"bond:e2"); memory->create(tb->f2,tablength,"bond:f2"); @@ -453,6 +453,9 @@ void BondTable::compute_table(Table *tb) tb->de[i] = tb->e[i+1] - tb->e[i]; tb->df[i] = tb->f[i+1] - tb->f[i]; } + // get final elements from linear extrapolation + tb->de[tlm1] = 2.0*tb->de[tlm1-1] - tb->de[tlm1-2]; + tb->df[tlm1] = 2.0*tb->df[tlm1-1] - tb->df[tlm1-2]; double ep0 = - tb->f[0]; double epn = - tb->f[tlm1]; From 40abc0886c1fbbcb28c1f2975a04f18e46d94f9c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 4 Jan 2022 23:02:17 -0500 Subject: [PATCH 114/193] adjust for double precision floating point --- src/MOLECULE/angle_table.cpp | 4 ++-- src/MOLECULE/bond_table.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/MOLECULE/angle_table.cpp b/src/MOLECULE/angle_table.cpp index 7e1528a5f3..84a1dafb27 100644 --- a/src/MOLECULE/angle_table.cpp +++ b/src/MOLECULE/angle_table.cpp @@ -578,7 +578,7 @@ void AngleTable::spline(double *x, double *y, int n, double p,qn,sig,un; double *u = new double[n]; - if (yp1 > 0.99e30) y2[0] = u[0] = 0.0; + if (yp1 > 0.99e300) y2[0] = u[0] = 0.0; else { y2[0] = -0.5; u[0] = (3.0/(x[1]-x[0])) * ((y[1]-y[0]) / (x[1]-x[0]) - yp1); @@ -590,7 +590,7 @@ void AngleTable::spline(double *x, double *y, int n, u[i] = (y[i+1]-y[i]) / (x[i+1]-x[i]) - (y[i]-y[i-1]) / (x[i]-x[i-1]); u[i] = (6.0*u[i] / (x[i+1]-x[i-1]) - sig*u[i-1]) / p; } - if (ypn > 0.99e30) qn = un = 0.0; + if (ypn > 0.99e300) qn = un = 0.0; else { qn = 0.5; un = (3.0/(x[n-1]-x[n-2])) * (ypn - (y[n-1]-y[n-2]) / (x[n-1]-x[n-2])); diff --git a/src/MOLECULE/bond_table.cpp b/src/MOLECULE/bond_table.cpp index 0a17873f7c..58c07b5aea 100644 --- a/src/MOLECULE/bond_table.cpp +++ b/src/MOLECULE/bond_table.cpp @@ -541,7 +541,7 @@ void BondTable::spline(double *x, double *y, int n, double p,qn,sig,un; double *u = new double[n]; - if (yp1 > 0.99e30) y2[0] = u[0] = 0.0; + if (yp1 > 0.99e300) y2[0] = u[0] = 0.0; else { y2[0] = -0.5; u[0] = (3.0/(x[1]-x[0])) * ((y[1]-y[0]) / (x[1]-x[0]) - yp1); @@ -553,7 +553,7 @@ void BondTable::spline(double *x, double *y, int n, u[i] = (y[i+1]-y[i]) / (x[i+1]-x[i]) - (y[i]-y[i-1]) / (x[i]-x[i-1]); u[i] = (6.0*u[i] / (x[i+1]-x[i-1]) - sig*u[i-1]) / p; } - if (ypn > 0.99e30) qn = un = 0.0; + if (ypn > 0.99e300) qn = un = 0.0; else { qn = 0.5; un = (3.0/(x[n-1]-x[n-2])) * (ypn - (y[n-1]-y[n-2]) / (x[n-1]-x[n-2])); From 4aba9e9bb61be24e7514abbf924844e586008e52 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 4 Jan 2022 23:08:32 -0500 Subject: [PATCH 115/193] cosmetic and whitespace changes --- src/EXTRA-MOLECULE/dihedral_table_cut.cpp | 25 ++++-------- src/MOLECULE/angle_table.cpp | 15 +++---- src/MOLECULE/bond_table.cpp | 15 +++---- src/MOLECULE/dihedral_table.cpp | 48 +++++++---------------- src/OPENMP/angle_table_omp.cpp | 5 ++- src/OPENMP/bond_table_omp.cpp | 4 +- 6 files changed, 38 insertions(+), 74 deletions(-) diff --git a/src/EXTRA-MOLECULE/dihedral_table_cut.cpp b/src/EXTRA-MOLECULE/dihedral_table_cut.cpp index b132104bdd..522eff8626 100644 --- a/src/EXTRA-MOLECULE/dihedral_table_cut.cpp +++ b/src/EXTRA-MOLECULE/dihedral_table_cut.cpp @@ -82,20 +82,14 @@ enum { //GSL status return codes. GSL_EBADLEN = 19 }; - - // cyc_splintD(): Evaluate the deriviative of a cyclic spline at position x, // with n control points at xa[], ya[], with parameters y2a[]. // The xa[] must be monotonically increasing and their // range should not exceed period (ie xa[n-1] < xa[0] + period). // x must lie in the range: [(xa[n-1]-period), (xa[0]+period)] // "period" is typically 2*PI. -static double cyc_splintD(double const *xa, - double const *ya, - double const *y2a, - int n, - double period, - double x) +static double cyc_splintD(double const *xa, double const *ya, double const *y2a, + int n, double period, double x) { int klo = -1; int khi = n; // (not n-1) @@ -490,8 +484,7 @@ void DihedralTableCut::coeff(int narg, char **arg) if (tb->ninput < 2) error->all(FLERR,"Invalid dihedral table length: {}",arg[5]); else if ((tb->ninput == 2) && (tabstyle == SPLINE)) - error->all(FLERR,"Invalid dihedral spline table length: {} " - "(Try linear)",arg[5]); + error->all(FLERR,"Invalid dihedral spline table length: {} (Try linear)",arg[5]); // check for monotonicity for (int i=0; i < tb->ninput-1; i++) { @@ -509,12 +502,10 @@ void DihedralTableCut::coeff(int narg, char **arg) double phihi = tb->phifile[tb->ninput-1]; if (tb->use_degrees) { if ((phihi - philo) >= 360) - error->all(FLERR,"Dihedral table angle range must be < 360 " - "degrees ({})",arg[5]); + error->all(FLERR,"Dihedral table angle range must be < 360 degrees ({})",arg[5]); } else { if ((phihi - philo) >= MY_2PI) - error->all(FLERR,"Dihedral table angle range must be < 2*PI " - "radians ({})",arg[5]); + error->all(FLERR,"Dihedral table angle range must be < 2*PI radians ({})",arg[5]); } // convert phi from degrees to radians @@ -532,9 +523,9 @@ void DihedralTableCut::coeff(int narg, char **arg) // We also want the angles to be sorted in increasing order. // This messy code fixes these problems with the user's data: { - double *phifile_tmp = new double [tb->ninput]; //temporary arrays - double *ffile_tmp = new double [tb->ninput]; //used for sorting - double *efile_tmp = new double [tb->ninput]; + double *phifile_tmp = new double[tb->ninput]; //temporary arrays + double *ffile_tmp = new double[tb->ninput]; //used for sorting + double *efile_tmp = new double[tb->ninput]; // After re-imaging, does the range of angles cross the 0 or 2*PI boundary? // If so, find the discontinuity: diff --git a/src/MOLECULE/angle_table.cpp b/src/MOLECULE/angle_table.cpp index 84a1dafb27..2d7356db01 100644 --- a/src/MOLECULE/angle_table.cpp +++ b/src/MOLECULE/angle_table.cpp @@ -618,8 +618,7 @@ double AngleTable::splint(double *xa, double *ya, double *y2a, int n, double x) h = xa[khi]-xa[klo]; a = (xa[khi]-x) / h; b = (x-xa[klo]) / h; - y = a*ya[klo] + b*ya[khi] + - ((a*a*a-a)*y2a[klo] + (b*b*b-b)*y2a[khi]) * (h*h)/6.0; + y = a*ya[klo] + b*ya[khi] + ((a*a*a-a)*y2a[klo] + (b*b*b-b)*y2a[khi]) * (h*h)/6.0; return y; } @@ -635,8 +634,9 @@ void AngleTable::uf_lookup(int type, double x, double &u, double &f) double fraction,a,b; const Table *tb = &tables[tabindex[type]]; - int itable = static_cast (x * tb->invdelta); + // invdelta is based on tablength-1 + int itable = static_cast (x * tb->invdelta); if (itable < 0) itable = 0; if (itable >= tablength) itable = tablength-1; @@ -650,11 +650,9 @@ void AngleTable::uf_lookup(int type, double x, double &u, double &f) b = (x - tb->ang[itable]) * tb->invdelta; a = 1.0 - b; u = a * tb->e[itable] + b * tb->e[itable+1] + - ((a*a*a-a)*tb->e2[itable] + (b*b*b-b)*tb->e2[itable+1]) * - tb->deltasq6; + ((a*a*a-a)*tb->e2[itable] + (b*b*b-b)*tb->e2[itable+1]) * tb->deltasq6; f = a * tb->f[itable] + b * tb->f[itable+1] + - ((a*a*a-a)*tb->f2[itable] + (b*b*b-b)*tb->f2[itable+1]) * - tb->deltasq6; + ((a*a*a-a)*tb->f2[itable] + (b*b*b-b)*tb->f2[itable+1]) * tb->deltasq6; } } @@ -684,7 +682,6 @@ void AngleTable::u_lookup(int type, double x, double &u) b = (x - tb->ang[itable]) * tb->invdelta; a = 1.0 - b; u = a * tb->e[itable] + b * tb->e[itable+1] + - ((a*a*a-a)*tb->e2[itable] + (b*b*b-b)*tb->e2[itable+1]) * - tb->deltasq6; + ((a*a*a-a)*tb->e2[itable] + (b*b*b-b)*tb->e2[itable+1]) * tb->deltasq6; } } diff --git a/src/MOLECULE/bond_table.cpp b/src/MOLECULE/bond_table.cpp index 58c07b5aea..48d7377682 100644 --- a/src/MOLECULE/bond_table.cpp +++ b/src/MOLECULE/bond_table.cpp @@ -581,8 +581,7 @@ double BondTable::splint(double *xa, double *ya, double *y2a, int n, double x) h = xa[khi]-xa[klo]; a = (xa[khi]-x) / h; b = (x-xa[klo]) / h; - y = a*ya[klo] + b*ya[khi] + - ((a*a*a-a)*y2a[klo] + (b*b*b-b)*y2a[khi]) * (h*h)/6.0; + y = a*ya[klo] + b*ya[khi] + ((a*a*a-a)*y2a[klo] + (b*b*b-b)*y2a[khi]) * (h*h)/6.0; return y; } @@ -601,11 +600,9 @@ void BondTable::uf_lookup(int type, double x, double &u, double &f) const Table *tb = &tables[tabindex[type]]; const int itable = static_cast ((x - tb->lo) * tb->invdelta); if (itable < 0) - error->one(FLERR,"Bond length < table inner cutoff: " - "type {} length {:.8}",type,x); + error->one(FLERR,"Bond length < table inner cutoff: type {} length {:.8}",type,x); else if (itable >= tablength) - error->one(FLERR,"Bond length > table outer cutoff: " - "type {} length {:.8}",type,x); + error->one(FLERR,"Bond length > table outer cutoff: type {} length {:.8}",type,x); if (tabstyle == LINEAR) { fraction = (x - tb->r[itable]) * tb->invdelta; @@ -617,10 +614,8 @@ void BondTable::uf_lookup(int type, double x, double &u, double &f) b = (x - tb->r[itable]) * tb->invdelta; a = 1.0 - b; u = a * tb->e[itable] + b * tb->e[itable+1] + - ((a*a*a-a)*tb->e2[itable] + (b*b*b-b)*tb->e2[itable+1]) * - tb->deltasq6; + ((a*a*a-a)*tb->e2[itable] + (b*b*b-b)*tb->e2[itable+1]) * tb->deltasq6; f = a * tb->f[itable] + b * tb->f[itable+1] + - ((a*a*a-a)*tb->f2[itable] + (b*b*b-b)*tb->f2[itable+1]) * - tb->deltasq6; + ((a*a*a-a)*tb->f2[itable] + (b*b*b-b)*tb->f2[itable+1]) * tb->deltasq6; } } diff --git a/src/MOLECULE/dihedral_table.cpp b/src/MOLECULE/dihedral_table.cpp index a91324dd98..dbca4a85c1 100644 --- a/src/MOLECULE/dihedral_table.cpp +++ b/src/MOLECULE/dihedral_table.cpp @@ -189,11 +189,8 @@ static int solve_cyc_tridiag( const double diag[], size_t d_stride, spline and splint routines modified from Numerical Recipes ------------------------------------------------------------------------- */ -static int cyc_spline(double const *xa, - double const *ya, - int n, - double period, - double *y2a, bool warn) +static int cyc_spline(double const *xa, double const *ya, int n, + double period, double *y2a, bool warn) { double *diag = new double[n]; @@ -264,12 +261,8 @@ static int cyc_spline(double const *xa, // range should not exceed period (ie xa[n-1] < xa[0] + period). // x must lie in the range: [(xa[n-1]-period), (xa[0]+period)] // "period" is typically 2*PI. -static double cyc_splint(double const *xa, - double const *ya, - double const *y2a, - int n, - double period, - double x) +static double cyc_splint(double const *xa, double const *ya, double const *y2a, + int n, double period, double x) { int klo = -1; int khi = n; @@ -302,11 +295,8 @@ static double cyc_splint(double const *xa, } // cyc_splint() -static double cyc_lin(double const *xa, - double const *ya, - int n, - double period, - double x) +static double cyc_lin(double const *xa, double const *ya, + int n, double period, double x) { int klo = -1; int khi = n; @@ -337,21 +327,14 @@ static double cyc_lin(double const *xa, } // cyc_lin() - - - // cyc_splintD(): Evaluate the deriviative of a cyclic spline at position x, // with n control points at xa[], ya[], with parameters y2a[]. // The xa[] must be monotonically increasing and their // range should not exceed period (ie xa[n-1] < xa[0] + period). // x must lie in the range: [(xa[n-1]-period), (xa[0]+period)] // "period" is typically 2*PI. -static double cyc_splintD(double const *xa, - double const *ya, - double const *y2a, - int n, - double period, - double x) +static double cyc_splintD(double const *xa, double const *ya, double const *y2a, + int n, double period, double x) { int klo = -1; int khi = n; // (not n-1) @@ -829,9 +812,9 @@ void DihedralTable::coeff(int narg, char **arg) // We also want the angles to be sorted in increasing order. // This messy code fixes these problems with the user's data: { - double *phifile_tmp = new double [tb->ninput]; //temporary arrays - double *ffile_tmp = new double [tb->ninput]; //used for sorting - double *efile_tmp = new double [tb->ninput]; + double *phifile_tmp = new double[tb->ninput]; //temporary arrays + double *ffile_tmp = new double[tb->ninput]; //used for sorting + double *efile_tmp = new double[tb->ninput]; // After re-imaging, does the range of angles cross the 0 or 2*PI boundary? // If so, find the discontinuity: @@ -1184,8 +1167,7 @@ void DihedralTable::compute_table(Table *tb) if (! tb->f_unspecified) tb->f[i] = cyc_splint(tb->phifile,tb->ffile,tb->f2file,tb->ninput,MY_2PI,phi); } - } // if (tabstyle == SPLINE) - else if (tabstyle == LINEAR) { + } else if (tabstyle == LINEAR) { if (! tb->f_unspecified) { for (int i = 0; i < tablength; i++) { double phi = i*tb->delta; @@ -1193,8 +1175,7 @@ void DihedralTable::compute_table(Table *tb) tb->e[i]= cyc_lin(tb->phifile,tb->efile,tb->ninput,MY_2PI,phi); tb->f[i]= cyc_lin(tb->phifile,tb->ffile,tb->ninput,MY_2PI,phi); } - } - else { + } else { for (int i = 0; i < tablength; i++) { double phi = i*tb->delta; tb->phi[i] = phi; @@ -1269,8 +1250,7 @@ void DihedralTable::param_extract(Table *tb, char *line) //else if (word == "EQ") { // tb->theta0 = values.next_double(); //} - else error->one(FLERR,"Invalid keyword in dihedral angle " - "table parameters ({})", word); + else error->one(FLERR,"Invalid keyword in dihedral angle table parameters ({})", word); } } catch (TokenizerException &e) { error->one(FLERR, e.what()); diff --git a/src/OPENMP/angle_table_omp.cpp b/src/OPENMP/angle_table_omp.cpp index 892f9295a5..cca34a67f7 100644 --- a/src/OPENMP/angle_table_omp.cpp +++ b/src/OPENMP/angle_table_omp.cpp @@ -16,15 +16,16 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ -#include "omp_compat.h" #include "angle_table_omp.h" -#include + #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" +#include +#include "omp_compat.h" #include "suffix.h" using namespace LAMMPS_NS; diff --git a/src/OPENMP/bond_table_omp.cpp b/src/OPENMP/bond_table_omp.cpp index faadca456a..dcc13c85c9 100644 --- a/src/OPENMP/bond_table_omp.cpp +++ b/src/OPENMP/bond_table_omp.cpp @@ -16,16 +16,16 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ -#include "omp_compat.h" #include "bond_table_omp.h" + #include "atom.h" #include "comm.h" #include "force.h" #include "neighbor.h" - #include +#include "omp_compat.h" #include "suffix.h" using namespace LAMMPS_NS; From e5416a9fee645d8ebc56b751ef233187269137d1 Mon Sep 17 00:00:00 2001 From: Donatas Surblys Date: Wed, 5 Jan 2022 19:02:25 +0900 Subject: [PATCH 116/193] update documentation for new centroid stress for shake and rigid/small --- doc/src/Bibliography.rst | 5 +++- doc/src/compute_heat_flux.rst | 21 +++++++++++---- doc/src/compute_stress_atom.rst | 45 ++++++++++++++++++++++++--------- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/doc/src/Bibliography.rst b/doc/src/Bibliography.rst index 0256552332..9f3591dcde 100644 --- a/doc/src/Bibliography.rst +++ b/doc/src/Bibliography.rst @@ -1123,9 +1123,12 @@ Bibliography **(Sun)** Sun, J. Phys. Chem. B, 102, 7338-7364 (1998). -**(Surblys)** +**(Surblys2019)** Surblys, Matsubara, Kikugawa, Ohara, Phys Rev E, 99, 051301(R) (2019). +**(Surblys2021)** + Surblys, Matsubara, Kikugawa, Ohara, J Appl Phys 130, 215104 (2021). + **(Sutmann)** Sutmann, Arnold, Fahrenberger, et. al., Physical review / E 88(6), 063308 (2013) diff --git a/doc/src/compute_heat_flux.rst b/doc/src/compute_heat_flux.rst index 94d6f09700..56975adc70 100644 --- a/doc/src/compute_heat_flux.rst +++ b/doc/src/compute_heat_flux.rst @@ -89,13 +89,20 @@ included in the calculation. .. warning:: The compute *heat/flux* has been reported to produce unphysical - values for angle, dihedral and improper contributions + values for angle, dihedral, improper and constraint force contributions when used with :doc:`compute stress/atom `, - as discussed in :ref:`(Surblys) ` and :ref:`(Boone) `. - You are strongly advised to + as discussed in :ref:`(Surblys2019) `, :ref:`(Boone) ` + and :ref:`(Surblys2021) `. You are strongly advised to use :doc:`compute centroid/stress/atom `, which has been implemented specifically for such cases. +.. warning:: + + Due to an implementation detail, the :math:`y` and :math:`z` + components of heat flux from :doc:`fix rigid ` + contribution when computed via :doc:`compute stress/atom ` + are highly unphysical and should not be used. + The Green-Kubo formulas relate the ensemble average of the auto-correlation of the heat flux :math:`\mathbf{J}` to the thermal conductivity :math:`\kappa`: @@ -232,10 +239,14 @@ none ---------- -.. _Surblys2: +.. _Surblys3: -**(Surblys)** Surblys, Matsubara, Kikugawa, Ohara, Phys Rev E, 99, 051301(R) (2019). +**(Surblys2019)** Surblys, Matsubara, Kikugawa, Ohara, Phys Rev E, 99, 051301(R) (2019). .. _Boone: **(Boone)** Boone, Babaei, Wilmer, J Chem Theory Comput, 15, 5579--5587 (2019). + +.. _Surblys4: + +**(Surblys2021)** Surblys, Matsubara, Kikugawa, Ohara, J Appl Phys 130, 215104 (2021). diff --git a/doc/src/compute_stress_atom.rst b/doc/src/compute_stress_atom.rst index cdb464a9d0..2c8be0c05a 100644 --- a/doc/src/compute_stress_atom.rst +++ b/doc/src/compute_stress_atom.rst @@ -87,6 +87,10 @@ Tersoff 3-body interaction) is assigned in equal portions to each atom in the set. E.g. 1/4 of the dihedral virial to each of the 4 atoms, or 1/3 of the fix virial due to SHAKE constraints applied to atoms in a water molecule via the :doc:`fix shake ` command. +As an exception, the virial contribution from +constraint forces in :doc:`fix rigid ` on each atom +is computed from the constraint force acting on the corresponding atom +and its position, i.e. the total virial is not equally distributed. In case of compute *centroid/stress/atom*, the virial contribution is: @@ -103,13 +107,25 @@ atom :math:`I` due to the interaction and the relative position :math:`\mathbf{r}_{I0}` of the atom :math:`I` to the geometric center of the interacting atoms, i.e. centroid, is used. As the geometric center is different for each interaction, the :math:`\mathbf{r}_{I0}` -also differs. The sixth and seventh terms, Kspace and :doc:`fix -` contribution respectively, are computed identical to compute -*stress/atom*. Although the total system virial is the same as +also differs. The sixth term, Kspace contribution, +is computed identically to compute *stress/atom*. +The seventh term is handed differently depending on +if the constraint forces are due to :doc:`fix shake ` +or :doc:`fix rigid `. +In case of SHAKE constraints, each distance constraint is +handed as a pairwise interaction. +E.g. in case of a water molecule, two OH and one HH distance +constraints are treated as three pairwise interactions. +In case of :doc:`fix rigid `, +all constraint forces in the molecule are treated +as a single many-body interaction with a single centroid position. +In case of water molecule, the formula expression would become +identical to that of the three-body angle interaction. +Although the total system virial is the same as compute *stress/atom*, compute *centroid/stress/atom* is know to -result in more consistent heat flux values for angle, dihedrals and -improper contributions when computed via :doc:`compute heat/flux -`. +result in more consistent heat flux values for angle, dihedrals, +improper and constraint force contributions +when computed via :doc:`compute heat/flux `. If no extra keywords are listed, the kinetic contribution all of the virial contribution terms are included in the per-atom stress tensor. @@ -134,7 +150,8 @@ contribution for the cluster interaction is divided evenly among those atoms. Details of how compute *centroid/stress/atom* obtains the virial for -individual atoms is given in :ref:`(Surblys) `, where the +individual atoms are given in :ref:`(Surblys2019) ` and +:ref:`(Surblys2021) `, where the idea is that the virial of the atom :math:`I` is the result of only the force :math:`\mathbf{F}_I` on the atom due to the interaction and its positional vector :math:`\mathbf{r}_{I0}`, relative to the @@ -235,10 +252,10 @@ between the pair of particles. All bond styles are supported. All angle, dihedral, improper styles are supported with the exception of INTEL and KOKKOS variants of specific styles. It also does not support models with long-range Coulombic or dispersion forces, -i.e. the kspace_style command in LAMMPS. It also does not support the -following fixes which add rigid-body constraints: :doc:`fix shake -`, :doc:`fix rattle `, :doc:`fix rigid -`, :doc:`fix rigid/small `. +i.e. the kspace_style command in LAMMPS. It also does not implement the +following fixes which add rigid-body constraints: +:doc:`fix rigid/* ` and the OpenMP accelerated version of :doc:`fix rigid/small `, +while all other :doc:`fix rigid/*/small ` are implemented. LAMMPS will generate an error if one of these options is included in your model. Extension of centroid stress calculations to these force @@ -270,4 +287,8 @@ none .. _Surblys1: -**(Surblys)** Surblys, Matsubara, Kikugawa, Ohara, Phys Rev E, 99, 051301(R) (2019). +**(Surblys2019)** Surblys, Matsubara, Kikugawa, Ohara, Phys Rev E, 99, 051301(R) (2019). + +.. _Surblys2: + +**(Surblys2021)** Surblys, Matsubara, Kikugawa, Ohara, J Appl Phys 130, 215104 (2021). From 3ff2f53ead0b8a6cdb6b96f0df311c14164a19c6 Mon Sep 17 00:00:00 2001 From: Donatas Surblys Date: Wed, 5 Jan 2022 18:45:35 +0900 Subject: [PATCH 117/193] add citations to centroid/stress/atom --- src/compute_centroid_stress_atom.cpp | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/compute_centroid_stress_atom.cpp b/src/compute_centroid_stress_atom.cpp index 66dd11ac43..7e52e0a920 100644 --- a/src/compute_centroid_stress_atom.cpp +++ b/src/compute_centroid_stress_atom.cpp @@ -16,6 +16,7 @@ #include "angle.h" #include "atom.h" #include "bond.h" +#include "citeme.h" #include "comm.h" #include "dihedral.h" #include "error.h" @@ -34,6 +35,36 @@ using namespace LAMMPS_NS; enum { NOBIAS, BIAS }; +static const char cite_centroid_angle_improper_dihedral[] = + "compute centroid/stress/atom for angles, impropers and dihedrals:\n\n" + "@article{PhysRevE.99.051301,\n" + " title = {Application of atomic stress to compute heat flux via molecular dynamics for " + "systems with many-body interactions},\n" + " author = {Surblys, Donatas and Matsubara, Hiroki and Kikugawa, Gota and Ohara, Taku},\n" + " journal = {Physical Review E},\n" + " volume = {99},\n" + " issue = {5},\n" + " pages = {051301},\n" + " year = {2019},\n" + " doi = {10.1103/PhysRevE.99.051301},\n" + " url = {https://link.aps.org/doi/10.1103/PhysRevE.99.051301}\n" + "}\n\n"; + +static const char cite_centroid_shake_rigid[] = + "compute centroid/stress/atom for constrained dynamics:\n\n" + "@article{doi:10.1063/5.0070930,\n" + " author = {Surblys, Donatas and Matsubara, Hiroki and Kikugawa, Gota and Ohara, Taku},\n" + " journal = {Journal of Applied Physics},\n" + " title = {Methodology and meaning of computing heat flux via atomic stress in systems with " + "constraint dynamics},\n" + " volume = {130},\n" + " number = {21},\n" + " pages = {215104},\n" + " year = {2021},\n" + " doi = {10.1063/5.0070930},\n" + " url = {https://doi.org/10.1063/5.0070930},\n" + "}\n\n"; + /* ---------------------------------------------------------------------- */ ComputeCentroidStressAtom::ComputeCentroidStressAtom(LAMMPS *lmp, int narg, char **arg) : @@ -105,6 +136,12 @@ ComputeCentroidStressAtom::ComputeCentroidStressAtom(LAMMPS *lmp, int narg, char } nmax = 0; + + if (lmp->citeme) { + if (angleflag || dihedralflag || improperflag) + lmp->citeme->add(cite_centroid_angle_improper_dihedral); + if (fixflag) lmp->citeme->add(cite_centroid_shake_rigid); + } } /* ---------------------------------------------------------------------- */ From 9c9bc4790bf1edcd19f5c9fbde0c6f3cadc085f5 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 6 Jan 2022 18:31:15 -0500 Subject: [PATCH 118/193] update to fmtlib-8.1.1 --- src/fmt/core.h | 38 ++++++++++++++++++++++++++------------ src/fmt/format-inl.h | 6 ++++++ src/fmt/format.h | 36 ++++++++++++------------------------ 3 files changed, 44 insertions(+), 36 deletions(-) diff --git a/src/fmt/core.h b/src/fmt/core.h index 34fbef36b4..b7f9a960c6 100644 --- a/src/fmt/core.h +++ b/src/fmt/core.h @@ -17,7 +17,7 @@ #include // The fmt library version in the form major * 10000 + minor * 100 + patch. -#define FMT_VERSION 80100 +#define FMT_VERSION 80101 #if defined(__clang__) && !defined(__ibmxl__) # define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) @@ -219,6 +219,20 @@ # endif #endif +#ifndef FMT_DEPRECATED +# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900 +# define FMT_DEPRECATED [[deprecated]] +# else +# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__) +# define FMT_DEPRECATED __attribute__((deprecated)) +# elif FMT_MSC_VER +# define FMT_DEPRECATED __declspec(deprecated) +# else +# define FMT_DEPRECATED /* deprecated */ +# endif +# endif +#endif + // LAMMPS customization // use 'v8_lmp' namespace instead of 'v8' so that our // bundled copy does not collide with linking other code @@ -571,6 +585,7 @@ constexpr auto to_string_view(const S& s) } FMT_BEGIN_DETAIL_NAMESPACE + void to_string_view(...); using fmt::to_string_view; @@ -606,7 +621,7 @@ struct error_handler { constexpr error_handler(const error_handler&) = default; // This function is intentionally not constexpr to give a compile-time error. - void on_error(const char* message) { throw_format_error(message); } + FMT_NORETURN FMT_API void on_error(const char* message); }; FMT_END_DETAIL_NAMESPACE @@ -1378,21 +1393,20 @@ template struct arg_mapper { using cstring_result = conditional_t::value, const char*, unformattable_pointer>; - // DEPRECATED! - FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val) -> cstring_result { - return map(reinterpret_cast(val)); - } - // DEPRECATED! - FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val) + FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val) -> cstring_result { return map(reinterpret_cast(val)); } - // DEPRECATED! - FMT_CONSTEXPR FMT_INLINE auto map(signed char* val) -> cstring_result { + FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val) + -> cstring_result { return map(reinterpret_cast(val)); } - // DEPRECATED! - FMT_CONSTEXPR FMT_INLINE auto map(unsigned char* val) -> cstring_result { + FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(signed char* val) + -> cstring_result { + return map(reinterpret_cast(val)); + } + FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(unsigned char* val) + -> cstring_result { return map(reinterpret_cast(val)); } diff --git a/src/fmt/format-inl.h b/src/fmt/format-inl.h index 0c277956f1..3c0739a1ed 100644 --- a/src/fmt/format-inl.h +++ b/src/fmt/format-inl.h @@ -2595,6 +2595,12 @@ FMT_FUNC void report_system_error(int error_code, report_error(format_system_error, error_code, message); } +// DEPRECATED! +// This function is defined here and not inline for ABI compatiblity. +FMT_FUNC void detail::error_handler::on_error(const char* message) { + throw_format_error(message); +} + FMT_FUNC std::string vformat(string_view fmt, format_args args) { // Don't optimize the "{}" case to keep the binary size small and because it // can be better optimized in fmt::format anyway. diff --git a/src/fmt/format.h b/src/fmt/format.h index 1a5ff23009..ee69651ca5 100644 --- a/src/fmt/format.h +++ b/src/fmt/format.h @@ -110,20 +110,6 @@ FMT_END_NAMESPACE # define FMT_CATCH(x) if (false) #endif -#ifndef FMT_DEPRECATED -# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900 -# define FMT_DEPRECATED [[deprecated]] -# else -# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__) -# define FMT_DEPRECATED __attribute__((deprecated)) -# elif FMT_MSC_VER -# define FMT_DEPRECATED __declspec(deprecated) -# else -# define FMT_DEPRECATED /* deprecated */ -# endif -# endif -#endif - #ifndef FMT_MAYBE_UNUSED # if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) # define FMT_MAYBE_UNUSED [[maybe_unused]] @@ -310,10 +296,18 @@ FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To { } inline auto is_big_endian() -> bool { +#ifdef _WIN32 + return false; +#elif defined(__BIG_ENDIAN__) + return true; +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) + return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__; +#else struct bytes { char data[sizeof(int)]; }; return bit_cast(1).data[0] == 0; +#endif } // A fallback implementation of uintptr_t for systems that lack it. @@ -323,7 +317,7 @@ struct fallback_uintptr { fallback_uintptr() = default; explicit fallback_uintptr(const void* p) { *this = bit_cast(p); - if (is_big_endian()) { + if (const_check(is_big_endian())) { for (size_t i = 0, j = sizeof(void*) - 1; i < j; ++i, --j) std::swap(value[i], value[j]); } @@ -526,7 +520,7 @@ FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e) return next; } -enum { invalid_code_point = ~uint32_t() }; +constexpr uint32_t invalid_code_point = ~uint32_t(); // Invokes f(cp, sv) for every code point cp in s with sv being the string view // corresponding to the code point. cp is invalid_code_point on error. @@ -3044,14 +3038,8 @@ constexpr auto operator"" _a(const char* s, size_t) -> detail::udl_arg { } # endif -/** - DEPRECATED! User-defined literal equivalent of fmt::format. - - **Example**:: - - using namespace fmt::literals; - std::string message = "The answer is {}"_format(42); - */ +// DEPRECATED! +// User-defined literal equivalent of fmt::format. FMT_DEPRECATED constexpr auto operator"" _format(const char* s, size_t n) -> detail::udl_formatter { return {{s, n}}; From e3dd2908d9ac1c1e944b8c648a00ce6acb0c9a17 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 6 Jan 2022 19:42:45 -0500 Subject: [PATCH 119/193] Step version strings for the next patch release --- doc/lammps.1 | 2 +- src/version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/lammps.1 b/doc/lammps.1 index a374e62604..58086b1fae 100644 --- a/doc/lammps.1 +++ b/doc/lammps.1 @@ -1,4 +1,4 @@ -.TH LAMMPS "1" "14 December 2021" "2021-12-14" +.TH LAMMPS "1" "7 January 2022" "2022-1-7" .SH NAME .B LAMMPS \- Molecular Dynamics Simulator. diff --git a/src/version.h b/src/version.h index 6bb32291be..c33ca6ee15 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define LAMMPS_VERSION "14 Dec 2021" +#define LAMMPS_VERSION "7 Jan 2022" From 240db21054ff8e5445d709caa825d76ee6e3ef57 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 11 Jan 2022 11:46:08 -0500 Subject: [PATCH 120/193] silence possible warnings about missing files on "make clean-all" --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 2d651c4986..d23058447a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -439,7 +439,7 @@ clean: clean-all: rm -rf Obj_* - rm style_*.h packages_*.h lmpgitversion.h lmpinstalledpkgs.h + rm -f style_*.h packages_*.h lmpgitversion.h lmpinstalledpkgs.h clean-%: @if [ $@ = "clean-serial" ]; \ From 698256f4fea42bcbbaa350f6e64163a32d3a1adf Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 12 Jan 2022 08:17:54 -0500 Subject: [PATCH 121/193] update fedora singularity image to Fedora 35 --- tools/singularity/{fedora34_mingw.def => fedora35_mingw.def} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename tools/singularity/{fedora34_mingw.def => fedora35_mingw.def} (99%) diff --git a/tools/singularity/fedora34_mingw.def b/tools/singularity/fedora35_mingw.def similarity index 99% rename from tools/singularity/fedora34_mingw.def rename to tools/singularity/fedora35_mingw.def index 8a1f108aec..c2108a378c 100644 --- a/tools/singularity/fedora34_mingw.def +++ b/tools/singularity/fedora35_mingw.def @@ -1,5 +1,5 @@ BootStrap: docker -From: fedora:34 +From: fedora:35 %post dnf -y update @@ -94,7 +94,7 @@ EOF CUSTOM_PROMPT_ENV=/.singularity.d/env/99-zz_custom_prompt.sh cat >$CUSTOM_PROMPT_ENV < Date: Fri, 14 Jan 2022 13:02:15 -0500 Subject: [PATCH 122/193] check return values for errors --- src/MANYBODY/pair_eam_cd.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/MANYBODY/pair_eam_cd.cpp b/src/MANYBODY/pair_eam_cd.cpp index 46d439b879..dc1ec360c6 100644 --- a/src/MANYBODY/pair_eam_cd.cpp +++ b/src/MANYBODY/pair_eam_cd.cpp @@ -499,10 +499,13 @@ void PairEAMCD::read_h_coeff(char *filename) // Seek to end of file, read last part into a buffer and // then skip over lines in buffer until reaching the end. - platform::fseek(fptr, platform::END_OF_FILE); - platform::fseek(fptr, platform::ftell(fptr) - MAXLINE); + if ( (platform::fseek(fptr, platform::END_OF_FILE) < 0) + || (platform::fseek(fptr, platform::ftell(fptr) - MAXLINE) < 0)) + error->one(FLERR,"Failure to seek to end-of-file for reading h(x) coeffs: {}", + utils::getsyserror()); + char *buf = new char[MAXLINE+1]; - fread(buf, 1, MAXLINE, fptr); + utils::sfread(FLERR, buf, 1, MAXLINE, fptr, filename, error); buf[MAXLINE] = '\0'; // must 0-terminate buffer for string processing Tokenizer lines(buf, "\n"); delete[] buf; From 2213eb8d3f090e88d06a977423e8d240e7201d35 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jan 2022 14:45:12 -0500 Subject: [PATCH 123/193] use enum with symbolic constants instead of numbers --- src/output.cpp | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/output.cpp b/src/output.cpp index a8fda4173d..4156c6fc5e 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -41,6 +41,8 @@ using namespace LAMMPS_NS; #define DELTA 1 #define EPSDT 1.0e-6 +enum {SETUP, WRITE, RESET_DT}; + /* ---------------------------------------------------------------------- initialize all output ------------------------------------------------------------------------- */ @@ -232,7 +234,7 @@ void Output::setup(int memflag) // only do this if dump written or dump has not been written yet if (writeflag || last_dump[idump] < 0) - calculate_next_dump(0,idump,ntimestep); + calculate_next_dump(SETUP,idump,ntimestep); // if dump not written now, use addstep_compute_all() // since don't know what computes the dump will invoke @@ -361,7 +363,7 @@ void Output::setup(int memflag) dump[idump]->write(); last_dump[idump] = ntimestep; - calculate_next_dump(1,idump,ntimestep); + calculate_next_dump(WRITE,idump,ntimestep); if (mode_dump[idump] == 0 && (dump[idump]->clearstep || var_dump[idump])) @@ -468,9 +470,9 @@ void Output::setup(int memflag) for timestep mode, set next_dump for simulation time mode, set next_time_dump and next_dump which flag depends on caller - 0 = from setup() at start of run - 1 = from write() during run each time a dump file is written - 2 = from reset_dt() called from fix dt/reset when it changes timestep size + SETUP = from setup() at start of run + WRITE = from write() during run each time a dump file is written + RESET_DT = from reset_dt() called from fix dt/reset when it changes timestep size ------------------------------------------------------------------------- */ void Output::calculate_next_dump(int which, int idump, bigint ntimestep) @@ -482,13 +484,13 @@ void Output::setup(int memflag) if (every_dump[idump]) { - // which = 0: nextdump = next multiple of every_dump - // which = 1: increment nextdump by every_dump + // which = SETUP: nextdump = next multiple of every_dump + // which = WRITE: increment nextdump by every_dump - if (which == 0) + if (which == SETUP) next_dump[idump] = (ntimestep/every_dump[idump])*every_dump[idump] + every_dump[idump]; - else if (which == 1) + else if (which == WRITE) next_dump[idump] += every_dump[idump]; } else { @@ -510,17 +512,28 @@ void Output::setup(int memflag) if (every_time_dump[idump] > 0.0) { - // which = 0: nexttime = next multiple of every_time_dump - // which = 1: increment nexttime by every_time_dump - // which = 2: no change to previous nexttime (only timestep has changed) + // which = SETUP: nexttime = next multiple of every_time_dump + // which = WRITE: increment nexttime by every_time_dump + // which = RESET_DT: no change to previous nexttime (only timestep has changed) - if (which == 0) + switch (which) { + case SETUP: nexttime = static_cast (tcurrent/every_time_dump[idump]) * every_time_dump[idump] + every_time_dump[idump]; - else if (which == 1) + break; + + case WRITE: nexttime = next_time_dump[idump] + every_time_dump[idump]; - else if (which == 2) + break; + + case RESET_DT: nexttime = next_time_dump[idump]; + break; + + default: + nexttime = 0; + error->all(FLERR,"Unexpected argument to calculate_next_dump"); + } nextdump = ntimestep + static_cast ((nexttime - tcurrent - EPSDT*update->dt) / @@ -541,10 +554,10 @@ void Output::setup(int memflag) } else { - // do not re-evaulate variable for which = 2, leave nexttime as-is + // do not re-evaulate variable for which = RESET_DT, leave nexttime as-is // unless next_time_dump < 0.0, which means variable never yet evaluated - if (which < 2 || next_time_dump[idump] < 0.0) { + if (which < RESET_DT || next_time_dump[idump] < 0.0) { nexttime = input->variable->compute_equal(ivar_dump[idump]); } else nexttime = next_time_dump[idump]; @@ -704,7 +717,7 @@ void Output::reset_dt() // since timestep change affects next step if (next_dump[idump] != ntimestep) - calculate_next_dump(2,idump,update->ntimestep); + calculate_next_dump(RESET_DT,idump,update->ntimestep); if (dump[idump]->clearstep || var_dump[idump]) next_time_dump_any = MIN(next_time_dump_any,next_dump[idump]); From dcb1ddb28272e87d76058c5bc2b7c2d9d90ca48c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jan 2022 14:55:13 -0500 Subject: [PATCH 124/193] remove redundant code --- src/fix_move.cpp | 63 ++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 39 deletions(-) diff --git a/src/fix_move.cpp b/src/fix_move.cpp index 72fd9b75d2..f7bc4d3640 100644 --- a/src/fix_move.cpp +++ b/src/fix_move.cpp @@ -522,7 +522,7 @@ void FixMove::initial_integrate(int /*vflag*/) } } - // for wiggle: X = X0 + A sin(w*dt) + // for wiggle: X = X0 + A sin(w*dt) } else if (mstyle == WIGGLE) { double arg = omega_rotate * delta; @@ -578,19 +578,19 @@ void FixMove::initial_integrate(int /*vflag*/) } } - // for rotate by right-hand rule around omega: - // P = point = vector = point of rotation - // R = vector = axis of rotation - // w = omega of rotation (from period) - // X0 = xoriginal = initial coord of atom - // R0 = runit = unit vector for R - // D = X0 - P = vector from P to X0 - // C = (D dot R0) R0 = projection of atom coord onto R line - // A = D - C = vector from R line to X0 - // B = R0 cross A = vector perp to A in plane of rotation - // A,B define plane of circular rotation around R line - // X = P + C + A cos(w*dt) + B sin(w*dt) - // V = w R0 cross (A cos(w*dt) + B sin(w*dt)) + // for rotate by right-hand rule around omega: + // P = point = vector = point of rotation + // R = vector = axis of rotation + // w = omega of rotation (from period) + // X0 = xoriginal = initial coord of atom + // R0 = runit = unit vector for R + // D = X0 - P = vector from P to X0 + // C = (D dot R0) R0 = projection of atom coord onto R line + // A = D - C = vector from R line to X0 + // B = R0 cross A = vector perp to A in plane of rotation + // A,B define plane of circular rotation around R line + // X = P + C + A cos(w*dt) + B sin(w*dt) + // V = w R0 cross (A cos(w*dt) + B sin(w*dt)) } else if (mstyle == ROTATE) { double arg = omega_rotate * delta; @@ -707,10 +707,10 @@ void FixMove::initial_integrate(int /*vflag*/) } } - // for variable: compute x,v from variables - // NOTE: also allow for changes to extra attributes? - // omega, angmom, theta, quat - // only necessary if prescribed motion involves rotation + // for variable: compute x,v from variables + // NOTE: also allow for changes to extra attributes? + // omega, angmom, theta, quat + // only necessary if prescribed motion involves rotation } else if (mstyle == VARIABLE) { @@ -778,21 +778,16 @@ void FixMove::initial_integrate(int /*vflag*/) } else if (vxvarstr) { if (vxvarstyle == EQUAL) v[i][0] = vx; else v[i][0] = velocity[i][0]; - if (rmass) { - x[i][0] += dtv * v[i][0]; - } else { - x[i][0] += dtv * v[i][0]; - } + x[i][0] += dtv * v[i][0]; } else { if (rmass) { dtfm = dtf / rmass[i]; v[i][0] += dtfm * f[i][0]; - x[i][0] += dtv * v[i][0]; } else { dtfm = dtf / mass[type[i]]; v[i][0] += dtfm * f[i][0]; - x[i][0] += dtv * v[i][0]; } + x[i][0] += dtv * v[i][0]; } if (yvarstr && vyvarstr) { @@ -806,21 +801,16 @@ void FixMove::initial_integrate(int /*vflag*/) } else if (vyvarstr) { if (vyvarstyle == EQUAL) v[i][1] = vy; else v[i][1] = velocity[i][1]; - if (rmass) { - x[i][1] += dtv * v[i][1]; - } else { - x[i][1] += dtv * v[i][1]; - } + x[i][1] += dtv * v[i][1]; } else { if (rmass) { dtfm = dtf / rmass[i]; v[i][1] += dtfm * f[i][1]; - x[i][1] += dtv * v[i][1]; } else { dtfm = dtf / mass[type[i]]; v[i][1] += dtfm * f[i][1]; - x[i][1] += dtv * v[i][1]; } + x[i][1] += dtv * v[i][1]; } if (zvarstr && vzvarstr) { @@ -834,21 +824,16 @@ void FixMove::initial_integrate(int /*vflag*/) } else if (vzvarstr) { if (vzvarstyle == EQUAL) v[i][2] = vz; else v[i][2] = velocity[i][2]; - if (rmass) { - x[i][2] += dtv * v[i][2]; - } else { - x[i][2] += dtv * v[i][2]; - } + x[i][2] += dtv * v[i][2]; } else { if (rmass) { dtfm = dtf / rmass[i]; v[i][2] += dtfm * f[i][2]; - x[i][2] += dtv * v[i][2]; } else { dtfm = dtf / mass[type[i]]; v[i][2] += dtfm * f[i][2]; - x[i][2] += dtv * v[i][2]; } + x[i][2] += dtv * v[i][2]; } domain->remap_near(x[i],xold); From ed702b930928584017f70a5d83a4b32304e8e1d5 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jan 2022 15:58:57 -0500 Subject: [PATCH 125/193] don't allow exceptions to "escape" a destructor --- src/REAXFF/fix_reaxff_species.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/REAXFF/fix_reaxff_species.cpp b/src/REAXFF/fix_reaxff_species.cpp index 4f44cc7c64..bed7fabb20 100644 --- a/src/REAXFF/fix_reaxff_species.cpp +++ b/src/REAXFF/fix_reaxff_species.cpp @@ -246,8 +246,10 @@ FixReaxFFSpecies::~FixReaxFFSpecies() if (posflag && multipos_opened) fclose(pos); } - modify->delete_compute(fmt::format("SPECATOM_{}",id)); - modify->delete_fix(fmt::format("SPECBOND_{}",id)); + try { + modify->delete_compute(fmt::format("SPECATOM_{}",id)); + modify->delete_fix(fmt::format("SPECBOND_{}",id)); + } catch (std::exception &) {} } /* ---------------------------------------------------------------------- */ From 11cc8a6a5928548a186f7b5536d00ff186f5ded0 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jan 2022 15:59:05 -0500 Subject: [PATCH 126/193] whitespace --- src/output.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output.cpp b/src/output.cpp index 4156c6fc5e..6c14900ade 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -475,7 +475,7 @@ void Output::setup(int memflag) RESET_DT = from reset_dt() called from fix dt/reset when it changes timestep size ------------------------------------------------------------------------- */ - void Output::calculate_next_dump(int which, int idump, bigint ntimestep) +void Output::calculate_next_dump(int which, int idump, bigint ntimestep) { // dump mode is by timestep // just set next_dump From e271a54802014cefd7e8d71de3fa9e125540e84a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jan 2022 20:25:00 -0500 Subject: [PATCH 127/193] re-enable using rerun after the changes from PR #3052 --- src/output.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/output.cpp b/src/output.cpp index a8fda4173d..b2b8011842 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -619,9 +619,8 @@ int Output::check_time_dumps(bigint ntimestep) { next_dump_any = MAXBIGINT; for (int idump = 0; idump < ndump; idump++) - if (last_dump[idump] >= 0) - error->all(FLERR, - "Cannot reset timestep with active dump - must undump first"); + if ((last_dump[idump] >= 0) && !update->whichflag) + error->all(FLERR, "Cannot reset timestep with active dump - must undump first"); if (restart_flag_single) { if (restart_every_single) { From 1e7969c7b9bf3977b08483fb56006c7b607708d3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 15 Jan 2022 19:34:47 -0500 Subject: [PATCH 128/193] add new pair styles harmonic/cut and harmonic/cut/omp --- doc/src/Commands_pair.rst | 1 + doc/src/pair_harmonic_cut.rst | 90 +++++ doc/src/pair_style.rst | 1 + src/.gitignore | 2 + src/EXTRA-PAIR/pair_harmonic_cut.cpp | 314 ++++++++++++++++++ src/EXTRA-PAIR/pair_harmonic_cut.h | 72 ++++ src/OPENMP/pair_harmonic_cut_omp.cpp | 152 +++++++++ src/OPENMP/pair_harmonic_cut_omp.h | 48 +++ .../tests/mol-pair-harmonic_cut.yaml | 94 ++++++ 9 files changed, 774 insertions(+) create mode 100644 doc/src/pair_harmonic_cut.rst create mode 100644 src/EXTRA-PAIR/pair_harmonic_cut.cpp create mode 100644 src/EXTRA-PAIR/pair_harmonic_cut.h create mode 100644 src/OPENMP/pair_harmonic_cut_omp.cpp create mode 100644 src/OPENMP/pair_harmonic_cut_omp.h create mode 100644 unittest/force-styles/tests/mol-pair-harmonic_cut.yaml diff --git a/doc/src/Commands_pair.rst b/doc/src/Commands_pair.rst index 9ac4fc851c..a226d73b36 100644 --- a/doc/src/Commands_pair.rst +++ b/doc/src/Commands_pair.rst @@ -119,6 +119,7 @@ OPT. * :doc:`granular ` * :doc:`gw ` * :doc:`gw/zbl ` + * :doc:`harmonic/cut (o) ` * :doc:`hbond/dreiding/lj (o) ` * :doc:`hbond/dreiding/morse (o) ` * :doc:`hdnnp ` diff --git a/doc/src/pair_harmonic_cut.rst b/doc/src/pair_harmonic_cut.rst new file mode 100644 index 0000000000..877d2d97ff --- /dev/null +++ b/doc/src/pair_harmonic_cut.rst @@ -0,0 +1,90 @@ +.. index:: pair_style harmonic/cut +.. index:: pair_style harmonic/cut/omp + +pair_style harmonic/cut command +=============================== + +Accelerator Variants: *harmonic/cut/omp* + +Syntax +"""""" + +.. code-block:: LAMMPS + + pair_style style + +* style = *harmonic/cut* + +Examples +"""""""" + +.. code-block:: LAMMPS + + pair_style harmonic/cut 2.5 + pair_coeff * * 0.2 2.0 + pair_coeff 1 1 0.5 2.5 + +Description +""""""""""" + +Style *harmonic/cut* computes pairwise repulsive-only harmonic interactions with the formula + +.. math:: + + E = k (r_c - r)^2 \qquad r < r_c + +: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 +above, or in the data file or restart files read by the +:doc:`read_data ` or :doc:`read_restart ` +commands: + +* :math:`k` (energy units) +* :math:`r_c` (distance units) + +---------- + +.. include:: accel_styles.rst + +---------- + +Mixing, shift, table, tail correction, restart, rRESPA info +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +For atom type pairs I,J and I != J, the :math:`k` and :math:`r_c` +coefficients can be mixed. The default mix value is *geometric*. +See the "pair_modify" command for details. + +Since the potential is zero at and beyond the cutoff parameter by +construction, there is no need to support support the :doc:`pair_modify +` shift or tail options for the energy and pressure of the +pair interaction. + +These pair styles write their 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. + +These pair styles can only be used via the *pair* keyword of the +:doc:`run_style respa ` command. They do not support the +*inner*, *middle*, *outer* keywords. + +---------- + +Restrictions +"""""""""""" + +The *harmonic/cut* pair style is only enabled if LAMMPS was +built with the EXTRA-PAIR package. +See the :doc:`Build package ` page for more info. + +Related commands +"""""""""""""""" + +:doc:`pair_coeff ` + +Default +""""""" + +none diff --git a/doc/src/pair_style.rst b/doc/src/pair_style.rst index 4bb3c90a8d..f657e29aa3 100644 --- a/doc/src/pair_style.rst +++ b/doc/src/pair_style.rst @@ -183,6 +183,7 @@ accelerated styles exist. * :doc:`gran/hooke/history ` - granular potential without history effects * :doc:`gw ` - Gao-Weber potential * :doc:`gw/zbl ` - Gao-Weber potential with a repulsive ZBL core +* :doc:`harmonic/cut ` - repulsive-only harmonic potential * :doc:`hbond/dreiding/lj ` - DREIDING hydrogen bonding LJ potential * :doc:`hbond/dreiding/morse ` - DREIDING hydrogen bonding Morse potential * :doc:`hdnnp ` - High-dimensional neural network potential diff --git a/src/.gitignore b/src/.gitignore index 695c9a19af..a9eef4b371 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1489,6 +1489,8 @@ /pair_dpd_fdt.h /pair_dpd_fdt_energy.cpp /pair_dpd_fdt_energy.h +/pair_harmonic_cut.cpp +/pair_harmonic_cut.h /pair_lennard_mdf.cpp /pair_lennard_mdf.h /pair_lj_cut_coul_long_cs.cpp diff --git a/src/EXTRA-PAIR/pair_harmonic_cut.cpp b/src/EXTRA-PAIR/pair_harmonic_cut.cpp new file mode 100644 index 0000000000..bd0e48efdc --- /dev/null +++ b/src/EXTRA-PAIR/pair_harmonic_cut.cpp @@ -0,0 +1,314 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Axel Kohlmeyer (Temple U) +------------------------------------------------------------------------- */ + +#include "pair_harmonic_cut.h" + +#include "atom.h" +#include "comm.h" +#include "error.h" +#include "force.h" +#include "math_const.h" +#include "memory.h" +#include "neigh_list.h" +#include "neighbor.h" +#include "update.h" + +#include +#include + +using namespace LAMMPS_NS; +using namespace MathConst; + +/* ---------------------------------------------------------------------- */ + +PairHarmonicCut::PairHarmonicCut(LAMMPS *lmp) : Pair(lmp) +{ + writedata = 1; +} + +/* ---------------------------------------------------------------------- */ + +PairHarmonicCut::~PairHarmonicCut() +{ + if (allocated) { + memory->destroy(setflag); + memory->destroy(k); + memory->destroy(cut); + memory->destroy(cutsq); + } +} + +/* ---------------------------------------------------------------------- */ + +void PairHarmonicCut::compute(int eflag, int vflag) +{ + int i, j, ii, jj, inum, jnum, itype, jtype; + double xtmp, ytmp, ztmp, fxtmp, fytmp, fztmp; + double delx, dely, delz, rsq, factor_lj; + int *ilist, *jlist, *numneigh, **firstneigh; + + ev_init(eflag, vflag); + + double **x = atom->x; + double **f = atom->f; + int *type = atom->type; + int nlocal = atom->nlocal; + double *special_lj = force->special_lj; + int newton_pair = force->newton_pair; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + // loop over neighbors of my atoms + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + fxtmp = fytmp = fztmp = 0.0; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + factor_lj = special_lj[sbmask(j)]; + j &= NEIGHMASK; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx * delx + dely * dely + delz * delz; + jtype = type[j]; + + if (rsq < cutsq[itype][jtype]) { + const double r = sqrt(rsq); + const double delta = cut[itype][jtype] - r; + const double philj = factor_lj * delta * k[itype][jtype]; + const double fpair = delta * philj / r; + + fxtmp += delx * fpair; + fytmp += dely * fpair; + fztmp += delz * fpair; + if (newton_pair || j < nlocal) { + f[j][0] -= delx * fpair; + f[j][1] -= dely * fpair; + f[j][2] -= delz * fpair; + } + + if (evflag) ev_tally(i, j, nlocal, newton_pair, philj, 0.0, fpair, delx, dely, delz); + } + } + f[i][0] += fxtmp; + f[i][1] += fytmp; + f[i][2] += fztmp; + } + + if (vflag_fdotr) virial_fdotr_compute(); +} + +/* ---------------------------------------------------------------------- + allocate all arrays +------------------------------------------------------------------------- */ + +void PairHarmonicCut::allocate() +{ + allocated = 1; + int n = atom->ntypes + 1; + + memory->create(setflag, n, n, "pair:setflag"); + for (int i = 1; i < n; i++) + for (int j = i; j < n; j++) setflag[i][j] = 0; + + memory->create(k, n, n, "pair:k"); + memory->create(cut, n, n, "pair:cut"); + memory->create(cutsq, n, n, "pair:cutsq"); +} + +/* ---------------------------------------------------------------------- + global settings +------------------------------------------------------------------------- */ + +void PairHarmonicCut::settings(int narg, char **arg) +{ + if (narg > 0) error->all(FLERR, "Illegal pair_style command"); +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs +------------------------------------------------------------------------- */ + +void PairHarmonicCut::coeff(int narg, char **arg) +{ + if (narg != 4) error->all(FLERR, "Incorrect args for pair coefficients"); + if (!allocated) allocate(); + + int ilo, ihi, jlo, jhi; + utils::bounds(FLERR, arg[0], 1, atom->ntypes, ilo, ihi, error); + utils::bounds(FLERR, arg[1], 1, atom->ntypes, jlo, jhi, error); + + double k_one = utils::numeric(FLERR, arg[2], false, lmp); + double cut_one = utils::numeric(FLERR, arg[3], false, lmp); + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + for (int j = MAX(jlo, i); j <= jhi; j++) { + k[i][j] = k_one; + cut[i][j] = cut_one; + setflag[i][j] = 1; + count++; + } + } + + if (count == 0) error->all(FLERR, "Incorrect args for pair coefficients"); +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i +------------------------------------------------------------------------- */ + +double PairHarmonicCut::init_one(int i, int j) +{ + if (setflag[i][j] == 0) { + cut[i][j] = mix_distance(cut[i][i], cut[j][j]); + cut[j][i] = cut[i][j]; + k[i][j] = mix_energy(k[i][i], k[j][j], cut[i][i], cut[j][j]); + k[j][i] = k[i][j]; + } + return cut[i][j]; +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairHarmonicCut::write_restart(FILE *fp) +{ + write_restart_settings(fp); + + int i, j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + fwrite(&setflag[i][j], sizeof(int), 1, fp); + if (setflag[i][j]) { + fwrite(&k[i][j], sizeof(double), 1, fp); + fwrite(&cut[i][j], sizeof(double), 1, fp); + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairHarmonicCut::read_restart(FILE *fp) +{ + read_restart_settings(fp); + allocate(); + + int i, j; + int me = comm->me; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + if (me == 0) utils::sfread(FLERR, &setflag[i][j], sizeof(int), 1, fp, nullptr, error); + MPI_Bcast(&setflag[i][j], 1, MPI_INT, 0, world); + if (setflag[i][j]) { + if (me == 0) { + utils::sfread(FLERR, &k[i][j], sizeof(double), 1, fp, nullptr, error); + utils::sfread(FLERR, &cut[i][j], sizeof(double), 1, fp, nullptr, error); + } + MPI_Bcast(&k[i][j], 1, MPI_DOUBLE, 0, world); + MPI_Bcast(&cut[i][j], 1, MPI_DOUBLE, 0, world); + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairHarmonicCut::write_restart_settings(FILE *fp) +{ + fwrite(&offset_flag, sizeof(int), 1, fp); + fwrite(&mix_flag, sizeof(int), 1, fp); + fwrite(&tail_flag, sizeof(int), 1, fp); +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairHarmonicCut::read_restart_settings(FILE *fp) +{ + int me = comm->me; + if (me == 0) { + utils::sfread(FLERR, &offset_flag, sizeof(int), 1, fp, nullptr, error); + utils::sfread(FLERR, &mix_flag, sizeof(int), 1, fp, nullptr, error); + utils::sfread(FLERR, &tail_flag, sizeof(int), 1, fp, nullptr, error); + } + MPI_Bcast(&offset_flag, 1, MPI_INT, 0, world); + MPI_Bcast(&mix_flag, 1, MPI_INT, 0, world); + MPI_Bcast(&tail_flag, 1, MPI_INT, 0, world); +} + +/* ---------------------------------------------------------------------- + proc 0 writes to data file +------------------------------------------------------------------------- */ + +void PairHarmonicCut::write_data(FILE *fp) +{ + for (int i = 1; i <= atom->ntypes; i++) fprintf(fp, "%d %g %g\n", i, k[i][i], cut[i][i]); +} + +/* ---------------------------------------------------------------------- + proc 0 writes all pairs to data file +------------------------------------------------------------------------- */ + +void PairHarmonicCut::write_data_all(FILE *fp) +{ + for (int i = 1; i <= atom->ntypes; i++) + for (int j = i; j <= atom->ntypes; j++) fprintf(fp, "%d %d %g %g\n", i, j, k[i][j], cut[i][j]); +} + +/* ---------------------------------------------------------------------- */ + +double PairHarmonicCut::single(int /*i*/, int /*j*/, int itype, int jtype, double rsq, + double /*factor_coul*/, double factor_lj, double &fforce) +{ + if (rsq >= cutsq[itype][jtype]) { + fforce = 0.0; + return 0.0; + } + const double r = sqrt(rsq); + const double delta = cut[itype][jtype] - r; + const double philj = factor_lj * delta * k[itype][jtype]; + fforce = delta * philj / r; + return philj; +} + +/* ---------------------------------------------------------------------- */ + +void *PairHarmonicCut::extract(const char *str, int &dim) +{ + dim = 2; + if (strcmp(str, "k") == 0) return (void *) k; + if (strcmp(str, "cut") == 0) return (void *) cut; + return nullptr; +} diff --git a/src/EXTRA-PAIR/pair_harmonic_cut.h b/src/EXTRA-PAIR/pair_harmonic_cut.h new file mode 100644 index 0000000000..7dfdea995a --- /dev/null +++ b/src/EXTRA-PAIR/pair_harmonic_cut.h @@ -0,0 +1,72 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS +// clang-format off +PairStyle(harmonic/cut,PairHarmonicCut); +// clang-format on +#else + +#ifndef LMP_PAIR_HARMONIC_CUT_H +#define LMP_PAIR_HARMONIC_CUT_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairHarmonicCut : public Pair { + public: + PairHarmonicCut(class LAMMPS *); + virtual ~PairHarmonicCut(); + virtual void compute(int, int); + void settings(int, char **); + void coeff(int, char **); + double init_one(int, int); + void write_restart(FILE *); + void read_restart(FILE *); + void write_restart_settings(FILE *); + void read_restart_settings(FILE *); + void write_data(FILE *); + void write_data_all(FILE *); + double single(int, int, int, int, double, double, double, double &); + void *extract(const char *, int &); + + protected: + double **k, **cut; + + virtual void allocate(); +}; + +} // namespace LAMMPS_NS + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +E: Incorrect args for pair coefficients + +Self-explanatory. Check the input script or data file. + +E: Pair cutoff < Respa interior cutoff + +One or more pairwise cutoffs are too short to use with the specified +rRESPA cutoffs. + +*/ diff --git a/src/OPENMP/pair_harmonic_cut_omp.cpp b/src/OPENMP/pair_harmonic_cut_omp.cpp new file mode 100644 index 0000000000..6fcdc50a63 --- /dev/null +++ b/src/OPENMP/pair_harmonic_cut_omp.cpp @@ -0,0 +1,152 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + This software is distributed under the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Axel Kohlmeyer (Temple U) +------------------------------------------------------------------------- */ + +#include "pair_harmonic_cut_omp.h" + +#include "atom.h" +#include "comm.h" +#include "force.h" +#include "neigh_list.h" +#include "suffix.h" + +#include "omp_compat.h" +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +PairHarmonicCutOMP::PairHarmonicCutOMP(LAMMPS *lmp) : PairHarmonicCut(lmp), ThrOMP(lmp, THR_PAIR) +{ + suffix_flag |= Suffix::OMP; +} + +/* ---------------------------------------------------------------------- */ + +void PairHarmonicCutOMP::compute(int eflag, int vflag) +{ + ev_init(eflag, vflag); + + const int nall = atom->nlocal + atom->nghost; + const int nthreads = comm->nthreads; + const int inum = list->inum; + +#if defined(_OPENMP) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag, vflag) +#endif + { + int ifrom, ito, tid; + + loop_setup_thr(ifrom, ito, tid, inum, nthreads); + ThrData *thr = fix->get_thr(tid); + thr->timer(Timer::START); + ev_setup_thr(eflag, vflag, nall, eatom, vatom, nullptr, thr); + + if (evflag) { + if (eflag) { + if (force->newton_pair) + eval<1, 1, 1>(ifrom, ito, thr); + else + eval<1, 1, 0>(ifrom, ito, thr); + } else { + if (force->newton_pair) + eval<1, 0, 1>(ifrom, ito, thr); + else + eval<1, 0, 0>(ifrom, ito, thr); + } + } else { + if (force->newton_pair) + eval<0, 0, 1>(ifrom, ito, thr); + else + eval<0, 0, 0>(ifrom, ito, thr); + } + thr->timer(Timer::PAIR); + reduce_thr(this, eflag, vflag, thr); + } // end of omp parallel region +} + +template +void PairHarmonicCutOMP::eval(int iifrom, int iito, ThrData *const thr) +{ + const dbl3_t *_noalias const x = (dbl3_t *) atom->x[0]; + dbl3_t *_noalias const f = (dbl3_t *) thr->get_f()[0]; + const int *_noalias const type = atom->type; + const double *_noalias const special_lj = force->special_lj; + const int *_noalias const ilist = list->ilist; + const int *_noalias const numneigh = list->numneigh; + const int *const *const firstneigh = list->firstneigh; + + double xtmp, ytmp, ztmp, delx, dely, delz, fxtmp, fytmp, fztmp; + double rsq, factor_lj; + + const int nlocal = atom->nlocal; + int j, jj, jnum, jtype; + + // loop over neighbors of my atoms + + for (int ii = iifrom; ii < iito; ++ii) { + const int i = ilist[ii]; + const int itype = type[i]; + const int *_noalias const jlist = firstneigh[i]; + const double *_noalias const cutsqi = cutsq[itype]; + + xtmp = x[i].x; + ytmp = x[i].y; + ztmp = x[i].z; + jnum = numneigh[i]; + fxtmp = fytmp = fztmp = 0.0; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + factor_lj = special_lj[sbmask(j)]; + j &= NEIGHMASK; + + delx = xtmp - x[j].x; + dely = ytmp - x[j].y; + delz = ztmp - x[j].z; + rsq = delx * delx + dely * dely + delz * delz; + jtype = type[j]; + + if (rsq < cutsqi[jtype]) { + const double r = sqrt(rsq); + const double delta = cut[itype][jtype] - r; + const double philj = factor_lj * delta * k[itype][jtype]; + const double fpair = delta * philj / r; + + fxtmp += delx * fpair; + fytmp += dely * fpair; + fztmp += delz * fpair; + if (NEWTON_PAIR || j < nlocal) { + f[j].x -= delx * fpair; + f[j].y -= dely * fpair; + f[j].z -= delz * fpair; + } + + if (EVFLAG) + ev_tally_thr(this, i, j, nlocal, NEWTON_PAIR, philj, 0.0, fpair, delx, dely, delz, thr); + } + } + f[i].x += fxtmp; + f[i].y += fytmp; + f[i].z += fztmp; + } +} + +/* ---------------------------------------------------------------------- */ + +double PairHarmonicCutOMP::memory_usage() +{ + double bytes = memory_usage_thr(); + bytes += PairHarmonicCut::memory_usage(); + + return bytes; +} diff --git a/src/OPENMP/pair_harmonic_cut_omp.h b/src/OPENMP/pair_harmonic_cut_omp.h new file mode 100644 index 0000000000..4f40d2cf2a --- /dev/null +++ b/src/OPENMP/pair_harmonic_cut_omp.h @@ -0,0 +1,48 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Axel Kohlmeyer (Temple U) +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS +// clang-format off +PairStyle(harmonic/cut/omp,PairHarmonicCutOMP); +// clang-format on +#else + +#ifndef LMP_PAIR_HARMONIC_CUT_OMP_H +#define LMP_PAIR_HARMONIC_CUT_OMP_H + +#include "pair_harmonic_cut.h" +#include "thr_omp.h" + +namespace LAMMPS_NS { + +class PairHarmonicCutOMP : public PairHarmonicCut, public ThrOMP { + + public: + PairHarmonicCutOMP(class LAMMPS *); + + virtual void compute(int, int); + virtual double memory_usage(); + + private: + template + void eval(int ifrom, int ito, ThrData *const thr); +}; + +} // namespace LAMMPS_NS + +#endif +#endif diff --git a/unittest/force-styles/tests/mol-pair-harmonic_cut.yaml b/unittest/force-styles/tests/mol-pair-harmonic_cut.yaml new file mode 100644 index 0000000000..f1c39f1bd5 --- /dev/null +++ b/unittest/force-styles/tests/mol-pair-harmonic_cut.yaml @@ -0,0 +1,94 @@ +--- +lammps_version: 7 Jan 2022 +tags: generated +date_generated: Sat Jan 15 17:42:24 2022 +epsilon: 5e-14 +skip_tests: +prerequisites: ! | + atom full + pair harmonic/cut +pre_commands: ! "" +post_commands: ! | + pair_modify mix arithmetic +input_file: in.fourmol +pair_style: harmonic/cut +pair_coeff: ! | + 1 1 0.2 2.5 + 2 2 0.05 1.0 + 2 4 0.05 0.5 + 3 3 0.2 3.4 + 4 4 0.15 3.1 + 5 5 0.15 3.1 +extract: ! | + k 2 + cut 2 +natoms: 29 +init_vdwl: 0.6229303832094011 +init_coul: 0 +init_stress: ! |2- + 2.7086112336155066e-01 2.7116413086977192e-01 3.9219767031763964e-01 -1.0030847564854772e-01 4.4609473180383268e-02 -4.3637124113592815e-02 +init_forces: ! |2 + 1 8.0131849873788189e-03 4.9888010120265600e-02 2.8122360795900539e-02 + 2 7.9791227934915224e-03 6.5662021486410233e-03 -9.3912001601608869e-03 + 3 -3.0383030044476164e-02 -2.4462070024746502e-02 -6.7080526995988831e-03 + 4 -4.2871382862959282e-03 1.2944422156819623e-04 -3.1664690534881235e-03 + 5 -2.5653599407787658e-03 -5.6347847352330024e-03 5.7588483204582012e-03 + 6 -2.7432516621812987e-02 2.2443342050432843e-02 6.0842119146428050e-03 + 7 -2.3732010354850359e-02 4.8925005245008778e-03 -1.0554388509160603e-01 + 8 -1.9721449495438432e-02 8.7099489439665806e-03 7.7340656614040257e-02 + 9 3.1079843659201794e-03 3.3474898466584100e-03 1.3753907856580455e-02 + 10 1.5600383364335340e-02 -3.4154073795756010e-02 -2.4568763191891510e-02 + 11 -6.4786170866648325e-04 -2.7187839165446434e-03 -4.0027246972607657e-03 + 12 4.5446169193717613e-02 9.5334383719478614e-03 -2.3805265135058946e-02 + 13 3.6852167147282842e-03 -1.4578336695269954e-03 -6.9263908097426375e-05 + 14 -1.4516812720744084e-03 2.9539789066737132e-04 -3.7646771444256287e-03 + 15 -5.4837745225155548e-05 3.7892348244262858e-03 1.3279622443994443e-03 + 16 2.7804441490434852e-02 -2.9016569654227675e-02 -2.3977127174652516e-02 + 17 -1.3606174403879238e-03 -1.2150893147040220e-02 7.2609480510219010e-02 + 18 0.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00 + 19 0.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00 + 20 0.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00 + 21 -2.8478436810585638e-03 -3.4997997565726423e-03 1.0311097670993996e-02 + 22 -5.0036838658335881e-03 -1.2125954307909393e-03 -7.8502223695393180e-03 + 23 7.8515275468921519e-03 4.7123951873635815e-03 -2.4608753014546784e-03 + 24 2.2422341594776187e-03 -9.2864513866737705e-03 5.4147040050256424e-03 + 25 -7.0931333559850684e-03 1.1418916865888746e-03 -5.9630640752421178e-03 + 26 4.8508991965074497e-03 8.1445597000848954e-03 5.4836007021647544e-04 + 27 1.4352981398486984e-03 -1.0223071626521522e-02 3.5886145449699289e-03 + 28 -7.4679157140535102e-03 3.2093693544577983e-03 -5.0528642356851916e-03 + 29 6.0326175742048118e-03 7.0137022720637250e-03 1.4642496907152625e-03 +run_vdwl: 0.6227892941470253 +run_coul: 0 +run_stress: ! |2- + 2.7079595899259656e-01 2.7106155255810421e-01 3.9199181631609364e-01 -1.0017597886837336e-01 4.4639512685950337e-02 -4.3538044335882868e-02 +run_forces: ! |2 + 1 8.0241133736762959e-03 4.9859217970288555e-02 2.8099645116503875e-02 + 2 7.9858506322803297e-03 6.5851530052680168e-03 -9.3657942914726639e-03 + 3 -3.0378796721416249e-02 -2.4495674709975927e-02 -6.7374520329115941e-03 + 4 -4.2659306402640165e-03 1.3406094892709258e-04 -3.1564081120146015e-03 + 5 -2.5644106889098472e-03 -5.6291258903991056e-03 5.7537772274397249e-03 + 6 -2.7398860728585855e-02 2.2446081967441193e-02 6.0769742046490674e-03 + 7 -2.3725250988273959e-02 4.8748360958146379e-03 -1.0543946577300001e-01 + 8 -1.9795760001146530e-02 8.7619549352892182e-03 7.7257651402956734e-02 + 9 3.1107511049119794e-03 3.3343639112369677e-03 1.3749677634153570e-02 + 10 1.5635110483272714e-02 -3.4177809303542570e-02 -2.4562568959156386e-02 + 11 -6.4680122415666373e-04 -2.7045376093154955e-03 -3.9833439702283155e-03 + 12 4.5410386808201031e-02 9.5232810722562407e-03 -2.3816427499003763e-02 + 13 3.6819606745360318e-03 -1.4490090012638590e-03 -6.8397423783681964e-05 + 14 -1.4472530230181654e-03 2.8919520744570527e-04 -3.7524156545238243e-03 + 15 -5.6155855006963267e-05 3.7938646788886268e-03 1.3339639717048200e-03 + 16 2.7787095304862428e-02 -2.9020839215424241e-02 -2.3998357673493245e-02 + 17 -1.3560485109625556e-03 -1.2125014062935051e-02 7.2608941832180307e-02 + 18 0.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00 + 19 0.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00 + 20 0.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00 + 21 -2.8538862991433229e-03 -3.4800313716197438e-03 1.0305823645864499e-02 + 22 -5.0214625596301642e-03 -1.2260879074991976e-03 -7.8500736428379052e-03 + 23 7.8753488587734871e-03 4.7061192791189414e-03 -2.4557500030265946e-03 + 24 2.2600769444580133e-03 -9.2990099176050046e-03 5.4253104994500942e-03 + 25 -7.1247130587123505e-03 1.1308496354809658e-03 -5.9913273289481242e-03 + 26 4.8646361142543372e-03 8.1681602821240384e-03 5.6601682949803040e-04 + 27 1.4504263375229804e-03 -1.0234012017965840e-02 3.5742943025157811e-03 + 28 -7.4838995855112476e-03 3.2116101208619755e-03 -5.0534250649872060e-03 + 29 6.0334732479882672e-03 7.0224018971038644e-03 1.4791307624714251e-03 +... From 943fe487b54f165796c77a2e1b2a6b44012f3a9d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 16 Jan 2022 15:36:01 -0500 Subject: [PATCH 129/193] update whitespace and argument formats for longer source lines --- src/molecule.cpp | 222 +++++++++++++++++------------------------------ 1 file changed, 81 insertions(+), 141 deletions(-) diff --git a/src/molecule.cpp b/src/molecule.cpp index 40ca218ecc..d6c839dfc4 100644 --- a/src/molecule.cpp +++ b/src/molecule.cpp @@ -57,8 +57,7 @@ Molecule::Molecule(LAMMPS *lmp, int narg, char **arg, int &index) : id = utils::strdup(arg[0]); if (!utils::is_id(id)) - error->all(FLERR,"Molecule template ID must have only " - "alphanumeric or underscore characters"); + error->all(FLERR,"Molecule template ID must have only alphanumeric or underscore characters"); // parse args until reach unknown arg (next file) @@ -130,8 +129,7 @@ Molecule::Molecule(LAMMPS *lmp, int narg, char **arg, int &index) : if (me == 0) { fp = fopen(arg[ifile],"r"); if (fp == nullptr) - error->one(FLERR,"Cannot open molecule file {}: {}", - arg[ifile], utils::getsyserror()); + error->one(FLERR,"Cannot open molecule file {}: {}",arg[ifile], utils::getsyserror()); } read(0); if (me == 0) fclose(fp); @@ -496,8 +494,7 @@ void Molecule::read(int flag) if (nmatch != nwant) error->one(FLERR,"Invalid header line format in molecule file"); } catch (TokenizerException &e) { - error->one(FLERR, "Invalid header in molecule file\n" - "{}", e.what()); + error->one(FLERR,"Invalid header in molecule file: {}", e.what()); } } @@ -618,11 +615,9 @@ void Molecule::read(int flag) // Error: Either a too long/short section or a typo in the keyword if (utils::strmatch(keyword,"^[A-Za-z ]+$")) - error->one(FLERR,"Unknown section '{}' in molecule " - "file\n",keyword); + error->one(FLERR,"Unknown section '{}' in molecule file\n",keyword); else error->one(FLERR,"Unexpected line in molecule file " - "while looking for the next " - "section:\n{}",line); + "while looking for the next section:\n{}",line); } keyword = parse_keyword(1,line); } @@ -648,8 +643,7 @@ void Molecule::read(int flag) if (bondflag && specialflag == 0) { if (domain->box_exist == 0) - error->all(FLERR,"Cannot auto-generate special bonds before " - "simulation box is defined"); + error->all(FLERR,"Cannot auto-generate special bonds before simulation box is defined"); if (flag) { special_generate(); @@ -691,8 +685,7 @@ void Molecule::coords(char *line) ValueTokenizer values(utils::trim_comment(line)); if (values.count() != 4) - error->all(FLERR,"Invalid line in Coords section of " - "molecule file: {}",line); + error->all(FLERR,"Invalid line in Coords section of molecule file: {}",line); int iatom = values.next_int() - 1; if (iatom < 0 || iatom >= natoms) @@ -707,19 +700,16 @@ void Molecule::coords(char *line) x[iatom][2] *= sizescale; } } catch (TokenizerException &e) { - error->all(FLERR,"Invalid line in Coords section of " - "molecule file: {}\n{}",e.what(),line); + error->all(FLERR,"Invalid line in Coords section of molecule file: {}\n{}",e.what(),line); } for (int i = 0; i < natoms; i++) - if (count[i] == 0) error->all(FLERR,"Atom {} missing in Coords " - "section of molecule file",i+1); + if (count[i] == 0) error->all(FLERR,"Atom {} missing in Coords section of molecule file",i+1); if (domain->dimension == 2) { for (int i = 0; i < natoms; i++) if (x[i][2] != 0.0) - error->all(FLERR,"Z coord in molecule file for atom {} " - "must be 0.0 for 2d-simulation.",i+1); + error->all(FLERR,"Z coord in molecule file for atom {} must be 0.0 for 2d-simulation",i+1); } } @@ -737,8 +727,7 @@ void Molecule::types(char *line) ValueTokenizer values(utils::trim_comment(line)); if (values.count() != 2) - error->all(FLERR,"Invalid line in Types section of " - "molecule file: {}",line); + error->all(FLERR,"Invalid line in Types section of molecule file: {}",line); int iatom = values.next_int() - 1; if (iatom < 0 || iatom >= natoms) @@ -748,17 +737,14 @@ void Molecule::types(char *line) type[iatom] += toffset; } } catch (TokenizerException &e) { - error->all(FLERR, "Invalid line in Types section of " - "molecule file: {}\n{}", e.what(),line); + error->all(FLERR,"Invalid line in Types section of molecule file: {}\n{}",e.what(),line); } for (int i = 0; i < natoms; i++) { - if (count[i] == 0) error->all(FLERR,"Atom {} missing in Types " - "section of molecule file",i+1); + if (count[i] == 0) error->all(FLERR,"Atom {} missing in Types section of molecule file",i+1); if ((type[i] <= 0) || (domain->box_exist && (type[i] > atom->ntypes))) - error->all(FLERR,"Invalid atom type {} for atom {} " - "in molecule file",type[i],i+1); + error->all(FLERR,"Invalid atom type {} for atom {} in molecule file",type[i],i+1); ntypes = MAX(ntypes,type[i]); } @@ -777,8 +763,7 @@ void Molecule::molecules(char *line) readline(line); ValueTokenizer values(utils::trim_comment(line)); if (values.count() != 2) - error->all(FLERR,"Invalid line in Molecules section of " - "molecule file: {}",line); + error->all(FLERR,"Invalid line in Molecules section of molecule file: {}",line); int iatom = values.next_int() - 1; if (iatom < 0 || iatom >= natoms) @@ -788,19 +773,17 @@ void Molecule::molecules(char *line) // molecule[iatom] += moffset; // placeholder for possible molecule offset } } catch (TokenizerException &e) { - error->all(FLERR, "Invalid line in Molecules section of " - "molecule file: {}\n{}",e.what(),line); + error->all(FLERR,"Invalid line in Molecules section of molecule file: {}\n{}",e.what(),line); } - for (int i = 0; i < natoms; i++) - if (count[i] == 0) error->all(FLERR,"Atom {} missing in Molecules " - "section of molecule file",i+1); - - for (int i = 0; i < natoms; i++) + for (int i = 0; i < natoms; i++) { + if (count[i] == 0) + error->all(FLERR,"Atom {} missing in Molecules section of molecule file",i+1); + } + for (int i = 0; i < natoms; i++) { if (molecule[i] < 0) - error->all(FLERR,"Invalid molecule ID {} for atom {} " - "in molecule file",molecule[i],i+1); - + error->all(FLERR,"Invalid molecule ID {} for atom {} in molecule file",molecule[i],i+1); + } for (int i = 0; i < natoms; i++) nmolecules = MAX(nmolecules,molecule[i]); } @@ -818,23 +801,21 @@ void Molecule::fragments(char *line) ValueTokenizer values(utils::trim_comment(line)); if ((int)values.count() > natoms+1) - error->all(FLERR,"Too many atoms per fragment in Fragments " - "section of molecule file"); + error->all(FLERR,"Too many atoms per fragment in Fragments section of molecule file"); fragmentnames[i] = values.next_string(); while (values.has_next()) { int iatom = values.next_int()-1; if (iatom < 0 || iatom >= natoms) - error->all(FLERR,"Invalid atom ID {} for fragment {} in " - "Fragments section of molecule file", - iatom+1, fragmentnames[i]); + error->all(FLERR,"Invalid atom ID {} for fragment {} in Fragments section of " + "molecule file", iatom+1, fragmentnames[i]); fragmentmask[i][iatom] = 1; } } } catch (TokenizerException &e) { - error->all(FLERR, "Invalid atom ID in Fragments section of " - "molecule file: {}\n{}", e.what(),line); + error->all(FLERR,"Invalid atom ID in Fragments section of " + "molecule file: {}\n{}", e.what(),line); } } @@ -851,8 +832,7 @@ void Molecule::charges(char *line) ValueTokenizer values(utils::trim_comment(line)); if ((int)values.count() != 2) - error->all(FLERR,"Invalid line in Charges section of " - "molecule file: {}",line); + error->all(FLERR,"Invalid line in Charges section of molecule file: {}",line); int iatom = values.next_int() - 1; if (iatom < 0 || iatom >= natoms) @@ -862,13 +842,13 @@ void Molecule::charges(char *line) q[iatom] = values.next_double(); } } catch (TokenizerException &e) { - error->all(FLERR, "Invalid line in Charges section of " - "molecule file: {}.\n{}",e.what(),line); + error->all(FLERR,"Invalid line in Charges section of molecule file: {}\n{}",e.what(),line); } - for (int i = 0; i < natoms; i++) - if (count[i] == 0) error->all(FLERR,"Atom {} missing in Charges " - "section of molecule file",i+1); + for (int i = 0; i < natoms; i++) { + if (count[i] == 0) + error->all(FLERR,"Atom {} missing in Charges section of molecule file",i+1); + } } /* ---------------------------------------------------------------------- @@ -885,8 +865,7 @@ void Molecule::diameters(char *line) ValueTokenizer values(utils::trim_comment(line)); if (values.count() != 2) - error->all(FLERR,"Invalid line in Diameters section of " - "molecule file: {}",line); + error->all(FLERR,"Invalid line in Diameters section of molecule file: {}",line); int iatom = values.next_int() - 1; if (iatom < 0 || iatom >= natoms) error->all(FLERR,"Invalid atom index in Diameters section of molecule file"); @@ -897,16 +876,14 @@ void Molecule::diameters(char *line) maxradius = MAX(maxradius,radius[iatom]); } } catch (TokenizerException &e) { - error->all(FLERR, "Invalid line in Diameters section of " - "molecule file: {}\n{}",e.what(),line); + error->all(FLERR,"Invalid line in Diameters section of molecule file: {}\n{}",e.what(),line); } for (int i = 0; i < natoms; i++) { - if (count[i] == 0) error->all(FLERR,"Atom {} missing in Diameters " - "section of molecule file",i+1); + if (count[i] == 0) + error->all(FLERR,"Atom {} missing in Diameters section of molecule file",i+1); if (radius[i] < 0.0) - error->all(FLERR,"Invalid atom diameter {} for atom {} " - "in molecule file", radius[i], i+1); + error->all(FLERR,"Invalid atom diameter {} for atom {} in molecule file", radius[i], i+1); } } @@ -923,8 +900,7 @@ void Molecule::masses(char *line) ValueTokenizer values(utils::trim_comment(line)); if (values.count() != 2) - error->all(FLERR,"Invalid line in Masses section of " - "molecule file: {}",line); + error->all(FLERR,"Invalid line in Masses section of molecule file: {}",line); int iatom = values.next_int() - 1; if (iatom < 0 || iatom >= natoms) @@ -934,8 +910,7 @@ void Molecule::masses(char *line) rmass[iatom] *= sizescale*sizescale*sizescale; } } catch (TokenizerException &e) { - error->all(FLERR, "Invalid line in Masses section of " - "molecule file: {}\n{}",e.what(),line); + error->all(FLERR,"Invalid line in Masses section of molecule file: {}\n{}",e.what(),line); } for (int i = 0; i < natoms; i++) { @@ -972,15 +947,13 @@ void Molecule::bonds(int flag, char *line) try { ValueTokenizer values(utils::trim_comment(line)); if (values.count() != 4) - error->all(FLERR,"Invalid line in Bonds section of " - "molecule file: {}",line); + error->all(FLERR,"Invalid line in Bonds section of molecule file: {}",line); values.next_int(); itype = values.next_int(); atom1 = values.next_tagint(); atom2 = values.next_tagint(); } catch (TokenizerException &e) { - error->all(FLERR, "Invalid line in Bonds section of " - "molecule file: {}\n{}",e.what(),line); + error->all(FLERR,"Invalid line in Bonds section of molecule file: {}\n{}",e.what(),line); } itype += boffset; @@ -1042,16 +1015,14 @@ void Molecule::angles(int flag, char *line) try { ValueTokenizer values(utils::trim_comment(line)); if (values.count() != 5) - error->all(FLERR,"Invalid line in Angles section of " - "molecule file: {}",line); + error->all(FLERR,"Invalid line in Angles section of molecule file: {}",line); values.next_int(); itype = values.next_int(); atom1 = values.next_tagint(); atom2 = values.next_tagint(); atom3 = values.next_tagint(); } catch (TokenizerException &e) { - error->all(FLERR, "Invalid line in Angles section of " - "molecule file: {}\n{}",e.what(),line); + error->all(FLERR,"Invalid line in Angles section of molecule file: {}\n{}",e.what(),line); } itype += aoffset; @@ -1128,8 +1099,7 @@ void Molecule::dihedrals(int flag, char *line) try { ValueTokenizer values(utils::trim_comment(line)); if (values.count() != 6) - error->all(FLERR,"Invalid line in Dihedrals section of " - "molecule file: {}",line); + error->all(FLERR,"Invalid line in Dihedrals section of molecule file: {}",line); values.next_int(); itype = values.next_int(); @@ -1138,8 +1108,7 @@ void Molecule::dihedrals(int flag, char *line) atom3 = values.next_tagint(); atom4 = values.next_tagint(); } catch (TokenizerException &e) { - error->all(FLERR, "Invalid line in Dihedrals section of " - "molecule file: {}\n{}",e.what(),line); + error->all(FLERR,"Invalid line in Dihedrals section of molecule file: {}\n{}",e.what(),line); } itype += doffset; @@ -1150,8 +1119,7 @@ void Molecule::dihedrals(int flag, char *line) (atom4 <= 0) || (atom4 > natoms) || (atom1 == atom2) || (atom1 == atom3) || (atom1 == atom4) || (atom2 == atom3) || (atom2 == atom4) || (atom3 == atom4)) - error->all(FLERR, - "Invalid atom ID in dihedrals section of molecule file"); + error->all(FLERR,"Invalid atom ID in dihedrals section of molecule file"); if ((itype <= 0) || (domain->box_exist && (itype > atom->ndihedraltypes))) error->all(FLERR,"Invalid dihedral type in Dihedrals section of molecule file"); @@ -1230,8 +1198,7 @@ void Molecule::impropers(int flag, char *line) try { ValueTokenizer values(utils::trim_comment(line)); if (values.count() != 6) - error->all(FLERR,"Invalid line in Impropers section of " - "molecule file: {}",line); + error->all(FLERR,"Invalid line in Impropers section of molecule file: {}",line); values.next_int(); itype = values.next_int(); atom1 = values.next_tagint(); @@ -1239,8 +1206,7 @@ void Molecule::impropers(int flag, char *line) atom3 = values.next_tagint(); atom4 = values.next_tagint(); } catch (TokenizerException &e) { - error->all(FLERR, "Invalid line in Impropers section of " - "molecule file: {}\n{}",e.what(),line); + error->all(FLERR,"Invalid line in Impropers section of molecule file: {}\n{}",e.what(),line); } itype += ioffset; @@ -1251,8 +1217,7 @@ void Molecule::impropers(int flag, char *line) (atom4 <= 0) || (atom4 > natoms) || (atom1 == atom2) || (atom1 == atom3) || (atom1 == atom4) || (atom2 == atom3) || (atom2 == atom4) || (atom3 == atom4)) - error->all(FLERR, - "Invalid atom ID in impropers section of molecule file"); + error->all(FLERR,"Invalid atom ID in impropers section of molecule file"); if ((itype <= 0) || (domain->box_exist && (itype > atom->nimpropertypes))) error->all(FLERR,"Invalid improper type in Impropers section of molecule file"); @@ -1325,15 +1290,14 @@ void Molecule::nspecial_read(int flag, char *line) try { ValueTokenizer values(utils::trim_comment(line)); if (values.count() != 4) - error->all(FLERR,"Invalid line in Special Bond Counts section of " - "molecule file: {}",line); + error->all(FLERR,"Invalid line in Special Bond Counts section of molecule file: {}",line); values.next_int(); c1 = values.next_tagint(); c2 = values.next_tagint(); c3 = values.next_tagint(); } catch (TokenizerException &e) { - error->all(FLERR, "Invalid line in Special Bond Counts section of " - "molecule file: {}\n{}",e.what(),line); + error->all(FLERR,"Invalid line in Special Bond Counts section of " + "molecule file: {}\n{}",e.what(),line); } if (flag) { @@ -1358,8 +1322,7 @@ void Molecule::special_read(char *line) int nwords = values.count(); if (nwords != nspecial[i][2]+1) - error->all(FLERR,"Molecule file special list " - "does not match special count"); + error->all(FLERR,"Molecule file special list does not match special count"); values.next_int(); // ignore @@ -1367,13 +1330,12 @@ void Molecule::special_read(char *line) special[i][m-1] = values.next_tagint(); if (special[i][m-1] <= 0 || special[i][m-1] > natoms || special[i][m-1] == i+1) - error->all(FLERR,"Invalid atom index in Special Bonds " - "section of molecule file"); + error->all(FLERR,"Invalid atom index in Special Bonds section of molecule file"); } } } catch (TokenizerException &e) { - error->all(FLERR, "Invalid line in Special Bonds section of " - "molecule file: {}\n{}",e.what(),line); + error->all(FLERR,"Invalid line in Special Bonds section of " + "molecule file: {}\n{}",e.what(),line); } } @@ -1502,8 +1464,7 @@ void Molecule::shakeflag_read(char *line) shake_flag[i] = values.next_int(); } } catch (TokenizerException &e) { - error->all(FLERR, "Invalid Shake Flags section in molecule file\n" - "{}", e.what()); + error->all(FLERR,"Invalid Shake Flags section in molecule file: {}", e.what()); } for (int i = 0; i < natoms; i++) @@ -1572,8 +1533,7 @@ void Molecule::shakeatom_read(char *line) } } catch (TokenizerException &e) { - error->all(FLERR,"Invalid shake atom in molecule file\n" - "{}", e.what()); + error->all(FLERR,"Invalid shake atom in molecule file: {}", e.what()); } for (int i = 0; i < natoms; i++) { @@ -1642,8 +1602,7 @@ void Molecule::shaketype_read(char *line) error->all(FLERR,"Invalid shake type data in molecule file"); } } catch (TokenizerException &e) { - error->all(FLERR, "Invalid shake type data in molecule file\n", - "{}", e.what()); + error->all(FLERR,"Invalid shake type data in molecule file: {}",e.what()); } for (int i = 0; i < natoms; i++) { @@ -1695,8 +1654,7 @@ void Molecule::body(int flag, int pflag, char *line) } else nword += ncount; } } catch (TokenizerException &e) { - error->all(FLERR, "Invalid body params in molecule file\n", - "{}", e.what()); + error->all(FLERR,"Invalid body params in molecule file: {}", e.what()); } } @@ -1735,8 +1693,7 @@ void Molecule::check_attributes(int flag) if (onemol->rmassflag && !atom->rmass_flag) mismatch = 1; if (mismatch && me == 0) - error->warning(FLERR, - "Molecule attributes do not match system attributes"); + error->warning(FLERR,"Molecule attributes do not match system attributes"); // for all atom styles, check nbondtype,etc @@ -1770,8 +1727,7 @@ void Molecule::check_attributes(int flag) // warn if molecule topology defined but no special settings if (onemol->bondflag && !onemol->specialflag) - if (me == 0) error->warning(FLERR,"Molecule has bond topology " - "but no special bond settings"); + if (me == 0) error->warning(FLERR,"Molecule has bond topology but no special bond settings"); } } @@ -1878,47 +1834,31 @@ void Molecule::allocate() memory->create(special,natoms,maxspecial,"molecule:special"); if (bondflag) { - memory->create(bond_type,natoms,bond_per_atom, - "molecule:bond_type"); - memory->create(bond_atom,natoms,bond_per_atom, - "molecule:bond_atom"); + memory->create(bond_type,natoms,bond_per_atom,"molecule:bond_type"); + memory->create(bond_atom,natoms,bond_per_atom,"molecule:bond_atom"); } if (angleflag) { - memory->create(angle_type,natoms,angle_per_atom, - "molecule:angle_type"); - memory->create(angle_atom1,natoms,angle_per_atom, - "molecule:angle_atom1"); - memory->create(angle_atom2,natoms,angle_per_atom, - "molecule:angle_atom2"); - memory->create(angle_atom3,natoms,angle_per_atom, - "molecule:angle_atom3"); + memory->create(angle_type,natoms,angle_per_atom,"molecule:angle_type"); + memory->create(angle_atom1,natoms,angle_per_atom,"molecule:angle_atom1"); + memory->create(angle_atom2,natoms,angle_per_atom,"molecule:angle_atom2"); + memory->create(angle_atom3,natoms,angle_per_atom,"molecule:angle_atom3"); } if (dihedralflag) { - memory->create(dihedral_type,natoms,dihedral_per_atom, - "molecule:dihedral_type"); - memory->create(dihedral_atom1,natoms,dihedral_per_atom, - "molecule:dihedral_atom1"); - memory->create(dihedral_atom2,natoms,dihedral_per_atom, - "molecule:dihedral_atom2"); - memory->create(dihedral_atom3,natoms,dihedral_per_atom, - "molecule:dihedral_atom3"); - memory->create(dihedral_atom4,natoms,dihedral_per_atom, - "molecule:dihedral_atom4"); + memory->create(dihedral_type,natoms,dihedral_per_atom,"molecule:dihedral_type"); + memory->create(dihedral_atom1,natoms,dihedral_per_atom,"molecule:dihedral_atom1"); + memory->create(dihedral_atom2,natoms,dihedral_per_atom,"molecule:dihedral_atom2"); + memory->create(dihedral_atom3,natoms,dihedral_per_atom,"molecule:dihedral_atom3"); + memory->create(dihedral_atom4,natoms,dihedral_per_atom,"molecule:dihedral_atom4"); } if (improperflag) { - memory->create(improper_type,natoms,improper_per_atom, - "molecule:improper_type"); - memory->create(improper_atom1,natoms,improper_per_atom, - "molecule:improper_atom1"); - memory->create(improper_atom2,natoms,improper_per_atom, - "molecule:improper_atom2"); - memory->create(improper_atom3,natoms,improper_per_atom, - "molecule:improper_atom3"); - memory->create(improper_atom4,natoms,improper_per_atom, - "molecule:improper_atom4"); + memory->create(improper_type,natoms,improper_per_atom,"molecule:improper_type"); + memory->create(improper_atom1,natoms,improper_per_atom,"molecule:improper_atom1"); + memory->create(improper_atom2,natoms,improper_per_atom,"molecule:improper_atom2"); + memory->create(improper_atom3,natoms,improper_per_atom,"molecule:improper_atom3"); + memory->create(improper_atom4,natoms,improper_per_atom,"molecule:improper_atom4"); } if (shakeflag) { @@ -2058,7 +1998,7 @@ void Molecule::skip_lines(int n, char *line, const std::string §ion) readline(line); if (utils::strmatch(utils::trim(utils::trim_comment(line)),"^[A-Za-z ]+$")) error->one(FLERR,"Unexpected line in molecule file while " - "skipping {} section:\n{}",section,line); + "skipping {} section:\n{}",section,line); } } From 0eeb3b203cf84fcde15a6b34f2c239d8045ba33d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 16 Jan 2022 16:50:23 -0500 Subject: [PATCH 130/193] add tests for molecule command --- unittest/formats/test_molecule_file.cpp | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/unittest/formats/test_molecule_file.cpp b/unittest/formats/test_molecule_file.cpp index 2cca7a6832..e802ebfa2c 100644 --- a/unittest/formats/test_molecule_file.cpp +++ b/unittest/formats/test_molecule_file.cpp @@ -176,6 +176,33 @@ TEST_F(MoleculeFileTest, minimal) ASSERT_THAT(output, MatchesRegex(".*Read molecule template.*1 molecules.*1 atoms.*0 bonds.*")); } +TEST_F(MoleculeFileTest, notype) +{ + BEGIN_CAPTURE_OUTPUT(); + command("atom_style atomic"); + command("region box block 0 1 0 1 0 1"); + command("create_box 1 box"); + run_mol_cmd(test_name, "", "Comment\n1 atoms\n\n Coords\n\n 1 0.0 0.0 0.0\n"); + auto output = END_CAPTURE_OUTPUT(); + ASSERT_THAT(output, MatchesRegex(".*Read molecule template.*1 molecules.*1 atoms.*0 bonds.*")); + TEST_FAILURE(".*ERROR: Create_atoms molecule must have atom types.*", + command("create_atoms 0 single 0.0 0.0 0.0 mol notype 542465");); + } + +TEST_F(MoleculeFileTest, extramass) +{ + BEGIN_CAPTURE_OUTPUT(); + command("atom_style atomic"); + command("region box block 0 1 0 1 0 1"); + command("create_box 1 box"); + run_mol_cmd(test_name, "", "Comment\n1 atoms\n\n Coords\n\n 1 0.0 0.0 0.0\n" + " Types\n\n 1 1\n Masses\n\n 1 1.0\n"); + command("create_atoms 0 single 0.0 0.0 0.0 mol extramass 73546"); + auto output = END_CAPTURE_OUTPUT(); + ASSERT_THAT(output, MatchesRegex(".*WARNING: Molecule attributes do not match " + "system attributes.*")); +} + TEST_F(MoleculeFileTest, twomols) { BEGIN_CAPTURE_OUTPUT(); From dc6e558191c756b64e9e01fc7505a40328c54491 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 16 Jan 2022 20:20:07 -0500 Subject: [PATCH 131/193] use Tokenizer class to parse bond colors --- src/dump_image.cpp | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/dump_image.cpp b/src/dump_image.cpp index c073d152f8..9aecb58120 100644 --- a/src/dump_image.cpp +++ b/src/dump_image.cpp @@ -1200,11 +1200,11 @@ int DumpImage::modify_param(int narg, char **arg) utils::bounds(FLERR,arg[1],1,atom->ntypes,nlo,nhi,error); // get list of colors + // assign colors in round-robin fashion to types + auto colors = Tokenizer(arg[2],"/").as_vector(); const int ncolors = colors.size(); - // assign colors in round-robin fashion to types - int m = 0; for (int i = nlo; i <= nhi; i++) { colortype[i] = image->color2rgb(colors[m%ncolors].c_str()); @@ -1249,32 +1249,19 @@ int DumpImage::modify_param(int narg, char **arg) int nlo,nhi; utils::bounds(FLERR,arg[1],1,atom->nbondtypes,nlo,nhi,error); - // ptrs = list of ncount colornames separated by '/' + // process list of ncount colornames separated by '/' + // assign colors in round-robin fashion to bond types - int ncount = 1; - char *nextptr; - char *ptr = arg[2]; - while ((nextptr = strchr(ptr,'/'))) { - ptr = nextptr + 1; - ncount++; - } - char **ptrs = new char*[ncount+1]; - ncount = 0; - ptrs[ncount++] = strtok(arg[2],"/"); - while ((ptrs[ncount++] = strtok(nullptr,"/"))); - ncount--; - - // assign each of ncount colors in round-robin fashion to types + auto colors = Tokenizer(arg[2],"/").as_vector(); + const int ncolors = colors.size(); int m = 0; for (int i = nlo; i <= nhi; i++) { - bcolortype[i] = image->color2rgb(ptrs[m%ncount]); + bcolortype[i] = image->color2rgb(colors[m%ncolors].c_str()); if (bcolortype[i] == nullptr) error->all(FLERR,"Invalid color in dump_modify command"); m++; } - - delete [] ptrs; return 3; } From cb796e8b601f0a29918a864fa84bf9daf8134451 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 17 Jan 2022 08:21:52 -0700 Subject: [PATCH 132/193] Fix HIP compile issues --- lib/kokkos/Makefile.kokkos | 3 +++ lib/kokkos/Makefile.targets | 2 ++ src/KOKKOS/fix_acks2_reaxff_kokkos.cpp | 2 ++ 3 files changed, 7 insertions(+) diff --git a/lib/kokkos/Makefile.kokkos b/lib/kokkos/Makefile.kokkos index 7ffea5a62c..899d6e49a2 100644 --- a/lib/kokkos/Makefile.kokkos +++ b/lib/kokkos/Makefile.kokkos @@ -1224,6 +1224,9 @@ ifeq ($(KOKKOS_INTERNAL_USE_HIP), 1) KOKKOS_SRC += $(wildcard $(KOKKOS_PATH)/core/src/HIP/*.cpp) + ifeq ($(KOKKOS_INTERNAL_ENABLE_DESUL_ATOMICS), 1) + KOKKOS_SRC += $(KOKKOS_PATH)/core/src/desul/src/Lock_Array_HIP.cpp + endif KOKKOS_HEADERS += $(wildcard $(KOKKOS_PATH)/core/src/HIP/*.hpp) KOKKOS_CXXFLAGS+=$(KOKKOS_INTERNAL_HIP_ARCH_FLAG) diff --git a/lib/kokkos/Makefile.targets b/lib/kokkos/Makefile.targets index 93854d0cf1..c097e80fec 100644 --- a/lib/kokkos/Makefile.targets +++ b/lib/kokkos/Makefile.targets @@ -68,6 +68,8 @@ Kokkos_HIP_Instance.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/HIP/Kokkos_ $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/HIP/Kokkos_HIP_Instance.cpp Kokkos_HIP_Locks.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/HIP/Kokkos_HIP_Locks.cpp $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/HIP/Kokkos_HIP_Locks.cpp +Lock_Array_HIP.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/desul/src/Lock_Array_HIP.cpp + $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/desul/src/Lock_Array_HIP.cpp endif ifeq ($(KOKKOS_INTERNAL_USE_PTHREADS), 1) diff --git a/src/KOKKOS/fix_acks2_reaxff_kokkos.cpp b/src/KOKKOS/fix_acks2_reaxff_kokkos.cpp index 8379dc8f46..582e9a39ce 100644 --- a/src/KOKKOS/fix_acks2_reaxff_kokkos.cpp +++ b/src/KOKKOS/fix_acks2_reaxff_kokkos.cpp @@ -633,6 +633,7 @@ void FixACKS2ReaxFFKokkos::compute_h_item(int ii, int &m_fill, const template template +KOKKOS_INLINE_FUNCTION void FixACKS2ReaxFFKokkos::compute_h_team( const typename Kokkos::TeamPolicy::member_type &team, int atoms_per_team, int vector_length) const { @@ -935,6 +936,7 @@ void FixACKS2ReaxFFKokkos::compute_x_item(int ii, int &m_fill, const template template +KOKKOS_INLINE_FUNCTION void FixACKS2ReaxFFKokkos::compute_x_team( const typename Kokkos::TeamPolicy::member_type &team, int atoms_per_team, int vector_length) const { From a93e5baa73d3f108f2503bd7cfcd41d252c1b115 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 17 Jan 2022 08:44:49 -0700 Subject: [PATCH 133/193] Add Kokkos HIP Makefiles --- src/MAKE/MACHINES/Makefile.crusher_kokkos | 123 ++++++++++++++++++++++ src/MAKE/MACHINES/Makefile.spock_kokkos | 123 ++++++++++++++++++++++ 2 files changed, 246 insertions(+) create mode 100644 src/MAKE/MACHINES/Makefile.crusher_kokkos create mode 100644 src/MAKE/MACHINES/Makefile.spock_kokkos diff --git a/src/MAKE/MACHINES/Makefile.crusher_kokkos b/src/MAKE/MACHINES/Makefile.crusher_kokkos new file mode 100644 index 0000000000..167341ec9c --- /dev/null +++ b/src/MAKE/MACHINES/Makefile.crusher_kokkos @@ -0,0 +1,123 @@ +# summit_kokkos = KOKKOS/CUDA, V100 GPU and Power9, IBM Spectrum MPI, nvcc compiler with gcc + +SHELL = /bin/sh + +# --------------------------------------------------------------------- +# compiler/linker settings +# specify flags and libraries needed for your compiler + +KOKKOS_ABSOLUTE_PATH = $(shell cd $(KOKKOS_PATH); pwd) + +CC = hipcc +CCFLAGS = -g -O3 -munsafe-fp-atomics -DNDEBUG +SHFLAGS = -fPIC +DEPFLAGS = -M + +LINK = hipcc +LINKFLAGS = -g -O3 +LIB = +SIZE = size + +ARCHIVE = ar +ARFLAGS = -rc +SHLIBFLAGS = -shared +KOKKOS_DEVICES = HIP +KOKKOS_ARCH = Zen3,Vega90A + +# --------------------------------------------------------------------- +# LAMMPS-specific settings, all OPTIONAL +# specify settings for LAMMPS features you will use +# if you change any -D setting, do full re-compile after "make clean" + +# LAMMPS ifdef settings +# see possible settings in Section 3.5 of the manual + +LMP_INC = -DLAMMPS_GZIP + +# MPI library +# 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 +# INC = path for mpi.h, MPI compiler settings +# PATH = path for MPI library +# LIB = name of MPI library + +MPI_INC = -DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1 -I${MPICH_DIR}/include +MPI_PATH = +MPI_LIB = -L${MPICH_DIR}/lib -lmpi -L${CRAY_MPICH_ROOTDIR}/gtl/lib -lmpi_gtl_hsa + +# FFT library +# see discussion in Section 3.5.2 of manual +# can be left blank to use provided KISS FFT library +# INC = -DFFT setting, e.g. -DFFT_FFTW, FFT compiler settings +# PATH = path for FFT library +# LIB = name of FFT library + +FFT_INC = +FFT_PATH = +FFT_LIB = + +# JPEG and/or PNG library +# see discussion in Section 3.5.4 of manual +# only needed if -DLAMMPS_JPEG or -DLAMMPS_PNG listed with LMP_INC +# INC = path(s) for jpeglib.h and/or png.h +# PATH = path(s) for JPEG library and/or PNG library +# LIB = name(s) of JPEG library and/or PNG library + +JPG_INC = +JPG_PATH = +JPG_LIB = + +# --------------------------------------------------------------------- +# build rules and dependencies +# do not edit this section + +include Makefile.package.settings +include Makefile.package + +EXTRA_INC = $(LMP_INC) $(PKG_INC) $(MPI_INC) $(FFT_INC) $(JPG_INC) $(PKG_SYSINC) +EXTRA_PATH = $(PKG_PATH) $(MPI_PATH) $(FFT_PATH) $(JPG_PATH) $(PKG_SYSPATH) +EXTRA_LIB = $(PKG_LIB) $(MPI_LIB) $(FFT_LIB) $(JPG_LIB) $(PKG_SYSLIB) +EXTRA_CPP_DEPENDS = $(PKG_CPP_DEPENDS) +EXTRA_LINK_DEPENDS = $(PKG_LINK_DEPENDS) + +# Path to src files + +vpath %.cpp .. +vpath %.h .. + +# Link target + +$(EXE): main.o $(LMPLIB) $(EXTRA_LINK_DEPENDS) + $(LINK) $(LINKFLAGS) main.o $(EXTRA_PATH) $(LMPLINK) $(EXTRA_LIB) $(LIB) -o $@ + $(SIZE) $@ + +# Library targets + +$(ARLIB): $(OBJ) $(EXTRA_LINK_DEPENDS) + @rm -f ../$(ARLIB) + $(ARCHIVE) $(ARFLAGS) ../$(ARLIB) $(OBJ) + @rm -f $(ARLIB) + @ln -s ../$(ARLIB) $(ARLIB) + +$(SHLIB): $(OBJ) $(EXTRA_LINK_DEPENDS) + $(CC) $(CCFLAGS) $(SHFLAGS) $(SHLIBFLAGS) $(EXTRA_PATH) -o ../$(SHLIB) \ + $(OBJ) $(EXTRA_LIB) $(LIB) + @rm -f $(SHLIB) + @ln -s ../$(SHLIB) $(SHLIB) + +# Compilation rules + +%.o:%.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) -c $< + +# Individual dependencies + +depend : fastdep.exe $(SRC) + @./fastdep.exe $(EXTRA_INC) -- $^ > .depend || exit 1 + +fastdep.exe: ../DEPEND/fastdep.c + cc -O -o $@ $< + +sinclude .depend diff --git a/src/MAKE/MACHINES/Makefile.spock_kokkos b/src/MAKE/MACHINES/Makefile.spock_kokkos new file mode 100644 index 0000000000..44fd213962 --- /dev/null +++ b/src/MAKE/MACHINES/Makefile.spock_kokkos @@ -0,0 +1,123 @@ +# summit_kokkos = KOKKOS/CUDA, V100 GPU and Power9, IBM Spectrum MPI, nvcc compiler with gcc + +SHELL = /bin/sh + +# --------------------------------------------------------------------- +# compiler/linker settings +# specify flags and libraries needed for your compiler + +KOKKOS_ABSOLUTE_PATH = $(shell cd $(KOKKOS_PATH); pwd) + +CC = hipcc +CCFLAGS = -g -O3 -DNDEBUG +SHFLAGS = -fPIC +DEPFLAGS = -M + +LINK = hipcc +LINKFLAGS = -g -O3 +LIB = +SIZE = size + +ARCHIVE = ar +ARFLAGS = -rc +SHLIBFLAGS = -shared +KOKKOS_DEVICES = HIP +KOKKOS_ARCH = Zen2,Vega908 + +# --------------------------------------------------------------------- +# LAMMPS-specific settings, all OPTIONAL +# specify settings for LAMMPS features you will use +# if you change any -D setting, do full re-compile after "make clean" + +# LAMMPS ifdef settings +# see possible settings in Section 3.5 of the manual + +LMP_INC = -DLAMMPS_GZIP + +# MPI library +# 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 +# INC = path for mpi.h, MPI compiler settings +# PATH = path for MPI library +# LIB = name of MPI library + +MPI_INC = -DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1 -I${MPICH_DIR}/include +MPI_PATH = +MPI_LIB = -L${MPICH_DIR}/lib -lmpi -L${CRAY_MPICH_ROOTDIR}/gtl/lib -lmpi_gtl_hsa + +# FFT library +# see discussion in Section 3.5.2 of manual +# can be left blank to use provided KISS FFT library +# INC = -DFFT setting, e.g. -DFFT_FFTW, FFT compiler settings +# PATH = path for FFT library +# LIB = name of FFT library + +FFT_INC = +FFT_PATH = +FFT_LIB = + +# JPEG and/or PNG library +# see discussion in Section 3.5.4 of manual +# only needed if -DLAMMPS_JPEG or -DLAMMPS_PNG listed with LMP_INC +# INC = path(s) for jpeglib.h and/or png.h +# PATH = path(s) for JPEG library and/or PNG library +# LIB = name(s) of JPEG library and/or PNG library + +JPG_INC = +JPG_PATH = +JPG_LIB = + +# --------------------------------------------------------------------- +# build rules and dependencies +# do not edit this section + +include Makefile.package.settings +include Makefile.package + +EXTRA_INC = $(LMP_INC) $(PKG_INC) $(MPI_INC) $(FFT_INC) $(JPG_INC) $(PKG_SYSINC) +EXTRA_PATH = $(PKG_PATH) $(MPI_PATH) $(FFT_PATH) $(JPG_PATH) $(PKG_SYSPATH) +EXTRA_LIB = $(PKG_LIB) $(MPI_LIB) $(FFT_LIB) $(JPG_LIB) $(PKG_SYSLIB) +EXTRA_CPP_DEPENDS = $(PKG_CPP_DEPENDS) +EXTRA_LINK_DEPENDS = $(PKG_LINK_DEPENDS) + +# Path to src files + +vpath %.cpp .. +vpath %.h .. + +# Link target + +$(EXE): main.o $(LMPLIB) $(EXTRA_LINK_DEPENDS) + $(LINK) $(LINKFLAGS) main.o $(EXTRA_PATH) $(LMPLINK) $(EXTRA_LIB) $(LIB) -o $@ + $(SIZE) $@ + +# Library targets + +$(ARLIB): $(OBJ) $(EXTRA_LINK_DEPENDS) + @rm -f ../$(ARLIB) + $(ARCHIVE) $(ARFLAGS) ../$(ARLIB) $(OBJ) + @rm -f $(ARLIB) + @ln -s ../$(ARLIB) $(ARLIB) + +$(SHLIB): $(OBJ) $(EXTRA_LINK_DEPENDS) + $(CC) $(CCFLAGS) $(SHFLAGS) $(SHLIBFLAGS) $(EXTRA_PATH) -o ../$(SHLIB) \ + $(OBJ) $(EXTRA_LIB) $(LIB) + @rm -f $(SHLIB) + @ln -s ../$(SHLIB) $(SHLIB) + +# Compilation rules + +%.o:%.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) -c $< + +# Individual dependencies + +depend : fastdep.exe $(SRC) + @./fastdep.exe $(EXTRA_INC) -- $^ > .depend || exit 1 + +fastdep.exe: ../DEPEND/fastdep.c + cc -O -o $@ $< + +sinclude .depend From 8b89be60619ba8879fee915ce4d01a93f4574d39 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 17 Jan 2022 08:49:00 -0700 Subject: [PATCH 134/193] Kokkos SNAP tuning for HIP --- src/KOKKOS/pair_snap_kokkos.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/KOKKOS/pair_snap_kokkos.h b/src/KOKKOS/pair_snap_kokkos.h index bd56d87f59..e7af536782 100644 --- a/src/KOKKOS/pair_snap_kokkos.h +++ b/src/KOKKOS/pair_snap_kokkos.h @@ -85,6 +85,19 @@ public: using complex = SNAComplex; // Static team/tile sizes for device offload + +#ifdef KOKKOS_ENABLE_HIP + static constexpr int team_size_compute_neigh = 2; + static constexpr int tile_size_compute_ck = 2; + static constexpr int tile_size_pre_ui = 2; + static constexpr int team_size_compute_ui = 2; + static constexpr int tile_size_transform_ui = 2; + static constexpr int tile_size_compute_zi = 2; + static constexpr int tile_size_compute_bi = 2; + static constexpr int tile_size_transform_bi = 2; + static constexpr int tile_size_compute_yi = 2; + static constexpr int team_size_compute_fused_deidrj = 2; +#else static constexpr int team_size_compute_neigh = 4; static constexpr int tile_size_compute_ck = 4; static constexpr int tile_size_pre_ui = 4; @@ -95,6 +108,7 @@ public: static constexpr int tile_size_transform_bi = 4; static constexpr int tile_size_compute_yi = 8; static constexpr int team_size_compute_fused_deidrj = sizeof(real_type) == 4 ? 4 : 2; +#endif // Custom MDRangePolicy, Rank3, to reduce verbosity of kernel launches // This hides the Kokkos::IndexType and Kokkos::Rank<3...> From af231d544702e6edcf1503cde09245530ebbde8a Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 17 Jan 2022 08:54:17 -0700 Subject: [PATCH 135/193] Fix comments in Makefiles --- src/MAKE/MACHINES/Makefile.crusher_kokkos | 2 +- src/MAKE/MACHINES/Makefile.spock_kokkos | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MAKE/MACHINES/Makefile.crusher_kokkos b/src/MAKE/MACHINES/Makefile.crusher_kokkos index 167341ec9c..065c20519f 100644 --- a/src/MAKE/MACHINES/Makefile.crusher_kokkos +++ b/src/MAKE/MACHINES/Makefile.crusher_kokkos @@ -1,4 +1,4 @@ -# summit_kokkos = KOKKOS/CUDA, V100 GPU and Power9, IBM Spectrum MPI, nvcc compiler with gcc +# crusher_kokkos = KOKKOS/HIP, AMD MI250X GPU and AMD EPYC 7A53 “Optimized 3rd Gen EPYC” CPU, Cray MPICH, hipcc compiler SHELL = /bin/sh diff --git a/src/MAKE/MACHINES/Makefile.spock_kokkos b/src/MAKE/MACHINES/Makefile.spock_kokkos index 44fd213962..f1302bf2db 100644 --- a/src/MAKE/MACHINES/Makefile.spock_kokkos +++ b/src/MAKE/MACHINES/Makefile.spock_kokkos @@ -1,4 +1,4 @@ -# summit_kokkos = KOKKOS/CUDA, V100 GPU and Power9, IBM Spectrum MPI, nvcc compiler with gcc +# spock_kokkos = KOKKOS/HIP, AMD MI100 GPU and AMD EPYC 7662 “Rome” CPU, Cray MPICH, hipcc compiler SHELL = /bin/sh From 241a44f1afbed0ccdfb09ede418ea9f0443622ca Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jan 2022 04:56:47 -0500 Subject: [PATCH 136/193] another workaround for rerun --- src/dump.h | 1 + src/output.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dump.h b/src/dump.h index 35da154d7c..482e87a207 100644 --- a/src/dump.h +++ b/src/dump.h @@ -19,6 +19,7 @@ namespace LAMMPS_NS { class Dump : protected Pointers { + friend class Output; public: char *id; // user-defined name of Dump char *style; // style of Dump diff --git a/src/output.cpp b/src/output.cpp index 449077d1fb..1376d365d8 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -632,7 +632,7 @@ int Output::check_time_dumps(bigint ntimestep) { next_dump_any = MAXBIGINT; for (int idump = 0; idump < ndump; idump++) - if ((last_dump[idump] >= 0) && !update->whichflag) + if ((last_dump[idump] >= 0) && !update->whichflag && !dump[idump]->multifile) error->all(FLERR, "Cannot reset timestep with active dump - must undump first"); if (restart_flag_single) { From f0f4a8e6dc20c1c4afbfa3b758acb50a970fbd2d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jan 2022 06:01:32 -0500 Subject: [PATCH 137/193] plug some memory leaks in MSM kspace style(s) --- src/KSPACE/msm.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/KSPACE/msm.cpp b/src/KSPACE/msm.cpp index 2259d2f829..a980be227d 100644 --- a/src/KSPACE/msm.cpp +++ b/src/KSPACE/msm.cpp @@ -626,15 +626,19 @@ void MSM::allocate() gcall->setup(ngcall_buf1,ngcall_buf2); npergrid = 1; + memory->destroy(gcall_buf1); + memory->destroy(gcall_buf2); memory->create(gcall_buf1,npergrid*ngcall_buf1,"msm:gcall_buf1"); memory->create(gcall_buf2,npergrid*ngcall_buf2,"msm:gcall_buf2"); // allocate memory for each grid level for (int n=0; ndestroy3d_offset(qgrid[n],nzlo_out[n],nylo_out[n],nxlo_out[n]); memory->create3d_offset(qgrid[n],nzlo_out[n],nzhi_out[n], nylo_out[n],nyhi_out[n],nxlo_out[n],nxhi_out[n],"msm:qgrid"); + memory->destroy3d_offset(egrid[n],nzlo_out[n],nylo_out[n],nxlo_out[n]); memory->create3d_offset(egrid[n],nzlo_out[n],nzhi_out[n], nylo_out[n],nyhi_out[n],nxlo_out[n],nxhi_out[n],"msm:egrid"); @@ -654,6 +658,8 @@ void MSM::allocate() gc[n]->setup(ngc_buf1[n],ngc_buf2[n]); npergrid = 1; + memory->destroy(gc_buf1[n]); + memory->destroy(gc_buf2[n]); memory->create(gc_buf1[n],npergrid*ngc_buf1[n],"msm:gc_buf1"); memory->create(gc_buf2[n],npergrid*ngc_buf2[n],"msm:gc_buf2"); } else { @@ -835,11 +841,15 @@ void MSM::deallocate_levels() { if (world_levels) { for (int n=0; n < levels; ++n) { - if (qgrid[n]) + if (qgrid[n]) { memory->destroy3d_offset(qgrid[n],nzlo_out[n],nylo_out[n],nxlo_out[n]); + qgrid[n] = nullptr; + } - if (egrid[n]) + if (egrid[n]) { memory->destroy3d_offset(egrid[n],nzlo_out[n],nylo_out[n],nxlo_out[n]); + egrid[n] = nullptr; + } if (gc) { if (gc[n]) { From a02e11040d55e0b99683efd990f374bb446d869d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jan 2022 06:34:57 -0500 Subject: [PATCH 138/193] whitespace --- src/KSPACE/msm.cpp | 78 +++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/KSPACE/msm.cpp b/src/KSPACE/msm.cpp index a980be227d..4415175bf0 100644 --- a/src/KSPACE/msm.cpp +++ b/src/KSPACE/msm.cpp @@ -116,7 +116,7 @@ void MSM::settings(int narg, char **arg) MSM::~MSM() { - delete [] factors; + delete[] factors; deallocate(); if (peratom_allocate_flag) deallocate_peratom(); deallocate_levels(); @@ -867,57 +867,57 @@ void MSM::deallocate_levels() } } - delete [] ngrid; + delete[] ngrid; ngrid = nullptr; memory->destroy(procneigh_levels); - delete [] world_levels; - delete [] active_flag; + delete[] world_levels; + delete[] active_flag; - delete [] gc; - delete [] gc_buf1; - delete [] gc_buf2; - delete [] ngc_buf1; - delete [] ngc_buf2; + delete[] gc; + delete[] gc_buf1; + delete[] gc_buf2; + delete[] ngc_buf1; + delete[] ngc_buf2; - delete [] alpha; - delete [] betax; - delete [] betay; - delete [] betaz; + delete[] alpha; + delete[] betax; + delete[] betay; + delete[] betaz; - delete [] nx_msm; - delete [] ny_msm; - delete [] nz_msm; + delete[] nx_msm; + delete[] ny_msm; + delete[] nz_msm; - delete [] nxlo_in; - delete [] nylo_in; - delete [] nzlo_in; + delete[] nxlo_in; + delete[] nylo_in; + delete[] nzlo_in; - delete [] nxhi_in; - delete [] nyhi_in; - delete [] nzhi_in; + delete[] nxhi_in; + delete[] nyhi_in; + delete[] nzhi_in; - delete [] nxlo_out; - delete [] nylo_out; - delete [] nzlo_out; + delete[] nxlo_out; + delete[] nylo_out; + delete[] nzlo_out; - delete [] nxhi_out; - delete [] nyhi_out; - delete [] nzhi_out; + delete[] nxhi_out; + delete[] nyhi_out; + delete[] nzhi_out; - delete [] delxinv; - delete [] delyinv; - delete [] delzinv; + delete[] delxinv; + delete[] delyinv; + delete[] delzinv; - delete [] qgrid; - delete [] egrid; + delete[] qgrid; + delete[] egrid; - delete [] v0grid; - delete [] v1grid; - delete [] v2grid; - delete [] v3grid; - delete [] v4grid; - delete [] v5grid; + delete[] v0grid; + delete[] v1grid; + delete[] v2grid; + delete[] v3grid; + delete[] v4grid; + delete[] v5grid; world_levels = nullptr; active_flag = nullptr; From 752552e0f82b0a979494b9594a5a77e6ae767a7d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jan 2022 06:39:20 -0500 Subject: [PATCH 139/193] remove duplicate code --- src/KSPACE/msm.cpp | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/KSPACE/msm.cpp b/src/KSPACE/msm.cpp index 4415175bf0..09ea775ef4 100644 --- a/src/KSPACE/msm.cpp +++ b/src/KSPACE/msm.cpp @@ -67,33 +67,7 @@ MSM::MSM(LAMMPS *lmp) factors[0] = 2; MPI_Comm_rank(world,&me); - - phi1d = dphi1d = nullptr; - nmax = 0; - part2grid = nullptr; - - g_direct = nullptr; - g_direct_top = nullptr; - - v0_direct = v1_direct = v2_direct = nullptr; - v3_direct = v4_direct = v5_direct = nullptr; - - v0_direct_top = v1_direct_top = v2_direct_top = nullptr; - v3_direct_top = v4_direct_top = v5_direct_top = nullptr; - - ngrid = nullptr; - - alpha = betax = betay = betaz = nullptr; - nx_msm = ny_msm = nz_msm = nullptr; - nxlo_in = nylo_in = nzlo_in = nullptr; - nxhi_in = nyhi_in = nzhi_in = nullptr; - nxlo_out = nylo_out = nzlo_out = nullptr; - nxhi_out = nyhi_out = nzhi_out = nullptr; - delxinv = delyinv = delzinv = nullptr; - qgrid = nullptr; - egrid = nullptr; - v0grid = v1grid = v2grid = v3grid = v4grid = v5grid = nullptr; peratom_allocate_flag = 0; scalar_pressure_flag = 1; From 2e85233b11936c3b12ff8a8f528967d0a7fb5b5a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jan 2022 07:20:28 -0500 Subject: [PATCH 140/193] before changing box settings, it must be initialized at least once otherwise change_box would not really be needed, but commands like boundary can (still) be used --- src/change_box.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/change_box.cpp b/src/change_box.cpp index bbac78ab3d..a79b023ac3 100644 --- a/src/change_box.cpp +++ b/src/change_box.cpp @@ -24,6 +24,7 @@ #include "lattice.h" #include "modify.h" #include "output.h" +#include "update.h" #include #include @@ -201,8 +202,11 @@ void ChangeBox::command(int narg, char **arg) scale[0] = domain->lattice->xlattice; scale[1] = domain->lattice->ylattice; scale[2] = domain->lattice->zlattice; - } - else scale[0] = scale[1] = scale[2] = 1.0; + } else scale[0] = scale[1] = scale[2] = 1.0; + + // enforce initialization if there has not one before + + if (!update->first_update) lmp->init(); // perform sequence of operations // first insure atoms are in current box & update box via shrink-wrap @@ -282,9 +286,7 @@ void ChangeBox::command(int narg, char **arg) } else if (ops[m].style == BOUNDARY) { domain->set_boundary(3,&arg[ops[m].boundindex],1); if (domain->dimension == 2 && domain->zperiodic == 0) - error->all(FLERR, - "Cannot change box z boundary to " - "non-periodic for a 2d simulation"); + error->all(FLERR, "Cannot change box z boundary to non-periodic for a 2d simulation"); domain->set_initial_box(); domain->set_global_box(); domain->set_local_box(); From c1f7685c988998a901d1f56bd4237f736d16f518 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jan 2022 08:30:54 -0500 Subject: [PATCH 141/193] Revert "before changing box settings, it must be initialized at least once" Looking for alternate solution since this change has too many unwanted side effects. This reverts commit 2e85233b11936c3b12ff8a8f528967d0a7fb5b5a. --- src/change_box.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/change_box.cpp b/src/change_box.cpp index a79b023ac3..bbac78ab3d 100644 --- a/src/change_box.cpp +++ b/src/change_box.cpp @@ -24,7 +24,6 @@ #include "lattice.h" #include "modify.h" #include "output.h" -#include "update.h" #include #include @@ -202,11 +201,8 @@ void ChangeBox::command(int narg, char **arg) scale[0] = domain->lattice->xlattice; scale[1] = domain->lattice->ylattice; scale[2] = domain->lattice->zlattice; - } else scale[0] = scale[1] = scale[2] = 1.0; - - // enforce initialization if there has not one before - - if (!update->first_update) lmp->init(); + } + else scale[0] = scale[1] = scale[2] = 1.0; // perform sequence of operations // first insure atoms are in current box & update box via shrink-wrap @@ -286,7 +282,9 @@ void ChangeBox::command(int narg, char **arg) } else if (ops[m].style == BOUNDARY) { domain->set_boundary(3,&arg[ops[m].boundindex],1); if (domain->dimension == 2 && domain->zperiodic == 0) - error->all(FLERR, "Cannot change box z boundary to non-periodic for a 2d simulation"); + error->all(FLERR, + "Cannot change box z boundary to " + "non-periodic for a 2d simulation"); domain->set_initial_box(); domain->set_global_box(); domain->set_local_box(); From 29b5c2659cf8782f79af96f3a684e9cd6cf0bdbe Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jan 2022 09:04:04 -0500 Subject: [PATCH 142/193] source code formatting --- src/KSPACE/msm.cpp | 6 ++---- src/KSPACE/pppm.cpp | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/KSPACE/msm.cpp b/src/KSPACE/msm.cpp index 09ea775ef4..9fd581618f 100644 --- a/src/KSPACE/msm.cpp +++ b/src/KSPACE/msm.cpp @@ -1044,8 +1044,7 @@ void MSM::set_grid_global() } if (flag && gridflag && me == 0) - error->warning(FLERR, - "Number of MSM mesh points changed to be a multiple of 2"); + error->warning(FLERR, "Number of MSM mesh points changed to be a multiple of 2"); // adjust Coulombic cutoff to give desired error (if requested) @@ -1071,8 +1070,7 @@ void MSM::set_grid_global() *p_cutoff = cutoff; if (me == 0) - error->warning(FLERR,"Adjusting Coulombic cutoff for " - "MSM, new cutoff = {:.8}", cutoff); + error->warning(FLERR,"Adjusting Coulombic cutoff for MSM, new cutoff = {:.8}", cutoff); } if (triclinic == 0) { diff --git a/src/KSPACE/pppm.cpp b/src/KSPACE/pppm.cpp index 06d90e5d0e..d531233a3a 100644 --- a/src/KSPACE/pppm.cpp +++ b/src/KSPACE/pppm.cpp @@ -197,11 +197,9 @@ void PPPM::init() error->all(FLERR,"Must redefine kspace_style after changing to triclinic box"); if (domain->triclinic && differentiation_flag == 1) - error->all(FLERR,"Cannot (yet) use PPPM with triclinic box " - "and kspace_modify diff ad"); + error->all(FLERR,"Cannot (yet) use PPPM with triclinic box and kspace_modify diff ad"); if (domain->triclinic && slabflag) - error->all(FLERR,"Cannot (yet) use PPPM with triclinic box and " - "slab correction"); + error->all(FLERR,"Cannot (yet) use PPPM with triclinic box and slab correction"); if (domain->dimension == 2) error->all(FLERR,"Cannot use PPPM with 2d simulation"); From 1c8f427e8a4fbcbebb5504aeb1aa095f6337a339 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jan 2022 09:09:19 -0500 Subject: [PATCH 143/193] detect when MSM::setup() is called before proper initialization and error out --- src/KSPACE/msm.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/KSPACE/msm.cpp b/src/KSPACE/msm.cpp index 9fd581618f..da4a2ad658 100644 --- a/src/KSPACE/msm.cpp +++ b/src/KSPACE/msm.cpp @@ -285,6 +285,11 @@ double MSM::estimate_total_error() void MSM::setup() { + // change_box may trigger MSM::setup() before MSM::init() was called + // error out and request full initialization. + + if (!delxinv) error->all(FLERR, "MSM must be fully initialized for this operation"); + double *prd; double a = cutoff; From 389c35a2d3517573a5b77f96f02dec9ae4aedfb7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jan 2022 09:09:37 -0500 Subject: [PATCH 144/193] use alternate method to create triclinic box for unit test --- unittest/python/python-commands.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/unittest/python/python-commands.py b/unittest/python/python-commands.py index bd8512894f..58a0772510 100644 --- a/unittest/python/python-commands.py +++ b/unittest/python/python-commands.py @@ -356,18 +356,16 @@ create_atoms 1 single & def test_extract_box_triclinic(self): self.lmp.command("boundary p p p") - self.lmp.command("region box block 0 2 0 2 0 2") + self.lmp.command("region box prism 0 2 0 2 0 2 0.1 0.2 0.3") self.lmp.command("create_box 1 box") - self.lmp.command("change_box all triclinic") - self.lmp.command("change_box all xy final 0.1 yz final 0.2 xz final 0.3") boxlo, boxhi, xy, yz, xz, periodicity, box_change = self.lmp.extract_box() self.assertEqual(boxlo, [0.0, 0.0, 0.0]) self.assertEqual(boxhi, [2.0, 2.0, 2.0]) self.assertEqual(xy, 0.1) - self.assertEqual(yz, 0.2) - self.assertEqual(xz, 0.3) + self.assertEqual(xz, 0.2) + self.assertEqual(yz, 0.3) self.assertEqual(periodicity, [1, 1, 1]) self.assertEqual(box_change, 0) From 38bcc493b011ca9bc4e1b47efc7fd57870dc73c8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jan 2022 10:28:40 -0500 Subject: [PATCH 145/193] simplify and modernize CMAP file parser --- src/MOLECULE/fix_cmap.cpp | 148 +++----------------------------------- 1 file changed, 11 insertions(+), 137 deletions(-) diff --git a/src/MOLECULE/fix_cmap.cpp b/src/MOLECULE/fix_cmap.cpp index a763c5d14c..c6e356e829 100644 --- a/src/MOLECULE/fix_cmap.cpp +++ b/src/MOLECULE/fix_cmap.cpp @@ -37,6 +37,7 @@ #include "force.h" #include "math_const.h" #include "memory.h" +#include "potential_file_reader.h" #include "respa.h" #include "tokenizer.h" #include "update.h" @@ -634,150 +635,23 @@ double FixCMAP::compute_scalar() void FixCMAP::read_grid_map(char *cmapfile) { - char linebuf[MAXLINE]; - char *chunk,*line; - int i1, i2, i3, i4, i5, i6, j1, j2, j3, j4, j5, j6, counter; - - FILE *fp = nullptr; if (comm->me == 0) { - fp = utils::open_potential(cmapfile,lmp,nullptr); - if (fp == nullptr) - error->one(FLERR,"Cannot open fix cmap file {}: {}", - cmapfile, utils::getsyserror()); + try { + memset(&cmapgrid[0][0][0], 6*CMAPDIM*CMAPDIM, sizeof(double)); + PotentialFileReader reader(lmp, cmapfile, "cmap grid"); - } + // there are six maps in this order. + // alanine, alanine-proline, proline, proline-proline, glycine, glycine-proline. + // read as one big blob of numbers while ignoring comments - for (int ix1 = 0; ix1 < 6; ix1++) - for (int ix2 = 0; ix2 < CMAPDIM; ix2++) - for (int ix3 = 0; ix3 < CMAPDIM; ix3++) - cmapgrid[ix1][ix2][ix3] = 0.0; + reader.next_dvector(&cmapgrid[0][0][0],6*CMAPDIM*CMAPDIM); - counter = 0; - i1 = i2 = i3 = i4 = i5 = i6 = 0; - j1 = j2 = j3 = j4 = j5 = j6 = 0; - - int done = 0; - - while (!done) { - // only read on rank 0 and broadcast to all other ranks - if (comm->me == 0) - done = (fgets(linebuf,MAXLINE,fp) == nullptr); - - MPI_Bcast(&done,1,MPI_INT,0,world); - if (done) continue; - - MPI_Bcast(linebuf,MAXLINE,MPI_CHAR,0,world); - - // remove leading whitespace - line = linebuf; - while (line && (*line == ' ' || *line == '\t' || *line == '\r')) ++line; - - // skip if empty line or comment - if (!line || *line =='\n' || *line == '\0' || *line == '#') continue; - - // read in the cmap grid point values - // NOTE: The order to read the 6 grid maps is HARD-CODED, thus errors - // will occur if content of the file "cmap.data" is altered - // - // Reading order of the maps: - // 1. Alanine map - // 2. Alanine before proline map - // 3. Proline map - // 4. Two adjacent prolines map - // 5. Glycine map - // 6. Glycine before proline map - - chunk = strtok(line, " \r\n"); - while (chunk != nullptr) { - - // alanine map - - if (counter < CMAPDIM*CMAPDIM) { - cmapgrid[0][i1][j1] = atof(chunk); - chunk = strtok(nullptr, " \r\n"); - j1++; - if (j1 == CMAPDIM) { - j1 = 0; - i1++; - } - counter++; - } - - // alanine-proline map - - else if (counter >= CMAPDIM*CMAPDIM && - counter < 2*CMAPDIM*CMAPDIM) { - cmapgrid[1][i2][j2]= atof(chunk); - chunk = strtok(nullptr, " \r\n"); - j2++; - if (j2 == CMAPDIM) { - j2 = 0; - i2++; - } - counter++; - } - - // proline map - - else if (counter >= 2*CMAPDIM*CMAPDIM && - counter < 3*CMAPDIM*CMAPDIM) { - cmapgrid[2][i3][j3] = atof(chunk); - chunk = strtok(nullptr, " \r\n"); - j3++; - if (j3 == CMAPDIM) { - j3 = 0; - i3++; - } - counter++; - } - - // 2 adjacent prolines map - - else if (counter >= 3*CMAPDIM*CMAPDIM && - counter < 4*CMAPDIM*CMAPDIM) { - cmapgrid[3][i4][j4] = atof(chunk); - chunk = strtok(nullptr, " \r\n"); - j4++; - if (j4 == CMAPDIM) { - j4 = 0; - i4++; - } - counter++; - } - - // glycine map - - else if (counter >= 4*CMAPDIM*CMAPDIM && - counter < 5*CMAPDIM*CMAPDIM) { - cmapgrid[4][i5][j5] = atof(chunk); - chunk = strtok(nullptr, " \r\n"); - j5++; - if (j5 == CMAPDIM) { - j5 = 0; - i5++; - } - counter++; - } - - // glycine-proline map - - else if (counter >= 5*CMAPDIM*CMAPDIM && - counter < 6*CMAPDIM*CMAPDIM) { - cmapgrid[5][i6][j6] = atof(chunk); - chunk = strtok(nullptr, " \r\n"); - j6++; - if (j6 == CMAPDIM) { - j6 = 0; - i6++; - } - counter++; - } - - else break; + } catch (std::exception &e) { + error->one(FLERR,"Error reading CMAP potential file: {}", e.what()); } } - if (comm->me == 0) fclose(fp); + MPI_Bcast(&cmapgrid[0][0][0],6*CMAPDIM*CMAPDIM,MPI_DOUBLE,0,world); } /* ---------------------------------------------------------------------- */ From be7e6d09399b2d7cbfb13565cb4056e46b71e1fb Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Tue, 18 Jan 2022 12:21:18 -0500 Subject: [PATCH 146/193] Avoid std::string copies --- src/pair_hybrid_scaled.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pair_hybrid_scaled.cpp b/src/pair_hybrid_scaled.cpp index 5bf593d147..0a4be44be0 100644 --- a/src/pair_hybrid_scaled.cpp +++ b/src/pair_hybrid_scaled.cpp @@ -524,7 +524,7 @@ void PairHybridScaled::write_restart(FILE *fp) int n = scalevars.size(); fwrite(&n, sizeof(int), 1, fp); - for (auto var : scalevars) { + for (auto &var : scalevars) { n = var.size() + 1; fwrite(&n, sizeof(int), 1, fp); fwrite(var.c_str(), sizeof(char), n, fp); From ef13455d6b3ad60cf494b79a588a74a8fb8a4f67 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jan 2022 16:48:07 -0500 Subject: [PATCH 147/193] add some metadata tags --- examples/PACKAGES/electron_stopping/Si.Si.elstop | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/PACKAGES/electron_stopping/Si.Si.elstop b/examples/PACKAGES/electron_stopping/Si.Si.elstop index 51618149ff..1a6952e571 100644 --- a/examples/PACKAGES/electron_stopping/Si.Si.elstop +++ b/examples/PACKAGES/electron_stopping/Si.Si.elstop @@ -1,8 +1,8 @@ -# Electronic stopping for Si in Si -# Uses metal units +# Electronic stopping for Si in Si UNITS: metal DATE: 2019-02-19 CONTRIBUTOR: Risto Toijala risto.toijala@helsinki.fi # Kinetic energy in eV, stopping power in eV/A # For other atom types, add columns. +# atom type 1 # energy Si in Si 3918.2 6.541 15672.9 13.091 From b890b564caa7571536c750ab16e148018e22fb03 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jan 2022 16:48:26 -0500 Subject: [PATCH 148/193] modernize electron stopping file reader --- src/EXTRA-FIX/fix_electron_stopping.cpp | 57 +++++++++++-------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/src/EXTRA-FIX/fix_electron_stopping.cpp b/src/EXTRA-FIX/fix_electron_stopping.cpp index bd54fea97d..49fcdd41bf 100644 --- a/src/EXTRA-FIX/fix_electron_stopping.cpp +++ b/src/EXTRA-FIX/fix_electron_stopping.cpp @@ -29,6 +29,7 @@ #include "neigh_list.h" #include "neigh_request.h" #include "neighbor.h" +#include "potential_file_reader.h" #include "region.h" #include "update.h" @@ -236,49 +237,43 @@ double FixElectronStopping::compute_scalar() return SeLoss_all; } -/* ---------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + read electron stopping parameters. only called from MPI rank 0. + format: energy then one column per atom type + read as many lines as available. + energies must be sorted in ascending order. + ---------------------------------------------------------------------- */ void FixElectronStopping::read_table(const char *file) { - char line[MAXLINE]; - - FILE *fp = utils::open_potential(file,lmp,nullptr); - if (fp == nullptr) - error->one(FLERR,"Cannot open stopping range table {}: {}", file, utils::getsyserror()); - const int ncol = atom->ntypes + 1; + int nlines = 0; + PotentialFileReader reader(lmp, file, "electron stopping data table"); - int l = 0; - while (true) { - if (fgets(line, MAXLINE, fp) == nullptr) break; // end of file - if (line[0] == '#') continue; // comment + try { + char *line; + double oldvalue = 0.0; - char *pch = strtok(line, " \t\n\r"); - if (pch == nullptr) continue; // blank line + while ((line = reader.next_line())) { + if (nlines >= maxlines) grow_table(); + ValueTokenizer values(line); + elstop_ranges[0][nlines] = values.next_double(); + if (elstop_ranges[0][nlines] <= oldvalue) + throw TokenizerException("energy values must be positive and in ascending order",line); - if (l >= maxlines) grow_table(); + oldvalue = elstop_ranges[0][nlines]; + for (int i = 1; i < ncol; ++i) + elstop_ranges[i][nlines] = values.next_double(); - int i = 0; - for ( ; i < ncol && pch != nullptr; i++) { - elstop_ranges[i][l] = utils::numeric(FLERR, pch,false,lmp); - pch = strtok(nullptr, " \t\n\r"); + ++nlines; } - - if (i != ncol || pch != nullptr) // too short or too long - error->one(FLERR, "fix electron/stopping: Invalid table line"); - - if (l >= 1 && elstop_ranges[0][l] <= elstop_ranges[0][l-1]) - error->one(FLERR, - "fix electron/stopping: Energies must be in ascending order"); - - l++; + } catch (std::exception &e) { + error->one(FLERR, "Problem parsing electron stopping data: {}", e.what()); } - table_entries = l; - - if (table_entries == 0) + if (nlines == 0) error->one(FLERR, "Did not find any data in electron/stopping table file"); - fclose(fp); + table_entries = nlines; } /* ---------------------------------------------------------------------- */ From e22f62f6db5ce02e8571150eab62437323e907d4 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jan 2022 19:55:30 -0500 Subject: [PATCH 149/193] add some metadata for fix gle matrix files --- examples/PACKAGES/gle/qt-300k.A | 2 ++ examples/PACKAGES/gle/qt-300k.C | 2 ++ examples/PACKAGES/gle/smart.A | 2 ++ 3 files changed, 6 insertions(+) diff --git a/examples/PACKAGES/gle/qt-300k.A b/examples/PACKAGES/gle/qt-300k.A index 073100ad9d..31ada37b05 100644 --- a/examples/PACKAGES/gle/qt-300k.A +++ b/examples/PACKAGES/gle/qt-300k.A @@ -1,3 +1,5 @@ +# DATE: 2014-11-24 UNITS: real CONTRIBUTOR: Michele Ceriotti michele.ceriotti@gmail.com + 3.904138445158e-4 4.681059722010e-2 3.079778738058e-2 4.428079381336e-2 5.057825203477e-2 2.591193419597e-2 1.513907125942e-2 -4.789343294190e-2 2.037551040972e-2 6.597801861779e-2 -8.528273506602e-3 -2.230839572773e-3 6.593086307870e-3 -6.653653981891e-2 -2.905096373618e-2 -6.597801861779e-2 2.086885297843e-2 1.145471984072e-2 3.111465343867e-2 1.101562087523e-2 -3.264959166486e-2 diff --git a/examples/PACKAGES/gle/qt-300k.C b/examples/PACKAGES/gle/qt-300k.C index 50d68df251..d6239ca8dc 100644 --- a/examples/PACKAGES/gle/qt-300k.C +++ b/examples/PACKAGES/gle/qt-300k.C @@ -1,3 +1,5 @@ +# DATE: 2014-11-24 UNITS: real CONTRIBUTOR: Michele Ceriotti michele.ceriotti@gmail.com + 2.999985914100e+2 5.937593337000e+0 2.144376751500e+2 5.883055908000e+1 -1.119803766000e+2 -6.793381764000e+1 1.379789732400e+1 5.937593337000e+0 3.781851303000e+2 -5.794518522000e+1 -2.178772681500e+2 -1.649310659100e+2 -6.557113452000e+1 3.833830743000e+1 2.144376751500e+2 -5.794518522000e+1 7.325759985000e+2 2.188507713000e+2 -3.704586531000e+2 -3.385193865000e+1 -4.827706758000e+0 diff --git a/examples/PACKAGES/gle/smart.A b/examples/PACKAGES/gle/smart.A index a63bd881c8..8abbdea76a 100644 --- a/examples/PACKAGES/gle/smart.A +++ b/examples/PACKAGES/gle/smart.A @@ -1,3 +1,5 @@ +# DATE: 2014-11-24 UNITS: real CONTRIBUTOR: Michele Ceriotti michele.ceriotti@gmail.com + 4.247358737218e-3 3.231404593065e-2 -9.715629522215e-3 8.199488441225e-3 7.288427565896e-3 -3.634229949055e-3 -3.294395982200e-3 4.887738278128e-2 5.978602802893e-1 -2.079222967202e-1 1.088740438247e-1 4.666954324786e-2 -1.334147134493e-2 -3.914996645811e-2 4.015863091190e-2 2.079222967202e-1 1.645970119444e-1 8.351952991453e-2 5.114740085468e-2 1.217862237677e-2 -4.506711205974e-2 From c4c3b545b2f4c3507dbeb2696c5f8e062a1af037 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jan 2022 19:55:50 -0500 Subject: [PATCH 150/193] modernize fix gle matrix file reading --- src/EXTRA-FIX/fix_gle.cpp | 104 ++++++++++---------------------------- 1 file changed, 26 insertions(+), 78 deletions(-) diff --git a/src/EXTRA-FIX/fix_gle.cpp b/src/EXTRA-FIX/fix_gle.cpp index de225c6980..d7061e199c 100644 --- a/src/EXTRA-FIX/fix_gle.cpp +++ b/src/EXTRA-FIX/fix_gle.cpp @@ -14,7 +14,7 @@ /* ---------------------------------------------------------------------- Contributing authors: Michele Ceriotti (EPFL), Joe Morrone (Stony Brook), - Axel Kohylmeyer (Temple U) + Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ #include "fix_gle.h" @@ -24,6 +24,7 @@ #include "error.h" #include "force.h" #include "memory.h" +#include "potential_file_reader.h" #include "random_mars.h" #include "respa.h" #include "update.h" @@ -221,46 +222,17 @@ FixGLE::FixGLE(LAMMPS *lmp, int narg, char **arg) : int seed = utils::inumeric(FLERR,arg[6],false,lmp); // LOADING A matrix - FILE *fgle = nullptr; char *fname = arg[7]; + memset(A, ns1sq, sizeof(double)); if (comm->me == 0) { - fgle = utils::open_potential(fname,lmp,nullptr); - if (fgle == nullptr) - error->one(FLERR,"Cannot open A-matrix file {}: {}",fname, utils::getsyserror()); - utils::logmesg(lmp,"Reading A-matrix from {}\n", fname); - } - - // read each line of the file, skipping blank lines or leading '#' - - char line[MAXLINE],*ptr; - int n,nwords,ndone=0,eof=0; - while (true) { - if (comm->me == 0) { - ptr = fgets(line,MAXLINE,fgle); - if (ptr == nullptr) { - eof = 1; - fclose(fgle); - } else n = strlen(line) + 1; + PotentialFileReader reader(lmp,fname,"fix gle A matrix"); + try { + reader.next_dvector(A, ns1sq); + } catch (std::exception &e) { + error->one(FLERR,"Error reading A-matrix: {}", e.what()); } - MPI_Bcast(&eof,1,MPI_INT,0,world); - if (eof) break; - MPI_Bcast(&n,1,MPI_INT,0,world); - MPI_Bcast(line,n,MPI_CHAR,0,world); - - // strip comment, skip line if blank - - if ((ptr = strchr(line,'#'))) *ptr = '\0'; - - nwords = utils::count_words(line); - if (nwords == 0) continue; - - ptr = strtok(line," \t\n\r\f"); - do { - A[ndone] = atof(ptr); - ptr = strtok(nullptr," \t\n\r\f"); - ndone++; - } while ((ptr != nullptr) && (ndone < ns1sq)); } + MPI_Bcast(A,ns1sq,MPI_DOUBLE,0,world); fnoneq=0; gle_every=1; gle_step=0; for (int iarg=8; iargme == 0) { - fgle = utils::open_potential(fname,lmp,nullptr); - if (fgle == nullptr) - error->one(FLERR,"Cannot open C-matrix file {}: {}",fname, utils::getsyserror()); - utils::logmesg(lmp,"Reading C-matrix from {}\n", fname); - } - - // read each line of the file, skipping blank lines or leading '#' - ndone = eof = 0; - const double cfac = force->boltz / force->mvv2e; - - while (true) { - if (comm->me == 0) { - ptr = fgets(line,MAXLINE,fgle); - if (ptr == nullptr) { - eof = 1; - fclose(fgle); - } else n = strlen(line) + 1; + PotentialFileReader reader(lmp,fname,"fix gle C matrix"); + try { + reader.next_dvector(C, ns1sq); + } catch (std::exception &e) { + error->one(FLERR,"Error reading C-matrix: {}", e.what()); } - MPI_Bcast(&eof,1,MPI_INT,0,world); - if (eof) break; - MPI_Bcast(&n,1,MPI_INT,0,world); - MPI_Bcast(line,n,MPI_CHAR,0,world); - - // strip comment, skip line if blank - - if ((ptr = strchr(line,'#'))) *ptr = '\0'; - - nwords = utils::count_words(line); - if (nwords == 0) continue; - - ptr = strtok(line," \t\n\r\f"); - do { - C[ndone] = cfac*atof(ptr); - ptr = strtok(nullptr," \t\n\r\f"); - ndone++; - } while ((ptr != nullptr) && (ndone < ns1sq)); } + MPI_Bcast(C,ns1sq,MPI_DOUBLE,0,world); + const double cfac = force->boltz / force->mvv2e; + for (int i=0; i < ns1sq; ++i) C[i] *= cfac; } #ifdef GLE_DEBUG @@ -366,12 +314,12 @@ FixGLE::FixGLE(LAMMPS *lmp, int narg, char **arg) : FixGLE::~FixGLE() { delete random; - delete [] A; - delete [] C; - delete [] S; - delete [] T; - delete [] TT; - delete [] ST; + delete[] A; + delete[] C; + delete[] S; + delete[] T; + delete[] TT; + delete[] ST; memory->destroy(sqrt_m); memory->destroy(gle_s); From 0595e4d7cd1f676975b96b71f9fa9f36d904cb09 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 19 Jan 2022 00:24:01 -0500 Subject: [PATCH 151/193] refactor parsing of pair style list parameter file --- src/MISC/pair_list.cpp | 258 +++++++++++++++++------------------------ src/MISC/pair_list.h | 20 ++-- 2 files changed, 113 insertions(+), 165 deletions(-) diff --git a/src/MISC/pair_list.cpp b/src/MISC/pair_list.cpp index d1051ecb11..54afcacaed 100644 --- a/src/MISC/pair_list.cpp +++ b/src/MISC/pair_list.cpp @@ -18,19 +18,28 @@ #include "pair_list.h" -#include -#include #include "atom.h" #include "comm.h" +#include "error.h" #include "force.h" #include "memory.h" -#include "error.h" +#include "text_file_reader.h" +#include "tokenizer.h" +#include +#include +#include +#include using namespace LAMMPS_NS; -static const char * const stylename[] = { - "none", "harmonic", "morse", "lj126", nullptr +enum { NONE = 0, HARM, MORSE, LJ126 }; + +static std::map stylename = { + { "none", NONE }, + { "harmonic", HARM }, + { "morse", MORSE }, + { "lj126", LJ126 } }; // fast power function for integer exponent > 0 @@ -55,7 +64,6 @@ PairList::PairList(LAMMPS *lmp) : Pair(lmp) restartinfo = 0; respa_enable = 0; cut_global = 0.0; - style = nullptr; params = nullptr; check_flag = 1; } @@ -66,7 +74,6 @@ PairList::~PairList() { memory->destroy(setflag); memory->destroy(cutsq); - memory->destroy(style); memory->destroy(params); } @@ -90,7 +97,7 @@ void PairList::compute(int eflag, int vflag) int pc = 0; for (int n=0; n < npairs; ++n) { - const list_parm_t &par = params[n]; + const list_param &par = params[n]; i = atom->map(par.id1); j = atom->map(par.id2); @@ -122,34 +129,34 @@ void PairList::compute(int eflag, int vflag) if (rsq < par.cutsq) { const double r2inv = 1.0/rsq; - if (style[n] == HARM) { + if (par.style == HARM) { const double r = sqrt(rsq); - const double dr = par.parm.harm.r0 - r; - fpair = 2.0*par.parm.harm.k*dr/r; + const double dr = par.param.harm.r0 - r; + fpair = 2.0*par.param.harm.k*dr/r; if (eflag_either) - epair = par.parm.harm.k*dr*dr - par.offset; + epair = par.param.harm.k*dr*dr - par.offset; - } else if (style[n] == MORSE) { + } else if (par.style == MORSE) { const double r = sqrt(rsq); - const double dr = par.parm.morse.r0 - r; - const double dexp = exp(par.parm.morse.alpha * dr); - fpair = 2.0*par.parm.morse.d0*par.parm.morse.alpha + const double dr = par.param.morse.r0 - r; + const double dexp = exp(par.param.morse.alpha * dr); + fpair = 2.0*par.param.morse.d0*par.param.morse.alpha * (dexp*dexp - dexp) / r; if (eflag_either) - epair = par.parm.morse.d0 * (dexp*dexp - 2.0*dexp) - par.offset; + epair = par.param.morse.d0 * (dexp*dexp - 2.0*dexp) - par.offset; - } else if (style[n] == LJ126) { + } else if (par.style == LJ126) { const double r6inv = r2inv*r2inv*r2inv; - const double sig6 = mypow(par.parm.lj126.sigma,6); - fpair = 24.0*par.parm.lj126.epsilon*r6inv + const double sig6 = mypow(par.param.lj126.sigma,6); + fpair = 24.0*par.param.lj126.epsilon*r6inv * (2.0*sig6*sig6*r6inv - sig6) * r2inv; if (eflag_either) - epair = 4.0*par.parm.lj126.epsilon*r6inv + epair = 4.0*par.param.lj126.epsilon*r6inv * (sig6*sig6*r6inv - sig6) - par.offset; } @@ -210,130 +217,73 @@ void PairList::settings(int narg, char **arg) if (strcmp(arg[2],"check") == 0) check_flag = 1; } - FILE *fp = utils::open_potential(arg[0],lmp,nullptr); - char line[1024]; - if (fp == nullptr) - error->all(FLERR,"Cannot open pair list file"); + std::vector mystyles; + std::vector myparams; - // count lines in file for upper limit of storage needed - int num = 1; - while (fgets(line,1024,fp)) ++num; - rewind(fp); - memory->create(style,num,"pair_list:style"); - memory->create(params,num,"pair_list:params"); - - // now read and parse pair list file for real - npairs = 0; - char *ptr; - tagint id1, id2; - int nharm=0, nmorse=0, nlj126=0; - - while (fgets(line,1024,fp)) { - ptr = strtok(line," \t\n\r\f"); - - // skip empty lines - if (!ptr) continue; - - // skip comment lines starting with # - if (*ptr == '#') continue; - - // get atom ids of pair - id1 = ATOTAGINT(ptr); - ptr = strtok(nullptr," \t\n\r\f"); - if (!ptr) - error->all(FLERR,"Incorrectly formatted pair list file"); - id2 = ATOTAGINT(ptr); - - // get potential type - ptr = strtok(nullptr," \t\n\r\f"); - if (!ptr) - error->all(FLERR,"Incorrectly formatted pair list file"); - - style[npairs] = NONE; - list_parm_t &par = params[npairs]; - par.id1 = id1; - par.id2 = id2; - - // harmonic potential - if (strcmp(ptr,stylename[HARM]) == 0) { - style[npairs] = HARM; - - ptr = strtok(nullptr," \t\n\r\f"); - if ((ptr == nullptr) || (*ptr == '#')) - error->all(FLERR,"Incorrectly formatted harmonic pair parameters"); - par.parm.harm.k = utils::numeric(FLERR,ptr,false,lmp); - - ptr = strtok(nullptr," \t\n\r\f"); - if ((ptr == nullptr) || (*ptr == '#')) - error->all(FLERR,"Incorrectly formatted harmonic pair parameters"); - par.parm.harm.r0 = utils::numeric(FLERR,ptr,false,lmp); - - ++nharm; - - // morse potential - } else if (strcmp(ptr,stylename[MORSE]) == 0) { - style[npairs] = MORSE; - - ptr = strtok(nullptr," \t\n\r\f"); - if (!ptr) - error->all(FLERR,"Incorrectly formatted morse pair parameters"); - par.parm.morse.d0 = utils::numeric(FLERR,ptr,false,lmp); - - ptr = strtok(nullptr," \t\n\r\f"); - if (!ptr) - error->all(FLERR,"Incorrectly formatted morse pair parameters"); - par.parm.morse.alpha = utils::numeric(FLERR,ptr,false,lmp); - - ptr = strtok(nullptr," \t\n\r\f"); - if (!ptr) - error->all(FLERR,"Incorrectly formatted morse pair parameters"); - par.parm.morse.r0 = utils::numeric(FLERR,ptr,false,lmp); - - ++nmorse; - - } else if (strcmp(ptr,stylename[LJ126]) == 0) { - // 12-6 lj potential - style[npairs] = LJ126; - - ptr = strtok(nullptr," \t\n\r\f"); - if (!ptr) - error->all(FLERR,"Incorrectly formatted 12-6 LJ pair parameters"); - par.parm.lj126.epsilon = utils::numeric(FLERR,ptr,false,lmp); - - ptr = strtok(nullptr," \t\n\r\f"); - if (!ptr) - error->all(FLERR,"Incorrectly formatted 12-6 LJ pair parameters"); - par.parm.lj126.sigma = utils::numeric(FLERR,ptr,false,lmp); - - ++nlj126; - - } else { - error->all(FLERR,"Unknown pair list potential style"); - } - - // optional cutoff parameter. if not specified use global value - ptr = strtok(nullptr," \t\n\r\f"); - if ((ptr != nullptr) && (*ptr != '#')) { - double cut = utils::numeric(FLERR,ptr,false,lmp); - par.cutsq = cut*cut; - } else { - par.cutsq = cut_global*cut_global; - } - - // count complete entry - ++npairs; - } - fclose(fp); - - // informative output + // read and parse potential file only on MPI rank 0. if (comm->me == 0) { - if (screen) - fprintf(screen,"Read %d (%d/%d/%d) interacting pairs from %s\n", - npairs, nharm, nmorse, nlj126, arg[0]); - if (logfile) - fprintf(logfile,"Read %d (%d/%d/%d) interacting pairs from %s\n", - npairs, nharm, nmorse, nlj126, arg[0]); + int nharm, nmorse, nlj126, nskipped; + FILE *fp = utils::open_potential(arg[0],lmp,nullptr); + TextFileReader reader(fp,"pair list coeffs"); + npairs = nharm = nmorse = nlj126 = nskipped = 0; + + try { + char *line; + while ((line = reader.next_line())) { + ValueTokenizer values(line); + list_param oneparam; + oneparam.id1 = values.next_tagint(); + oneparam.id2 = values.next_tagint(); + oneparam.style = stylename[values.next_string()]; + ++npairs; + + switch (oneparam.style) { + + case HARM: + oneparam.param.harm.k = values.next_double(); + oneparam.param.harm.r0 = values.next_double(); + ++nharm; + break; + + case MORSE: + oneparam.param.morse.d0 = values.next_double(); + oneparam.param.morse.alpha = values.next_double(); + oneparam.param.morse.r0 = values.next_double(); + ++nmorse; + break; + + case LJ126: + oneparam.param.lj126.epsilon = values.next_double(); + oneparam.param.lj126.sigma = values.next_double(); + ++nlj126; + break; + + case NONE: // fallthrough + error->warning(FLERR,"Skipping unrecognized pair list potential entry: {}", + utils::trim(line)); + ++nskipped; + break; + } + if (values.has_next()) + oneparam.cutsq = values.next_double(); + else + oneparam.cutsq = cut_global*cut_global; + + myparams.push_back(oneparam); + } + } catch (std::exception &e) { + error->one(FLERR,"Error reading pair list coeffs file: {}", e.what()); + } + utils::logmesg(lmp, "Read {} ({}/{}/{}) interacting pair lines from {}. " + "{} skipped entries.\n", npairs, nharm, nmorse, nlj126, arg[0], nskipped); + + memory->create(params,npairs,"pair_list:params"); + memcpy(params, myparams.data(),npairs*sizeof(list_param)); + fclose(fp); } + MPI_Bcast(&npairs, 1, MPI_INT, 0, world); + if (comm->me != 0) memory->create(params,npairs,"pair_list:params"); + MPI_Bcast(params, npairs*sizeof(list_param), MPI_CHAR, 0, world); } /* ---------------------------------------------------------------------- @@ -374,21 +324,21 @@ void PairList::init_style() if (offset_flag) { for (int n=0; n < npairs; ++n) { - list_parm_t &par = params[n]; + list_param &par = params[n]; - if (style[n] == HARM) { - const double dr = sqrt(par.cutsq) - par.parm.harm.r0; - par.offset = par.parm.harm.k*dr*dr; + if (par.style == HARM) { + const double dr = sqrt(par.cutsq) - par.param.harm.r0; + par.offset = par.param.harm.k*dr*dr; - } else if (style[n] == MORSE) { - const double dr = par.parm.morse.r0 - sqrt(par.cutsq); - const double dexp = exp(par.parm.morse.alpha * dr); - par.offset = par.parm.morse.d0 * (dexp*dexp - 2.0*dexp); + } else if (par.style == MORSE) { + const double dr = par.param.morse.r0 - sqrt(par.cutsq); + const double dexp = exp(par.param.morse.alpha * dr); + par.offset = par.param.morse.d0 * (dexp*dexp - 2.0*dexp); - } else if (style[n] == LJ126) { + } else if (par.style == LJ126) { const double r6inv = par.cutsq*par.cutsq*par.cutsq; - const double sig6 = mypow(par.parm.lj126.sigma,6); - par.offset = 4.0*par.parm.lj126.epsilon*r6inv * (sig6*sig6*r6inv - sig6); + const double sig6 = mypow(par.param.lj126.sigma,6); + par.offset = 4.0*par.param.lj126.epsilon*r6inv * (sig6*sig6*r6inv - sig6); } } } @@ -411,7 +361,7 @@ double PairList::init_one(int, int) double PairList::memory_usage() { double bytes = (double)npairs * sizeof(int); - bytes += (double)npairs * sizeof(list_parm_t); + bytes += (double)npairs * sizeof(list_param); const int n = atom->ntypes+1; bytes += (double)n*(n*sizeof(int) + sizeof(int *)); bytes += (double)n*(n*sizeof(double) + sizeof(double *)); diff --git a/src/MISC/pair_list.h b/src/MISC/pair_list.h index 60fd3a7a24..b7161c4f2c 100644 --- a/src/MISC/pair_list.h +++ b/src/MISC/pair_list.h @@ -39,8 +39,6 @@ class PairList : public Pair { protected: void allocate(); - enum { NONE = 0, HARM, MORSE, LJ126 }; - // potential specific parameters struct harm_p { double k, r0; @@ -52,23 +50,23 @@ class PairList : public Pair { double epsilon, sigma; }; - union parm_u { - struct harm_p harm; - struct morse_p morse; - struct lj126_p lj126; + union param_u { + harm_p harm; + morse_p morse; + lj126_p lj126; }; - typedef struct { + struct list_param { + int style; // potential style indicator tagint id1, id2; // global atom ids double cutsq; // cutoff**2 for this pair double offset; // energy offset - union parm_u parm; // parameters for style - } list_parm_t; + union param_u param; // parameters for style + }; protected: double cut_global; // global cutoff distance - int *style; // list of styles for pair interactions - list_parm_t *params; // lisf of pair interaction parameters + list_param *params; // lisf of pair interaction parameters int npairs; // # of atom pairs in global list int check_flag; // 1 if checking for missing pairs }; From f5ad91f9feef5b8179cc5e1dd2e8a12c78579102 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 19 Jan 2022 06:28:53 -0500 Subject: [PATCH 152/193] minor tweaks --- src/MANYBODY/pair_tersoff.cpp | 3 +-- src/MISC/pair_list.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/MANYBODY/pair_tersoff.cpp b/src/MANYBODY/pair_tersoff.cpp index f21c3bffca..484adc7436 100644 --- a/src/MANYBODY/pair_tersoff.cpp +++ b/src/MANYBODY/pair_tersoff.cpp @@ -431,8 +431,7 @@ void PairTersoff::read_file(char *file) // transparently convert units for supported conversions int unit_convert = reader.get_unit_convert(); - double conversion_factor = utils::get_conversion_factor(utils::ENERGY, - unit_convert); + double conversion_factor = utils::get_conversion_factor(utils::ENERGY,unit_convert); while ((line = reader.next_line(NPARAMS_PER_LINE))) { try { ValueTokenizer values(line); diff --git a/src/MISC/pair_list.cpp b/src/MISC/pair_list.cpp index 54afcacaed..5215cdc7e2 100644 --- a/src/MISC/pair_list.cpp +++ b/src/MISC/pair_list.cpp @@ -283,7 +283,7 @@ void PairList::settings(int narg, char **arg) } MPI_Bcast(&npairs, 1, MPI_INT, 0, world); if (comm->me != 0) memory->create(params,npairs,"pair_list:params"); - MPI_Bcast(params, npairs*sizeof(list_param), MPI_CHAR, 0, world); + MPI_Bcast(params, npairs*sizeof(list_param), MPI_BYTE, 0, world); } /* ---------------------------------------------------------------------- From 7676f66674f22296e711a6e358aa93ce424fa09b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 19 Jan 2022 06:29:27 -0500 Subject: [PATCH 153/193] modernize potential file parsing --- src/MANYBODY/pair_edip.cpp | 203 ++++++--------- src/MANYBODY/pair_edip.h | 21 +- src/MANYBODY/pair_edip_multi.cpp | 424 ++++++++++++++----------------- src/MANYBODY/pair_edip_multi.h | 16 +- 4 files changed, 294 insertions(+), 370 deletions(-) diff --git a/src/MANYBODY/pair_edip.cpp b/src/MANYBODY/pair_edip.cpp index af2314b8b9..611b1af455 100644 --- a/src/MANYBODY/pair_edip.cpp +++ b/src/MANYBODY/pair_edip.cpp @@ -31,6 +31,7 @@ #include "neigh_list.h" #include "neigh_request.h" #include "neighbor.h" +#include "potential_file_reader.h" #include #include @@ -368,7 +369,7 @@ void PairEDIP::compute(int eflag, int vflag) directorCos_ik_z = invR_ik * dr_ik[2]; cosTeta = directorCos_ij_x * directorCos_ik_x + directorCos_ij_y * directorCos_ik_y + - directorCos_ij_z * directorCos_ik_z; + directorCos_ij_z * directorCos_ik_z; cosTetaDiff = cosTeta + tauFunction; cosTetaDiffCosTetaDiff = cosTetaDiff * cosTetaDiff; @@ -376,33 +377,33 @@ void PairEDIP::compute(int eflag, int vflag) expMinusQFunctionCosTetaDiffCosTetaDiff = exp(-qFunctionCosTetaDiffCosTetaDiff); potentia3B_factor = lambda * - ((1.0 - expMinusQFunctionCosTetaDiffCosTetaDiff) + - eta * qFunctionCosTetaDiffCosTetaDiff); + ((1.0 - expMinusQFunctionCosTetaDiffCosTetaDiff) + + eta * qFunctionCosTetaDiffCosTetaDiff); exp3B_ik = preExp3B_ij[neighbor_k]; exp3BDerived_ik = preExp3BDerived_ij[neighbor_k]; forceMod3B_factor1_ij = -exp3BDerived_ij * exp3B_ik * potentia3B_factor; forceMod3B_factor2 = 2.0 * lambda * exp3B_ij * exp3B_ik * qFunction * cosTetaDiff * - (eta + expMinusQFunctionCosTetaDiffCosTetaDiff); + (eta + expMinusQFunctionCosTetaDiffCosTetaDiff); forceMod3B_factor2_ij = forceMod3B_factor2 * invR_ij; f_ij[0] = forceMod3B_factor1_ij * directorCos_ij_x + - forceMod3B_factor2_ij * (cosTeta * directorCos_ij_x - directorCos_ik_x); + forceMod3B_factor2_ij * (cosTeta * directorCos_ij_x - directorCos_ik_x); f_ij[1] = forceMod3B_factor1_ij * directorCos_ij_y + - forceMod3B_factor2_ij * (cosTeta * directorCos_ij_y - directorCos_ik_y); + forceMod3B_factor2_ij * (cosTeta * directorCos_ij_y - directorCos_ik_y); f_ij[2] = forceMod3B_factor1_ij * directorCos_ij_z + - forceMod3B_factor2_ij * (cosTeta * directorCos_ij_z - directorCos_ik_z); + forceMod3B_factor2_ij * (cosTeta * directorCos_ij_z - directorCos_ik_z); forceMod3B_factor1_ik = -exp3BDerived_ik * exp3B_ij * potentia3B_factor; forceMod3B_factor2_ik = forceMod3B_factor2 * invR_ik; f_ik[0] = forceMod3B_factor1_ik * directorCos_ik_x + - forceMod3B_factor2_ik * (cosTeta * directorCos_ik_x - directorCos_ij_x); + forceMod3B_factor2_ik * (cosTeta * directorCos_ik_x - directorCos_ij_x); f_ik[1] = forceMod3B_factor1_ik * directorCos_ik_y + - forceMod3B_factor2_ik * (cosTeta * directorCos_ik_y - directorCos_ij_y); + forceMod3B_factor2_ik * (cosTeta * directorCos_ik_y - directorCos_ij_y); f_ik[2] = forceMod3B_factor1_ik * directorCos_ik_z + - forceMod3B_factor2_ik * (cosTeta * directorCos_ik_z - directorCos_ij_z); + forceMod3B_factor2_ik * (cosTeta * directorCos_ik_z - directorCos_ij_z); forceModCoord += (forceMod3B_factor2 * (tauFunctionDerived - 0.5 * mu * cosTetaDiff)); @@ -765,136 +766,92 @@ double PairEDIP::init_one(int i, int j) void PairEDIP::read_file(char *file) { - int params_per_line = 20; - char **words = new char *[params_per_line + 1]; - memory->sfree(params); params = nullptr; nparams = maxparam = 0; // open file on proc 0 - FILE *fp; if (comm->me == 0) { - fp = utils::open_potential(file, lmp, nullptr); - if (fp == nullptr) - error->one(FLERR, "Cannot open EDIP potential file {}: {}", file, utils::getsyserror()); - } + PotentialFileReader reader(lmp, file, "edip"); + char *line; - // read each set of params from potential file - // one set of params can span multiple lines - // store params if all 3 element tags are in element list + while ((line = reader.next_line(NPARAMS_PER_LINE))) { + try { + ValueTokenizer values(line); + std::string iname = values.next_string(); + std::string jname = values.next_string(); + std::string kname = values.next_string(); - int n, nwords, ielement, jelement, kelement; - char line[MAXLINE], *ptr; - int eof = 0; + // ielement,jelement,kelement = 1st args + // if all 3 args are in element list, then parse this line + // else skip to next entry in file + int ielement, jelement, kelement; - while (true) { - if (comm->me == 0) { - ptr = fgets(line, MAXLINE, fp); - if (ptr == nullptr) { - eof = 1; - fclose(fp); - } else - n = strlen(line) + 1; - } - MPI_Bcast(&eof, 1, MPI_INT, 0, world); - if (eof) break; - MPI_Bcast(&n, 1, MPI_INT, 0, world); - MPI_Bcast(line, n, MPI_CHAR, 0, world); + for (ielement = 0; ielement < nelements; ielement++) + if (iname == elements[ielement]) break; + if (ielement == nelements) continue; + for (jelement = 0; jelement < nelements; jelement++) + if (jname == elements[jelement]) break; + if (jelement == nelements) continue; + for (kelement = 0; kelement < nelements; kelement++) + if (kname == elements[kelement]) break; + if (kelement == nelements) continue; - // strip comment, skip line if blank + // load up parameter settings and error check their values - if ((ptr = strchr(line, '#'))) *ptr = '\0'; - nwords = utils::count_words(line); - if (nwords == 0) continue; + if (nparams == maxparam) { + maxparam += DELTA; + params = (Param *) memory->srealloc(params,maxparam*sizeof(Param), + "pair:params"); - // concatenate additional lines until have params_per_line words + // make certain all addional allocated storage is initialized + // to avoid false positives when checking with valgrind - while (nwords < params_per_line) { - n = strlen(line); - if (comm->me == 0) { - ptr = fgets(&line[n], MAXLINE - n, fp); - if (ptr == nullptr) { - eof = 1; - fclose(fp); - } else - n = strlen(line) + 1; + memset(params + nparams, 0, DELTA*sizeof(Param)); + } + + params[nparams].ielement = ielement; + params[nparams].jelement = jelement; + params[nparams].kelement = kelement; + params[nparams].A = values.next_double(); + params[nparams].B = values.next_double(); + params[nparams].cutoffA = values.next_double(); + params[nparams].cutoffC = values.next_double(); + params[nparams].alpha = values.next_double(); + params[nparams].beta = values.next_double(); + params[nparams].eta = values.next_double(); + params[nparams].gamma = values.next_double(); + params[nparams].lambda = values.next_double(); + params[nparams].mu = values.next_double(); + params[nparams].rho = values.next_double(); + params[nparams].sigma = values.next_double(); + params[nparams].Q0 = values.next_double(); + params[nparams].u1 = values.next_double(); + params[nparams].u2 = values.next_double(); + params[nparams].u3 = values.next_double(); + params[nparams].u4 = values.next_double(); + } catch (std::exception &e) { + error->one(FLERR, "Error reading EDIP potential file: {}", e.what()); } - MPI_Bcast(&eof, 1, MPI_INT, 0, world); - if (eof) break; - MPI_Bcast(&n, 1, MPI_INT, 0, world); - MPI_Bcast(line, n, MPI_CHAR, 0, world); - if ((ptr = strchr(line, '#'))) *ptr = '\0'; - nwords = utils::count_words(line); + + if (params[nparams].A < 0.0 || params[nparams].B < 0.0 || params[nparams].cutoffA < 0.0 || + params[nparams].cutoffC < 0.0 || params[nparams].alpha < 0.0 || + params[nparams].beta < 0.0 || params[nparams].eta < 0.0 || params[nparams].gamma < 0.0 || + params[nparams].lambda < 0.0 || params[nparams].mu < 0.0 || params[nparams].rho < 0.0 || + params[nparams].sigma < 0.0) + error->all(FLERR, "Illegal EDIP parameter"); + + nparams++; } - - if (nwords != params_per_line) error->all(FLERR, "Incorrect format in EDIP potential file"); - - // words = ptrs to all words in line - - nwords = 0; - words[nwords++] = strtok(line, " \t\n\r\f"); - while ((words[nwords++] = strtok(nullptr, " \t\n\r\f"))) continue; - - // ielement,jelement,kelement = 1st args - // if all 3 args are in element list, then parse this line - // else skip to next entry in file - - for (ielement = 0; ielement < nelements; ielement++) - if (strcmp(words[0], elements[ielement]) == 0) break; - if (ielement == nelements) continue; - for (jelement = 0; jelement < nelements; jelement++) - if (strcmp(words[1], elements[jelement]) == 0) break; - if (jelement == nelements) continue; - for (kelement = 0; kelement < nelements; kelement++) - if (strcmp(words[2], elements[kelement]) == 0) break; - if (kelement == nelements) continue; - - // load up parameter settings and error check their values - - if (nparams == maxparam) { - maxparam += DELTA; - params = (Param *) memory->srealloc(params, maxparam * sizeof(Param), "pair:params"); - - // make certain all addional allocated storage is initialized - // to avoid false positives when checking with valgrind - - memset(params + nparams, 0, DELTA * sizeof(Param)); - } - - params[nparams].ielement = ielement; - params[nparams].jelement = jelement; - params[nparams].kelement = kelement; - params[nparams].A = atof(words[3]); - params[nparams].B = atof(words[4]); - params[nparams].cutoffA = atof(words[5]); - params[nparams].cutoffC = atof(words[6]); - params[nparams].alpha = atof(words[7]); - params[nparams].beta = atof(words[8]); - params[nparams].eta = atof(words[9]); - params[nparams].gamm = atof(words[10]); - params[nparams].lambda = atof(words[11]); - params[nparams].mu = atof(words[12]); - params[nparams].rho = atof(words[13]); - params[nparams].sigma = atof(words[14]); - params[nparams].Q0 = atof(words[15]); - params[nparams].u1 = atof(words[16]); - params[nparams].u2 = atof(words[17]); - params[nparams].u3 = atof(words[18]); - params[nparams].u4 = atof(words[19]); - - if (params[nparams].A < 0.0 || params[nparams].B < 0.0 || params[nparams].cutoffA < 0.0 || - params[nparams].cutoffC < 0.0 || params[nparams].alpha < 0.0 || - params[nparams].beta < 0.0 || params[nparams].eta < 0.0 || params[nparams].gamm < 0.0 || - params[nparams].lambda < 0.0 || params[nparams].mu < 0.0 || params[nparams].rho < 0.0 || - params[nparams].sigma < 0.0) - error->all(FLERR, "Illegal EDIP parameter"); - - nparams++; } + MPI_Bcast(&nparams, 1, MPI_INT, 0, world); + MPI_Bcast(&maxparam, 1, MPI_INT, 0, world); - delete[] words; + if (comm->me != 0) + params = (Param *) memory->srealloc(params,maxparam*sizeof(Param), "pair:params"); + + MPI_Bcast(params, maxparam*sizeof(Param), MPI_BYTE, 0, world); } /* ---------------------------------------------------------------------- */ @@ -946,7 +903,7 @@ void PairEDIP::setup_params() cutoffC = params[0].cutoffC; sigma = params[0].sigma; lambda = params[0].lambda; - gamm = params[0].gamm; + gamm = params[0].gamma; eta = params[0].eta; Q0 = params[0].Q0; mu = params[0].mu; diff --git a/src/MANYBODY/pair_edip.h b/src/MANYBODY/pair_edip.h index 5812768d55..a0d1e45613 100644 --- a/src/MANYBODY/pair_edip.h +++ b/src/MANYBODY/pair_edip.h @@ -34,14 +34,23 @@ class PairEDIP : public Pair { double init_one(int, int); void init_style(); + static constexpr int NPARAMS_PER_LINE = 20; + protected: struct Param { - double A, B; - double cutoffA, cutoffC, cutsq; - double alpha, beta; - double eta, gamm, lambda, mu, rho, sigma, Q0; - double u1, u2, u3, u4; - int ielement, jelement, kelement; + double A, B; // coefficients for pair interaction I-J + double cutoffA; // cut-off distance for pair interaction I-J + double cutoffC; // lower cut-off distance for calculating Z_I + double alpha; // coefficient for calculating Z_I + double beta; // attractive term for pair I-J + double sigma; // cut-off coefficient for pair I-J + double rho; // pair I-J + double gamma; // coefficient for three-body interaction I-J-K + double eta, lambda; // coefficients for function h(l,Z) + double mu, Q0; // coefficients for function Q(Z) + double u1, u2, u3, u4; // coefficients for function tau(Z) + double cutsq; + int ielement, jelement, kelement, dummy; // dummy added for better alignment }; double *preInvR_ij; diff --git a/src/MANYBODY/pair_edip_multi.cpp b/src/MANYBODY/pair_edip_multi.cpp index 8017fa4f8e..ffbc135a34 100644 --- a/src/MANYBODY/pair_edip_multi.cpp +++ b/src/MANYBODY/pair_edip_multi.cpp @@ -30,6 +30,7 @@ #include "neigh_list.h" #include "neigh_request.h" #include "neighbor.h" +#include "potential_file_reader.h" #include #include @@ -118,8 +119,8 @@ void PairEDIPMulti::compute(int eflag, int vflag) double costheta; double dpairZ,dtripleZ; - // eflag != 0 means compute energy contributions in this step - // vflag != 0 means compute virial contributions in this step + // eflag != 0 means compute energy contributions in this step + // vflag != 0 means compute virial contributions in this step evdwl = 0.0; ev_init(eflag,vflag); @@ -155,39 +156,40 @@ void PairEDIPMulti::compute(int eflag, int vflag) // pre-loop to compute environment coordination f(Z) for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - j &= NEIGHMASK; + j = jlist[jj]; + j &= NEIGHMASK; - double delx, dely, delz, r_ij; + double delx, dely, delz, r_ij; - delx = x[j][0] - xtmp; - dely = x[j][1] - ytmp; - delz = x[j][2] - ztmp; - r_ij = delx * delx + dely * dely + delz * delz; + delx = x[j][0] - xtmp; + dely = x[j][1] - ytmp; + delz = x[j][2] - ztmp; + r_ij = delx * delx + dely * dely + delz * delz; - jtype = map[type[j]]; - ijparam = elem3param[itype][jtype][jtype]; - if (r_ij > params[ijparam].cutsq) continue; + jtype = map[type[j]]; + const Param ¶m = params[elem3param[itype][jtype][jtype]]; - r_ij = sqrt(r_ij); + if (r_ij > param.cutsq) continue; - // zeta and its derivative dZ/dr + r_ij = sqrt(r_ij); - if (r_ij < params[ijparam].cutoffC) zeta_i += 1.0; - else { - double f, fdr; - edip_fc(r_ij, ¶ms[ijparam], f, fdr); - zeta_i += f; - dzetair = -fdr / r_ij; + // zeta and its derivative dZ/dr - preForceCoord_counter=numForceCoordPairs*5; - preForceCoord[preForceCoord_counter+0]=dzetair; - preForceCoord[preForceCoord_counter+1]=delx; - preForceCoord[preForceCoord_counter+2]=dely; - preForceCoord[preForceCoord_counter+3]=delz; - preForceCoord[preForceCoord_counter+4]=j; - numForceCoordPairs++; - } + if (r_ij < param.cutoffC) zeta_i += 1.0; + else { + double f, fdr; + edip_fc(r_ij, param, f, fdr); + zeta_i += f; + dzetair = -fdr / r_ij; + + preForceCoord_counter=numForceCoordPairs*5; + preForceCoord[preForceCoord_counter+0]=dzetair; + preForceCoord[preForceCoord_counter+1]=delx; + preForceCoord[preForceCoord_counter+2]=dely; + preForceCoord[preForceCoord_counter+3]=delz; + preForceCoord[preForceCoord_counter+4]=j; + numForceCoordPairs++; + } } // two-body interactions @@ -217,7 +219,7 @@ void PairEDIPMulti::compute(int eflag, int vflag) // already considered in constructing the potential double fdr, fdZ; - edip_pair(r_ij, zeta_i, ¶ms[ijparam], evdwl, fdr, fdZ); + edip_pair(r_ij, zeta_i, params[ijparam], evdwl, fdr, fdZ); fpair = -fdr / r_ij; dpairZ += fdZ; @@ -234,102 +236,102 @@ void PairEDIPMulti::compute(int eflag, int vflag) // three-body Forces for (kk = jj + 1; kk < jnum; kk++) { - double dr_ik[3], r_ik, f_ik[3]; + double dr_ik[3], r_ik, f_ik[3]; - k = jlist[kk]; - k &= NEIGHMASK; - ktype = map[type[k]]; - ikparam = elem3param[itype][ktype][ktype]; - ijkparam = elem3param[itype][jtype][ktype]; + k = jlist[kk]; + k &= NEIGHMASK; + ktype = map[type[k]]; + ikparam = elem3param[itype][ktype][ktype]; + ijkparam = elem3param[itype][jtype][ktype]; - dr_ik[0] = x[k][0] - xtmp; - dr_ik[1] = x[k][1] - ytmp; - dr_ik[2] = x[k][2] - ztmp; - r_ik = dr_ik[0]*dr_ik[0] + dr_ik[1]*dr_ik[1] + dr_ik[2]*dr_ik[2]; + dr_ik[0] = x[k][0] - xtmp; + dr_ik[1] = x[k][1] - ytmp; + dr_ik[2] = x[k][2] - ztmp; + r_ik = dr_ik[0]*dr_ik[0] + dr_ik[1]*dr_ik[1] + dr_ik[2]*dr_ik[2]; - if (r_ik > params[ikparam].cutsq) continue; + if (r_ik > params[ikparam].cutsq) continue; - r_ik = sqrt(r_ik); + r_ik = sqrt(r_ik); - costheta=dot3(dr_ij, dr_ik) / r_ij / r_ik; + costheta=dot3(dr_ij, dr_ik) / r_ij / r_ik; - double v1, v2, v3, v4, v5, v6, v7; + double v1, v2, v3, v4, v5, v6, v7; - edip_fcut3(r_ij, ¶ms[ijparam], v1, v2); - edip_fcut3(r_ik, ¶ms[ikparam], v3, v4); - edip_h(costheta, zeta_i, ¶ms[ijkparam], v5, v6, v7); + edip_fcut3(r_ij, params[ijparam], v1, v2); + edip_fcut3(r_ik, params[ikparam], v3, v4); + edip_h(costheta, zeta_i, params[ijkparam], v5, v6, v7); - // potential energy and forces - evdwl = v1 * v3 * v5; - dtripleZ += v1 * v3 * v7; + // potential energy and forces + evdwl = v1 * v3 * v5; + dtripleZ += v1 * v3 * v7; - double dri[3], drj[3], drk[3]; - double dhl, dfr; + double dri[3], drj[3], drk[3]; + double dhl, dfr; - dhl = v1 * v3 * v6; + dhl = v1 * v3 * v6; - costheta_d(dr_ij, r_ij, dr_ik, r_ik, dri, drj, drk); + costheta_d(dr_ij, r_ij, dr_ik, r_ik, dri, drj, drk); - f_ij[0] = -dhl * drj[0]; - f_ij[1] = -dhl * drj[1]; - f_ij[2] = -dhl * drj[2]; - f_ik[0] = -dhl * drk[0]; - f_ik[1] = -dhl * drk[1]; - f_ik[2] = -dhl * drk[2]; + f_ij[0] = -dhl * drj[0]; + f_ij[1] = -dhl * drj[1]; + f_ij[2] = -dhl * drj[2]; + f_ik[0] = -dhl * drk[0]; + f_ik[1] = -dhl * drk[1]; + f_ik[2] = -dhl * drk[2]; - dfr = v2 * v3 * v5; - fpair = -dfr / r_ij; + dfr = v2 * v3 * v5; + fpair = -dfr / r_ij; - f_ij[0] += fpair * dr_ij[0]; - f_ij[1] += fpair * dr_ij[1]; - f_ij[2] += fpair * dr_ij[2]; + f_ij[0] += fpair * dr_ij[0]; + f_ij[1] += fpair * dr_ij[1]; + f_ij[2] += fpair * dr_ij[2]; - dfr = v1 * v4 * v5; - fpair = -dfr / r_ik; + dfr = v1 * v4 * v5; + fpair = -dfr / r_ik; - f_ik[0] += fpair * dr_ik[0]; - f_ik[1] += fpair * dr_ik[1]; - f_ik[2] += fpair * dr_ik[2]; + f_ik[0] += fpair * dr_ik[0]; + f_ik[1] += fpair * dr_ik[1]; + f_ik[2] += fpair * dr_ik[2]; - f[j][0] += f_ij[0]; - f[j][1] += f_ij[1]; - f[j][2] += f_ij[2]; + f[j][0] += f_ij[0]; + f[j][1] += f_ij[1]; + f[j][2] += f_ij[2]; - f[k][0] += f_ik[0]; - f[k][1] += f_ik[1]; - f[k][2] += f_ik[2]; + f[k][0] += f_ik[0]; + f[k][1] += f_ik[1]; + f[k][2] += f_ik[2]; - f[i][0] -= f_ij[0] + f_ik[0]; - f[i][1] -= f_ij[1] + f_ik[1]; - f[i][2] -= f_ij[2] + f_ik[2]; + f[i][0] -= f_ij[0] + f_ik[0]; + f[i][1] -= f_ij[1] + f_ik[1]; + f[i][2] -= f_ij[2] + f_ik[2]; - if (evflag) ev_tally3(i,j,k,evdwl,0.0,f_ij,f_ik,dr_ij,dr_ik); + if (evflag) ev_tally3(i,j,k,evdwl,0.0,f_ij,f_ik,dr_ij,dr_ik); } } // forces due to environment coordination f(Z) for (int idx = 0; idx < numForceCoordPairs; idx++) { - double delx, dely, delz; + double delx, dely, delz; - preForceCoord_counter = idx * 5; - dzetair = preForceCoord[preForceCoord_counter+0]; - delx = preForceCoord[preForceCoord_counter+1]; - dely = preForceCoord[preForceCoord_counter+2]; - delz = preForceCoord[preForceCoord_counter+3]; - j = static_cast (preForceCoord[preForceCoord_counter+4]); + preForceCoord_counter = idx * 5; + dzetair = preForceCoord[preForceCoord_counter+0]; + delx = preForceCoord[preForceCoord_counter+1]; + dely = preForceCoord[preForceCoord_counter+2]; + delz = preForceCoord[preForceCoord_counter+3]; + j = static_cast (preForceCoord[preForceCoord_counter+4]); - dzetair *= (dpairZ + dtripleZ); + dzetair *= (dpairZ + dtripleZ); - f[j][0] += dzetair * delx; - f[j][1] += dzetair * dely; - f[j][2] += dzetair * delz; + f[j][0] += dzetair * delx; + f[j][1] += dzetair * dely; + f[j][2] += dzetair * delz; - f[i][0] -= dzetair * delx; - f[i][1] -= dzetair * dely; - f[i][2] -= dzetair * delz; + f[i][0] -= dzetair * delx; + f[i][1] -= dzetair * dely; + f[i][2] -= dzetair * delz; - evdwl = 0.0; - if (evflag) ev_tally(i, j, nlocal, newton_pair, evdwl, 0.0, dzetair, -delx, -dely, -delz); + evdwl = 0.0; + if (evflag) ev_tally(i, j, nlocal, newton_pair, evdwl, 0.0, dzetair, -delx, -dely, -delz); } } @@ -342,13 +344,13 @@ double sqr(double x) } //pair Vij, partial derivatives dVij(r,Z)/dr and dVij(r,Z)/dZ -void PairEDIPMulti::edip_pair(double r, double z, Param *param, double &eng, +void PairEDIPMulti::edip_pair(double r, double z, const Param ¶m, double &eng, double &fdr, double &fZ) { - double A = param->A; - double B = param->B; - double rho = param->rho; - double beta = param->beta; + double A = param.A; + double B = param.B; + double rho = param.rho; + double beta = param.beta; double v1,v2,v3,v4; v1 = pow(B / r, rho); @@ -361,11 +363,11 @@ void PairEDIPMulti::edip_pair(double r, double z, Param *param, double &eng, } //function fc(r) in calculating coordination Z and derivative fc'(r) -void PairEDIPMulti::edip_fc(double r, Param *param, double &f, double &fdr) +void PairEDIPMulti::edip_fc(double r, const Param ¶m, double &f, double &fdr) { - double a = param->cutoffA; - double c = param->cutoffC; - double alpha = param->alpha; + double a = param.cutoffA; + double c = param.cutoffC; + double alpha = param.alpha; double x; double v1, v2; @@ -392,10 +394,10 @@ void PairEDIPMulti::edip_fc(double r, Param *param, double &f, double &fdr) } //cut-off function for Vij and its derivative fcut2'(r) -void PairEDIPMulti::edip_fcut2(double r, Param *param, double &f, double &fdr) +void PairEDIPMulti::edip_fcut2(double r, const Param ¶m, double &f, double &fdr) { - double sigma = param->sigma; - double a = param->cutoffA; + double sigma = param.sigma; + double a = param.cutoffA; double v1; if (r > a - 1E-6) @@ -411,12 +413,12 @@ void PairEDIPMulti::edip_fcut2(double r, Param *param, double &f, double &fdr) } //function tau(Z) and its derivative tau'(Z) -void PairEDIPMulti::edip_tau(double z, Param *param, double &f, double &fdZ) +void PairEDIPMulti::edip_tau(double z, const Param ¶m, double &f, double &fdZ) { - double u1 = param->u1; - double u2 = param->u2; - double u3 = param->u3; - double u4 = param->u4; + double u1 = param.u1; + double u2 = param.u2; + double u3 = param.u3; + double u4 = param.u4; double v1, v2; v1 = exp(-u4 * z); @@ -427,13 +429,13 @@ void PairEDIPMulti::edip_tau(double z, Param *param, double &f, double &fdZ) } //function h(l,Z) and its partial derivatives dh(l,Z)/dl and dh(l,Z)/dZ -void PairEDIPMulti::edip_h(double l, double z, Param *param, double &f, +void PairEDIPMulti::edip_h(double l, double z, const Param ¶m, double &f, double &fdl, double &fdZ) { - double lambda = param->lambda; - double eta = param->eta; - double Q0 = param->Q0; - double mu = param->mu; + double lambda = param.lambda; + double eta = param.eta; + double Q0 = param.Q0; + double mu = param.mu; double Q, QdZ, Tau, TaudZ; double u2, du2l, du2Z; double v1, v2, v3; @@ -464,10 +466,10 @@ void PairEDIPMulti::edip_h(double l, double z, Param *param, double &f, } //cut-off function for Vijk and its derivative fcut3'(r) -void PairEDIPMulti::edip_fcut3(double r, Param *param, double &f, double &fdr) +void PairEDIPMulti::edip_fcut3(double r, const Param ¶m, double &f, double &fdr) { - double gamma = param->gamma; - double a = param->cutoffA; + double gamma = param.gamma; + double a = param.cutoffA; double v1; if (r > a - 1E-6) @@ -578,137 +580,92 @@ double PairEDIPMulti::init_one(int i, int j) void PairEDIPMulti::read_file(char *file) { - int params_per_line = 20; - char **words = new char*[params_per_line+1]; - memory->sfree(params); params = nullptr; nparams = maxparam = 0; // open file on proc 0 - FILE *fp; if (comm->me == 0) { - fp = utils::open_potential(file,lmp,nullptr); - if (fp == nullptr) - error->one(FLERR,"Cannot open EDIP potential file {}: {}",file,utils::getsyserror()); - } + PotentialFileReader reader(lmp, file, "edip"); + char *line; - // read each set of params from potential file - // one set of params can span multiple lines - // store params if all 3 element tags are in element list + while ((line = reader.next_line(NPARAMS_PER_LINE))) { + try { + ValueTokenizer values(line); + std::string iname = values.next_string(); + std::string jname = values.next_string(); + std::string kname = values.next_string(); - int n,nwords,ielement,jelement,kelement; - char line[MAXLINE],*ptr; - int eof = 0; + // ielement,jelement,kelement = 1st args + // if all 3 args are in element list, then parse this line + // else skip to next entry in file + int ielement, jelement, kelement; - while (true) { - if (comm->me == 0) { - ptr = fgets(line,MAXLINE,fp); - if (ptr == nullptr) { - eof = 1; - fclose(fp); - } else n = strlen(line) + 1; - } - MPI_Bcast(&eof,1,MPI_INT,0,world); - if (eof) break; - MPI_Bcast(&n,1,MPI_INT,0,world); - MPI_Bcast(line,n,MPI_CHAR,0,world); + for (ielement = 0; ielement < nelements; ielement++) + if (iname == elements[ielement]) break; + if (ielement == nelements) continue; + for (jelement = 0; jelement < nelements; jelement++) + if (jname == elements[jelement]) break; + if (jelement == nelements) continue; + for (kelement = 0; kelement < nelements; kelement++) + if (kname == elements[kelement]) break; + if (kelement == nelements) continue; - // strip comment, skip line if blank + // load up parameter settings and error check their values - if ((ptr = strchr(line,'#'))) *ptr = '\0'; - nwords = utils::count_words(line); - if (nwords == 0) continue; + if (nparams == maxparam) { + maxparam += DELTA; + params = (Param *) memory->srealloc(params,maxparam*sizeof(Param), + "pair:params"); - // concatenate additional lines until have params_per_line words + // make certain all addional allocated storage is initialized + // to avoid false positives when checking with valgrind - while (nwords < params_per_line) { - n = strlen(line); - if (comm->me == 0) { - ptr = fgets(&line[n],MAXLINE-n,fp); - if (ptr == nullptr) { - eof = 1; - fclose(fp); - } else n = strlen(line) + 1; + memset(params + nparams, 0, DELTA*sizeof(Param)); + } + + params[nparams].ielement = ielement; + params[nparams].jelement = jelement; + params[nparams].kelement = kelement; + params[nparams].A = values.next_double(); + params[nparams].B = values.next_double(); + params[nparams].cutoffA = values.next_double(); + params[nparams].cutoffC = values.next_double(); + params[nparams].alpha = values.next_double(); + params[nparams].beta = values.next_double(); + params[nparams].eta = values.next_double(); + params[nparams].gamma = values.next_double(); + params[nparams].lambda = values.next_double(); + params[nparams].mu = values.next_double(); + params[nparams].rho = values.next_double(); + params[nparams].sigma = values.next_double(); + params[nparams].Q0 = values.next_double(); + params[nparams].u1 = values.next_double(); + params[nparams].u2 = values.next_double(); + params[nparams].u3 = values.next_double(); + params[nparams].u4 = values.next_double(); + } catch (std::exception &e) { + error->one(FLERR, "Error reading EDIP potential file: {}", e.what()); } - MPI_Bcast(&eof,1,MPI_INT,0,world); - if (eof) break; - MPI_Bcast(&n,1,MPI_INT,0,world); - MPI_Bcast(line,n,MPI_CHAR,0,world); - if ((ptr = strchr(line,'#'))) *ptr = '\0'; - nwords = utils::count_words(line); + + if (params[nparams].A < 0.0 || params[nparams].B < 0.0 || params[nparams].cutoffA < 0.0 || + params[nparams].cutoffC < 0.0 || params[nparams].alpha < 0.0 || + params[nparams].beta < 0.0 || params[nparams].eta < 0.0 || params[nparams].gamma < 0.0 || + params[nparams].lambda < 0.0 || params[nparams].mu < 0.0 || params[nparams].rho < 0.0 || + params[nparams].sigma < 0.0) + error->all(FLERR, "Illegal EDIP parameter"); + + nparams++; } - - if (nwords != params_per_line) - error->all(FLERR,"Incorrect format in EDIP potential file"); - - // words = ptrs to all words in line - - nwords = 0; - words[nwords++] = strtok(line," \t\n\r\f"); - while ((words[nwords++] = strtok(nullptr," \t\n\r\f"))) continue; - - // ielement,jelement,kelement = 1st args - // if all 3 args are in element list, then parse this line - // else skip to next entry in file - - for (ielement = 0; ielement < nelements; ielement++) - if (strcmp(words[0],elements[ielement]) == 0) break; - if (ielement == nelements) continue; - for (jelement = 0; jelement < nelements; jelement++) - if (strcmp(words[1],elements[jelement]) == 0) break; - if (jelement == nelements) continue; - for (kelement = 0; kelement < nelements; kelement++) - if (strcmp(words[2],elements[kelement]) == 0) break; - if (kelement == nelements) continue; - - // load up parameter settings and error check their values - - if (nparams == maxparam) { - maxparam += DELTA; - params = (Param *) memory->srealloc(params,maxparam*sizeof(Param), - "pair:params"); - - // make certain all addional allocated storage is initialized - // to avoid false positives when checking with valgrind - - memset(params + nparams, 0, DELTA*sizeof(Param)); - } - - params[nparams].ielement = ielement; - params[nparams].jelement = jelement; - params[nparams].kelement = kelement; - params[nparams].A = atof(words[3]); - params[nparams].B = atof(words[4]); - params[nparams].cutoffA = atof(words[5]); - params[nparams].cutoffC = atof(words[6]); - params[nparams].alpha = atof(words[7]); - params[nparams].beta = atof(words[8]); - params[nparams].eta = atof(words[9]); - params[nparams].gamma = atof(words[10]); - params[nparams].lambda = atof(words[11]); - params[nparams].mu = atof(words[12]); - params[nparams].rho = atof(words[13]); - params[nparams].sigma = atof(words[14]); - params[nparams].Q0 = atof(words[15]); - params[nparams].u1 = atof(words[16]); - params[nparams].u2 = atof(words[17]); - params[nparams].u3 = atof(words[18]); - params[nparams].u4 = atof(words[19]); - - if (params[nparams].A < 0.0 || params[nparams].B < 0.0 || - params[nparams].cutoffA < 0.0 || params[nparams].cutoffC < 0.0 || - params[nparams].alpha < 0.0 || params[nparams].beta < 0.0 || - params[nparams].eta < 0.0 || params[nparams].gamma < 0.0 || - params[nparams].lambda < 0.0 || params[nparams].mu < 0.0 || - params[nparams].rho < 0.0 || params[nparams].sigma < 0.0) - error->all(FLERR,"Illegal EDIP parameter"); - - nparams++; } + MPI_Bcast(&nparams, 1, MPI_INT, 0, world); + MPI_Bcast(&maxparam, 1, MPI_INT, 0, world); - delete [] words; + if (comm->me != 0) + params = (Param *) memory->srealloc(params,maxparam*sizeof(Param), "pair:params"); + + MPI_Bcast(params, maxparam*sizeof(Param), MPI_BYTE, 0, world); } /* ---------------------------------------------------------------------- */ @@ -753,5 +710,4 @@ void PairEDIPMulti::setup() rtmp = sqrt(params[m].cutsq); if (rtmp > cutmax) cutmax = rtmp; } - } diff --git a/src/MANYBODY/pair_edip_multi.h b/src/MANYBODY/pair_edip_multi.h index 3ee7347a56..1070956bc2 100644 --- a/src/MANYBODY/pair_edip_multi.h +++ b/src/MANYBODY/pair_edip_multi.h @@ -34,6 +34,8 @@ class PairEDIPMulti : public Pair { double init_one(int, int); void init_style(); + static constexpr int NPARAMS_PER_LINE = 20; + protected: struct Param { double A, B; // coefficients for pair interaction I-J @@ -48,7 +50,7 @@ class PairEDIPMulti : public Pair { double mu, Q0; // coefficients for function Q(Z) double u1, u2, u3, u4; // coefficients for function tau(Z) double cutsq; - int ielement, jelement, kelement; + int ielement, jelement, kelement, dummy; // dummy added for better alignment }; double *preForceCoord; @@ -63,12 +65,12 @@ class PairEDIPMulti : public Pair { void read_file(char *); void setup(); - void edip_pair(double, double, Param *, double &, double &, double &); - void edip_fc(double, Param *, double &, double &); - void edip_fcut2(double, Param *, double &, double &); - void edip_tau(double, Param *, double &, double &); - void edip_h(double, double, Param *, double &, double &, double &); - void edip_fcut3(double, Param *, double &, double &); + void edip_pair(double, double, const Param &, double &, double &, double &); + void edip_fc(double, const Param &, double &, double &); + void edip_fcut2(double, const Param &, double &, double &); + void edip_tau(double, const Param &, double &, double &); + void edip_h(double, double, const Param &, double &, double &, double &); + void edip_fcut3(double, const Param &, double &, double &); }; } // namespace LAMMPS_NS From c85cdb2732312e07ffaf5acbeeb83f1caffd1772 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 19 Jan 2022 10:11:16 -0500 Subject: [PATCH 154/193] always fall back to using the .so extension if available in the LAMMPS module folder --- python/lammps/core.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/lammps/core.py b/python/lammps/core.py index fcd5c76ad5..0bc8d0cb3f 100644 --- a/python/lammps/core.py +++ b/python/lammps/core.py @@ -122,6 +122,9 @@ class lammps(object): for f in os.listdir(winpath)]): lib_ext = ".dll" modpath = winpath + elif any([f.startswith('liblammps') and f.endswith('.so') + for f in os.listdir(modpath)]): + lib_ext = ".so" else: import platform if platform.system() == "Darwin": From 4f0cde40fd04c8f66cc530056d2a53557708e05a Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Wed, 19 Jan 2022 10:16:53 -0700 Subject: [PATCH 155/193] White no longer exists --- src/MAKE/MACHINES/Makefile.white | 128 ------------------------------- 1 file changed, 128 deletions(-) delete mode 100644 src/MAKE/MACHINES/Makefile.white diff --git a/src/MAKE/MACHINES/Makefile.white b/src/MAKE/MACHINES/Makefile.white deleted file mode 100644 index cb101998b3..0000000000 --- a/src/MAKE/MACHINES/Makefile.white +++ /dev/null @@ -1,128 +0,0 @@ -# white = KOKKOS/CUDA package, OpenMPI with nvcc compiler, Pascal GPU, Power8 CPU - -SHELL = /bin/sh - -# --------------------------------------------------------------------- -# compiler/linker settings -# specify flags and libraries needed for your compiler - -KOKKOS_ABSOLUTE_PATH = $(shell cd $(KOKKOS_PATH); pwd) -export OMPI_CXX = $(KOKKOS_ABSOLUTE_PATH)/bin/nvcc_wrapper -CC = mpicxx -CCFLAGS = -g -O3 -SHFLAGS = -fPIC -DEPFLAGS = -M - -LINK = mpicxx -LINKFLAGS = -g -O3 -LIB = -SIZE = size - -ARCHIVE = ar -ARFLAGS = -rc -SHLIBFLAGS = -shared -KOKKOS_DEVICES = Cuda -KOKKOS_ARCH = Pascal60,Power8 - -# --------------------------------------------------------------------- -# LAMMPS-specific settings, all OPTIONAL -# specify settings for LAMMPS features you will use -# if you change any -D setting, do full re-compile after "make clean" - -# LAMMPS ifdef settings -# see possible settings in Section 3.5 of the manual - -LMP_INC = -DLAMMPS_GZIP - -# MPI library -# 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 -# INC = path for mpi.h, MPI compiler settings -# PATH = path for MPI library -# LIB = name of MPI library - -MPI_INC = -DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1 -MPI_PATH = -MPI_LIB = - -# FFT library -# see discussion in Section 3.5.2 of manual -# can be left blank to use provided KISS FFT library -# INC = -DFFT setting, e.g. -DFFT_FFTW, FFT compiler settings -# PATH = path for FFT library -# LIB = name of FFT library - -FFT_INC = -FFT_PATH = -FFT_LIB = - -# JPEG and/or PNG library -# see discussion in Section 3.5.4 of manual -# only needed if -DLAMMPS_JPEG or -DLAMMPS_PNG listed with LMP_INC -# INC = path(s) for jpeglib.h and/or png.h -# PATH = path(s) for JPEG library and/or PNG library -# LIB = name(s) of JPEG library and/or PNG library - -JPG_INC = -JPG_PATH = -JPG_LIB = - -# library for loading shared objects (defaults to -ldl, should be empty on Windows) -# uncomment to change the default - -# override DYN_LIB = - -# --------------------------------------------------------------------- -# build rules and dependencies -# do not edit this section - -include Makefile.package.settings -include Makefile.package - -EXTRA_INC = $(LMP_INC) $(PKG_INC) $(MPI_INC) $(FFT_INC) $(JPG_INC) $(PKG_SYSINC) -EXTRA_PATH = $(PKG_PATH) $(MPI_PATH) $(FFT_PATH) $(JPG_PATH) $(PKG_SYSPATH) -EXTRA_LIB = $(PKG_LIB) $(MPI_LIB) $(FFT_LIB) $(JPG_LIB) $(PKG_SYSLIB) $(DYN_LIB) -EXTRA_CPP_DEPENDS = $(PKG_CPP_DEPENDS) -EXTRA_LINK_DEPENDS = $(PKG_LINK_DEPENDS) - -# Path to src files - -vpath %.cpp .. -vpath %.h .. - -# Link target - -$(EXE): main.o $(LMPLIB) $(EXTRA_LINK_DEPENDS) - $(LINK) $(LINKFLAGS) main.o $(EXTRA_PATH) $(LMPLINK) $(EXTRA_LIB) $(LIB) -o $@ - $(SIZE) $@ - -# Library targets - -$(ARLIB): $(OBJ) $(EXTRA_LINK_DEPENDS) - @rm -f ../$(ARLIB) - $(ARCHIVE) $(ARFLAGS) ../$(ARLIB) $(OBJ) - @rm -f $(ARLIB) - @ln -s ../$(ARLIB) $(ARLIB) - -$(SHLIB): $(OBJ) $(EXTRA_LINK_DEPENDS) - $(CC) $(CCFLAGS) $(SHFLAGS) $(SHLIBFLAGS) $(EXTRA_PATH) -o ../$(SHLIB) \ - $(OBJ) $(EXTRA_LIB) $(LIB) - @rm -f $(SHLIB) - @ln -s ../$(SHLIB) $(SHLIB) - -# Compilation rules - -%.o:%.cpp - $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) -c $< - -# Individual dependencies - -depend : fastdep.exe $(SRC) - @./fastdep.exe $(EXTRA_INC) -- $^ > .depend || exit 1 - -fastdep.exe: ../DEPEND/fastdep.c - gcc -O -o $@ $< - -sinclude .depend From 0a89e5bd24e76a70401909bba1ad88a0f087bb91 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Wed, 19 Jan 2022 10:18:25 -0700 Subject: [PATCH 156/193] Remove non-ASCII chars --- src/MAKE/MACHINES/Makefile.crusher_kokkos | 2 +- src/MAKE/MACHINES/Makefile.spock_kokkos | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MAKE/MACHINES/Makefile.crusher_kokkos b/src/MAKE/MACHINES/Makefile.crusher_kokkos index 065c20519f..7dc1447d4e 100644 --- a/src/MAKE/MACHINES/Makefile.crusher_kokkos +++ b/src/MAKE/MACHINES/Makefile.crusher_kokkos @@ -1,4 +1,4 @@ -# crusher_kokkos = KOKKOS/HIP, AMD MI250X GPU and AMD EPYC 7A53 “Optimized 3rd Gen EPYC” CPU, Cray MPICH, hipcc compiler +# crusher_kokkos = KOKKOS/HIP, AMD MI250X GPU and AMD EPYC 7A53 "Optimized 3rd Gen EPYC" CPU, Cray MPICH, hipcc compiler SHELL = /bin/sh diff --git a/src/MAKE/MACHINES/Makefile.spock_kokkos b/src/MAKE/MACHINES/Makefile.spock_kokkos index f1302bf2db..a85ebb3039 100644 --- a/src/MAKE/MACHINES/Makefile.spock_kokkos +++ b/src/MAKE/MACHINES/Makefile.spock_kokkos @@ -1,4 +1,4 @@ -# spock_kokkos = KOKKOS/HIP, AMD MI100 GPU and AMD EPYC 7662 “Rome” CPU, Cray MPICH, hipcc compiler +# spock_kokkos = KOKKOS/HIP, AMD MI100 GPU and AMD EPYC 7662 "Rome" CPU, Cray MPICH, hipcc compiler SHELL = /bin/sh From 0a8cbcef2bf7f3261698b273e10868beea9c16cc Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Wed, 19 Jan 2022 10:19:50 -0700 Subject: [PATCH 157/193] Add -DNDEBUG to Kokkos Makefiles --- src/MAKE/MACHINES/Makefile.summit_kokkos | 2 +- src/MAKE/OPTIONS/Makefile.kokkos_cuda_mpi | 2 +- src/MAKE/OPTIONS/Makefile.kokkos_mpi_only | 2 +- src/MAKE/OPTIONS/Makefile.kokkos_omp | 2 +- src/MAKE/OPTIONS/Makefile.kokkos_phi | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/MAKE/MACHINES/Makefile.summit_kokkos b/src/MAKE/MACHINES/Makefile.summit_kokkos index 87f8c75da2..f22b27cc74 100644 --- a/src/MAKE/MACHINES/Makefile.summit_kokkos +++ b/src/MAKE/MACHINES/Makefile.summit_kokkos @@ -9,7 +9,7 @@ SHELL = /bin/sh KOKKOS_ABSOLUTE_PATH = $(shell cd $(KOKKOS_PATH); pwd) CC = $(KOKKOS_ABSOLUTE_PATH)/bin/nvcc_wrapper -CCFLAGS = -g -O3 +CCFLAGS = -g -O3 -DNDEBUG SHFLAGS = -fPIC DEPFLAGS = -M diff --git a/src/MAKE/OPTIONS/Makefile.kokkos_cuda_mpi b/src/MAKE/OPTIONS/Makefile.kokkos_cuda_mpi index cb3ef0e442..42a8236c7c 100644 --- a/src/MAKE/OPTIONS/Makefile.kokkos_cuda_mpi +++ b/src/MAKE/OPTIONS/Makefile.kokkos_cuda_mpi @@ -10,7 +10,7 @@ KOKKOS_ABSOLUTE_PATH = $(shell cd $(KOKKOS_PATH); pwd) export MPICH_CXX = $(KOKKOS_ABSOLUTE_PATH)/bin/nvcc_wrapper export OMPI_CXX = $(KOKKOS_ABSOLUTE_PATH)/bin/nvcc_wrapper CC = mpicxx -CCFLAGS = -g -O3 +CCFLAGS = -g -O3 -DNDEBUG SHFLAGS = -fPIC DEPFLAGS = -M diff --git a/src/MAKE/OPTIONS/Makefile.kokkos_mpi_only b/src/MAKE/OPTIONS/Makefile.kokkos_mpi_only index 6d5e8d779e..0adb53eef0 100644 --- a/src/MAKE/OPTIONS/Makefile.kokkos_mpi_only +++ b/src/MAKE/OPTIONS/Makefile.kokkos_mpi_only @@ -7,7 +7,7 @@ SHELL = /bin/sh # specify flags and libraries needed for your compiler CC = mpicxx -CCFLAGS = -g -O3 +CCFLAGS = -g -O3 -DNDEBUG SHFLAGS = -fPIC DEPFLAGS = -M diff --git a/src/MAKE/OPTIONS/Makefile.kokkos_omp b/src/MAKE/OPTIONS/Makefile.kokkos_omp index e505da8ae2..82144652dd 100644 --- a/src/MAKE/OPTIONS/Makefile.kokkos_omp +++ b/src/MAKE/OPTIONS/Makefile.kokkos_omp @@ -7,7 +7,7 @@ SHELL = /bin/sh # specify flags and libraries needed for your compiler CC = mpicxx -CCFLAGS = -g -O3 +CCFLAGS = -g -O3 -DNDEBUG SHFLAGS = -fPIC DEPFLAGS = -M diff --git a/src/MAKE/OPTIONS/Makefile.kokkos_phi b/src/MAKE/OPTIONS/Makefile.kokkos_phi index b825ad691a..9d5691251c 100644 --- a/src/MAKE/OPTIONS/Makefile.kokkos_phi +++ b/src/MAKE/OPTIONS/Makefile.kokkos_phi @@ -7,7 +7,7 @@ SHELL = /bin/sh # specify flags and libraries needed for your compiler CC = mpicxx -CCFLAGS = -g -O3 +CCFLAGS = -g -O3 -DNDEBUG SHFLAGS = -fPIC DEPFLAGS = -M From 6e8d9cb532b7ac44fbb9cb461dcc884f136daba4 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Wed, 19 Jan 2022 10:27:02 -0700 Subject: [PATCH 158/193] Port bugfix in Kokkos --- lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.cpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.cpp index 6964d5b41b..418aa14c68 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.cpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.cpp @@ -694,7 +694,7 @@ std::pair CudaInternal::resize_team_scratch_space( int current_team_scratch = 0; int zero = 0; int one = 1; - while (m_team_scratch_pool[current_team_scratch].compare_exchange_weak( + while (!m_team_scratch_pool[current_team_scratch].compare_exchange_weak( zero, one, std::memory_order_release, std::memory_order_relaxed)) { current_team_scratch = (current_team_scratch + 1) % m_n_team_scratch; } From 0b24c5b498a882a3fcc1aec450f1103f73d2693c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 20 Jan 2022 16:04:07 -0500 Subject: [PATCH 159/193] workaround for segfaults due to NULL pointer dereference with hybrid styles --- src/INTEL/npair_intel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/INTEL/npair_intel.cpp b/src/INTEL/npair_intel.cpp index 395e50006c..76a56ef90f 100644 --- a/src/INTEL/npair_intel.cpp +++ b/src/INTEL/npair_intel.cpp @@ -367,7 +367,7 @@ void NPairIntel::bin_newton(const int offload, NeighList *list, ty[u] = x[j].y; tz[u] = x[j].z; tjtype[u] = x[j].w; - if (THREE) ttag[u] = tag[j]; + if (THREE && ttag) ttag[u] = tag[j]; } if (FULL == 0 && TRI != 1) { @@ -515,7 +515,7 @@ void NPairIntel::bin_newton(const int offload, NeighList *list, } if (THREE) { - const tagint jtag = ttag[u]; + const tagint jtag = ttag ? ttag[u] : tag[j]; int flist = 0; if (itag > jtag) { if (((itag+jtag) & 1) == 0) flist = 1; From dbe267cb88ace551797d0258d24cdc183d998606 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 20 Jan 2022 16:04:26 -0500 Subject: [PATCH 160/193] join lines, whitespace --- src/INTEL/fix_intel.cpp | 45 +++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/src/INTEL/fix_intel.cpp b/src/INTEL/fix_intel.cpp index 519181be52..2fe6b94515 100644 --- a/src/INTEL/fix_intel.cpp +++ b/src/INTEL/fix_intel.cpp @@ -303,8 +303,7 @@ void FixIntel::init() if (force->pair_match("^hybrid", 0) != nullptr) { _pair_hybrid_flag = 1; if (force->newton_pair != 0 && force->pair->no_virial_fdotr_compute) - error->all(FLERR, - "Intel package requires fdotr virial with newton on."); + error->all(FLERR,"Intel package requires fdotr virial with newton on."); } else _pair_hybrid_flag = 0; @@ -325,8 +324,7 @@ void FixIntel::init() _pair_hybrid_zero = 0; if (force->newton_pair == 0) _pair_hybrid_flag = 0; if (nstyles > 1) - error->all(FLERR, - "Currently, cannot offload more than one intel style with hybrid."); + error->all(FLERR,"Currently, cannot offload more than one intel style with hybrid."); } #endif @@ -356,15 +354,12 @@ void FixIntel::init() void FixIntel::setup(int vflag) { if (neighbor->style != Neighbor::BIN) - error->all(FLERR, - "Currently, neighbor style BIN must be used with Intel package."); + error->all(FLERR,"Currently, neighbor style BIN must be used with Intel package."); if (vflag > 3) - error->all(FLERR, - "Cannot currently get per-atom virials with Intel package."); + error->all(FLERR,"Cannot currently get per-atom virials with Intel package."); #ifdef _LMP_INTEL_OFFLOAD if (neighbor->exclude_setting() != 0) - error->all(FLERR, - "Currently, cannot use neigh_modify exclude with Intel package offload."); + error->all(FLERR,"Currently, cannot use neigh_modify exclude with Intel package offload."); post_force(vflag); #endif } @@ -425,14 +420,14 @@ void FixIntel::pair_init_check(const bool cdmessage) if (_offload_balance != 0.0 && comm->me == 0) { #ifndef __INTEL_COMPILER_BUILD_DATE - error->warning(FLERR, "Unknown Intel Compiler Version\n"); + error->warning(FLERR,"Unknown Intel Compiler Version\n"); #else if (__INTEL_COMPILER_BUILD_DATE != 20131008 && __INTEL_COMPILER_BUILD_DATE < 20141023) - error->warning(FLERR, "Unsupported Intel Compiler."); + error->warning(FLERR,"Unsupported Intel Compiler."); #endif #if !defined(__INTEL_COMPILER) - error->warning(FLERR, "Unsupported Intel Compiler."); + error->warning(FLERR,"Unsupported Intel Compiler."); #endif } @@ -505,8 +500,7 @@ void FixIntel::bond_init_check() { if ((_offload_balance != 0.0) && (atom->molecular != Atom::ATOMIC) && (force->newton_pair != force->newton_bond)) - error->all(FLERR, - "INTEL package requires same setting for newton bond and non-bond."); + error->all(FLERR,"INTEL package requires same setting for newton bond and non-bond."); int intel_pair = 0; if (force->pair_match("/intel$", 0) != nullptr) @@ -517,7 +511,7 @@ void FixIntel::bond_init_check() } if (intel_pair == 0) - error->all(FLERR, "Intel styles for bond/angle/dihedral/improper " + error->all(FLERR,"Intel styles for bond/angle/dihedral/improper " "require intel pair style."); } @@ -534,7 +528,7 @@ void FixIntel::kspace_init_check() } if (intel_pair == 0) - error->all(FLERR, "Intel styles for kspace require intel pair style."); + error->all(FLERR,"Intel styles for kspace require intel pair style."); } /* ---------------------------------------------------------------------- */ @@ -551,7 +545,7 @@ void FixIntel::check_neighbor_intel() _offload_noghost = 0; } if (neighbor->requests[i]->skip && _offload_balance != 0.0) - error->all(FLERR, "Cannot yet use hybrid styles with Intel offload."); + error->all(FLERR,"Cannot yet use hybrid styles with Intel offload."); // avoid flagging a neighbor list as both INTEL and OPENMP if (neighbor->requests[i]->intel) @@ -786,8 +780,7 @@ void FixIntel::add_oresults(const ft * _noalias const f_in, if (f_in[1].w == 1) error->all(FLERR,"Bad matrix inversion in mldivide3"); else - error->all(FLERR, - "Sphere particles not yet supported for gayberne/intel"); + error->all(FLERR,"Sphere particles not yet supported for gayberne/intel"); } } @@ -926,7 +919,7 @@ void FixIntel::add_off_results(const ft * _noalias const f_in, int nlocal = atom->nlocal; if (neighbor->ago == 0) { if (_off_overflow_flag[LMP_OVERFLOW]) - error->one(FLERR, "Neighbor list overflow, boost neigh_modify one"); + error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); _offload_nlocal = _off_overflow_flag[LMP_LOCAL_MAX] + 1; _offload_min_ghost = _off_overflow_flag[LMP_GHOST_MIN]; _offload_nghost = _off_overflow_flag[LMP_GHOST_MAX] + 1 - @@ -938,7 +931,7 @@ void FixIntel::add_off_results(const ft * _noalias const f_in, if (atom->torque) if (f_in[1].w < 0.0) - error->all(FLERR, "Bad matrix inversion in mldivide3"); + error->all(FLERR,"Bad matrix inversion in mldivide3"); add_results(f_in, ev_global, _off_results_eatom, _off_results_vatom, 1); // Load balance? @@ -1043,8 +1036,7 @@ void FixIntel::output_timing_data() { timers[TIME_OFFLOAD_PAIR]; double tt = MAX(ht,ct); if (timers[TIME_OFFLOAD_LATENCY] / tt > 0.07 && _separate_coi == 0) - error->warning(FLERR, - "Leaving a core free can improve performance for offload"); + error->warning(FLERR,"Leaving a core free can improve performance for offload"); } fprintf(_tscreen, "------------------------------------------------\n"); } @@ -1109,7 +1101,7 @@ void FixIntel::set_offload_affinity() int ppn = get_ppn(node_rank); if (ppn % _ncops != 0) - error->all(FLERR, "MPI tasks per node must be multiple of offload_cards"); + error->all(FLERR,"MPI tasks per node must be multiple of offload_cards"); ppn = ppn / _ncops; _cop = node_rank / ppn; node_rank = node_rank % ppn; @@ -1214,8 +1206,7 @@ int FixIntel::set_host_affinity(const int nomp) int subscription = nthreads * ppn; if (subscription > ncores) { if (rank == 0) - error->warning(FLERR, - "More MPI tasks/OpenMP threads than available cores"); + error->warning(FLERR,"More MPI tasks/OpenMP threads than available cores"); return 0; } if (subscription == ncores) From 49dca516ea74d8d675f5fb534f790e1550485a57 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 20 Jan 2022 16:48:44 -0500 Subject: [PATCH 161/193] simplify API of Force::store_style() --- src/angle_hybrid.cpp | 2 +- src/bond_hybrid.cpp | 2 +- src/dihedral_hybrid.cpp | 2 +- src/force.cpp | 16 ++++++++-------- src/force.h | 2 +- src/improper_hybrid.cpp | 2 +- src/pair_hybrid.cpp | 2 +- src/pair_hybrid_scaled.cpp | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/angle_hybrid.cpp b/src/angle_hybrid.cpp index 12bc9aa97a..41f46ae878 100644 --- a/src/angle_hybrid.cpp +++ b/src/angle_hybrid.cpp @@ -240,7 +240,7 @@ void AngleHybrid::settings(int narg, char **arg) error->all(FLERR, "Angle style hybrid cannot have none as an argument"); styles[nstyles] = force->new_angle(arg[i], 1, dummy); - force->store_style(keywords[nstyles], arg[i], 0); + keywords[nstyles] = force->store_style(arg[i], 0); istyle = i; if (strcmp(arg[i], "table") == 0) i++; diff --git a/src/bond_hybrid.cpp b/src/bond_hybrid.cpp index dad1010a1e..3139d9ecd8 100644 --- a/src/bond_hybrid.cpp +++ b/src/bond_hybrid.cpp @@ -242,7 +242,7 @@ void BondHybrid::settings(int narg, char **arg) if (strncmp(arg[i], "quartic", 7) == 0) has_quartic = m; styles[nstyles] = force->new_bond(arg[i], 1, dummy); - force->store_style(keywords[nstyles], arg[i], 0); + keywords[nstyles] = force->store_style(arg[i], 0); istyle = i; if (strcmp(arg[i], "table") == 0) i++; diff --git a/src/dihedral_hybrid.cpp b/src/dihedral_hybrid.cpp index 24a18e6783..0f72f999c9 100644 --- a/src/dihedral_hybrid.cpp +++ b/src/dihedral_hybrid.cpp @@ -241,7 +241,7 @@ void DihedralHybrid::settings(int narg, char **arg) error->all(FLERR, "Dihedral style hybrid cannot have none as an argument"); styles[nstyles] = force->new_dihedral(arg[i], 1, dummy); - force->store_style(keywords[nstyles], arg[i], 0); + keywords[nstyles] = force->store_style(arg[i], 0); istyle = i; if (strcmp(arg[i], "table") == 0) i++; diff --git a/src/force.cpp b/src/force.cpp index 6b7e9033ca..928b95ee78 100644 --- a/src/force.cpp +++ b/src/force.cpp @@ -229,7 +229,7 @@ void Force::create_pair(const std::string &style, int trysuffix) int sflag; pair = new_pair(style,trysuffix,sflag); - store_style(pair_style,style,sflag); + pair_style = store_style(style,sflag); } /* ---------------------------------------------------------------------- @@ -350,7 +350,7 @@ void Force::create_bond(const std::string &style, int trysuffix) int sflag; bond = new_bond(style,trysuffix,sflag); - store_style(bond_style,style,sflag); + bond_style = store_style(style,sflag); } /* ---------------------------------------------------------------------- @@ -427,7 +427,7 @@ void Force::create_angle(const std::string &style, int trysuffix) int sflag; angle = new_angle(style,trysuffix,sflag); - store_style(angle_style,style,sflag); + angle_style = store_style(style,sflag); } /* ---------------------------------------------------------------------- @@ -504,7 +504,7 @@ void Force::create_dihedral(const std::string &style, int trysuffix) int sflag; dihedral = new_dihedral(style,trysuffix,sflag); - store_style(dihedral_style,style,sflag); + dihedral_style = store_style(style,sflag); } /* ---------------------------------------------------------------------- @@ -581,7 +581,7 @@ void Force::create_improper(const std::string &style, int trysuffix) int sflag; improper = new_improper(style,trysuffix,sflag); - store_style(improper_style,style,sflag); + improper_style = store_style(style,sflag); } /* ---------------------------------------------------------------------- @@ -658,7 +658,7 @@ void Force::create_kspace(const std::string &style, int trysuffix) int sflag; kspace = new_kspace(style,trysuffix,sflag); - store_style(kspace_style,style,sflag); + kspace_style = store_style(style,sflag); } /* ---------------------------------------------------------------------- @@ -729,14 +729,14 @@ KSpace *Force::kspace_match(const std::string &word, int exact) if sflag = 1/2/3, append suffix or suffix2 or suffixp to style ------------------------------------------------------------------------- */ -void Force::store_style(char *&str, const std::string &style, int sflag) +char *Force::store_style(const std::string &style, int sflag) { std::string estyle = style; if (sflag == 1) estyle += std::string("/") + lmp->suffix; else if (sflag == 2) estyle += std::string("/") + lmp->suffix2; else if (sflag == 3) estyle += std::string("/") + lmp->suffixp; - str = utils::strdup(estyle); + return utils::strdup(estyle); } /* ---------------------------------------------------------------------- diff --git a/src/force.h b/src/force.h index 09e13c7bd1..cc9ad06282 100644 --- a/src/force.h +++ b/src/force.h @@ -146,7 +146,7 @@ class Force : protected Pointers { KSpace *new_kspace(const std::string &, int, int &); KSpace *kspace_match(const std::string &, int); - void store_style(char *&, const std::string &, int); + char *store_style(const std::string &, int); void set_special(int, char **); double memory_usage(); diff --git a/src/improper_hybrid.cpp b/src/improper_hybrid.cpp index d3a9403a6b..0354f8e92e 100644 --- a/src/improper_hybrid.cpp +++ b/src/improper_hybrid.cpp @@ -241,7 +241,7 @@ void ImproperHybrid::settings(int narg, char **arg) error->all(FLERR, "Improper style hybrid cannot have none as an argument"); styles[nstyles] = force->new_improper(arg[i], 1, dummy); - force->store_style(keywords[nstyles], arg[i], 0); + keywords[nstyles] = force->store_style(arg[i], 0); istyle = i; if (strcmp(arg[i], "table") == 0) i++; diff --git a/src/pair_hybrid.cpp b/src/pair_hybrid.cpp index e962e02c9e..8c0326d7b8 100644 --- a/src/pair_hybrid.cpp +++ b/src/pair_hybrid.cpp @@ -322,7 +322,7 @@ void PairHybrid::settings(int narg, char **arg) error->all(FLERR,"Pair style hybrid cannot have none as an argument"); styles[nstyles] = force->new_pair(arg[iarg],1,dummy); - force->store_style(keywords[nstyles],arg[iarg],0); + keywords[nstyles] = force->store_style(arg[iarg],0); special_lj[nstyles] = special_coul[nstyles] = nullptr; compute_tally[nstyles] = 1; diff --git a/src/pair_hybrid_scaled.cpp b/src/pair_hybrid_scaled.cpp index 0a4be44be0..68a6199e19 100644 --- a/src/pair_hybrid_scaled.cpp +++ b/src/pair_hybrid_scaled.cpp @@ -328,7 +328,7 @@ void PairHybridScaled::settings(int narg, char **arg) error->all(FLERR, "Pair style hybrid/scaled cannot have none as an argument"); styles[nstyles] = force->new_pair(arg[iarg], 1, dummy); - force->store_style(keywords[nstyles], arg[iarg], 0); + keywords[nstyles] = force->store_style(arg[iarg], 0); special_lj[nstyles] = special_coul[nstyles] = nullptr; compute_tally[nstyles] = 1; From 4104353d7a2971cf9cde79e20341b26a9a1cbcc6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 20 Jan 2022 16:55:59 -0500 Subject: [PATCH 162/193] plug memory leak --- src/read_data.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/read_data.cpp b/src/read_data.cpp index 89b3ecadec..dda418b8a2 100644 --- a/src/read_data.cpp +++ b/src/read_data.cpp @@ -903,23 +903,28 @@ void ReadData::command(int narg, char **arg) // restore old styles, when reading with nocoeff flag given if (coeffflag == 0) { - if (force->pair) delete force->pair; + delete force->pair; + delete[] force->pair_style; force->pair = saved_pair; force->pair_style = saved_pair_style; - if (force->bond) delete force->bond; + delete force->bond; + delete[] force->bond_style; force->bond = saved_bond; force->bond_style = saved_bond_style; - if (force->angle) delete force->angle; + delete force->angle; + delete[] force->angle_style; force->angle = saved_angle; force->angle_style = saved_angle_style; - if (force->dihedral) delete force->dihedral; + delete force->dihedral; + delete[] force->dihedral_style; force->dihedral = saved_dihedral; force->dihedral_style = saved_dihedral_style; - if (force->improper) delete force->improper; + delete force->improper; + delete[] force->improper_style; force->improper = saved_improper; force->improper_style = saved_improper_style; From e73158bd7ee77025117ab54b0c79f7043f205ab7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 20 Jan 2022 16:56:12 -0500 Subject: [PATCH 163/193] whitespace/formatting --- src/force.cpp | 28 ++++++++++++++-------------- src/pair_hybrid.cpp | 36 ++++++++++++++++++------------------ 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/force.cpp b/src/force.cpp index 928b95ee78..333a6e4715 100644 --- a/src/force.cpp +++ b/src/force.cpp @@ -133,14 +133,14 @@ void _noopt Force::create_factories() Force::~Force() { - delete [] pair_style; - delete [] bond_style; - delete [] angle_style; - delete [] dihedral_style; - delete [] improper_style; - delete [] kspace_style; + delete[] pair_style; + delete[] bond_style; + delete[] angle_style; + delete[] dihedral_style; + delete[] improper_style; + delete[] kspace_style; - delete [] pair_restart; + delete[] pair_restart; if (pair) delete pair; if (bond) delete bond; @@ -220,9 +220,9 @@ void Force::setup() void Force::create_pair(const std::string &style, int trysuffix) { - delete [] pair_style; + delete[] pair_style; if (pair) delete pair; - if (pair_restart) delete [] pair_restart; + if (pair_restart) delete[] pair_restart; pair_style = nullptr; pair = nullptr; pair_restart = nullptr; @@ -345,7 +345,7 @@ char *Force::pair_match_ptr(Pair *ptr) void Force::create_bond(const std::string &style, int trysuffix) { - delete [] bond_style; + delete[] bond_style; if (bond) delete bond; int sflag; @@ -422,7 +422,7 @@ Bond *Force::bond_match(const std::string &style) void Force::create_angle(const std::string &style, int trysuffix) { - delete [] angle_style; + delete[] angle_style; if (angle) delete angle; int sflag; @@ -499,7 +499,7 @@ Angle *Force::angle_match(const std::string &style) void Force::create_dihedral(const std::string &style, int trysuffix) { - delete [] dihedral_style; + delete[] dihedral_style; if (dihedral) delete dihedral; int sflag; @@ -576,7 +576,7 @@ Dihedral *Force::dihedral_match(const std::string &style) void Force::create_improper(const std::string &style, int trysuffix) { - delete [] improper_style; + delete[] improper_style; if (improper) delete improper; int sflag; @@ -653,7 +653,7 @@ Improper *Force::improper_match(const std::string &style) void Force::create_kspace(const std::string &style, int trysuffix) { - delete [] kspace_style; + delete[] kspace_style; if (kspace) delete kspace; int sflag; diff --git a/src/pair_hybrid.cpp b/src/pair_hybrid.cpp index 8c0326d7b8..6287fb97db 100644 --- a/src/pair_hybrid.cpp +++ b/src/pair_hybrid.cpp @@ -50,20 +50,20 @@ PairHybrid::~PairHybrid() if (nstyles > 0) { for (int m = 0; m < nstyles; m++) { delete styles[m]; - delete [] keywords[m]; - if (special_lj[m]) delete [] special_lj[m]; - if (special_coul[m]) delete [] special_coul[m]; + delete[] keywords[m]; + if (special_lj[m]) delete[] special_lj[m]; + if (special_coul[m]) delete[] special_coul[m]; } } - delete [] styles; - delete [] keywords; - delete [] multiple; + delete[] styles; + delete[] keywords; + delete[] multiple; - delete [] special_lj; - delete [] special_coul; - delete [] compute_tally; + delete[] special_lj; + delete[] special_coul; + delete[] compute_tally; - delete [] svector; + delete[] svector; if (allocated) { memory->destroy(setflag); @@ -187,7 +187,7 @@ void PairHybrid::compute(int eflag, int vflag) } - delete [] saved_special; + delete[] saved_special; if (vflag_fdotr) virial_fdotr_compute(); } @@ -274,9 +274,9 @@ void PairHybrid::settings(int narg, char **arg) if (nstyles > 0) { for (int m = 0; m < nstyles; m++) { delete styles[m]; - delete [] keywords[m]; - if (special_lj[m]) delete [] special_lj[m]; - if (special_coul[m]) delete [] special_coul[m]; + delete[] keywords[m]; + if (special_lj[m]) delete[] special_lj[m]; + if (special_coul[m]) delete[] special_coul[m]; } delete[] styles; delete[] keywords; @@ -297,8 +297,8 @@ void PairHybrid::settings(int narg, char **arg) // allocate list of sub-styles as big as possibly needed if no extra args - styles = new Pair*[narg]; - keywords = new char*[narg]; + styles = new Pair *[narg]; + keywords = new char *[narg]; multiple = new int[narg]; special_lj = new double*[narg]; @@ -454,7 +454,7 @@ void PairHybrid::init_svector() single_extra = MAX(single_extra,styles[m]->single_extra); if (single_extra) { - delete [] svector; + delete[] svector; svector = new double[single_extra]; } } @@ -667,7 +667,7 @@ void PairHybrid::init_style() neighbor->requests[i]->iskip = iskip; neighbor->requests[i]->ijskip = ijskip; } else { - delete [] iskip; + delete[] iskip; memory->destroy(ijskip); } } From 9c8431bf87dda3d7b87f5acbfc99f7dc79890225 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 21 Jan 2022 06:55:06 -0500 Subject: [PATCH 164/193] correct calls to memset() --- src/EXTRA-FIX/fix_gle.cpp | 5 ++--- src/EXTRA-PAIR/pair_e3b.cpp | 3 +-- src/EXTRA-PAIR/pair_e3b.h | 1 - src/MOLECULE/fix_cmap.cpp | 2 +- src/REAXFF/fix_acks2_reaxff.cpp | 2 +- src/REAXFF/fix_qeq_reaxff.cpp | 2 +- 6 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/EXTRA-FIX/fix_gle.cpp b/src/EXTRA-FIX/fix_gle.cpp index d7061e199c..acb7b84fe1 100644 --- a/src/EXTRA-FIX/fix_gle.cpp +++ b/src/EXTRA-FIX/fix_gle.cpp @@ -211,6 +211,8 @@ FixGLE::FixGLE(LAMMPS *lmp, int narg, char **arg) : S = new double[ns1sq]; TT = new double[ns1sq]; ST = new double[ns1sq]; + memset(A,0,sizeof(double)*ns1sq); + memset(C,0,sizeof(double)*ns1sq); // start temperature (t ramp) t_start = utils::numeric(FLERR,arg[4],false,lmp); @@ -223,7 +225,6 @@ FixGLE::FixGLE(LAMMPS *lmp, int narg, char **arg) : // LOADING A matrix char *fname = arg[7]; - memset(A, ns1sq, sizeof(double)); if (comm->me == 0) { PotentialFileReader reader(lmp,fname,"fix gle A matrix"); try { @@ -256,14 +257,12 @@ FixGLE::FixGLE(LAMMPS *lmp, int narg, char **arg) : if (fnoneq == 0) { t_target=t_start; const double kT = t_target * force->boltz / force->mvv2e; - memset(C,0,sizeof(double)*ns1sq); for (int i=0; ime == 0) { PotentialFileReader reader(lmp,fname,"fix gle C matrix"); try { diff --git a/src/EXTRA-PAIR/pair_e3b.cpp b/src/EXTRA-PAIR/pair_e3b.cpp index 7e865ac6f8..3af8e754c0 100644 --- a/src/EXTRA-PAIR/pair_e3b.cpp +++ b/src/EXTRA-PAIR/pair_e3b.cpp @@ -99,7 +99,7 @@ void PairE3B::compute(int eflag, int vflag) ev_init(eflag, vflag); //clear sumExp array - memset(sumExp, 0.0, nbytes); + memset(sumExp, 0, sizeof(double)*maxID); evdwl = 0.0; pvector[0] = pvector[1] = pvector[2] = pvector[3] = 0.0; @@ -364,7 +364,6 @@ void PairE3B::allocateE3B() maxID = find_maxID(); if (!natoms) error->all(FLERR, "No atoms found"); memory->create(sumExp, maxID, "pair:sumExp"); - nbytes = sizeof(double) * maxID; } /* ---------------------------------------------------------------------- diff --git a/src/EXTRA-PAIR/pair_e3b.h b/src/EXTRA-PAIR/pair_e3b.h index f6cf916918..1f38c18293 100644 --- a/src/EXTRA-PAIR/pair_e3b.h +++ b/src/EXTRA-PAIR/pair_e3b.h @@ -50,7 +50,6 @@ class PairE3B : public Pair { int **pairO, ***pairH; // pair lists double ***exps, ****del3, ***fpair3, *sumExp; int maxID; //size of global sumExp array - size_t nbytes; //size of sumExp array in bytes int natoms; //to make sure number of atoms is constant virtual void allocate(); diff --git a/src/MOLECULE/fix_cmap.cpp b/src/MOLECULE/fix_cmap.cpp index c6e356e829..34f54ef26c 100644 --- a/src/MOLECULE/fix_cmap.cpp +++ b/src/MOLECULE/fix_cmap.cpp @@ -637,7 +637,7 @@ void FixCMAP::read_grid_map(char *cmapfile) { if (comm->me == 0) { try { - memset(&cmapgrid[0][0][0], 6*CMAPDIM*CMAPDIM, sizeof(double)); + memset(&cmapgrid[0][0][0], 0, 6*CMAPDIM*CMAPDIM*sizeof(double)); PotentialFileReader reader(lmp, cmapfile, "cmap grid"); // there are six maps in this order. diff --git a/src/REAXFF/fix_acks2_reaxff.cpp b/src/REAXFF/fix_acks2_reaxff.cpp index b6789b1b2e..21cce5b55a 100644 --- a/src/REAXFF/fix_acks2_reaxff.cpp +++ b/src/REAXFF/fix_acks2_reaxff.cpp @@ -429,7 +429,7 @@ void FixACKS2ReaxFF::compute_X() double **x = atom->x; int *mask = atom->mask; - memset(X_diag,0.0,atom->nmax*sizeof(double)); + memset(X_diag,0,atom->nmax*sizeof(double)); // fill in the X matrix m_fill = 0; diff --git a/src/REAXFF/fix_qeq_reaxff.cpp b/src/REAXFF/fix_qeq_reaxff.cpp index fa8fa79e00..08a4e21fe5 100644 --- a/src/REAXFF/fix_qeq_reaxff.cpp +++ b/src/REAXFF/fix_qeq_reaxff.cpp @@ -1084,7 +1084,7 @@ void FixQEqReaxFF::vector_add(double* dest, double c, double* v, int k) void FixQEqReaxFF::get_chi_field() { - memset(&chi_field[0],0.0,atom->nmax*sizeof(double)); + memset(&chi_field[0],0,atom->nmax*sizeof(double)); if (!efield) return; const double * const *x = (const double * const *)atom->x; From 67dec40afa7aafccfdb629835e34ad93a58b1b36 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 21 Jan 2022 06:55:20 -0500 Subject: [PATCH 165/193] make certain pointers are initialized --- src/EXTRA-PAIR/pair_harmonic_cut.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EXTRA-PAIR/pair_harmonic_cut.cpp b/src/EXTRA-PAIR/pair_harmonic_cut.cpp index bd0e48efdc..f2e1c422fe 100644 --- a/src/EXTRA-PAIR/pair_harmonic_cut.cpp +++ b/src/EXTRA-PAIR/pair_harmonic_cut.cpp @@ -35,7 +35,7 @@ using namespace MathConst; /* ---------------------------------------------------------------------- */ -PairHarmonicCut::PairHarmonicCut(LAMMPS *lmp) : Pair(lmp) +PairHarmonicCut::PairHarmonicCut(LAMMPS *lmp) : Pair(lmp), k(nullptr), cut(nullptr) { writedata = 1; } From 3a6bd2e698b06efca393294ac2f212527b4acc1a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 21 Jan 2022 10:47:49 -0500 Subject: [PATCH 166/193] update comment about pair_write restrictions --- doc/src/pair_write.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/src/pair_write.rst b/doc/src/pair_write.rst index 1d88137255..b62383cb7b 100644 --- a/doc/src/pair_write.rst +++ b/doc/src/pair_write.rst @@ -76,8 +76,10 @@ must be set before this command can be invoked. Due to how the pairwise force is computed, an inner value > 0.0 must be specified even if the potential has a finite value at r = 0.0. -For EAM potentials, the pair_write command only tabulates the -pairwise portion of the potential, not the embedding portion. +The *pair_write* command can only be used for pairwise additive +interactions for which a `Pair::single()` function can be and has +been implemented. This excludes for example manybody potentials +or TIP4P coulomb styles. Related commands """""""""""""""" From 3311b1344cee3676468ebe06679c6b95c28639cb Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 21 Jan 2022 10:48:35 -0500 Subject: [PATCH 167/193] consolidate pair-wise vs pairwise spelling --- doc/src/Developer_org.rst | 2 +- doc/src/Errors_warnings.rst | 2 +- doc/src/Run_output.rst | 4 ++-- doc/src/Speed_kokkos.rst | 2 +- doc/src/balance.rst | 2 +- doc/src/compute_pressure_cylinder.rst | 2 +- doc/src/package.rst | 2 +- doc/src/pair_charmm.rst | 2 +- doc/src/pair_dpd.rst | 2 +- doc/src/pair_python.rst | 2 +- doc/src/pair_style.rst | 4 ++-- doc/src/pair_sw.rst | 2 +- doc/src/run_style.rst | 2 +- 13 files changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/src/Developer_org.rst b/doc/src/Developer_org.rst index b5acdf5631..ce36d9a590 100644 --- a/doc/src/Developer_org.rst +++ b/doc/src/Developer_org.rst @@ -225,7 +225,7 @@ follows: commands in an input script. - The Force class computes various forces between atoms. The Pair - parent class is for non-bonded or pair-wise forces, which in LAMMPS + parent class is for non-bonded or pairwise forces, which in LAMMPS also includes many-body forces such as the Tersoff 3-body potential if those are computed by walking pairwise neighbor lists. The Bond, Angle, Dihedral, Improper parent classes are styles for bonded diff --git a/doc/src/Errors_warnings.rst b/doc/src/Errors_warnings.rst index d7a97c1507..2d588a1b77 100644 --- a/doc/src/Errors_warnings.rst +++ b/doc/src/Errors_warnings.rst @@ -416,7 +416,7 @@ This will most likely cause errors in kinetic fluctuations. not defined for the specified atom style. *Molecule has bond topology but no special bond settings* - This means the bonded atoms will not be excluded in pair-wise + This means the bonded atoms will not be excluded in pairwise interactions. *Molecule template for create_atoms has multiple molecules* diff --git a/doc/src/Run_output.rst b/doc/src/Run_output.rst index 8adfd4b293..a988be94ad 100644 --- a/doc/src/Run_output.rst +++ b/doc/src/Run_output.rst @@ -106,7 +106,7 @@ individual ranks. Here is an example output for this section: ---------- The third section above lists the number of owned atoms (Nlocal), -ghost atoms (Nghost), and pair-wise neighbors stored per processor. +ghost atoms (Nghost), and pairwise neighbors stored per processor. The max and min values give the spread of these values across processors with a 10-bin histogram showing the distribution. The total number of histogram counts is equal to the number of processors. @@ -114,7 +114,7 @@ number of histogram counts is equal to the number of processors. ---------- The last section gives aggregate statistics (across all processors) -for pair-wise neighbors and special neighbors that LAMMPS keeps track +for pairwise neighbors and special neighbors that LAMMPS keeps track of (see the :doc:`special_bonds ` command). The number of times neighbor lists were rebuilt is tallied, as is the number of potentially *dangerous* rebuilds. If atom movement triggered neighbor diff --git a/doc/src/Speed_kokkos.rst b/doc/src/Speed_kokkos.rst index 14c2ec680e..8b9b2e99af 100644 --- a/doc/src/Speed_kokkos.rst +++ b/doc/src/Speed_kokkos.rst @@ -214,7 +214,7 @@ threads/task as Nt. The product of these two values should be N, i.e. The default for the :doc:`package kokkos ` command when running on KNL is to use "half" neighbor lists and set the Newton flag to "on" for both pairwise and bonded interactions. This will typically - be best for many-body potentials. For simpler pair-wise potentials, it + be best for many-body potentials. For simpler pairwise potentials, it may be faster to use a "full" neighbor list with Newton flag to "off". Use the "-pk kokkos" :doc:`command-line switch ` to change the default :doc:`package kokkos ` options. See its page for diff --git a/doc/src/balance.rst b/doc/src/balance.rst index 5063a502bb..1d24e467d8 100644 --- a/doc/src/balance.rst +++ b/doc/src/balance.rst @@ -383,7 +383,7 @@ multiple groups, its weight is the product of the weight factors. This weight style is useful in combination with pair style :doc:`hybrid `, e.g. when combining a more costly many-body -potential with a fast pair-wise potential. It is also useful when +potential with a fast pairwise potential. It is also useful when using :doc:`run_style respa ` where some portions of the system have many bonded interactions and others none. It assumes that the computational cost for each group remains constant over time. diff --git a/doc/src/compute_pressure_cylinder.rst b/doc/src/compute_pressure_cylinder.rst index a008254540..9913ef159b 100644 --- a/doc/src/compute_pressure_cylinder.rst +++ b/doc/src/compute_pressure_cylinder.rst @@ -61,7 +61,7 @@ Restrictions This compute currently calculates the pressure tensor contributions for pair styles only (i.e. no bond, angle, dihedral, etc. contributions and in the presence of bonded interactions, the result will be incorrect -due to exclusions for special bonds) and requires pair-wise force +due to exclusions for special bonds) and requires pairwise force calculations not available for most many-body pair styles. K-space calculations are also excluded. Note that this pressure compute outputs the configurational terms only; the kinetic contribution is not included diff --git a/doc/src/package.rst b/doc/src/package.rst index 2cf772ea5a..437601dc60 100644 --- a/doc/src/package.rst +++ b/doc/src/package.rst @@ -460,7 +460,7 @@ using *neigh/thread* *on*, a full neighbor list must also be used. Using is turned on by default only when there are 16K atoms or less owned by an MPI rank and when using a full neighbor list. Not all KOKKOS-enabled potentials support this keyword yet, and only thread over atoms. Many -simple pair-wise potentials such as Lennard-Jones do support threading +simple pairwise potentials such as Lennard-Jones do support threading over both atoms and neighbors. The *newton* keyword sets the Newton flags for pairwise and bonded diff --git a/doc/src/pair_charmm.rst b/doc/src/pair_charmm.rst index d45ef58060..e1469ae323 100644 --- a/doc/src/pair_charmm.rst +++ b/doc/src/pair_charmm.rst @@ -119,7 +119,7 @@ name are the older, original LAMMPS implementations. They compute the LJ and Coulombic interactions with an energy switching function (esw, shown in the formula below as S(r)), which ramps the energy smoothly to zero between the inner and outer cutoff. This can cause -irregularities in pair-wise forces (due to the discontinuous second +irregularities in pairwise forces (due to the discontinuous second derivative of energy at the boundaries of the switching region), which in some cases can result in detectable artifacts in an MD simulation. diff --git a/doc/src/pair_dpd.rst b/doc/src/pair_dpd.rst index 8a8b35e50a..8c61c789a6 100644 --- a/doc/src/pair_dpd.rst +++ b/doc/src/pair_dpd.rst @@ -50,7 +50,7 @@ Style *dpd* computes a force field for dissipative particle dynamics Style *dpd/tstat* invokes a DPD thermostat on pairwise interactions, which is equivalent to the non-conservative portion of the DPD force -field. This pair-wise thermostat can be used in conjunction with any +field. This pairwise thermostat can be used in conjunction with any :doc:`pair style `, and in leiu of per-particle thermostats like :doc:`fix langevin ` or ensemble thermostats like Nose Hoover as implemented by :doc:`fix nvt `. To use diff --git a/doc/src/pair_python.rst b/doc/src/pair_python.rst index 35e07dbd11..65e1cd1611 100644 --- a/doc/src/pair_python.rst +++ b/doc/src/pair_python.rst @@ -164,7 +164,7 @@ Following the *LJCutMelt* example, here are the two functions: .. note:: The evaluation of scripted python code will slow down the - computation pair-wise interactions quite significantly. However, this + computation pairwise interactions quite significantly. However, this can be largely worked around through using the python pair style not for the actual simulation, but to generate tabulated potentials on the fly using the :doc:`pair_write ` command. Please see below diff --git a/doc/src/pair_style.rst b/doc/src/pair_style.rst index f657e29aa3..4f1f1e733f 100644 --- a/doc/src/pair_style.rst +++ b/doc/src/pair_style.rst @@ -154,10 +154,10 @@ accelerated styles exist. * :doc:`coul/wolf/cs ` - Coulomb via Wolf potential with core/shell adjustments * :doc:`dpd ` - dissipative particle dynamics (DPD) * :doc:`dpd/ext ` - generalized force field for DPD -* :doc:`dpd/ext/tstat ` - pair-wise DPD thermostatting with generalized force field +* :doc:`dpd/ext/tstat ` - pairwise DPD thermostatting with generalized force field * :doc:`dpd/fdt ` - DPD for constant temperature and pressure * :doc:`dpd/fdt/energy ` - DPD for constant energy and enthalpy -* :doc:`dpd/tstat ` - pair-wise DPD thermostatting +* :doc:`dpd/tstat ` - pairwise DPD thermostatting * :doc:`dsmc ` - Direct Simulation Monte Carlo (DSMC) * :doc:`e3b ` - Explicit-three body (E3B) water model * :doc:`drip ` - Dihedral-angle-corrected registry-dependent interlayer potential (DRIP) diff --git a/doc/src/pair_sw.rst b/doc/src/pair_sw.rst index d71999b2d4..d87da43b2c 100644 --- a/doc/src/pair_sw.rst +++ b/doc/src/pair_sw.rst @@ -202,7 +202,7 @@ elements are the same. Thus the two-body parameters for Si interacting with C, comes from the SiCC entry. The three-body parameters can in principle be specific to the three elements of the configuration. In the literature, however, the three-body parameters -are usually defined by simple formulas involving two sets of pair-wise +are usually defined by simple formulas involving two sets of pairwise parameters, corresponding to the ij and ik pairs, where i is the center atom. The user must ensure that the correct combining rule is used to calculate the values of the three-body parameters for diff --git a/doc/src/run_style.rst b/doc/src/run_style.rst index b4d1c22113..fd63c82b90 100644 --- a/doc/src/run_style.rst +++ b/doc/src/run_style.rst @@ -89,7 +89,7 @@ in its 3d FFTs. In this scenario, splitting your P total processors into 2 subsets of processors, P1 in the first partition and P2 in the second partition, can enable your simulation to run faster. This is because the long-range forces in PPPM can be calculated at the same -time as pair-wise and bonded forces are being calculated, and the FFTs +time as pairwise and bonded forces are being calculated, and the FFTs can actually speed up when running on fewer processors. To use this style, you must define 2 partitions where P1 is a multiple From 75d20c40ed4e2c03d5f675f9c201f21688532247 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 21 Jan 2022 11:26:26 -0500 Subject: [PATCH 168/193] remove threebody tag caching altogether since it is not reliable --- src/INTEL/npair_intel.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/INTEL/npair_intel.cpp b/src/INTEL/npair_intel.cpp index 76a56ef90f..9578de9965 100644 --- a/src/INTEL/npair_intel.cpp +++ b/src/INTEL/npair_intel.cpp @@ -310,7 +310,6 @@ void NPairIntel::bin_newton(const int offload, NeighList *list, flt_t * _noalias const tz = ncachez + toffs; int * _noalias const tj = ncachej + toffs; int * _noalias const tjtype = ncachejtype + toffs; - tagint * _noalias const ttag = ncachetag + toffs; flt_t * _noalias itx; flt_t * _noalias ity; @@ -367,7 +366,6 @@ void NPairIntel::bin_newton(const int offload, NeighList *list, ty[u] = x[j].y; tz[u] = x[j].z; tjtype[u] = x[j].w; - if (THREE && ttag) ttag[u] = tag[j]; } if (FULL == 0 && TRI != 1) { @@ -515,7 +513,7 @@ void NPairIntel::bin_newton(const int offload, NeighList *list, } if (THREE) { - const tagint jtag = ttag ? ttag[u] : tag[j]; + const tagint jtag = tag[j]; int flist = 0; if (itag > jtag) { if (((itag+jtag) & 1) == 0) flist = 1; From 57def1a2d5497c67cc2722437b8f7fc411b07191 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 21 Jan 2022 11:26:55 -0500 Subject: [PATCH 169/193] output reformatting and refactoring --- src/INTEL/fix_intel.cpp | 41 +++++++++++++++++++------------------ src/INTEL/npair_intel.cpp | 4 ++-- src/INTEL/pair_sw_intel.cpp | 3 +-- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/INTEL/fix_intel.cpp b/src/INTEL/fix_intel.cpp index 2fe6b94515..97d4f21788 100644 --- a/src/INTEL/fix_intel.cpp +++ b/src/INTEL/fix_intel.cpp @@ -469,27 +469,28 @@ void FixIntel::pair_init_check(const bool cdmessage) #endif if (_print_pkg_info && comm->me == 0) { - if (screen) { - fprintf(screen, - "----------------------------------------------------------\n"); - if (_offload_balance != 0.0) { - fprintf(screen,"Using Intel Coprocessor with %d threads per core, ", - _offload_tpc); - fprintf(screen,"%d threads per task\n",_offload_threads); - } else { - fprintf(screen,"Using Intel Package without Coprocessor.\n"); - } - fprintf(screen,"Precision: %s\n",kmode); - if (cdmessage) { - #ifdef LMP_USE_AVXCD - fprintf(screen,"AVX512 CD Optimizations: Enabled\n"); - #else - fprintf(screen,"AVX512 CD Optimizations: Disabled\n"); - #endif - } - fprintf(screen, - "----------------------------------------------------------\n"); + utils::logmesg(lmp, "----------------------------------------------------------\n"); + if (_offload_balance != 0.0) { + utils::logmesg(lmp,"Using Intel Coprocessor with {} threads per core, " + "{} threads per task\n",_offload_tpc, _offload_threads); + } else { + utils::logmesg(lmp,"Using INTEL Package without Coprocessor.\n"); } + utils::logmesg(lmp,"Compiler: {}\n",platform::compiler_info()); + #ifdef LMP_SIMD_COMPILER + utils::logmesg(lmp,"SIMD compiler directives: Enabled\n"); + #else + utils::logmesg(lmp,"SIMD compiler directives: Disabled\n"); + #endif + utils::logmesg(lmp,"Precision: {}\n",kmode); + if (cdmessage) { + #ifdef LMP_USE_AVXCD + utils::logmesg(lmp,"AVX512 CD Optimizations: Enabled\n"); + #else + utils::logmesg(lmp,"AVX512 CD Optimizations: Disabled\n"); + #endif + } + utils::logmesg(lmp, "----------------------------------------------------------\n"); } _print_pkg_info = 0; } diff --git a/src/INTEL/npair_intel.cpp b/src/INTEL/npair_intel.cpp index 9578de9965..67cd2517e4 100644 --- a/src/INTEL/npair_intel.cpp +++ b/src/INTEL/npair_intel.cpp @@ -31,8 +31,7 @@ using namespace LAMMPS_NS; NPairIntel::NPairIntel(LAMMPS *lmp) : NPair(lmp) { int ifix = modify->find_fix("package_intel"); if (ifix < 0) - error->all(FLERR, - "The 'package intel' command is required for /intel styles"); + error->all(FLERR,"The 'package intel' command is required for /intel styles"); _fix = static_cast(modify->fix[ifix]); #ifdef _LMP_INTEL_OFFLOAD _cop = _fix->coprocessor_number(); @@ -657,6 +656,7 @@ void NPairIntel::bin_newton(const int offload, NeighList *list, ns += n2 - pack_offset - maxnbors; #ifdef LMP_INTEL_3BODY_FAST + int alln = n; n = lane; for (int u = pack_offset; u < alln; u++) { neighptr[n] = neighptr2[u]; diff --git a/src/INTEL/pair_sw_intel.cpp b/src/INTEL/pair_sw_intel.cpp index fd043ae5a1..8743fbe54c 100644 --- a/src/INTEL/pair_sw_intel.cpp +++ b/src/INTEL/pair_sw_intel.cpp @@ -1115,8 +1115,7 @@ void PairSWIntel::init_style() int ifix = modify->find_fix("package_intel"); if (ifix < 0) - error->all(FLERR, - "The 'package intel' command is required for /intel styles"); + error->all(FLERR,"The 'package intel' command is required for /intel styles"); fix = static_cast(modify->fix[ifix]); fix->pair_init_check(true); From 6506be94092341f2a114b54ac73b971c5266dca3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 21 Jan 2022 15:56:58 -0500 Subject: [PATCH 170/193] update programming style --- src/INTEL/intel_buffers.cpp | 13 ++++--------- src/fix_balance.cpp | 16 +++++++++------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/INTEL/intel_buffers.cpp b/src/INTEL/intel_buffers.cpp index d86570b0d3..3470c18db8 100644 --- a/src/INTEL/intel_buffers.cpp +++ b/src/INTEL/intel_buffers.cpp @@ -296,9 +296,7 @@ void IntelBuffers::free_list_ptrs() /* ---------------------------------------------------------------------- */ template -void IntelBuffers::grow_data3(NeighList *list, - int *&numneighhalf, - int *&cnumneigh) +void IntelBuffers::grow_data3(NeighList *list, int *&numneighhalf, int *&cnumneigh) { const int size = list->get_maxlocal(); int list_num; @@ -321,10 +319,8 @@ void IntelBuffers::grow_data3(NeighList *list, lmp->memory->destroy(_neigh_list_ptrs[list_num].cnumneigh); lmp->memory->destroy(_neigh_list_ptrs[list_num].numneighhalf); } - lmp->memory->create(_neigh_list_ptrs[list_num].cnumneigh, size, - "_cnumneigh"); - lmp->memory->create(_neigh_list_ptrs[list_num].numneighhalf, size, - "_cnumneigh"); + lmp->memory->create(_neigh_list_ptrs[list_num].cnumneigh, size, "_cnumneigh"); + lmp->memory->create(_neigh_list_ptrs[list_num].numneighhalf, size, "_cnumneigh"); _neigh_list_ptrs[list_num].size = size; } numneighhalf = _neigh_list_ptrs[list_num].numneighhalf; @@ -334,8 +330,7 @@ void IntelBuffers::grow_data3(NeighList *list, /* ---------------------------------------------------------------------- */ template -void IntelBuffers::_grow_list_local(NeighList *list, - const int three_body, +void IntelBuffers::_grow_list_local(NeighList *list, const int three_body, const int offload_end) { free_list_local(); diff --git a/src/fix_balance.cpp b/src/fix_balance.cpp index 2c76f13bf0..6b5c4b6ab1 100644 --- a/src/fix_balance.cpp +++ b/src/fix_balance.cpp @@ -13,20 +13,22 @@ ------------------------------------------------------------------------- */ #include "fix_balance.h" -#include -#include "balance.h" -#include "update.h" + #include "atom.h" +#include "balance.h" #include "comm.h" #include "domain.h" -#include "neighbor.h" -#include "irregular.h" +#include "error.h" +#include "fix_store.h" #include "force.h" +#include "irregular.h" #include "kspace.h" #include "modify.h" -#include "fix_store.h" +#include "neighbor.h" #include "rcb.h" -#include "error.h" +#include "update.h" + +#include using namespace LAMMPS_NS; using namespace FixConst; From 900ff39403a8fa0f24f87fe89e5e075d26a82c99 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 22 Jan 2022 16:33:44 -0500 Subject: [PATCH 171/193] make consistent --- src/tabular_function.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tabular_function.cpp b/src/tabular_function.cpp index a3a904d644..07df49729a 100644 --- a/src/tabular_function.cpp +++ b/src/tabular_function.cpp @@ -1,6 +1,6 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://www.lammps.org/ Sandia National Laboratories + https://www.lammps.org/, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract From c93fba5e2da9d37079969ab928fa424af94734be Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 22 Jan 2022 16:45:38 -0500 Subject: [PATCH 172/193] make certain that offset is always initialized --- src/MISC/pair_list.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MISC/pair_list.cpp b/src/MISC/pair_list.cpp index 5215cdc7e2..f5c82ed5e6 100644 --- a/src/MISC/pair_list.cpp +++ b/src/MISC/pair_list.cpp @@ -232,6 +232,7 @@ void PairList::settings(int narg, char **arg) while ((line = reader.next_line())) { ValueTokenizer values(line); list_param oneparam; + oneparam.offset = 0.0; oneparam.id1 = values.next_tagint(); oneparam.id2 = values.next_tagint(); oneparam.style = stylename[values.next_string()]; From d854e58d002993c6dc627c56bb9801d0e227e0ea Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 22 Jan 2022 16:51:07 -0500 Subject: [PATCH 173/193] add sanity check --- src/reader_native.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/reader_native.cpp b/src/reader_native.cpp index ba7a576a50..065adb5d01 100644 --- a/src/reader_native.cpp +++ b/src/reader_native.cpp @@ -130,6 +130,7 @@ void ReaderNative::skip() // read chunk and skip them read_buf(&nchunk, sizeof(int), 1); + if (nchunk < 0) error->one(FLERR,"Dump file is invalid or corrupted"); int n; for (int i = 0; i < nchunk; i++) { From 458ae4e38aa2df2748c9bba16dbe09238ba2ef4d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 22 Jan 2022 17:06:13 -0500 Subject: [PATCH 174/193] initialize pointers, remove unused class member --- src/EXTRA-MOLECULE/bond_fene_nm.cpp | 2 +- src/EXTRA-MOLECULE/bond_fene_nm.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/EXTRA-MOLECULE/bond_fene_nm.cpp b/src/EXTRA-MOLECULE/bond_fene_nm.cpp index 147a63512a..8abaf97bec 100644 --- a/src/EXTRA-MOLECULE/bond_fene_nm.cpp +++ b/src/EXTRA-MOLECULE/bond_fene_nm.cpp @@ -29,7 +29,7 @@ using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ -BondFENENM::BondFENENM(LAMMPS *lmp) : BondFENE(lmp) {} +BondFENENM::BondFENENM(LAMMPS *lmp) : BondFENE(lmp), nn(nullptr), mm(nullptr) {} /* ---------------------------------------------------------------------- */ diff --git a/src/EXTRA-MOLECULE/bond_fene_nm.h b/src/EXTRA-MOLECULE/bond_fene_nm.h index f00394c6d8..4dbf64a331 100644 --- a/src/EXTRA-MOLECULE/bond_fene_nm.h +++ b/src/EXTRA-MOLECULE/bond_fene_nm.h @@ -38,7 +38,6 @@ class BondFENENM : public BondFENE { virtual void *extract(const char *, int &); protected: - double TWO_1_3; double *nn, *mm; virtual void allocate(); From f814dc5ff9ee7f94391751336443c301c0848641 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 22 Jan 2022 17:06:28 -0500 Subject: [PATCH 175/193] add checks after reading data --- src/reader_native.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/reader_native.cpp b/src/reader_native.cpp index 065adb5d01..32b2279a60 100644 --- a/src/reader_native.cpp +++ b/src/reader_native.cpp @@ -142,8 +142,7 @@ void ReaderNative::skip() read_lines(2); bigint natoms; int rv = sscanf(line,BIGINT_FORMAT,&natoms); - if (rv != 1) - error->one(FLERR,"Dump file is incorrectly formatted"); + if (rv != 1) error->one(FLERR,"Dump file is incorrectly formatted"); read_lines(5); @@ -164,20 +163,17 @@ void ReaderNative::skip_reading_magic_str() if (is_known_magic_str() && revision > 0x0001) { int len; read_buf(&len, sizeof(int), 1); + if (len < 0) error->one(FLERR,"Dump file is invalid or corrupted"); - if (len > 0) { - // has units - skip_buf(sizeof(char)*len); - } + // has units + if (len > 0) skip_buf(sizeof(char)*len); char flag = 0; read_buf(&flag, sizeof(char), 1); - - if (flag) { - skip_buf(sizeof(double)); - } + if (flag) skip_buf(sizeof(double)); read_buf(&len, sizeof(int), 1); + if (len < 0) error->one(FLERR,"Dump file is invalid or corrupted"); skip_buf(sizeof(char)*len); } } From 81e7583a8d00faba5f2833d8e37ad5cd13e893f8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 22 Jan 2022 17:07:12 -0500 Subject: [PATCH 176/193] initialize pointers, use provided constant, reorder include statements --- src/MOLECULE/bond_quartic.cpp | 25 +++++++++++++------------ src/MOLECULE/bond_quartic.h | 1 - src/OPENMP/bond_quartic_omp.cpp | 8 +++++--- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/MOLECULE/bond_quartic.cpp b/src/MOLECULE/bond_quartic.cpp index b3eea79064..30fd460dcc 100644 --- a/src/MOLECULE/bond_quartic.cpp +++ b/src/MOLECULE/bond_quartic.cpp @@ -18,24 +18,25 @@ #include "bond_quartic.h" -#include #include "atom.h" -#include "neighbor.h" #include "comm.h" -#include "force.h" -#include "pair.h" -#include "memory.h" #include "error.h" +#include "force.h" +#include "memory.h" +#include "neighbor.h" +#include "pair.h" +#include + +#include "math_const.h" using namespace LAMMPS_NS; +using namespace MathConst; /* ---------------------------------------------------------------------- */ -BondQuartic::BondQuartic(LAMMPS *lmp) : Bond(lmp) -{ - TWO_1_3 = pow(2.0,(1.0/3.0)); -} +BondQuartic::BondQuartic(LAMMPS *lmp) : Bond(lmp), k(nullptr), + b1(nullptr), b2(nullptr), rc(nullptr), u0(nullptr) {} /* ---------------------------------------------------------------------- */ @@ -120,7 +121,7 @@ void BondQuartic::compute(int eflag, int vflag) rb = dr - b2[type]; fbond = -k[type]/r * (r2*(ra+rb) + 2.0*dr*ra*rb); - if (rsq < TWO_1_3) { + if (rsq < MY_CUBEROOT2) { sr2 = 1.0/rsq; sr6 = sr2*sr2*sr2; fbond += 48.0*sr6*(sr6-0.5)/rsq; @@ -128,7 +129,7 @@ void BondQuartic::compute(int eflag, int vflag) if (eflag) { ebond = k[type]*r2*ra*rb + u0[type]; - if (rsq < TWO_1_3) ebond += 4.0*sr6*(sr6-1.0) + 1.0; + if (rsq < MY_CUBEROOT2) ebond += 4.0*sr6*(sr6-1.0) + 1.0; } // apply force to each of 2 atoms @@ -336,7 +337,7 @@ double BondQuartic::single(int type, double rsq, int i, int j, eng += k[type]*r2*ra*rb + u0[type]; fforce = -k[type]/r * (r2*(ra+rb) + 2.0*dr*ra*rb); - if (rsq < TWO_1_3) { + if (rsq < MY_CUBEROOT2) { sr2 = 1.0/rsq; sr6 = sr2*sr2*sr2; eng += 4.0*sr6*(sr6-1.0) + 1.0; diff --git a/src/MOLECULE/bond_quartic.h b/src/MOLECULE/bond_quartic.h index 35ec705849..3973477e68 100644 --- a/src/MOLECULE/bond_quartic.h +++ b/src/MOLECULE/bond_quartic.h @@ -38,7 +38,6 @@ class BondQuartic : public Bond { double single(int, double, int, int, double &); protected: - double TWO_1_3; double *k, *b1, *b2, *rc, *u0; void allocate(); diff --git a/src/OPENMP/bond_quartic_omp.cpp b/src/OPENMP/bond_quartic_omp.cpp index 00e8357644..427293dd3e 100644 --- a/src/OPENMP/bond_quartic_omp.cpp +++ b/src/OPENMP/bond_quartic_omp.cpp @@ -22,13 +22,15 @@ #include "comm.h" #include "force.h" #include "neighbor.h" - #include "pair.h" #include #include "suffix.h" +#include "math_const.h" + using namespace LAMMPS_NS; +using namespace MathConst; /* ---------------------------------------------------------------------- */ @@ -143,7 +145,7 @@ void BondQuarticOMP::eval(int nfrom, int nto, ThrData * const thr) rb = dr - b2[type]; fbond = -k[type]/r * (r2*(ra+rb) + 2.0*dr*ra*rb); - if (rsq < TWO_1_3) { + if (rsq < MY_CUBEROOT2) { sr2 = 1.0/rsq; sr6 = sr2*sr2*sr2; fbond += 48.0*sr6*(sr6-0.5)/rsq; @@ -151,7 +153,7 @@ void BondQuarticOMP::eval(int nfrom, int nto, ThrData * const thr) if (EFLAG) { ebond = k[type]*r2*ra*rb + u0[type]; - if (rsq < TWO_1_3) ebond += 4.0*sr6*(sr6-1.0) + 1.0; + if (rsq < MY_CUBEROOT2) ebond += 4.0*sr6*(sr6-1.0) + 1.0; } // apply force to each of 2 atoms From cd165562569770015214004cf49b320c3fe423f7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 22 Jan 2022 17:13:54 -0500 Subject: [PATCH 177/193] add missing break statements. @GenieTim this bug may have tainted your results. you would always get the energy value for any of the dx, dy, dz keywords --- src/compute_pair_local.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/compute_pair_local.cpp b/src/compute_pair_local.cpp index ff9acdc4ef..b98f6eec33 100644 --- a/src/compute_pair_local.cpp +++ b/src/compute_pair_local.cpp @@ -277,10 +277,13 @@ int ComputePairLocal::compute_pairs(int flag) break; case DX: ptr[n] = delx*directionCorrection; + break; case DY: ptr[n] = dely*directionCorrection; + break; case DZ: ptr[n] = delz*directionCorrection; + break; case ENG: ptr[n] = eng; break; From 88dadd0fffea798fcd56a9253cb6d020ea41f83c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 23 Jan 2022 21:12:22 -0500 Subject: [PATCH 178/193] consistently refer to INTEL package in upper case --- src/INTEL/fix_intel.cpp | 13 ++++++------- src/INTEL/nbin_intel.cpp | 6 ++---- src/INTEL/verlet_lrt_intel.cpp | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/INTEL/fix_intel.cpp b/src/INTEL/fix_intel.cpp index 97d4f21788..6a848a366e 100644 --- a/src/INTEL/fix_intel.cpp +++ b/src/INTEL/fix_intel.cpp @@ -43,7 +43,7 @@ using namespace FixConst; #ifdef __INTEL_OFFLOAD #ifndef _LMP_INTEL_OFFLOAD -#warning "Not building Intel package with Xeon Phi offload support." +#warning "Not building INTEL package with Xeon Phi offload support." #endif #endif @@ -303,7 +303,7 @@ void FixIntel::init() if (force->pair_match("^hybrid", 0) != nullptr) { _pair_hybrid_flag = 1; if (force->newton_pair != 0 && force->pair->no_virial_fdotr_compute) - error->all(FLERR,"Intel package requires fdotr virial with newton on."); + error->all(FLERR,"INTEL package requires fdotr virial with newton on."); } else _pair_hybrid_flag = 0; @@ -354,12 +354,12 @@ void FixIntel::init() void FixIntel::setup(int vflag) { if (neighbor->style != Neighbor::BIN) - error->all(FLERR,"Currently, neighbor style BIN must be used with Intel package."); + error->all(FLERR,"Currently, neighbor style BIN must be used with INTEL package."); if (vflag > 3) - error->all(FLERR,"Cannot currently get per-atom virials with Intel package."); + error->all(FLERR,"Cannot currently get per-atom virials with INTEL package."); #ifdef _LMP_INTEL_OFFLOAD if (neighbor->exclude_setting() != 0) - error->all(FLERR,"Currently, cannot use neigh_modify exclude with Intel package offload."); + error->all(FLERR,"Currently, cannot use neigh_modify exclude with INTEL package offload."); post_force(vflag); #endif } @@ -512,8 +512,7 @@ void FixIntel::bond_init_check() } if (intel_pair == 0) - error->all(FLERR,"Intel styles for bond/angle/dihedral/improper " - "require intel pair style."); + error->all(FLERR,"Intel styles for bond/angle/dihedral/improper require intel pair style."); } /* ---------------------------------------------------------------------- */ diff --git a/src/INTEL/nbin_intel.cpp b/src/INTEL/nbin_intel.cpp index 94f18002a0..29bc7c9ced 100644 --- a/src/INTEL/nbin_intel.cpp +++ b/src/INTEL/nbin_intel.cpp @@ -161,10 +161,8 @@ void NBinIntel::bin_atoms(IntelBuffers * buffers) { const flt_t dx = (INTEL_BIGP - bboxhi[0]); const flt_t dy = (INTEL_BIGP - bboxhi[1]); const flt_t dz = (INTEL_BIGP - bboxhi[2]); - if (dx * dx + dy * dy + dz * dz < - static_cast(neighbor->cutneighmaxsq)) - error->one(FLERR, - "Intel package expects no atoms within cutoff of {1e15,1e15,1e15}."); + if (dx * dx + dy * dy + dz * dz < static_cast(neighbor->cutneighmaxsq)) + error->one(FLERR,"INTEL package expects no atoms within cutoff of (1e15,1e15,1e15)."); } // ---------- Grow and cast/pack buffers ------------- diff --git a/src/INTEL/verlet_lrt_intel.cpp b/src/INTEL/verlet_lrt_intel.cpp index 216ba98302..f867ad73e6 100644 --- a/src/INTEL/verlet_lrt_intel.cpp +++ b/src/INTEL/verlet_lrt_intel.cpp @@ -71,7 +71,7 @@ void VerletLRTIntel::init() #ifndef LMP_INTEL_USELRT error->all(FLERR, - "LRT otion for Intel package disabled at compile time"); + "LRT otion for INTEL package disabled at compile time"); #endif } From f9a2006d732670265cbb0d47631bb3d4291150b3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 24 Jan 2022 08:44:29 -0500 Subject: [PATCH 179/193] reorder includes --- src/ASPHERE/pair_gayberne.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ASPHERE/pair_gayberne.cpp b/src/ASPHERE/pair_gayberne.cpp index 08af6ee3c9..39cb88f81b 100644 --- a/src/ASPHERE/pair_gayberne.cpp +++ b/src/ASPHERE/pair_gayberne.cpp @@ -18,18 +18,18 @@ #include "pair_gayberne.h" -#include -#include "math_extra.h" #include "atom.h" #include "atom_vec_ellipsoid.h" -#include "comm.h" -#include "force.h" -#include "neighbor.h" -#include "neigh_list.h" #include "citeme.h" -#include "memory.h" +#include "comm.h" #include "error.h" +#include "force.h" +#include "math_extra.h" +#include "memory.h" +#include "neigh_list.h" +#include "neighbor.h" +#include using namespace LAMMPS_NS; From 16810b84eba91c85e23dd9d0f62392d0d7f4ec87 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 24 Jan 2022 14:35:27 -0700 Subject: [PATCH 180/193] Add option to balance dump file output --- src/dump.cpp | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/dump.h | 2 + 2 files changed, 167 insertions(+) diff --git a/src/dump.cpp b/src/dump.cpp index e5652c210c..cdf2f57d9e 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -75,6 +75,7 @@ Dump::Dump(LAMMPS *lmp, int /*narg*/, char **arg) : Pointers(lmp) clearstep = 0; sort_flag = 0; + balance_flag = 0; append_flag = 0; buffer_allow = 0; buffer_flag = 0; @@ -222,6 +223,9 @@ void Dump::init() ids = idsort = nullptr; index = proclist = nullptr; irregular = nullptr; + + if (balance_flag) + error->all(FLERR,"Cannot balance dump output without sorting enabled"); } if (sort_flag) { @@ -417,6 +421,7 @@ void Dump::write() if (sort_flag && sortcol == 0) pack(ids); else pack(nullptr); if (sort_flag) sort(); + if (balance_flag) balance(); // write timestep header // for multiproc, @@ -888,6 +893,161 @@ int Dump::bufcompare_reverse(const int i, const int j, void *ptr) #endif +/* ---------------------------------------------------------------------- + parallel load balance of buf across all procs + must come after sort +------------------------------------------------------------------------- */ + +void Dump::balance() +{ + bigint *proc_offsets,*proc_new_offsets; + memory->create(proc_offsets,nprocs+1,"dump:proc_offsets"); + memory->create(proc_new_offsets,nprocs+1,"dump:proc_new_offsets"); + + // compute atom offset for this proc + + bigint offset; + bigint bnme = nme; + MPI_Scan(&bnme,&offset,1,MPI_LMP_BIGINT,MPI_SUM,world); + + // gather atom offsets for all procs + + MPI_Allgather(&offset,1,MPI_LMP_BIGINT,&proc_offsets[1],1,MPI_LMP_BIGINT,world); + + proc_offsets[0] = 0; + + // how many atoms should I own after balance + + int nme_balance = static_cast(ntotal/nprocs); + + // include remainder atoms on first procs + + int remainder = ntotal % nprocs; + if (me < remainder) nme_balance += 1; + + // compute new atom offset for this proc + + bigint offset_balance; + bigint bnme_balance = nme_balance; + MPI_Scan(&bnme_balance,&offset_balance,1,MPI_LMP_BIGINT,MPI_SUM,world); + + // gather new atom offsets for all procs + + MPI_Allgather(&offset_balance,1,MPI_LMP_BIGINT,&proc_new_offsets[1],1,MPI_LMP_BIGINT,world); + + proc_new_offsets[0] = 0; + + bigint start = proc_new_offsets[me]; + bigint end = proc_new_offsets[me+1]; + + // reset buf size to largest of any post-balance nme values + // this insures proc 0 can receive everyone's info + + int nmax; + MPI_Allreduce(&nme_balance,&nmax,1,MPI_INT,MPI_MAX,world); + + // allocate a second buffer for balanced data + + double* buf_balance; + memory->create(buf_balance,nmax*size_one,"dump:buf_balance"); + + // compute from which procs I am receiving atoms + // post recvs first + + int nswap = 0; + MPI_Request *request = new MPI_Request[nprocs]; + int procstart = start; + int iproc = me; + int iproc_prev; + + for (bigint i = start; i < end; i++) { + + // find which proc this atom belongs to + + while (i < proc_offsets[iproc]) iproc--; + while (i > proc_offsets[iproc+1]-1) iproc++; + + if (i != start && (iproc != iproc_prev || i == end-1)) { + + // finished with proc + + int procrecv = iproc; + if (iproc != iproc_prev) procrecv = iproc_prev; + + int procnrecv = i - procstart + 1; + if (iproc != iproc_prev) procnrecv--; + + // post receive for this proc + + if (iproc_prev != me) + MPI_Irecv(&buf_balance[(procstart - start)*size_one],procnrecv*size_one,MPI_DOUBLE, + procrecv,0,world,&request[nswap++]); + + procstart = i; + } + + iproc_prev = iproc; + } + + // compute which atoms I am sending and to which procs + + procstart = 0; + iproc = me; + for (int i = 0; i < nme; i++) { + + // find which proc this atom should belong to + + while (proc_offsets[me] + i < proc_new_offsets[iproc]) iproc--; + while (proc_offsets[me] + i > proc_new_offsets[iproc+1] - 1) iproc++; + + if (i != 0 && (iproc != iproc_prev || i == nme - 1)) { + + // finished with proc + + int procsend = iproc; + if (iproc != iproc_prev) procsend = iproc_prev; + + int procnsend = i - procstart + 1; + if (iproc != iproc_prev) procnsend--; + + // send for this proc + + if (iproc_prev != me) { + MPI_Send(&buf[procstart*size_one],procnsend*size_one,MPI_DOUBLE,procsend,0,world); + } else { + + // sending to self, copy buffers + + int offset_me = proc_offsets[me] - start; + memcpy(&buf_balance[(offset_me + procstart)*size_one],&buf[procstart*size_one],procnsend*size_one*sizeof(double)); + } + + procstart = i; + } + + iproc_prev = iproc; + } + + // wait for all recvs + + for (int n = 0; n < nswap; n++) + MPI_Wait(&request[n],MPI_STATUS_IGNORE); + + nme = nme_balance; + + // swap buffers + + double *tmp = buf; + buf = buf_balance; + + // cleanup + + memory->destroy(tmp); + memory->destroy(proc_offsets); + memory->destroy(proc_new_offsets); + delete [] request; +} + /* ---------------------------------------------------------------------- process params common to all dumps here if unknown param, call modify_param specific to the dump @@ -1108,6 +1268,11 @@ void Dump::modify_params(int narg, char **arg) } iarg += 2; + } else if (strcmp(arg[iarg],"balance") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); + balance_flag = utils::logical(FLERR,arg[iarg+1],false,lmp); + iarg += 2; + } else if (strcmp(arg[iarg],"time") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); time_flag = utils::logical(FLERR,arg[iarg+1],false,lmp); diff --git a/src/dump.h b/src/dump.h index 482e87a207..83edda3810 100644 --- a/src/dump.h +++ b/src/dump.h @@ -67,6 +67,7 @@ class Dump : protected Pointers { int header_flag; // 0 = item, 2 = xyz int flush_flag; // 0 if no flush, 1 if flush every dump int sort_flag; // 1 if sorted output + int balance_flag; // 1 if load balanced output int append_flag; // 1 if open file in append mode, 0 if not int buffer_allow; // 1 if style allows for buffer_flag, 0 if not int buffer_flag; // 1 if buffer output as one big string, 0 if not @@ -161,6 +162,7 @@ class Dump : protected Pointers { static int bufcompare(const int, const int, void *); static int bufcompare_reverse(const int, const int, void *); #endif + void balance(); }; } // namespace LAMMPS_NS From 1d60e4c4639614cfc95e1e291e030d1398fc16da Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 24 Jan 2022 15:16:49 -0700 Subject: [PATCH 181/193] Add docs --- doc/src/dump_modify.rst | 11 ++++++++++- src/dump.cpp | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/doc/src/dump_modify.rst b/doc/src/dump_modify.rst index be75153f6f..52efa47d7c 100644 --- a/doc/src/dump_modify.rst +++ b/doc/src/dump_modify.rst @@ -17,13 +17,14 @@ Syntax * one or more keyword/value pairs may be appended * these keywords apply to various dump styles -* keyword = *append* or *at* or *buffer* or *delay* or *element* or *every* or *every/time* or *fileper* or *first* or *flush* or *format* or *header* or *image* or *label* or *maxfiles* or *nfile* or *pad* or *pbc* or *precision* or *region* or *refresh* or *scale* or *sfactor* or *sort* or *tfactor* or *thermo* or *thresh* or *time* or *units* or *unwrap* +* keyword = *append* or *at* or *balance* or *buffer* or *delay* or *element* or *every* or *every/time* or *fileper* or *first* or *flush* or *format* or *header* or *image* or *label* or *maxfiles* or *nfile* or *pad* or *pbc* or *precision* or *region* or *refresh* or *scale* or *sfactor* or *sort* or *tfactor* or *thermo* or *thresh* or *time* or *units* or *unwrap* .. parsed-literal:: *append* arg = *yes* or *no* *at* arg = N N = index of frame written upon first dump + *balance* arg = *yes* or *no* *buffer* arg = *yes* or *no* *delay* arg = Dstep Dstep = delay output until this timestep @@ -658,6 +659,13 @@ atom ID. A sort value of N or -N means sort the output by the value in the Nth column of per-atom info in either ascending or descending order. +In a parallel run, the per-processor dump file pieces can have +significant imbalance in number of lines of per-atom info. The *balance* +keyword determines whether lines of per-atom output for each processor +snapshot in a parallel run are balanced to be nearly the same. A balance +value of *no* means no balancing will be done, while *yes* means +balancing will be performed. For a serial run, this option is ignored. + The dump *local* style cannot be sorted by atom ID, since there are typically multiple lines of output per atom. Some dump styles, such as *dcd* and *xtc*, require sorting by atom ID to format the output @@ -832,6 +840,7 @@ Default The option defaults are * append = no +* balance = no * buffer = yes for dump styles *atom*, *custom*, *loca*, and *xyz* * element = "C" for every atom type * every = whatever it was set to via the :doc:`dump ` command diff --git a/src/dump.cpp b/src/dump.cpp index cdf2f57d9e..21803d79ab 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -1270,7 +1270,8 @@ void Dump::modify_params(int narg, char **arg) } else if (strcmp(arg[iarg],"balance") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); - balance_flag = utils::logical(FLERR,arg[iarg+1],false,lmp); + if (nprocs > 1) + balance_flag = utils::logical(FLERR,arg[iarg+1],false,lmp); iarg += 2; } else if (strcmp(arg[iarg],"time") == 0) { From aeb25b5a3729ed2c5ecb43d8897ea04794a75fc0 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 24 Jan 2022 15:28:40 -0700 Subject: [PATCH 182/193] Tweak docs --- doc/src/dump_modify.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/src/dump_modify.rst b/doc/src/dump_modify.rst index 52efa47d7c..5f77b79347 100644 --- a/doc/src/dump_modify.rst +++ b/doc/src/dump_modify.rst @@ -661,10 +661,11 @@ order. In a parallel run, the per-processor dump file pieces can have significant imbalance in number of lines of per-atom info. The *balance* -keyword determines whether lines of per-atom output for each processor -snapshot in a parallel run are balanced to be nearly the same. A balance -value of *no* means no balancing will be done, while *yes* means -balancing will be performed. For a serial run, this option is ignored. +keyword determines whether the number of lines in each processor +snapshot are balanced to be nearly the same. A balance value of *no* +means no balancing will be done, while *yes* means balancing will be +performed. For a serial run, this option is ignored since the output is +already balanced. Dump sorting must be enabled to use balancing. The dump *local* style cannot be sorted by atom ID, since there are typically multiple lines of output per atom. Some dump styles, such From a80f7ed11fdce58dd2b2b38597ef7f1a91531490 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 24 Jan 2022 15:32:20 -0700 Subject: [PATCH 183/193] Add error message to header file --- src/dump.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/dump.h b/src/dump.h index 83edda3810..9054546a2d 100644 --- a/src/dump.h +++ b/src/dump.h @@ -176,6 +176,10 @@ E: Dump file MPI-IO output not allowed with % in filename This is because a % signifies one file per processor and MPI-IO creates one large file for all processors. +E: Cannot balance dump output without sorting enabled + +Self-explanatory. + E: Cannot dump sort when 'nfile' or 'fileper' keywords are set to non-default values Can only dump sort when the number of dump file pieces using % in filename equals the number of processors From cb9ba8c0a3fb7b4c3876cea64f80b9e3003abe34 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 24 Jan 2022 16:05:27 -0700 Subject: [PATCH 184/193] Simplify code --- src/dump.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/dump.cpp b/src/dump.cpp index 21803d79ab..6bc7f401a6 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -937,9 +937,6 @@ void Dump::balance() proc_new_offsets[0] = 0; - bigint start = proc_new_offsets[me]; - bigint end = proc_new_offsets[me+1]; - // reset buf size to largest of any post-balance nme values // this insures proc 0 can receive everyone's info @@ -956,18 +953,18 @@ void Dump::balance() int nswap = 0; MPI_Request *request = new MPI_Request[nprocs]; - int procstart = start; + int procstart = 0; int iproc = me; int iproc_prev; - for (bigint i = start; i < end; i++) { + for (int i = 0; i < nme_balance; i++) { // find which proc this atom belongs to - while (i < proc_offsets[iproc]) iproc--; - while (i > proc_offsets[iproc+1]-1) iproc++; + while (proc_new_offsets[me] + i < proc_offsets[iproc]) iproc--; + while (proc_new_offsets[me] + i > proc_offsets[iproc+1]-1) iproc++; - if (i != start && (iproc != iproc_prev || i == end-1)) { + if (i != 0 && (iproc != iproc_prev || i == nme_balance - 1)) { // finished with proc @@ -980,7 +977,7 @@ void Dump::balance() // post receive for this proc if (iproc_prev != me) - MPI_Irecv(&buf_balance[(procstart - start)*size_one],procnrecv*size_one,MPI_DOUBLE, + MPI_Irecv(&buf_balance[procstart*size_one],procnrecv*size_one,MPI_DOUBLE, procrecv,0,world,&request[nswap++]); procstart = i; @@ -1018,7 +1015,7 @@ void Dump::balance() // sending to self, copy buffers - int offset_me = proc_offsets[me] - start; + int offset_me = proc_offsets[me] - proc_new_offsets[me]; memcpy(&buf_balance[(offset_me + procstart)*size_one],&buf[procstart*size_one],procnsend*size_one*sizeof(double)); } From 67af170929006eb73e9108e5fa27b0f22902d9d6 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 24 Jan 2022 16:22:55 -0700 Subject: [PATCH 185/193] Sorting is not required for balancing --- doc/src/dump_modify.rst | 16 ++++++++-------- src/dump.cpp | 3 --- src/dump.h | 4 ---- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/doc/src/dump_modify.rst b/doc/src/dump_modify.rst index 5f77b79347..d3a79ab073 100644 --- a/doc/src/dump_modify.rst +++ b/doc/src/dump_modify.rst @@ -659,14 +659,6 @@ atom ID. A sort value of N or -N means sort the output by the value in the Nth column of per-atom info in either ascending or descending order. -In a parallel run, the per-processor dump file pieces can have -significant imbalance in number of lines of per-atom info. The *balance* -keyword determines whether the number of lines in each processor -snapshot are balanced to be nearly the same. A balance value of *no* -means no balancing will be done, while *yes* means balancing will be -performed. For a serial run, this option is ignored since the output is -already balanced. Dump sorting must be enabled to use balancing. - The dump *local* style cannot be sorted by atom ID, since there are typically multiple lines of output per atom. Some dump styles, such as *dcd* and *xtc*, require sorting by atom ID to format the output @@ -676,6 +668,14 @@ keywords are set to non-default values (i.e. the number of dump file pieces is not equal to the number of procs), then sorting cannot be performed. +In a parallel run, the per-processor dump file pieces can have +significant imbalance in number of lines of per-atom info. The *balance* +keyword determines whether the number of lines in each processor +snapshot are balanced to be nearly the same. A balance value of *no* +means no balancing will be done, while *yes* means balancing will be +performed. For a serial run, this option is ignored since the output is +already balanced. + .. note:: Unless it is required by the dump style, sorting dump file diff --git a/src/dump.cpp b/src/dump.cpp index 6bc7f401a6..1043970d33 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -223,9 +223,6 @@ void Dump::init() ids = idsort = nullptr; index = proclist = nullptr; irregular = nullptr; - - if (balance_flag) - error->all(FLERR,"Cannot balance dump output without sorting enabled"); } if (sort_flag) { diff --git a/src/dump.h b/src/dump.h index 9054546a2d..83edda3810 100644 --- a/src/dump.h +++ b/src/dump.h @@ -176,10 +176,6 @@ E: Dump file MPI-IO output not allowed with % in filename This is because a % signifies one file per processor and MPI-IO creates one large file for all processors. -E: Cannot balance dump output without sorting enabled - -Self-explanatory. - E: Cannot dump sort when 'nfile' or 'fileper' keywords are set to non-default values Can only dump sort when the number of dump file pieces using % in filename equals the number of processors From c914fc6bafa2764a990bc6f023b6bb103e997f59 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 24 Jan 2022 16:33:11 -0700 Subject: [PATCH 186/193] Small doc tweak --- doc/src/dump_modify.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/dump_modify.rst b/doc/src/dump_modify.rst index d3a79ab073..b25e5815a7 100644 --- a/doc/src/dump_modify.rst +++ b/doc/src/dump_modify.rst @@ -673,8 +673,8 @@ significant imbalance in number of lines of per-atom info. The *balance* keyword determines whether the number of lines in each processor snapshot are balanced to be nearly the same. A balance value of *no* means no balancing will be done, while *yes* means balancing will be -performed. For a serial run, this option is ignored since the output is -already balanced. +performed. This balancing preserves dump sorting order. For a serial +run, this option is ignored since the output is already balanced. .. note:: From 0b693e729df89ad575c32894b36876f9930f6f6b Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Mon, 24 Jan 2022 17:33:36 -0700 Subject: [PATCH 187/193] Whitespace --- doc/src/dump_modify.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/dump_modify.rst b/doc/src/dump_modify.rst index b25e5815a7..352f9c61bf 100644 --- a/doc/src/dump_modify.rst +++ b/doc/src/dump_modify.rst @@ -674,7 +674,7 @@ keyword determines whether the number of lines in each processor snapshot are balanced to be nearly the same. A balance value of *no* means no balancing will be done, while *yes* means balancing will be performed. This balancing preserves dump sorting order. For a serial -run, this option is ignored since the output is already balanced. +run, this option is ignored since the output is already balanced. .. note:: From 35dbabd4716765aa8886d01c7384a24a1393e3e9 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 25 Jan 2022 07:39:37 -0500 Subject: [PATCH 188/193] alternate fix for tag caching issue in INTEL package --- src/INTEL/fix_intel.cpp | 2 +- src/INTEL/intel_buffers.cpp | 2 -- src/INTEL/npair_intel.cpp | 4 +++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/INTEL/fix_intel.cpp b/src/INTEL/fix_intel.cpp index 6a848a366e..a201386724 100644 --- a/src/INTEL/fix_intel.cpp +++ b/src/INTEL/fix_intel.cpp @@ -447,7 +447,7 @@ void FixIntel::pair_init_check(const bool cdmessage) #endif int need_tag = 0; - if (atom->molecular != Atom::ATOMIC) need_tag = 1; + if (atom->molecular != Atom::ATOMIC || three_body_neighbor()) need_tag = 1; // Clear buffers used for pair style char kmode[80]; diff --git a/src/INTEL/intel_buffers.cpp b/src/INTEL/intel_buffers.cpp index 3470c18db8..cbbc609fc0 100644 --- a/src/INTEL/intel_buffers.cpp +++ b/src/INTEL/intel_buffers.cpp @@ -207,8 +207,6 @@ void IntelBuffers::free_nmax() template void IntelBuffers::_grow_nmax(const int offload_end) { - if (lmp->atom->molecular) _need_tag = 1; - else _need_tag = 0; #ifdef _LMP_INTEL_OFFLOAD free_nmax(); int size = lmp->atom->nmax; diff --git a/src/INTEL/npair_intel.cpp b/src/INTEL/npair_intel.cpp index 67cd2517e4..2fffb2353a 100644 --- a/src/INTEL/npair_intel.cpp +++ b/src/INTEL/npair_intel.cpp @@ -309,6 +309,7 @@ void NPairIntel::bin_newton(const int offload, NeighList *list, flt_t * _noalias const tz = ncachez + toffs; int * _noalias const tj = ncachej + toffs; int * _noalias const tjtype = ncachejtype + toffs; + tagint * _noalias const ttag = ncachetag + toffs; flt_t * _noalias itx; flt_t * _noalias ity; @@ -365,6 +366,7 @@ void NPairIntel::bin_newton(const int offload, NeighList *list, ty[u] = x[j].y; tz[u] = x[j].z; tjtype[u] = x[j].w; + if (THREE) ttag[u] = tag[j]; } if (FULL == 0 && TRI != 1) { @@ -512,7 +514,7 @@ void NPairIntel::bin_newton(const int offload, NeighList *list, } if (THREE) { - const tagint jtag = tag[j]; + const tagint jtag = ttag[u]; int flist = 0; if (itag > jtag) { if (((itag+jtag) & 1) == 0) flist = 1; From 64dbce26dce54fe77839df0d720bea3f493fd348 Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Tue, 25 Jan 2022 08:45:13 -0700 Subject: [PATCH 189/193] Cannot shrink buf --- src/dump.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/dump.cpp b/src/dump.cpp index 1043970d33..732f4a73ef 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -939,11 +939,14 @@ void Dump::balance() int nmax; MPI_Allreduce(&nme_balance,&nmax,1,MPI_INT,MPI_MAX,world); + if (nmax > maxbuf) { + maxbuf = nmax; + } // allocate a second buffer for balanced data double* buf_balance; - memory->create(buf_balance,nmax*size_one,"dump:buf_balance"); + memory->create(buf_balance,maxbuf*size_one,"dump:buf_balance"); // compute from which procs I am receiving atoms // post recvs first From 75a00f4d11a538d99509fd71326a51c1bb3dc94b Mon Sep 17 00:00:00 2001 From: Stan Gerald Moore Date: Tue, 25 Jan 2022 08:52:53 -0700 Subject: [PATCH 190/193] minor cleanup --- src/dump.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/dump.cpp b/src/dump.cpp index 732f4a73ef..181a56ff46 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -936,12 +936,11 @@ void Dump::balance() // reset buf size to largest of any post-balance nme values // this insures proc 0 can receive everyone's info + // cannot shrink buf to nme_balance, must use previous maxbuf value int nmax; MPI_Allreduce(&nme_balance,&nmax,1,MPI_INT,MPI_MAX,world); - if (nmax > maxbuf) { - maxbuf = nmax; - } + if (nmax > maxbuf) maxbuf = nmax; // allocate a second buffer for balanced data From 120662c438be8bb5fa8da37543426c7458ac3945 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 26 Jan 2022 10:45:30 -0500 Subject: [PATCH 191/193] correct citation info --- src/MC/fix_bond_swap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MC/fix_bond_swap.cpp b/src/MC/fix_bond_swap.cpp index 5f7ffcbbe5..c0978f51cb 100644 --- a/src/MC/fix_bond_swap.cpp +++ b/src/MC/fix_bond_swap.cpp @@ -39,7 +39,7 @@ using namespace LAMMPS_NS; using namespace FixConst; static const char cite_fix_bond_swap[] = - "neighbor multi command:\n\n" + "fix bond/swap command:\n\n" "@Article{Auhl03,\n" " author = {R. Auhl, R. Everaers, G. S. Grest, K. Kremer, S. J. Plimpton},\n" " title = {Equilibration of long chain polymer melts in computer simulations},\n" From 8ca1004c03d527b6ba827436161ae45ddd45fb11 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 26 Jan 2022 10:45:46 -0500 Subject: [PATCH 192/193] cosmetic. align with clang-format --- src/RIGID/fix_rigid_small.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/RIGID/fix_rigid_small.cpp b/src/RIGID/fix_rigid_small.cpp index 14742155db..cbaef073da 100644 --- a/src/RIGID/fix_rigid_small.cpp +++ b/src/RIGID/fix_rigid_small.cpp @@ -220,7 +220,7 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : } else if (strcmp(arg[iarg],"infile") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid/small command"); - delete [] inpfile; + delete[] inpfile; inpfile = utils::strdup(arg[iarg+1]); restart_file = 1; reinitflag = 0; @@ -327,7 +327,7 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : if (strcmp(arg[iarg+1],"all") == 0) allremap = 1; else { allremap = 0; - delete [] id_dilate; + delete[] id_dilate; id_dilate = utils::strdup(arg[iarg+1]); int idilate = group->find(id_dilate); if (idilate == -1) @@ -354,7 +354,7 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : } else if (strcmp(arg[iarg],"gravity") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid/small command"); - delete [] id_gravity; + delete[] id_gravity; id_gravity = utils::strdup(arg[iarg+1]); iarg += 2; @@ -395,7 +395,7 @@ FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) : double time1 = platform::walltime(); create_bodies(bodyID); - if (customflag) delete [] bodyID; + if (customflag) delete[] bodyID; if (comm->me == 0) utils::logmesg(lmp," create bodies CPU = {:.3f} seconds\n", @@ -501,9 +501,9 @@ FixRigidSmall::~FixRigidSmall() memory->destroy(dorient); delete random; - delete [] inpfile; - delete [] id_dilate; - delete [] id_gravity; + delete[] inpfile; + delete[] id_dilate; + delete[] id_gravity; memory->destroy(langextra); memory->destroy(mass_body); @@ -2578,8 +2578,8 @@ void FixRigidSmall::readfile(int which, double **array, int *inbody) if (me == 0) fclose(fp); - delete [] buffer; - delete [] values; + delete[] buffer; + delete[] values; } /* ---------------------------------------------------------------------- From 71a373cadbf22214c3400d4312a72e59f9d07a2e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 26 Jan 2022 10:46:19 -0500 Subject: [PATCH 193/193] reshuffle Body struct members and add dummy for better alignment --- src/RIGID/fix_rigid_small.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/RIGID/fix_rigid_small.h b/src/RIGID/fix_rigid_small.h index e289c179d9..27076ccac3 100644 --- a/src/RIGID/fix_rigid_small.h +++ b/src/RIGID/fix_rigid_small.h @@ -84,8 +84,9 @@ class FixRigidSmall : public Fix { double maxextent; // furthest distance from body owner to body atom struct Body { - double mass; // total mass of body int natoms; // total number of atoms in body + int ilocal; // index of owning atom + double mass; // total mass of body double xcm[3]; // COM position double xgc[3]; // geometric center position double vcm[3]; // COM velocity @@ -97,12 +98,12 @@ class FixRigidSmall : public Fix { double ey_space[3]; double ez_space[3]; double xgc_body[3]; // geometric center relative to xcm in body coords - double angmom[3]; // space-frame angular momentum of body - double omega[3]; // space-frame omega of body - double conjqm[4]; // conjugate quaternion momentum - imageint image; // image flags of xcm - int remapflag[4]; // PBC remap flags - int ilocal; // index of owning atom + double angmom[3]; // space-frame angular momentum of body + double omega[3]; // space-frame omega of body + double conjqm[4]; // conjugate quaternion momentum + int remapflag[4]; // PBC remap flags + imageint image; // image flags of xcm + imageint dummy; // dummy entry for better alignment }; Body *body; // list of rigid bodies, owned and ghost