From 52b563a83e15c6512bb8d30be00b7c97c99cdf98 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 31 Mar 2022 07:36:50 -0400 Subject: [PATCH] modernize parsing in fix tmd, add support for comments and empty lines --- doc/src/fix_tmd.rst | 19 ++++--- src/EXTRA-FIX/fix_tmd.cpp | 110 +++++++++++++++++++++----------------- 2 files changed, 72 insertions(+), 57 deletions(-) diff --git a/doc/src/fix_tmd.rst b/doc/src/fix_tmd.rst index b4595d24cd..ccebb35823 100644 --- a/doc/src/fix_tmd.rst +++ b/doc/src/fix_tmd.rst @@ -29,10 +29,10 @@ Description """"""""""" Perform targeted molecular dynamics (TMD) on a group of atoms. A -holonomic constraint is used to force the atoms to move towards (or -away from) the target configuration. The parameter "rho" is -monotonically decreased (or increased) from its initial value to -rho_final at the end of the run. +holonomic constraint is used to force the atoms to move towards (or away +from) the target configuration. The parameter "rho" is monotonically +decreased (or increased) from its initial value to rho_final at the end +of the run. Rho has distance units and is a measure of the root-mean-squared distance (RMSD) between the current configuration of the atoms in the @@ -55,22 +55,25 @@ a .gz suffix). The format of the target file1 is as follows: The first 3 lines may or may not be needed, depending on the format of the atoms to follow. If image flags are included with the atoms, the -first 3 lo/hi lines must appear in the file. If image flags are not -included, the first 3 lines should not appear. The 3 lines contain the +first 3 lo/hi lines **must** appear in the file. If image flags are not +included, the first 3 lines **must not** appear. The 3 lines contain the simulation box dimensions for the atom coordinates, in the same format as in a LAMMPS data file (see the :doc:`read_data ` command). The remaining lines each contain an atom ID and its target x,y,z coordinates. The atom lines (all or none of them) can optionally be -followed by 3 integer values: nx,ny,nz. For periodic dimensions, they +followed by 3 integer values: nx,ny,nz.For periodic dimensions, they specify which image of the box the atom is considered to be in, i.e. a value of N (positive or negative) means add N times the box length to -the coordinate to get the true value. +the coordinate to get the true value. Those 3 integers either must +be given for all atoms or none. The atom lines can be listed in any order, but every atom in the group must be listed in the file. Atoms not in the fix group may also be listed; they will be ignored. +Comments starting with '#' and empty lines may be included as well. + TMD statistics are written to file2 every N timesteps, unless N is specified as 0, which means no statistics. diff --git a/src/EXTRA-FIX/fix_tmd.cpp b/src/EXTRA-FIX/fix_tmd.cpp index 4d85687e4d..8ee6e3e141 100644 --- a/src/EXTRA-FIX/fix_tmd.cpp +++ b/src/EXTRA-FIX/fix_tmd.cpp @@ -27,6 +27,7 @@ #include "memory.h" #include "modify.h" #include "respa.h" +#include "tokenizer.h" #include "update.h" #include @@ -268,10 +269,8 @@ void FixTMD::initial_integrate(int /*vflag*/) work_lambda += lambda*(rho_target - rho_old); if (!(update->ntimestep % nfileevery) && (previous_stat != update->ntimestep)) { - fprintf(fp, - BIGINT_FORMAT " %g %g %g %g %g %g %g\n", - update->ntimestep,rho_target,rho_old, - gamma_back,gamma_forward,lambda,work_lambda,work_analytical); + fmt::print(fp, "{} {} {} {} {} {} {} {}\n", update->ntimestep,rho_target,rho_old, + gamma_back,gamma_forward,lambda,work_lambda,work_analytical); fflush(fp); previous_stat = update->ntimestep; } @@ -392,7 +391,7 @@ void FixTMD::readfile(char *file) char *buffer = new char[CHUNK*MAXLINE]; char *next,*bufptr; - int i,m,n,nlines,imageflag,ix,iy,iz; + int i,m,nlines,imageflag,ix,iy,iz; tagint itag; double x,y,z,xprd,yprd,zprd; @@ -422,53 +421,66 @@ void FixTMD::readfile(char *file) for (i = 0; i < nlines; i++) { next = strchr(bufptr,'\n'); *next = '\0'; - - if (firstline) { - if (utils::strmatch(bufptr,"^\\s*\\f+\\s+\\f+\\s+xlo\\s+xhi")) { - double lo,hi; - n = sscanf(bufptr,"%lg %lg",&lo,&hi); - if (n != 2) - error->all(FLERR,"Incorrect format in TMD target file"); - xprd = hi - lo; - bufptr = next + 1; - continue; - } else if (utils::strmatch(bufptr,"^\\s*\\f+\\s+\\f+\\s+ylo\\s+yhi")) { - double lo,hi; - n = sscanf(bufptr,"%lg %lg",&lo,&hi); - if (n != 2) - error->all(FLERR,"Incorrect format in TMD target file"); - yprd = hi - lo; - bufptr = next + 1; - continue; - } else if (utils::strmatch(bufptr,"^\\s*\\f+\\s+\\f+\\s+zlo\\s+zhi")) { - double lo,hi; - n = sscanf(bufptr,"%lg %lg",&lo,&hi); - if (n != 2) - error->all(FLERR,"Incorrect format in TMD target file"); - zprd = hi - lo; - bufptr = next + 1; - continue; - } else if (utils::trim_and_count_words(bufptr) == 4) { - if (xprd >= 0.0 || yprd >= 0.0 || zprd >= 0.0) - error->all(FLERR,"Incorrect format in TMD target file"); - imageflag = 0; - firstline = 0; - } else if (utils::trim_and_count_words(bufptr) == 7) { - if (xprd < 0.0 || yprd < 0.0 || zprd < 0.0) - error->all(FLERR,"Incorrect format in TMD target file"); - imageflag = 1; - firstline = 0; - } else error->all(FLERR,"Incorrect format in TMD target file"); + // trim comments and skip empty lines + char *comment = strchr(bufptr,'#'); + if (comment) *comment = '\0'; + if (!strlen(bufptr)) { + bufptr = next + 1; + continue; } - if (imageflag) - n = 7 - sscanf(bufptr,TAGINT_FORMAT " %lg %lg %lg %d %d %d", - &itag,&x,&y,&z,&ix,&iy,&iz); - else - n = 4 - sscanf(bufptr,TAGINT_FORMAT " %lg %lg %lg",&itag,&x,&y,&z); + if (firstline) { + try { + ValueTokenizer values(bufptr); - if (n != 0) { - error->all(FLERR,"Incorrectly formatted line in TMD target file"); + if (utils::strmatch(bufptr,"^\\s*\\f+\\s+\\f+\\s+xlo\\s+xhi")) { + auto lo = values.next_double(); + auto hi = values.next_double(); + xprd = hi - lo; + bufptr = next + 1; + continue; + } else if (utils::strmatch(bufptr,"^\\s*\\f+\\s+\\f+\\s+ylo\\s+yhi")) { + auto lo = values.next_double(); + auto hi = values.next_double(); + yprd = hi - lo; + bufptr = next + 1; + continue; + } else if (utils::strmatch(bufptr,"^\\s*\\f+\\s+\\f+\\s+zlo\\s+zhi")) { + auto lo = values.next_double(); + auto hi = values.next_double(); + zprd = hi - lo; + bufptr = next + 1; + continue; + } else if (utils::trim_and_count_words(bufptr) == 4) { + if (xprd >= 0.0 || yprd >= 0.0 || zprd >= 0.0) + throw TokenizerException("must use imageflags when providing box boundaries", bufptr); + imageflag = 0; + firstline = 0; + } else if (utils::trim_and_count_words(bufptr) == 7) { + if (xprd < 0.0 || yprd < 0.0 || zprd < 0.0) + throw TokenizerException("Invalid box boundaries",""); + imageflag = 1; + firstline = 0; + } else throw TokenizerException("unknown data", bufptr); + } + catch (std::exception &e) { + error->all(FLERR,"Incorrect format in TMD target file: {}", e.what()); + } + } + + try { + ValueTokenizer values(bufptr); + itag = values.next_tagint(); + x = values.next_double(); + y = values.next_double(); + z = values.next_double(); + if (imageflag) { + ix = values.next_int(); + iy = values.next_int(); + iz = values.next_int(); + } + } catch (std::exception &e) { + error->all(FLERR,"Incorrectly formatted line in TMD target file: {}", e.what()); bufptr = next + 1; continue; }