update parsing of file and atomfile variable files

this allows to handle comments and empty lines everywhere for atomfile
and file variables and in a consistent manner since it used utils functions.
also error messages are improved and more specific.
This commit is contained in:
Axel Kohlmeyer
2024-04-10 03:08:08 -04:00
parent 069919ddcd
commit 9f88867b37
2 changed files with 29 additions and 32 deletions

View File

@ -369,7 +369,8 @@ void Variable::set(int narg, char **arg)
data[nvar][0] = new char[MAXLINE]; data[nvar][0] = new char[MAXLINE];
reader[nvar] = new VarReader(lmp,arg[0],arg[2],SCALARFILE); reader[nvar] = new VarReader(lmp,arg[0],arg[2],SCALARFILE);
int flag = reader[nvar]->read_scalar(data[nvar][0]); int flag = reader[nvar]->read_scalar(data[nvar][0]);
if (flag) error->all(FLERR,"File variable could not read value"); if (flag)
error->all(FLERR,"File variable {} could not read value from {}", arg[0], arg[2]);
// ATOMFILE for numbers // ATOMFILE for numbers
// which = 1st value // which = 1st value
@ -387,7 +388,8 @@ void Variable::set(int narg, char **arg)
data[nvar][0] = nullptr; data[nvar][0] = nullptr;
reader[nvar] = new VarReader(lmp,arg[0],arg[2],ATOMFILE); reader[nvar] = new VarReader(lmp,arg[0],arg[2],ATOMFILE);
int flag = reader[nvar]->read_peratom(); int flag = reader[nvar]->read_peratom();
if (flag) error->all(FLERR,"Atomfile variable could not read values"); if (flag)
error->all(FLERR,"Atomfile variable {} could not read values from {}", arg[0], arg[2]);
// FORMAT // FORMAT
// num = 3, which = 1st value // num = 3, which = 1st value
@ -5405,7 +5407,8 @@ VarReader::VarReader(LAMMPS *lmp, char *name, char *file, int flag) :
if (me == 0) { if (me == 0) {
fp = fopen(file,"r"); fp = fopen(file,"r");
if (fp == nullptr) if (fp == nullptr)
error->one(FLERR,"Cannot open file variable file {}: {}", file, utils::getsyserror()); error->one(FLERR,"Cannot open {} variable {} file {}: {}", (style == Variable::ATOMFILE)
? "atomfile" : "file", name, file, utils::getsyserror());
} }
// if atomfile-style variable, must store per-atom values read from file // if atomfile-style variable, must store per-atom values read from file
@ -5463,14 +5466,12 @@ int VarReader::read_scalar(char *str)
while (true) { while (true) {
ptr = fgets(str,MAXLINE,fp); ptr = fgets(str,MAXLINE,fp);
if (!ptr) { n=0; break; } // end of file if (!ptr) { n=0; break; } // end of file
ptr[strcspn(ptr,"#")] = '\0'; // strip comment auto line = utils::trim(utils::trim_comment(str));
ptr += strspn(ptr," \t\n\r\f"); // strip leading whitespace n = line.size() + 1;
ptr[strcspn(ptr," \t\n\r\f")] = '\0'; // strip trailing whitespace
n = strlen(ptr) + 1;
if (n == 1) continue; // skip if blank line if (n == 1) continue; // skip if blank line
memcpy(str, line.c_str(), n);
break; break;
} }
if (n > 0) memmove(str,ptr,n); // move trimmed string back
} }
MPI_Bcast(&n,1,MPI_INT,0,world); MPI_Bcast(&n,1,MPI_INT,0,world);
if (n == 0) return 1; if (n == 0) return 1;
@ -5486,9 +5487,9 @@ int VarReader::read_scalar(char *str)
int VarReader::read_peratom() int VarReader::read_peratom()
{ {
int i,m,n,nchunk,eof; int i,m,nchunk,eof;
tagint tag; tagint tag;
char *ptr,*next; char *ptr;
double value; double value;
// set all per-atom values to 0.0 // set all per-atom values to 0.0
@ -5502,24 +5503,22 @@ int VarReader::read_peratom()
// read one string from file, convert to Nlines // read one string from file, convert to Nlines
char str[MAXLINE]; char str[MAXLINE];
bigint nlines = 0;
if (me == 0) { if (me == 0) {
while (true) { while (true) {
ptr = fgets(str,MAXLINE,fp); ptr = fgets(str,MAXLINE,fp);
if (!ptr) { n=0; break; } // end of file if (!ptr) { nlines = 0; break; } // end of file
ptr[strcspn(ptr,"#")] = '\0'; // strip comment Tokenizer words(utils::trim(utils::trim_comment(str)));
ptr += strspn(ptr," \t\n\r\f"); // strip leading whitespace if (words.count() == 0) continue; // skip if blank or comment line
ptr[strcspn(ptr," \t\n\r\f")] = '\0'; // strip trailing whitespace if (words.count() != 1)
n = strlen(ptr) + 1; error->one(FLERR, "Expected 1 token but found {} when parsing {}", words.count(), str);
if (n == 1) continue; // skip if blank line nlines = utils::bnumeric(FLERR,words.next(),true,lmp);
break; break;
} }
memmove(str,ptr,n); // move trimmed string back
} }
MPI_Bcast(&nlines,1,MPI_LMP_BIGINT,0,world);
if (nlines == 0) return 1;
MPI_Bcast(&n,1,MPI_INT,0,world);
if (n == 0) return 1;
MPI_Bcast(str,n,MPI_CHAR,0,world);
bigint nlines = utils::bnumeric(FLERR,str,false,lmp);
tagint map_tag_max = atom->map_tag_max; tagint map_tag_max = atom->map_tag_max;
bigint nread = 0; bigint nread = 0;
@ -5528,24 +5527,22 @@ int VarReader::read_peratom()
eof = utils::read_lines_from_file(fp,nchunk,MAXLINE,buffer,me,world); eof = utils::read_lines_from_file(fp,nchunk,MAXLINE,buffer,me,world);
if (eof) return 1; if (eof) return 1;
char *buf = buffer; for (const auto &line : utils::split_lines(buffer)) {
for (i = 0; i < nchunk; i++) {
next = strchr(buf,'\n');
*next = '\0';
try { try {
ValueTokenizer words(buf); ValueTokenizer words(utils::trim_comment(utils::trim(line)));
if (words.count() == 0) continue; // skip comment or empty lines
if (words.count() != 2)
throw TokenizerException(fmt::format("expected 2 tokens but found {}", words.count()), "");
tag = words.next_bigint(); tag = words.next_bigint();
value = words.next_double(); value = words.next_double();
++nread;
} catch (TokenizerException &e) { } catch (TokenizerException &e) {
error->all(FLERR,"Invalid atomfile line '{}': {}",buf,e.what()); error->all(FLERR,"Invalid atomfile line '{}': {}", line, e.what());
} }
if ((tag <= 0) || (tag > map_tag_max)) if ((tag <= 0) || (tag > map_tag_max))
error->all(FLERR,"Invalid atom ID {} in variable file", tag); error->all(FLERR,"Invalid atom ID {} in variable file", tag);
if ((m = atom->map(tag)) >= 0) vstore[m] = value; if ((m = atom->map(tag)) >= 0) vstore[m] = value;
buf = next + 1;
} }
nread += nchunk;
} }
return 0; return 0;

