From b9dbfc6eb23f428f15221126464c1f7657c8efc5 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 17 Jan 2025 10:40:34 -0500 Subject: [PATCH] add support to flag failed arguments for calls to expand_args() --- src/fix_ave_time.cpp | 41 ++++++++++++++++++------------- src/fix_ave_time.h | 1 + src/utils.cpp | 57 ++++++++++++++++++++++++++++---------------- src/utils.h | 27 +++++++++++++-------- 4 files changed, 78 insertions(+), 48 deletions(-) diff --git a/src/fix_ave_time.cpp b/src/fix_ave_time.cpp index 72ff8ab6c1..8c7d902b86 100644 --- a/src/fix_ave_time.cpp +++ b/src/fix_ave_time.cpp @@ -68,7 +68,7 @@ FixAveTime::FixAveTime(LAMMPS *lmp, int narg, char **arg) : } else break; } if (nvalues == 0) - error->all(FLERR,"No values from computes, fixes, or variables used in fix ave/time command"); + error->all(FLERR, 6, "No values from computes, fixes, or variables used in fix ave/time command"); // parse optional keywords @@ -79,7 +79,8 @@ FixAveTime::FixAveTime(LAMMPS *lmp, int narg, char **arg) : int expand = 0; char **earg; - nvalues = utils::expand_args(FLERR,nvalues,&arg[6],mode,earg,lmp); + int *amap; + nvalues = utils::expand_args(FLERR,nvalues,&arg[6],mode,earg,lmp,&amap); key2col.clear(); if (earg != &arg[6]) expand = 1; @@ -97,9 +98,10 @@ FixAveTime::FixAveTime(LAMMPS *lmp, int narg, char **arg) : key2col[arg[i]] = i; if ((val.which == ArgInfo::NONE) || (val.which == ArgInfo::UNKNOWN) || (argi.get_dim() > 1)) - error->all(FLERR,"Invalid fix ave/time argument: {}", arg[i]); + error->all(FLERR, amap[i]+6,"Invalid fix ave/time argument: {}", arg[i]); val.argindex = argi.get_index1(); + val.iarg = amap[i] + 6; val.varlen = 0; val.offcol = 0; val.id = argi.get_name(); @@ -122,9 +124,9 @@ FixAveTime::FixAveTime(LAMMPS *lmp, int narg, char **arg) : // for fix inputs, check that fix frequency is acceptable // set variable_length if any compute is variable length - if (nevery <= 0) error->all(FLERR,"Illegal fix ave/time nevery value: {}", nevery); - if (nrepeat <= 0) error->all(FLERR,"Illegal fix ave/time nrepeat value: {}", nrepeat); - if (nfreq <= 0) error->all(FLERR,"Illegal fix ave/time nfreq value: {}", nfreq); + if (nevery <= 0) error->all(FLERR, 3, "Illegal fix ave/time nevery value: {}", nevery); + if (nrepeat <= 0) error->all(FLERR, 4, "Illegal fix ave/time nrepeat value: {}", nrepeat); + if (nfreq <= 0) error->all(FLERR, 5, "Illegal fix ave/time nfreq value: {}", nfreq); if (nfreq % nevery || nrepeat*nevery > nfreq) error->all(FLERR,"Inconsistent fix ave/time nevery/nrepeat/nfreq values"); if (ave != RUNNING && overwrite) @@ -134,25 +136,29 @@ FixAveTime::FixAveTime(LAMMPS *lmp, int narg, char **arg) : if ((val.which == ArgInfo::COMPUTE) && (mode == SCALAR)) { val.val.c = modify->get_compute_by_id(val.id); - if (!val.val.c) error->all(FLERR,"Compute ID {} for fix ave/time does not exist", val.id); + if (!val.val.c) + error->all(FLERR, val.iarg, "Compute ID {} for fix ave/time does not exist", val.id); if (val.argindex == 0 && (val.val.c->scalar_flag == 0)) - error->all(FLERR,"Fix ave/time compute {} does not calculate a scalar", val.id); + error->all(FLERR, val.iarg, "Fix ave/time compute {} does not calculate a scalar", val.id); if (val.argindex && (val.val.c->vector_flag == 0)) - error->all(FLERR,"Fix ave/time compute {} does not calculate a vector", val.id); + error->all(FLERR, val.iarg, "Fix ave/time compute {} does not calculate a vector", val.id); if (val.argindex && (val.argindex > val.val.c->size_vector) && (val.val.c->size_vector_variable == 0)) - error->all(FLERR, "Fix ave/time compute {} vector is accessed out-of-range", val.id); + error->all(FLERR, val.iarg, "Fix ave/time compute {} vector is accessed out-of-range", + val.id); if (val.argindex && val.val.c->size_vector_variable) val.varlen = 1; } else if ((val.which == ArgInfo::COMPUTE) && (mode == VECTOR)) { val.val.c = modify->get_compute_by_id(val.id); - if (!val.val.c) error->all(FLERR,"Compute ID {} for fix ave/time does not exist", val.id); + if (!val.val.c) + error->all(FLERR, val.iarg, "Compute ID {} for fix ave/time does not exist", val.id); if ((val.argindex == 0) && (val.val.c->vector_flag == 0)) - error->all(FLERR,"Fix ave/time compute {} does not calculate a vector", val.id); + error->all(FLERR, val.iarg, "Fix ave/time compute {} does not calculate a vector", val.id); if (val.argindex && (val.val.c->array_flag == 0)) - error->all(FLERR,"Fix ave/time compute {} does not calculate an array", val.id); + error->all(FLERR, val.iarg, "Fix ave/time compute {} does not calculate an array", val.id); if (val.argindex && (val.argindex > val.val.c->size_array_cols)) - error->all(FLERR,"Fix ave/time compute {} array is accessed out-of-range", val.id); + error->all(FLERR, val.iarg, "Fix ave/time compute {} array is accessed out-of-range", + val.id); if ((val.argindex == 0) && (val.val.c->size_vector_variable)) val.varlen = 1; if (val.argindex && (val.val.c->size_array_rows_variable)) val.varlen = 1; @@ -1042,7 +1048,7 @@ void FixAveTime::options(int iarg, int narg, char **arg) if (strcmp(arg[iarg],"file") == 0) fp = fopen(arg[iarg+1],"w"); else fp = fopen(arg[iarg+1],"a"); if (fp == nullptr) - error->one(FLERR,"Cannot open fix ave/time file {}: {}", + error->one(FLERR, iarg+1, "Cannot open fix ave/time file {}: {}", arg[iarg+1], utils::getsyserror()); } iarg += 2; @@ -1051,12 +1057,13 @@ void FixAveTime::options(int iarg, int narg, char **arg) if (strcmp(arg[iarg+1],"one") == 0) ave = ONE; else if (strcmp(arg[iarg+1],"running") == 0) ave = RUNNING; else if (strcmp(arg[iarg+1],"window") == 0) ave = WINDOW; - else error->all(FLERR,"Unknown fix ave/time ave keyword {}", arg[iarg+1]); + else error->all(FLERR, iarg+1, "Unknown fix ave/time ave keyword {}", arg[iarg+1]); if (ave == WINDOW) { if (iarg+3 > narg) utils::missing_cmd_args(FLERR, "fix ave/time ave window", error); nwindow = utils::inumeric(FLERR,arg[iarg+2],false,lmp); if (nwindow <= 0) - error->all(FLERR,"Illegal fix ave/time ave window argument {}; must be > 0", nwindow); + error->all(FLERR, iarg+2, "Illegal fix ave/time ave window argument {}; must be > 0", + nwindow); } iarg += 2; if (ave == WINDOW) iarg++; diff --git a/src/fix_ave_time.h b/src/fix_ave_time.h index 5b25a68ab5..5aedc4443d 100644 --- a/src/fix_ave_time.h +++ b/src/fix_ave_time.h @@ -43,6 +43,7 @@ class FixAveTime : public Fix { struct value_t { int which; // type of data: COMPUTE, FIX, VARIABLE int argindex; // 1-based index if data is vector, else 0 + int iarg; // argument index in original argument list int varlen; // 1 if value is from variable-length compute int offcol; std::string id; // compute/fix/variable ID diff --git a/src/utils.cpp b/src/utils.cpp index 4cb87d0131..90d165202a 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -136,7 +136,7 @@ std::string utils::point_to_error(Input *input, int failed) { if (input) { std::string cmdline = "--> parsed line: "; - int indicator = cmdline.size(); // error indicator points to command by default + int indicator = cmdline.size(); // error indicator points to command by default cmdline += input->command; cmdline += ' '; @@ -156,7 +156,8 @@ std::string utils::point_to_error(Input *input, int failed) cmdline += inputarg; cmdline += '"'; } - } else cmdline += inputarg; + } else + cmdline += inputarg; cmdline += ' '; } // construct and append error indicator line @@ -165,7 +166,8 @@ std::string utils::point_to_error(Input *input, int failed) cmdline += std::string(strlen(input->arg[failed]), '^'); cmdline += '\n'; return cmdline; - } else return std::string("(Failed command line text not available)"); + } else + return std::string("(Failed command line text not available)"); } /* specialization for the case of just a single string argument */ @@ -682,14 +684,14 @@ tagint utils::tnumeric(const char *file, int line, const char *str, bool do_abor // clang-format off template void utils::bounds(const char *file, int line, const std::string &str, - bigint nmin, bigint nmax, TYPE &nlo, TYPE &nhi, Error *error) + bigint nmin, bigint nmax, TYPE &nlo, TYPE &nhi, Error *error, int failed) { nlo = nhi = -1; // check for illegal characters size_t found = str.find_first_not_of("*-0123456789"); if (found != std::string::npos) { - if (error) error->all(file, line, "Invalid range string: {}", str); + if (error) error->all(file, line, failed, "Invalid range string: {}", str); return; } @@ -712,23 +714,23 @@ void utils::bounds(const char *file, int line, const std::string &str, if (error) { if ((nlo <= 0) || (nhi <= 0)) - error->all(file, line, "Invalid range string: {}", str); + error->all(file, line, failed, "Invalid range string: {}", str); if (nlo < nmin) - error->all(file, line, "Numeric index {} is out of bounds ({}-{})", nlo, nmin, nmax); + error->all(file, line, failed, "Numeric index {} is out of bounds ({}-{})", nlo, nmin, nmax); else if (nhi > nmax) - error->all(file, line, "Numeric index {} is out of bounds ({}-{})", nhi, nmin, nmax); + error->all(file, line, failed, "Numeric index {} is out of bounds ({}-{})", nhi, nmin, nmax); else if (nlo > nhi) - error->all(file, line, "Numeric index {} is out of bounds ({}-{})", nlo, nmin, nhi); + error->all(file, line, failed, "Numeric index {} is out of bounds ({}-{})", nlo, nmin, nhi); } } template void utils::bounds<>(const char *, int, const std::string &, - bigint, bigint, int &, int &, Error *); + bigint, bigint, int &, int &, Error *, int); template void utils::bounds<>(const char *, int, const std::string &, - bigint, bigint, long &, long &, Error *); + bigint, bigint, long &, long &, Error *, int); template void utils::bounds<>(const char *, int, const std::string &, - bigint, bigint, long long &, long long &, Error *); + bigint, bigint, long long &, long long &, Error *, int); // clang-format on /* ---------------------------------------------------------------------- @@ -768,7 +770,7 @@ template void utils::bounds_typelabel<>(const char *, int, const std::string &, ------------------------------------------------------------------------- */ int utils::expand_args(const char *file, int line, int narg, char **arg, int mode, char **&earg, - LAMMPS *lmp) + LAMMPS *lmp, int **argmap) { int iarg; @@ -783,10 +785,16 @@ int utils::expand_args(const char *file, int line, int narg, char **arg, int mod return narg; } + // determine argument offset + int ioffset = 0; + for (int i = 0; i < lmp->input->narg; ++i) + if (lmp->input->arg[i] == arg[0]) ioffset = i; + // maxarg should always end up equal to newarg, so caller can free earg int maxarg = narg - iarg; - earg = (char **) lmp->memory->smalloc(maxarg * sizeof(char *), "input:earg"); + earg = (char **) lmp->memory->smalloc(maxarg * sizeof(char *), "expand_args:earg"); + int *amap = (int *) lmp->memory->smalloc(maxarg * sizeof(int), "expand_args:amap"); int newarg = 0, expandflag, nlo, nhi, nmax; std::string id, wc, tail; @@ -849,16 +857,18 @@ int utils::expand_args(const char *file, int line, int narg, char **arg, int mod // expand wild card string to nlo/nhi numbers if (expandflag) { - utils::bounds(file, line, wc, 1, nmax, nlo, nhi, lmp->error); + utils::bounds(file, line, wc, 1, nmax, nlo, nhi, lmp->error, iarg + ioffset); if (newarg + nhi - nlo + 1 > maxarg) { maxarg += nhi - nlo + 1; - earg = (char **) lmp->memory->srealloc(earg, maxarg * sizeof(char *), "input:earg"); + earg = (char **) lmp->memory->srealloc(earg, maxarg * sizeof(char *), "expand_args:earg"); + amap = (int *) lmp->memory->srealloc(amap, maxarg * sizeof(char *), "expand_args:amap"); } for (int index = nlo; index <= nhi; index++) { earg[newarg] = utils::strdup(fmt::format("{}:{}:{}[{}]{}", gridid[0], gridid[1], id, index, tail)); + amap[newarg] = iarg; newarg++; } } @@ -936,7 +946,7 @@ int utils::expand_args(const char *file, int line, int narg, char **arg, int mod if (index >= 0) { if (mode == 0 && lmp->input->variable->vectorstyle(index)) { - utils::bounds(file, line, wc, 1, MAXSMALLINT, nlo, nhi, lmp->error); + utils::bounds(file, line, wc, 1, MAXSMALLINT, nlo, nhi, lmp->error, iarg + ioffset); if (nhi < MAXSMALLINT) { nmax = nhi; expandflag = 1; @@ -968,11 +978,12 @@ int utils::expand_args(const char *file, int line, int narg, char **arg, int mod // expand wild card string to nlo/nhi numbers - utils::bounds(file, line, wc, 1, nmax, nlo, nhi, lmp->error); + utils::bounds(file, line, wc, 1, nmax, nlo, nhi, lmp->error, iarg + ioffset); if (newarg + nhi - nlo + 1 > maxarg) { maxarg += nhi - nlo + 1; - earg = (char **) lmp->memory->srealloc(earg, maxarg * sizeof(char *), "input:earg"); + earg = (char **) lmp->memory->srealloc(earg, maxarg * sizeof(char *), "expand_args:earg"); + amap = (int *) lmp->memory->srealloc(amap, maxarg * sizeof(char *), "expand_args:amap"); } for (int index = nlo; index <= nhi; index++) { @@ -980,6 +991,7 @@ int utils::expand_args(const char *file, int line, int narg, char **arg, int mod earg[newarg] = utils::strdup(fmt::format("{}2_{}[{}]{}", word[0], id, index, tail)); else earg[newarg] = utils::strdup(fmt::format("{}_{}[{}]{}", word[0], id, index, tail)); + amap[newarg] = iarg; newarg++; } } @@ -990,14 +1002,17 @@ int utils::expand_args(const char *file, int line, int narg, char **arg, int mod if (!expandflag) { if (newarg == maxarg) { maxarg++; - earg = (char **) lmp->memory->srealloc(earg, maxarg * sizeof(char *), "input:earg"); + earg = (char **) lmp->memory->srealloc(earg, maxarg * sizeof(char *), "expand_args:earg"); + amap = (int *) lmp->memory->srealloc(amap, maxarg * sizeof(char *), "expand_args:amap"); } earg[newarg] = utils::strdup(word); + amap[newarg] = iarg; newarg++; } } - // printf("NEWARG %d\n",newarg); for (int i = 0; i < newarg; i++) printf(" arg %d: %s\n",i,earg[i]); + if (argmap && *argmap) *argmap = amap; + // fprintf(stderr, "NEWARG %d\n",newarg); for (int i = 0; i < newarg; i++) printf(" arg %d: %s %d\n",i,earg[i], amap ? amap[i] : -1); return newarg; } diff --git a/src/utils.h b/src/utils.h index 63f0643616..1854c07cf5 100644 --- a/src/utils.h +++ b/src/utils.h @@ -336,11 +336,12 @@ namespace utils { * \param nmax largest allowed upper bound * \param nlo lower bound * \param nhi upper bound - * \param error pointer to Error class for out-of-bounds messages */ + * \param error pointer to Error class for out-of-bounds messages + * \param failed argument index with failed expansion (optional) */ template void bounds(const char *file, int line, const std::string &str, bigint nmin, bigint nmax, - TYPE &nlo, TYPE &nhi, Error *error); + TYPE &nlo, TYPE &nhi, Error *error, int failed = -2); // -2 = Error::NOPOINTER /*! Same as utils::bounds(), but string may be a typelabel * @@ -386,17 +387,23 @@ This functions adds the following case to :cpp:func:`utils::bounds()