allow vector variable to be initialized

This commit is contained in:
Steve Plimpton
2023-05-03 16:36:05 -06:00
parent c9cfc952aa
commit 936b24e3b0
2 changed files with 113 additions and 6 deletions

View File

@ -479,6 +479,8 @@ void Variable::set(int narg, char **arg)
// replace pre-existing var if also style VECTOR (allows it to be reset) // replace pre-existing var if also style VECTOR (allows it to be reset)
// num = 1, which = 1st value // num = 1, which = 1st value
// data = 1 value, string to eval // data = 1 value, string to eval
// if formula string is [value,value,...] then
// immediately store it as N-length vector and set dynamic flag to 0
} else if (strcmp(arg[1],"vector") == 0) { } else if (strcmp(arg[1],"vector") == 0) {
if (narg != 3) error->all(FLERR,"Illegal variable command: expected 3 arguments but found {}", narg); if (narg != 3) error->all(FLERR,"Illegal variable command: expected 3 arguments but found {}", narg);
@ -488,6 +490,10 @@ void Variable::set(int narg, char **arg)
error->all(FLERR,"Cannot redefine variable as a different style"); error->all(FLERR,"Cannot redefine variable as a different style");
delete[] data[ivar][0]; delete[] data[ivar][0];
data[ivar][0] = utils::strdup(arg[2]); data[ivar][0] = utils::strdup(arg[2]);
if (data[ivar][0][0] == '[') {
parse_vector(ivar,data[ivar][0]);
vecs[ivar].dynamic = 0;
} else vecs[ivar].dynamic = 1;
replaceflag = 1; replaceflag = 1;
} else { } else {
if (nvar == maxvar) grow(); if (nvar == maxvar) grow();
@ -497,6 +503,10 @@ void Variable::set(int narg, char **arg)
pad[nvar] = 0; pad[nvar] = 0;
data[nvar] = new char*[num[nvar]]; data[nvar] = new char*[num[nvar]];
data[nvar][0] = utils::strdup(arg[2]); data[nvar][0] = utils::strdup(arg[2]);
if (data[nvar][0][0] == '[') {
parse_vector(nvar,data[nvar][0]);
vecs[nvar].dynamic = 0;
} else vecs[nvar].dynamic = 1;
} }
// PYTHON // PYTHON
@ -1137,18 +1147,30 @@ void Variable::compute_atom(int ivar, int igroup, double *result, int stride, in
compute result of vector-style variable evaluation compute result of vector-style variable evaluation
return length of vector and result pointer to vector values return length of vector and result pointer to vector values
if length == 0 or -1 (mismatch), generate an error if length == 0 or -1 (mismatch), generate an error
if variable already computed on this timestep, just return if necessary, evaluate the formula and its length,
else evaluate the formula and its length, store results in VecVar entry store results in VecVar entry and return them
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
int Variable::compute_vector(int ivar, double **result) int Variable::compute_vector(int ivar, double **result)
{ {
Tree *tree = nullptr; Tree *tree = nullptr;
// if vector is not dynamic, just return stored values
if (!vecs[ivar].dynamic) {
*result = vecs[ivar].values;
return vecs[ivar].n;
}
// if vector already computed on this timestep, just return stored values
if (vecs[ivar].currentstep == update->ntimestep) { if (vecs[ivar].currentstep == update->ntimestep) {
*result = vecs[ivar].values; *result = vecs[ivar].values;
return vecs[ivar].n; return vecs[ivar].n;
} }
// evaluate vector afresh
if (eval_in_progress[ivar]) if (eval_in_progress[ivar])
print_var_error(FLERR,"has a circular dependency",ivar); print_var_error(FLERR,"has a circular dependency",ivar);
@ -1246,7 +1268,8 @@ void Variable::grow()
vecs = (VecVar *) memory->srealloc(vecs,maxvar*sizeof(VecVar),"var:vecvar"); vecs = (VecVar *) memory->srealloc(vecs,maxvar*sizeof(VecVar),"var:vecvar");
for (int i = old; i < maxvar; i++) { for (int i = old; i < maxvar; i++) {
vecs[i].nmax = 0; vecs[i].n = vecs[i].nmax = 0;
vecs[i].dynamic = 1;
vecs[i].currentstep = -1; vecs[i].currentstep = -1;
vecs[i].values = nullptr; vecs[i].values = nullptr;
} }
@ -4008,8 +4031,13 @@ int Variable::special_function(char *word, char *contents, Tree **tree, Tree **t
if (!atom->labelmapflag) if (!atom->labelmapflag)
print_var_error(FLERR,"Cannot use label2type() function without a labelmap",ivar); print_var_error(FLERR,"Cannot use label2type() function without a labelmap",ivar);
std::string typestr(args[0]); std::string contents_copy(contents);
std::string kind(args[1]); auto pos = contents_copy.find_first_of(',');
if (pos == std::string::npos)
print_var_error(FLERR, fmt::format("Invalid label2type({}) function in variable formula",
contents_copy), ivar);
std::string typestr = contents_copy.substr(pos+1);
std::string kind = contents_copy.substr(0, pos);
int value = -1; int value = -1;
if (kind == "atom") { if (kind == "atom") {
@ -4692,6 +4720,52 @@ void Variable::atom_vector(char *word, Tree **tree, Tree **treestack, int &ntree
else if (strcmp(word,"fz") == 0) newtree->array = &atom->f[0][2]; else if (strcmp(word,"fz") == 0) newtree->array = &atom->f[0][2];
} }
/* ----------------------------------------------------------------------
parse vector string with format [value,value,...] for vector-style variable
store numeric values in vecs[ivar]
------------------------------------------------------------------------- */
void Variable::parse_vector(int ivar, char *str)
{
// unlimited allows for any vector length
char **args;
int nvec = parse_args_unlimited(str,args);
if (args[nvec-1][strlen(args[nvec-1])-1] != ']')
error->all(FLERR,"Vector variable formula lacks closing brace: {}",str);
vecs[ivar].n = nvec;
vecs[ivar].nmax = nvec;
vecs[ivar].currentstep = -1;
memory->destroy(vecs[ivar].values);
memory->create(vecs[ivar].values,vecs[ivar].nmax,"variable:values");
char *onearg,*copy;
for (int i = 0; i < nvec; i++) {
onearg = utils::strdup(args[i]);
if (onearg[0] == '[') {
copy = utils::strdup(utils::trim(&onearg[1]));
delete[] onearg;
onearg = copy;
}
if (onearg[strlen(onearg)-1] == ']') {
onearg[strlen(onearg)-1] = '\0';
copy = utils::strdup(utils::trim(onearg));
delete[] onearg;
onearg = copy;
}
vecs[ivar].values[i] = utils::numeric(FLERR, onearg, false, lmp);
delete[] onearg;
}
// delete stored args
for (int i = 0; i < nvec; i++) delete[] args[i];
memory->sfree(args);
}
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
parse string for comma-separated args parse string for comma-separated args
store copy of each arg in args array store copy of each arg in args array
@ -4717,6 +4791,37 @@ int Variable::parse_args(char *str, char **args)
return narg; return narg;
} }
/* ----------------------------------------------------------------------
parse string for comma-separated args
store copy of each arg in args array
grow args array as large as needed
------------------------------------------------------------------------- */
int Variable::parse_args_unlimited(char *str, char **&args)
{
char *ptrnext;
int narg = 0;
char *ptr = str;
int maxarg = 0;
args = nullptr;
while (ptr) {
ptrnext = find_next_comma(ptr);
if (ptrnext) *ptrnext = '\0';
if (narg == maxarg) {
maxarg += CHUNK;
args = (char **) memory->srealloc(args,maxarg*sizeof(char *),"variable:args");
}
args[narg] = utils::strdup(utils::trim(ptr));
narg++;
ptr = ptrnext;
if (ptr) ptr++;
}
return narg;
}
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
find next comma in str find next comma in str
skip commas inside one or more nested parenthesis skip commas inside one or more nested parenthesis
@ -4734,7 +4839,6 @@ char *Variable::find_next_comma(char *str)
return nullptr; return nullptr;
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
helper routine for printing variable name with error message helper routine for printing variable name with error message
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */

View File

@ -90,6 +90,7 @@ class Variable : protected Pointers {
struct VecVar { struct VecVar {
int n, nmax; int n, nmax;
int dynamic;
bigint currentstep; bigint currentstep;
double *values; double *values;
}; };
@ -146,6 +147,8 @@ class Variable : protected Pointers {
int is_atom_vector(char *); int is_atom_vector(char *);
void atom_vector(char *, Tree **, Tree **, int &); void atom_vector(char *, Tree **, Tree **, int &);
int parse_args(char *, char **); int parse_args(char *, char **);
int parse_args_unlimited(char *, char **&);
void parse_vector(int, char *);
char *find_next_comma(char *); char *find_next_comma(char *);
void print_var_error(const std::string &, int, const std::string &, int, int global = 1); void print_var_error(const std::string &, int, const std::string &, int, int global = 1);
void print_tree(Tree *, int); void print_tree(Tree *, int);