View File

@ -216,7 +216,7 @@ TEST_F(VariableTest, CreateDelete)
command("variable one internal 2");); command("variable one internal 2"););
TEST_FAILURE(".*ERROR: Cannot use atomfile-style variable unless an atom map exists.*", TEST_FAILURE(".*ERROR: Cannot use atomfile-style variable unless an atom map exists.*",
command("variable eleven atomfile test_variable.atomfile");); command("variable eleven atomfile test_variable.atomfile"););
TEST_FAILURE(".*ERROR on proc 0: Cannot open file variable file test_variable.xxx.*", TEST_FAILURE(".*ERROR on proc 0: Cannot open file variable nine1 file test_variable.xxx.*",
command("variable nine1 file test_variable.xxx");); command("variable nine1 file test_variable.xxx"););
TEST_FAILURE(".*ERROR: World variable count doesn't match # of partitions.*", TEST_FAILURE(".*ERROR: World variable count doesn't match # of partitions.*",
command("variable ten10 world xxx xxx");); command("variable ten10 world xxx xxx"););
@ -293,7 +293,7 @@ TEST_F(VariableTest, AtomicSystem)
command("variable one atom x");); command("variable one atom x"););
TEST_FAILURE(".*ERROR: Cannot redefine variable as a different style.*", TEST_FAILURE(".*ERROR: Cannot redefine variable as a different style.*",
command("variable id vector f_press");); command("variable id vector f_press"););
TEST_FAILURE(".*ERROR on proc 0: Cannot open file variable file test_variable.xxx.*", TEST_FAILURE(".*ERROR on proc 0: Cannot open atomfile variable ten1 file test_variable.xxx.*",
command("variable ten1 atomfile test_variable.xxx");); command("variable ten1 atomfile test_variable.xxx"););
TEST_FAILURE(".*ERROR: Variable loop: has a circular dependency.*", TEST_FAILURE(".*ERROR: Variable loop: has a circular dependency.*",
variable->compute_equal("v_loop");); variable->compute_equal("v_loop"););