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
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
variable, as discussed below. Unlike most variable styles
atomfile-style variables are **deleted** during a :doc:`clear <clear>`
command.
variable, as discussed below. Unlike most variable styles, which
remain defined, atomfile-style variables are **deleted** during a
:doc:`clear <clear>` command.
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.
@ -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
on a line and all text following and the "#" character are ignored;
text starting with the comment character is stripped. Blank lines
are skipped. The first "word" of a non-blank line, delimited by
white-space, is read as the count N of per-atom lines to immediately
follow. N can be the total number of atoms in the system, or only a
subset. The next N lines have the following format
.. parsed-literal::
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.
are skipped. The first non-blank line is expected to contain a single
integer number as the count *N* of per-atom lines to follow. *N* can
be the total number of atoms in the system or less, indicating that data
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
point number with the value. The atom-IDs may be listed in any order.
.. note::
Every time a set of per-atom lines is read, the value for all
atoms is first set to 0.0. Thus values for atoms whose ID does not
appear in the set, will remain 0.0.
Every time a set of per-atom lines is read, the value of the atomfile
variable for **all** atoms is first initialized to 0.0. Thus values
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];
reader[nvar] = new VarReader(lmp,arg[0],arg[2],SCALARFILE);
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
// which = 1st value
@ -387,7 +388,8 @@ void Variable::set(int narg, char **arg)
data[nvar][0] = nullptr;
reader[nvar] = new VarReader(lmp,arg[0],arg[2],ATOMFILE);
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
// num = 3, which = 1st value
@ -5405,7 +5407,8 @@ VarReader::VarReader(LAMMPS *lmp, char *name, char *file, int flag) :
if (me == 0) {
fp = fopen(file,"r");
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
@ -5463,14 +5466,12 @@ int VarReader::read_scalar(char *str)
while (true) {
ptr = fgets(str,MAXLINE,fp);
if (!ptr) { n=0; break; } // end of file
ptr[strcspn(ptr,"#")] = '\0'; // strip comment
ptr += strspn(ptr," \t\n\r\f"); // strip leading whitespace
ptr[strcspn(ptr," \t\n\r\f")] = '\0'; // strip trailing whitespace
n = strlen(ptr) + 1;
auto line = utils::trim(utils::trim_comment(str));
n = line.size() + 1;
if (n == 1) continue; // skip if blank line
memcpy(str, line.c_str(), n);
break;
}
if (n > 0) memmove(str,ptr,n); // move trimmed string back
}
MPI_Bcast(&n,1,MPI_INT,0,world);
if (n == 0) return 1;
@ -5486,9 +5487,9 @@ int VarReader::read_scalar(char *str)
int VarReader::read_peratom()
{
int i,m,n,nchunk,eof;
int i,m,nchunk,eof;
tagint tag;
char *ptr,*next;
char *ptr;
double value;
// set all per-atom values to 0.0
@ -5502,24 +5503,22 @@ int VarReader::read_peratom()
// read one string from file, convert to Nlines
char str[MAXLINE];
bigint nlines = 0;
if (me == 0) {
while (true) {
ptr = fgets(str,MAXLINE,fp);
if (!ptr) { n=0; break; } // end of file
ptr[strcspn(ptr,"#")] = '\0'; // strip comment
ptr += strspn(ptr," \t\n\r\f"); // strip leading whitespace
ptr[strcspn(ptr," \t\n\r\f")] = '\0'; // strip trailing whitespace
n = strlen(ptr) + 1;
if (n == 1) continue; // skip if blank line
if (!ptr) { nlines = 0; break; } // end of file
Tokenizer words(utils::trim(utils::trim_comment(str)));
if (words.count() == 0) continue; // skip if blank or comment line
if (words.count() != 1)
error->one(FLERR, "Expected 1 token but found {} when parsing {}", words.count(), str);
nlines = utils::bnumeric(FLERR,words.next(),true,lmp);
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;
bigint nread = 0;
@ -5528,24 +5527,22 @@ int VarReader::read_peratom()
eof = utils::read_lines_from_file(fp,nchunk,MAXLINE,buffer,me,world);
if (eof) return 1;
char *buf = buffer;
for (i = 0; i < nchunk; i++) {
next = strchr(buf,'\n');
*next = '\0';
for (const auto &line : utils::split_lines(buffer)) {
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();
value = words.next_double();
++nread;
} 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))
error->all(FLERR,"Invalid atom ID {} in variable file", tag);
if ((m = atom->map(tag)) >= 0) vstore[m] = value;
buf = next + 1;
}
nread += nchunk;
}
return 0;

View File

@ -216,7 +216,7 @@ TEST_F(VariableTest, CreateDelete)
command("variable one internal 2"););
TEST_FAILURE(".*ERROR: Cannot use atomfile-style variable unless an atom map exists.*",
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"););
TEST_FAILURE(".*ERROR: World variable count doesn't match # of partitions.*",
command("variable ten10 world xxx xxx"););
@ -293,7 +293,7 @@ TEST_F(VariableTest, AtomicSystem)
command("variable one atom x"););
TEST_FAILURE(".*ERROR: Cannot redefine variable as a different style.*",
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"););
TEST_FAILURE(".*ERROR: Variable loop: has a circular dependency.*",
variable->compute_equal("v_loop"););