Merge branch 'develop' into pedone-potentials

This commit is contained in:
Axel Kohlmeyer
2024-04-10 18:02:31 -04:00
3 changed files with 60 additions and 49 deletions

View File

@ -279,9 +279,9 @@ This means the variable can then be evaluated as many times as desired
and will return those values. There are two ways to cause the next and will return those values. There are two ways to cause the next
set of per-atom values from the file to be read: use the set of per-atom values from the file to be read: use the
:doc:`next <next>` command or the next() function in an atom-style :doc:`next <next>` command or the next() function in an atom-style
variable, as discussed below. Unlike most variable styles variable, as discussed below. Unlike most variable styles, which
atomfile-style variables are **deleted** during a :doc:`clear <clear>` remain defined, atomfile-style variables are **deleted** during a
command. :doc:`clear <clear>` command.
The rules for formatting the file are as follows. Each time a set of The rules for formatting the file are as follows. Each time a set of
per-atom values is read, a non-blank line is searched for in the file. per-atom values is read, a non-blank line is searched for in the file.
@ -289,23 +289,37 @@ The file is read line by line but only up to 254 characters are used.
The rest are ignored. A comment character "#" can be used anywhere The rest are ignored. A comment character "#" can be used anywhere
on a line and all text following and the "#" character are ignored; on a line and all text following and the "#" character are ignored;
text starting with the comment character is stripped. Blank lines text starting with the comment character is stripped. Blank lines
are skipped. The first "word" of a non-blank line, delimited by are skipped. The first non-blank line is expected to contain a single
white-space, is read as the count N of per-atom lines to immediately integer number as the count *N* of per-atom lines to follow. *N* can
follow. N can be the total number of atoms in the system, or only a be the total number of atoms in the system or less, indicating that data
subset. The next N lines have the following format for a subset is read. The next N lines must consist of two numbers,
the atom-ID of the atom for which a value is set followed by a floating
.. parsed-literal:: point number with the value. The atom-IDs may be listed in any order.
ID value
where ID is an atom ID and value is the per-atom numeric value that
will be assigned to that atom. IDs can be listed in any order.
.. note:: .. note::
Every time a set of per-atom lines is read, the value for all Every time a set of per-atom lines is read, the value of the atomfile
atoms is first set to 0.0. Thus values for atoms whose ID does not variable for **all** atoms is first initialized to 0.0. Thus values
appear in the set, will remain 0.0. for atoms whose ID do not appear in the set in the file will remain
at 0.0.
Below is a small example for the atomfile variable file format:
.. parsed-literal::
# first set
4
# atom-ID value
3 1
4 -4
1 0.5
2 -0.5
# second set
2
2 1.0
4 -1.0
---------- ----------

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"););