diff --git a/src/ASPHERE/compute_temp_asphere.cpp b/src/ASPHERE/compute_temp_asphere.cpp index 5920002dc1c332314eed17c16047ff70eebbbffd..79c55fc24c10a1c1149c254091989d19167d38f2 100755 --- a/src/ASPHERE/compute_temp_asphere.cpp +++ b/src/ASPHERE/compute_temp_asphere.cpp @@ -31,8 +31,6 @@ using namespace LAMMPS_NS; -enum{DUMMY0,INVOKED_SCALAR,INVOKED_VECTOR,DUMMMY3,INVOKED_PERATOM}; - /* ---------------------------------------------------------------------- */ ComputeTempAsphere::ComputeTempAsphere(LAMMPS *lmp, int narg, char **arg) : diff --git a/src/compute.h b/src/compute.h index bf3aae4708a4facc54870e578d0e2cdc17fac849..83a6882b57ffeac0c15d387086beea254fbc5358 100644 --- a/src/compute.h +++ b/src/compute.h @@ -25,7 +25,7 @@ class Compute : protected Pointers { double scalar; // computed global scalar double *vector; // computed global vector - double *array; // computed global array + double **array; // computed global array double *vector_atom; // computed per-atom vector double **array_atom; // computed per-atom array double *vector_local; // computed local vector @@ -48,7 +48,7 @@ class Compute : protected Pointers { int extscalar; // 0/1 if global scalar is intensive/extensive int extvector; // 0/1/-1 if global vector is all int/ext/extlist int *extlist; // list of 0/1 int/ext for each vec component - int extarray; // 0/1 if global array is intensive/extensive + int extarray; // 0/1 if global array is all intensive/extensive int tempflag; // 1 if Compute can be used as temperature // must have both compute_scalar, compute_vector diff --git a/src/compute_heat_flux.cpp b/src/compute_heat_flux.cpp index 738509903cf78c41ccdb4733a811eca289d04855..e038020524b309b21a95ba071c4b14881fcf4331 100644 --- a/src/compute_heat_flux.cpp +++ b/src/compute_heat_flux.cpp @@ -35,7 +35,7 @@ using namespace LAMMPS_NS; -enum{DUMMY0,INVOKED_SCALAR,INVOKED_VECTOR,DUMMMY3,INVOKED_PERATOM}; +#define INVOKED_PERATOM 8 /* ---------------------------------------------------------------------- */ @@ -67,6 +67,7 @@ ComputeHeatFlux::ComputeHeatFlux(LAMMPS *lmp, int narg, char **arg) : ComputeHeatFlux::~ComputeHeatFlux() { + delete [] id_atomPE; delete [] vector; } diff --git a/src/compute_pressure.cpp b/src/compute_pressure.cpp index a827198b1a42b15cb9e7b5d4450d608675d6d381..e8c2221df2eb3d52141b52111b68ccb7952055a0 100644 --- a/src/compute_pressure.cpp +++ b/src/compute_pressure.cpp @@ -31,8 +31,6 @@ using namespace LAMMPS_NS; -enum{DUMMY0,INVOKED_SCALAR,INVOKED_VECTOR,DUMMMY3,INVOKED_PERATOM}; - /* ---------------------------------------------------------------------- */ ComputePressure::ComputePressure(LAMMPS *lmp, int narg, char **arg) : diff --git a/src/compute_reduce.cpp b/src/compute_reduce.cpp index cdd159b6c9d73f132f81c1cc043010efbc281185..5cda51396b6442958c4e154a8259a67880047b57 100644 --- a/src/compute_reduce.cpp +++ b/src/compute_reduce.cpp @@ -21,6 +21,7 @@ #include "fix.h" #include "force.h" #include "comm.h" +#include "group.h" #include "input.h" #include "variable.h" #include "memory.h" @@ -28,9 +29,14 @@ using namespace LAMMPS_NS; -enum{SUM,MINN,MAXX}; +enum{SUM,MINN,MAXX,AVE}; enum{X,V,F,COMPUTE,FIX,VARIABLE}; -enum{DUMMY0,INVOKED_SCALAR,INVOKED_VECTOR,DUMMMY3,INVOKED_PERATOM}; +enum{GLOBAL,PERATOM,LOCAL}; + +#define INVOKED_VECTOR 2 +#define INVOKED_ARRAY 4 +#define INVOKED_PERATOM 8 +#define INVOKED_LOCAL 16 #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) @@ -55,6 +61,7 @@ ComputeReduce::ComputeReduce(LAMMPS *lmp, int narg, char **arg) : if (strcmp(arg[iarg],"sum") == 0) mode = SUM; else if (strcmp(arg[iarg],"min") == 0) mode = MINN; else if (strcmp(arg[iarg],"max") == 0) mode = MAXX; + else if (strcmp(arg[iarg],"ave") == 0) mode = AVE; else error->all("Illegal compute reduce command"); iarg++; @@ -62,6 +69,7 @@ ComputeReduce::ComputeReduce(LAMMPS *lmp, int narg, char **arg) : which = new int[narg-4]; argindex = new int[narg-4]; + flavor = new int[narg-4]; ids = new char*[narg-4]; value2index = new int[narg-4]; nvalues = 0; @@ -136,26 +144,88 @@ ComputeReduce::ComputeReduce(LAMMPS *lmp, int narg, char **arg) : int icompute = modify->find_compute(ids[i]); if (icompute < 0) error->all("Compute ID for compute reduce does not exist"); - if (modify->compute[icompute]->peratom_flag == 0) - error->all("Compute reduce compute does not " - "calculate per-atom values"); - if (argindex[i] == 0 && - modify->compute[icompute]->size_peratom_cols != 0) - error->all("Compute reduce compute does not " - "calculate a per-atom vector"); - if (argindex[i] && modify->compute[icompute]->size_peratom_cols == 0) - error->all("Compute reduce compute does not " - "calculate a per-atom array"); + if (modify->compute[icompute]->vector_flag || + modify->compute[icompute]->array_flag) { + flavor[i] = GLOBAL; + if (argindex[i] == 0 && + modify->compute[icompute]->vector_flag == 0) + error->all("Compute reduce compute does not " + "calculate a global vector"); + if (argindex[i] && modify->compute[icompute]->array_flag == 0) + error->all("Compute reduce compute does not " + "calculate a global array"); + if (argindex[i] && + argindex[i] > modify->compute[icompute]->size_array_cols) + error->all("Compute reduce compute array is accessed out-of-range"); + } else if (modify->compute[icompute]->peratom_flag) { + flavor[i] = PERATOM; + if (argindex[i] == 0 && + modify->compute[icompute]->size_peratom_cols != 0) + error->all("Compute reduce compute does not " + "calculate a per-atom vector"); + if (argindex[i] && modify->compute[icompute]->size_peratom_cols == 0) + error->all("Compute reduce compute does not " + "calculate a per-atom array"); + if (argindex[i] && + argindex[i] > modify->compute[icompute]->size_peratom_cols) + error->all("Compute reduce compute array is accessed out-of-range"); + } else if (modify->compute[icompute]->local_flag) { + flavor[i] = LOCAL; + if (argindex[i] == 0 && + modify->compute[icompute]->size_local_cols != 0) + error->all("Compute reduce compute does not " + "calculate a local vector"); + if (argindex[i] && modify->compute[icompute]->size_local_cols == 0) + error->all("Compute reduce compute does not " + "calculate a local array"); + if (argindex[i] && + argindex[i] > modify->compute[icompute]->size_local_cols) + error->all("Compute reduce compute array is accessed out-of-range"); + } + } else if (which[i] == FIX) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all("Fix ID for compute reduce does not exist"); - if (modify->fix[ifix]->peratom_flag == 0) - error->all("Compute reduce fix does not calculate per-atom values"); - if (argindex[i] == 0 && modify->fix[ifix]->size_peratom_cols != 0) - error->all("Compute reduce fix does not calculate a per-atom vector"); - if (argindex[i] && modify->fix[ifix]->size_peratom_cols == 0) - error->all("Compute reduce fix does not calculate a per-atom array"); + if (modify->fix[ifix]->vector_flag || + modify->fix[ifix]->array_flag) { + flavor[i] = GLOBAL; + if (argindex[i] == 0 && + modify->fix[ifix]->vector_flag == 0) + error->all("Compute reduce fix does not " + "calculate a global vector"); + if (argindex[i] && modify->fix[ifix]->array_flag == 0) + error->all("Compute reduce fix does not " + "calculate a global array"); + if (argindex[i] && + argindex[i] > modify->fix[ifix]->size_array_cols) + error->all("Compute reduce fix array is accessed out-of-range"); + } else if (modify->fix[ifix]->peratom_flag) { + flavor[i] = PERATOM; + if (argindex[i] == 0 && + modify->fix[ifix]->size_peratom_cols != 0) + error->all("Compute reduce fix does not " + "calculate a per-atom vector"); + if (argindex[i] && modify->fix[ifix]->size_peratom_cols == 0) + error->all("Compute reduce fix does not " + "calculate a per-atom array"); + if (argindex[i] && + argindex[i] > modify->fix[ifix]->size_peratom_cols) + error->all("Compute reduce fix array is accessed out-of-range"); + } else if (modify->fix[ifix]->local_flag) { + flavor[i] = LOCAL; + if (argindex[i] == 0 && + modify->fix[ifix]->size_local_cols != 0) + error->all("Compute reduce fix does not " + "calculate a local vector"); + if (argindex[i] && modify->fix[ifix]->size_local_cols == 0) + error->all("Compute reduce fix does not " + "calculate a local array"); + if (argindex[i] && + argindex[i] > modify->fix[ifix]->size_local_cols) + error->all("Compute reduce fix array is accessed out-of-range"); + } + } else if (which[i] == VARIABLE) { int ivariable = input->variable->find(ids[i]); if (ivariable < 0) @@ -192,6 +262,7 @@ ComputeReduce::~ComputeReduce() { delete [] which; delete [] argindex; + delete [] flavor; for (int m = 0; m < nvalues; m++) delete [] ids[m]; delete [] ids; delete [] value2index; @@ -238,12 +309,17 @@ double ComputeReduce::compute_scalar() invoked_scalar = update->ntimestep; double one = compute_one(0); + if (mode == SUM) MPI_Allreduce(&one,&scalar,1,MPI_DOUBLE,MPI_SUM,world); else if (mode == MINN) MPI_Allreduce(&one,&scalar,1,MPI_DOUBLE,MPI_MIN,world); else if (mode == MAXX) MPI_Allreduce(&one,&scalar,1,MPI_DOUBLE,MPI_MAX,world); + else if (mode == AVE) { + MPI_Allreduce(&one,&scalar,1,MPI_DOUBLE,MPI_SUM,world); + scalar /= count(0); + } return scalar; } @@ -254,12 +330,17 @@ void ComputeReduce::compute_vector() invoked_vector = update->ntimestep; for (int m = 0; m < nvalues; m++) onevec[m] = compute_one(m); + if (mode == SUM) MPI_Allreduce(onevec,vector,size_vector,MPI_DOUBLE,MPI_SUM,world); else if (mode == MINN) MPI_Allreduce(onevec,vector,size_vector,MPI_DOUBLE,MPI_MIN,world); else if (mode == MAXX) MPI_Allreduce(onevec,vector,size_vector,MPI_DOUBLE,MPI_MAX,world); + else if (mode == AVE) { + MPI_Allreduce(onevec,vector,size_vector,MPI_DOUBLE,MPI_MAX,world); + for (int m = 0; m < nvalues; m++) vector[m] /= count(m); + } } /* ---------------------------------------------------------------------- */ @@ -269,15 +350,15 @@ double ComputeReduce::compute_one(int m) int i; // invoke the appropriate attribute,compute,fix,variable - // compute scalar quantity by summing over atom scalars - // only include atoms in group - - int *mask = atom->mask; - int nlocal = atom->nlocal; + // compute scalar quantity by summing over atom properties + // only include atoms in group for atom properties and per-atom quantities int n = value2index[m]; int j = argindex[m]; + int *mask = atom->mask; + int nlocal = atom->nlocal; + double one; if (mode == SUM) one = 0.0; else if (mode == MINN) one = BIG; @@ -300,37 +381,114 @@ double ComputeReduce::compute_one(int m) } else if (which[m] == COMPUTE) { Compute *compute = modify->compute[n]; - if (!(compute->invoked_flag & INVOKED_PERATOM)) { - compute->compute_peratom(); - compute->invoked_flag |= INVOKED_PERATOM; - } - - if (j == 0) { - double *compute_vector = compute->vector_atom; - for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit) combine(one,compute_vector[i]); - } else { - double **compute_array = compute->array_atom; - int jm1 = j - 1; - for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit) combine(one,compute_array[i][jm1]); + + if (flavor[m] == GLOBAL) { + if (j == 0) { + if (!(compute->invoked_flag & INVOKED_VECTOR)) { + compute->compute_vector(); + compute->invoked_flag |= INVOKED_VECTOR; + } + double *compute_vector = compute->vector; + int n = compute->size_vector; + for (i = 0; i < n; i++) + combine(one,compute_vector[i]); + } else { + if (!(compute->invoked_flag & INVOKED_ARRAY)) { + compute->compute_array(); + compute->invoked_flag |= INVOKED_ARRAY; + } + double **compute_array = compute->array; + int n = compute->size_array_rows; + int jm1 = j - 1; + for (i = 0; i < n; i++) + combine(one,compute_array[i][jm1]); + } + + } else if (flavor[m] == PERATOM) { + if (!(compute->invoked_flag & INVOKED_PERATOM)) { + compute->compute_peratom(); + compute->invoked_flag |= INVOKED_PERATOM; + } + + if (j == 0) { + double *compute_vector = compute->vector_atom; + int n = nlocal; + for (i = 0; i < n; i++) + if (mask[i] & groupbit) combine(one,compute_vector[i]); + } else { + double **compute_array = compute->array_atom; + int n = nlocal; + int jm1 = j - 1; + for (i = 0; i < n; i++) + if (mask[i] & groupbit) combine(one,compute_array[i][jm1]); + } + + } else if (flavor[m] == LOCAL) { + if (!(compute->invoked_flag & INVOKED_LOCAL)) { + compute->compute_local(); + compute->invoked_flag |= INVOKED_LOCAL; + } + + if (j == 0) { + double *compute_vector = compute->vector_local; + int n = compute->size_local_rows; + for (i = 0; i < n; i++) + combine(one,compute_vector[i]); + } else { + double **compute_array = compute->array_local; + int n = compute->size_local_rows; + int jm1 = j - 1; + for (i = 0; i < n; i++) + combine(one,compute_array[i][jm1]); + } } - // access fix fields, check if frequency is a match + // access fix fields, check if fix frequency is a match } else if (which[m] == FIX) { if (update->ntimestep % modify->fix[n]->peratom_freq) error->all("Fix used in compute reduce not computed at compatible time"); - - if (j == 0) { - double *fix_vector = modify->fix[n]->vector_atom; - for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit) combine(one,fix_vector[i]); - } else { - double **fix_array = modify->fix[n]->array_atom; - int jm1 = j - 1; - for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit) combine(one,fix_array[i][jm1]); + Fix *fix = modify->fix[n]; + + if (flavor[m] == GLOBAL) { + if (j == 0) { + int n = fix->size_vector; + for (i = 0; i < n; i++) + combine(one,fix->compute_vector(i)); + } else { + int n = fix->size_array_rows; + int jm1 = j - 1; + for (i = 0; i < nlocal; i++) + combine(one,fix->compute_array(i,jm1)); + } + + } else if (flavor[m] == PERATOM) { + if (j == 0) { + double *fix_vector = fix->vector_atom; + int n = nlocal; + for (i = 0; i < n; i++) + if (mask[i] & groupbit) combine(one,fix_vector[i]); + } else { + double **fix_array = fix->array_atom; + int n = nlocal; + int jm1 = j - 1; + for (i = 0; i < nlocal; i++) + if (mask[i] & groupbit) combine(one,fix_array[i][jm1]); + } + + } else if (flavor[m] == LOCAL) { + if (j == 0) { + double *fix_vector = fix->vector_local; + int n = fix->size_local_rows; + for (i = 0; i < n; i++) + combine(one,fix_vector[i]); + } else { + double **fix_array = fix->array_local; + int n = fix->size_local_rows; + int jm1 = j - 1; + for (i = 0; i < n; i++) + combine(one,fix_array[i][jm1]); + } } // evaluate atom-style variable @@ -351,13 +509,57 @@ double ComputeReduce::compute_one(int m) return one; } +/* ---------------------------------------------------------------------- */ + +double ComputeReduce::count(int m) +{ + int n = value2index[m]; + int j = argindex[m]; + + int *mask = atom->mask; + int nlocal = atom->nlocal; + + if (which[m] == X || which[m] == V || which[m] == F) + return group->count(igroup); + else if (which[m] == COMPUTE) { + Compute *compute = modify->compute[n]; + if (flavor[m] == GLOBAL) { + if (j == 0) return(1.0*compute->size_vector); + else return(1.0*compute->size_array_rows); + } else if (flavor[m] == PERATOM) { + return group->count(igroup); + } else if (flavor[m] == LOCAL) { + double ncount = compute->size_local_rows; + double ncountall; + MPI_Allreduce(&ncount,&ncountall,1,MPI_DOUBLE,MPI_SUM,world); + return ncountall; + } + } else if (which[m] == FIX) { + Fix *fix = modify->fix[n]; + if (flavor[m] == GLOBAL) { + if (j == 0) return(1.0*fix->size_vector); + else return(1.0*fix->size_array_rows); + } else if (flavor[m] == PERATOM) { + return group->count(igroup); + } else if (flavor[m] == LOCAL) { + double ncount = fix->size_local_rows; + double ncountall; + MPI_Allreduce(&ncount,&ncountall,1,MPI_DOUBLE,MPI_SUM,world); + return ncountall; + } + } else if (which[m] == VARIABLE) + return group->count(igroup); + + return 0.0; +} + /* ---------------------------------------------------------------------- combine two values according to reduction mode ------------------------------------------------------------------------- */ void ComputeReduce::combine(double &one, double two) { - if (mode == SUM) one += two; + if (mode == SUM || mode == AVE) one += two; else if (mode == MINN) one = MIN(one,two); else if (mode == MAXX) one = MAX(one,two); } diff --git a/src/compute_reduce.h b/src/compute_reduce.h index 82fe48ffb6d7cc4db7489139f325ed08e0eb7435..633cd6ab6985a6d1e8cc382e8883a1061111a6cf 100644 --- a/src/compute_reduce.h +++ b/src/compute_reduce.h @@ -29,7 +29,7 @@ class ComputeReduce : public Compute { protected: int mode,nvalues,iregion; - int *which,*argindex,*value2index; + int *which,*argindex,*flavor,*value2index; char **ids; double *onevec; @@ -37,6 +37,7 @@ class ComputeReduce : public Compute { double *varatom; virtual double compute_one(int); + virtual double count(int); void combine(double &, double); }; diff --git a/src/compute_reduce_region.cpp b/src/compute_reduce_region.cpp index 9e46aab4fefdd89f04850d19c09794284db2fb79..3976714e87f70eda1b66860f22aafbeaa99e46a6 100644 --- a/src/compute_reduce_region.cpp +++ b/src/compute_reduce_region.cpp @@ -18,6 +18,7 @@ #include "update.h" #include "modify.h" #include "domain.h" +#include "group.h" #include "region.h" #include "fix.h" #include "input.h" @@ -29,7 +30,12 @@ using namespace LAMMPS_NS; enum{SUM,MINN,MAXX}; enum{X,V,F,COMPUTE,FIX,VARIABLE}; -enum{DUMMY0,INVOKED_SCALAR,INVOKED_VECTOR,DUMMMY3,INVOKED_PERATOM}; +enum{GLOBAL,PERATOM,LOCAL}; + +#define INVOKED_VECTOR 2 +#define INVOKED_ARRAY 4 +#define INVOKED_PERATOM 8 +#define INVOKED_LOCAL 16 #define BIG 1.0e20 @@ -81,41 +87,118 @@ double ComputeReduceRegion::compute_one(int m) } else if (which[m] == COMPUTE) { Compute *compute = modify->compute[n]; - if (!(compute->invoked_flag & INVOKED_PERATOM)) { - compute->compute_peratom(); - compute->invoked_flag |= INVOKED_PERATOM; - } + + if (flavor[m] == GLOBAL) { + if (j == 0) { + if (!(compute->invoked_flag & INVOKED_VECTOR)) { + compute->compute_vector(); + compute->invoked_flag |= INVOKED_VECTOR; + } + double *compute_vector = compute->vector; + int n = compute->size_vector; + for (i = 0; i < n; i++) + combine(one,compute_vector[i]); + } else { + if (!(compute->invoked_flag & INVOKED_ARRAY)) { + compute->compute_array(); + compute->invoked_flag |= INVOKED_ARRAY; + } + double **compute_array = compute->array; + int n = compute->size_array_rows; + int jm1 = j - 1; + for (i = 0; i < n; i++) + combine(one,compute_array[i][jm1]); + } + + } else if (flavor[m] == PERATOM) { + if (!(compute->invoked_flag & INVOKED_PERATOM)) { + compute->compute_peratom(); + compute->invoked_flag |= INVOKED_PERATOM; + } + + if (j == 0) { + double *compute_vector = compute->vector_atom; + int n = nlocal; + for (i = 0; i < n; i++) + if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) + combine(one,compute_vector[i]); + } else { + double **compute_array = compute->array_atom; + int n = nlocal; + int jm1 = j - 1; + for (i = 0; i < n; i++) + if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) + combine(one,compute_array[i][jm1]); + } - if (j == 0) { - double *compute_vector = compute->vector_atom; - for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) + } else if (flavor[m] == LOCAL) { + if (!(compute->invoked_flag & INVOKED_LOCAL)) { + compute->compute_local(); + compute->invoked_flag |= INVOKED_LOCAL; + } + + if (j == 0) { + double *compute_vector = compute->vector_local; + int n = compute->size_local_rows; + for (i = 0; i < n; i++) combine(one,compute_vector[i]); - } else { - double **compute_array = compute->array_atom; - int jm1 = j - 1; - for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) + } else { + double **compute_array = compute->array_local; + int n = compute->size_local_rows; + int jm1 = j - 1; + for (i = 0; i < n; i++) combine(one,compute_array[i][jm1]); + } } - // access fix fields, check if frequency is a match + // check if fix frequency is a match } else if (which[m] == FIX) { if (update->ntimestep % modify->fix[n]->peratom_freq) error->all("Fix used in compute reduce not computed at compatible time"); + Fix *fix = modify->fix[n]; + + if (flavor[m] == GLOBAL) { + if (j == 0) { + int n = fix->size_vector; + for (i = 0; i < n; i++) + combine(one,fix->compute_vector(i)); + } else { + int n = fix->size_array_rows; + int jm1 = j - 1; + for (i = 0; i < nlocal; i++) + combine(one,fix->compute_array(i,jm1)); + } + + } else if (flavor[m] == PERATOM) { + if (j == 0) { + double *fix_vector = fix->vector_atom; + int n = nlocal; + for (i = 0; i < n; i++) + if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) + combine(one,fix_vector[i]); + } else { + double **fix_array = fix->array_atom; + int n = nlocal; + int jm1 = j - 1; + for (i = 0; i < nlocal; i++) + if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) + combine(one,fix_array[i][jm1]); + } - if (j == 0) { - double *fix_vector = modify->fix[n]->vector_atom; - for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) + } else if (flavor[m] == LOCAL) { + if (j == 0) { + double *fix_vector = fix->vector_local; + int n = fix->size_local_rows; + for (i = 0; i < n; i++) combine(one,fix_vector[i]); - } else { - double **fix_array = modify->fix[n]->array_atom; - int jm1 = j - 1; - for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) + } else { + double **fix_array = fix->array_local; + int n = fix->size_local_rows; + int jm1 = j - 1; + for (i = 0; i < n; i++) combine(one,fix_array[i][jm1]); + } } // evaluate atom-style variable @@ -136,3 +219,47 @@ double ComputeReduceRegion::compute_one(int m) return one; } + +/* ---------------------------------------------------------------------- */ + +double ComputeReduceRegion::count(int m) +{ + int n = value2index[m]; + int j = argindex[m]; + + int *mask = atom->mask; + int nlocal = atom->nlocal; + + if (which[m] == X || which[m] == V || which[m] == F) + return group->count(igroup,iregion); + else if (which[m] == COMPUTE) { + Compute *compute = modify->compute[n]; + if (flavor[m] == GLOBAL) { + if (j == 0) return(1.0*compute->size_vector); + else return(1.0*compute->size_array_rows); + } else if (flavor[m] == PERATOM) { + return group->count(igroup,iregion); + } else if (flavor[m] == LOCAL) { + double ncount = compute->size_local_rows; + double ncountall; + MPI_Allreduce(&ncount,&ncountall,1,MPI_DOUBLE,MPI_SUM,world); + return ncountall; + } + } else if (which[m] == FIX) { + Fix *fix = modify->fix[n]; + if (flavor[m] == GLOBAL) { + if (j == 0) return(1.0*fix->size_vector); + else return(1.0*fix->size_array_rows); + } else if (flavor[m] == PERATOM) { + return group->count(igroup,iregion); + } else if (flavor[m] == LOCAL) { + double ncount = fix->size_local_rows; + double ncountall; + MPI_Allreduce(&ncount,&ncountall,1,MPI_DOUBLE,MPI_SUM,world); + return ncountall; + } + } else if (which[m] == VARIABLE) + return group->count(igroup,iregion); + + return 0.0; +} diff --git a/src/compute_reduce_region.h b/src/compute_reduce_region.h index 6aaf1741e58dabba3dd2b3af446ab6e480657c8b..5ceb834d4dbb685380b5d6016d730eed28fd036f 100644 --- a/src/compute_reduce_region.h +++ b/src/compute_reduce_region.h @@ -25,6 +25,7 @@ class ComputeReduceRegion : public ComputeReduce { private: double compute_one(int); + double count(int); }; } diff --git a/src/compute_temp_sphere.cpp b/src/compute_temp_sphere.cpp index 43409fe79d7d899e9bb209b3fc981bf948952389..bd8aa03362b076d0d08f17b1186bfd09ee95379e 100644 --- a/src/compute_temp_sphere.cpp +++ b/src/compute_temp_sphere.cpp @@ -26,8 +26,6 @@ using namespace LAMMPS_NS; -enum{DUMMY0,INVOKED_SCALAR,INVOKED_VECTOR,DUMMMY3,INVOKED_PERATOM}; - #define INERTIA 0.4 // moment of inertia for sphere /* ---------------------------------------------------------------------- */ diff --git a/src/dump_custom.cpp b/src/dump_custom.cpp index 1b0fb20060be8402f8882af5e208f7ea27df2c80..07b97fb0550ea7d45365f3de340fc53df86ca1d3 100644 --- a/src/dump_custom.cpp +++ b/src/dump_custom.cpp @@ -40,7 +40,8 @@ enum{ID,MOL,TYPE,MASS, COMPUTE,FIX,VARIABLE}; enum{LT,LE,GT,GE,EQ,NEQ}; enum{INT,DOUBLE}; -enum{DUMMY0,INVOKED_SCALAR,INVOKED_VECTOR,DUMMMY3,INVOKED_PERATOM}; + +#define INVOKED_PERATOM 8 /* ---------------------------------------------------------------------- */ @@ -960,7 +961,7 @@ void DumpCustom::parse_fields(int narg, char **arg) vtype[i] = DOUBLE; // compute value = c_ID - // if no trailing [], then arg is set to 0, else arg is between [] + // if no trailing [], then arg is set to 0, else arg is int between [] } else if (strncmp(arg[iarg],"c_",2) == 0) { pack_choice[i] = &DumpCustom::pack_compute; @@ -981,14 +982,14 @@ void DumpCustom::parse_fields(int narg, char **arg) n = modify->find_compute(suffix); if (n < 0) error->all("Could not find dump custom compute ID"); if (modify->compute[n]->peratom_flag == 0) - error->all("Dump custom compute ID does not compute per-atom info"); + error->all("Dump custom compute does not compute per-atom info"); if (argindex[i] == 0 && modify->compute[n]->size_peratom_cols > 0) - error->all("Dump custom compute ID does not compute per-atom vector"); + error->all("Dump custom compute does not calculate per-atom vector"); if (argindex[i] > 0 && modify->compute[n]->size_peratom_cols == 0) - error->all("Dump custom compute ID does not compute per-atom array"); + error->all("Dump custom compute does not calculate per-atom array"); if (argindex[i] > 0 && argindex[i] > modify->compute[n]->size_peratom_cols) - error->all("Dump custom compute ID vector is not large enough"); + error->all("Dump custom compute vector is accessed out-of-range"); field2index[i] = add_compute(suffix); delete [] suffix; @@ -1015,14 +1016,14 @@ void DumpCustom::parse_fields(int narg, char **arg) n = modify->find_fix(suffix); if (n < 0) error->all("Could not find dump custom fix ID"); if (modify->fix[n]->peratom_flag == 0) - error->all("Dump custom fix ID does not compute per-atom info"); + error->all("Dump custom fix does not compute per-atom info"); if (argindex[i] == 0 && modify->fix[n]->size_peratom_cols > 0) - error->all("Dump custom fix ID does not compute per-atom vector"); + error->all("Dump custom fix does not compute per-atom vector"); if (argindex[i] > 0 && modify->fix[n]->size_peratom_cols == 0) - error->all("Dump custom fix ID does not compute per-atom array"); + error->all("Dump custom fix does not compute per-atom array"); if (argindex[i] > 0 && argindex[i] > modify->fix[n]->size_peratom_cols) - error->all("Dump custom fix ID vector is not large enough"); + error->all("Dump custom fix vector is accessed out-of-range"); field2index[i] = add_fix(suffix); delete [] suffix; @@ -1398,7 +1399,6 @@ void DumpCustom::pack_compute(int n) double *vector = compute[field2index[n]]->vector_atom; double **array = compute[field2index[n]]->array_atom; int index = argindex[n]; - int nlocal = atom->nlocal; if (index == 0) { @@ -1424,7 +1424,6 @@ void DumpCustom::pack_fix(int n) double *vector = fix[field2index[n]]->vector_atom; double **array = fix[field2index[n]]->array_atom; int index = argindex[n]; - int nlocal = atom->nlocal; if (index == 0) { @@ -1448,7 +1447,6 @@ void DumpCustom::pack_fix(int n) void DumpCustom::pack_variable(int n) { double *vector = vbuf[field2index[n]]; - int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) diff --git a/src/fix.h b/src/fix.h index b8bd3a525a76877675c1e4da5df2f399bbd1a20e..9379d87d40fd55116fadcd070d20ecb321b770bf 100644 --- a/src/fix.h +++ b/src/fix.h @@ -136,7 +136,7 @@ class Fix : protected Pointers { virtual double compute_scalar() {return 0.0;} virtual double compute_vector(int) {return 0.0;} - virtual double compute_array(int) {return 0.0;} + virtual double compute_array(int,int) {return 0.0;} virtual int dof(int) {return 0;} virtual void deform(int) {} diff --git a/src/fix_ave_atom.cpp b/src/fix_ave_atom.cpp index 3a637884e7e122747bc85761029a3c615f63f4ab..acc1ff8dc92130f806ddcbd4fd907112594349e9 100644 --- a/src/fix_ave_atom.cpp +++ b/src/fix_ave_atom.cpp @@ -27,7 +27,8 @@ using namespace LAMMPS_NS; enum{X,XU,V,F,COMPUTE,FIX,VARIABLE}; -enum{DUMMY0,INVOKED_SCALAR,INVOKED_VECTOR,DUMMMY3,INVOKED_PERATOM}; + +#define INVOKED_PERATOM 8 /* ---------------------------------------------------------------------- */ @@ -125,6 +126,7 @@ FixAveAtom::FixAveAtom(LAMMPS *lmp, int narg, char **arg) : } // setup and error check + // for fix inputs, check that fix frequency is acceptable if (nevery <= 0) error->all("Illegal fix ave/atom command"); if (peratom_freq < nevery || peratom_freq % nevery || @@ -147,19 +149,23 @@ FixAveAtom::FixAveAtom(LAMMPS *lmp, int narg, char **arg) : "calculate a per-atom array"); if (argindex[i] && argindex[i] > modify->compute[icompute]->size_peratom_cols) - error->all("Fix ave/atom compute vector is accessed out-of-range"); + error->all("Fix ave/atom compute array is accessed out-of-range"); + } else if (which[i] == FIX) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) error->all("Fix ID for fix ave/atom does not exist"); if (modify->fix[ifix]->peratom_flag == 0) error->all("Fix ave/atom fix does not calculate per-atom values"); - if (argindex[i] && modify->fix[ifix]->size_peratom_cols != 0) + if (argindex[i] == 0 && modify->fix[ifix]->size_peratom_cols != 0) error->all("Fix ave/atom fix does not calculate a per-atom vector"); if (argindex[i] && modify->fix[ifix]->size_peratom_cols == 0) error->all("Fix ave/atom fix does not calculate a per-atom array"); if (argindex[i] && argindex[i] > modify->fix[ifix]->size_peratom_cols) - error->all("Fix ave/atom fix vector is accessed out-of-range"); + error->all("Fix ave/atom fix array is accessed out-of-range"); + if (nevery % modify->fix[ifix]->peratom_freq) + error->all("Fix for fix ave/atom not computed at compatible time"); + } else if (which[i] == VARIABLE) { int ivariable = input->variable->find(ids[i]); if (ivariable < 0) @@ -240,7 +246,6 @@ int FixAveAtom::setmask() void FixAveAtom::init() { // set indices and check validity of all computes,fixes,variables - // check that fix frequency is acceptable for (int m = 0; m < nvalues; m++) { if (which[m] == COMPUTE) { @@ -255,9 +260,6 @@ void FixAveAtom::init() error->all("Fix ID for fix ave/atom does not exist"); value2index[m] = ifix; - if (nevery % modify->fix[ifix]->peratom_freq) - error->all("Fix for fix ave/atom not computed at compatible time"); - } else if (which[m] == VARIABLE) { int ivariable = input->variable->find(ids[m]); if (ivariable < 0) diff --git a/src/fix_ave_spatial.cpp b/src/fix_ave_spatial.cpp index 06ba4f8d86d740a8659e17ad57055e0f507817f6..2af3684477b0d0864b47e16e25fae5473bdd717e 100644 --- a/src/fix_ave_spatial.cpp +++ b/src/fix_ave_spatial.cpp @@ -36,7 +36,8 @@ enum{X,V,F,DENSITY_NUMBER,DENSITY_MASS,COMPUTE,FIX,VARIABLE}; enum{SAMPLE,ALL}; enum{BOX,LATTICE,REDUCED}; enum{ONE,RUNNING,WINDOW}; -enum{DUMMY0,INVOKED_SCALAR,INVOKED_VECTOR,DUMMMY3,INVOKED_PERATOM}; + +#define INVOKED_PERATOM 8 #define BIG 1000000000 @@ -154,6 +155,9 @@ FixAveSpatial::FixAveSpatial(LAMMPS *lmp, int narg, char **arg) : scaleflag = LATTICE; fp = NULL; ave = ONE; + char *title1 = NULL; + char *title2 = NULL; + char *title3 = NULL; while (iarg < narg) { if (strcmp(arg[iarg],"norm") == 0) { @@ -193,6 +197,27 @@ FixAveSpatial::FixAveSpatial(LAMMPS *lmp, int narg, char **arg) : } iarg += 2; if (ave == WINDOW) iarg++; + } else if (strcmp(arg[iarg],"title1") == 0) { + if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); + delete [] title1; + int n = strlen(arg[iarg+1]) + 1; + title1 = new char[n]; + strcpy(title1,arg[iarg+1]); + iarg += 2; + } else if (strcmp(arg[iarg],"title2") == 0) { + if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); + delete [] title2; + int n = strlen(arg[iarg+1]) + 1; + title2 = new char[n]; + strcpy(title2,arg[iarg+1]); + iarg += 2; + } else if (strcmp(arg[iarg],"title3") == 0) { + if (iarg+2 > narg) error->all("Illegal fix ave/spatial command"); + delete [] title3; + int n = strlen(arg[iarg+1]) + 1; + title3 = new char[n]; + strcpy(title3,arg[iarg+1]); + iarg += 2; } else error->all("Illegal fix ave/spatial command"); } @@ -243,27 +268,38 @@ FixAveSpatial::FixAveSpatial(LAMMPS *lmp, int narg, char **arg) : } } - // print header into file + // print file comment lines if (fp && me == 0) { - fprintf(fp,"# Spatial-averaged data for fix %s and group %s\n",id,arg[1]); - fprintf(fp,"# TimeStep Number-of-layers\n"); - fprintf(fp,"# Layer Coordinate Natoms"); - for (int i = 0; i < nvalues; i++) - if (which[i] == COMPUTE) fprintf(fp," c_%s",ids[i]); - else if (which[i] == FIX) fprintf(fp," f_%s",ids[i]); - else if (which[i] == VARIABLE) fprintf(fp," v_%s",ids[i]); - else fprintf(fp," %s",arg[9+i]); - fprintf(fp,"\n"); + if (title1) fprintf(fp,"%s\n",title1); + else fprintf(fp,"# Spatial-averaged data for fix %s and group %s\n", + id,arg[1]); + if (title2) fprintf(fp,"%s\n",title2); + else fprintf(fp,"# Timestep Number-of-layers\n"); + if (title3) fprintf(fp,"%s\n",title3); + else { + fprintf(fp,"# Layer Coord Ncount"); + for (int i = 0; i < nvalues; i++) { + if (which[i] == COMPUTE) fprintf(fp," c_%s",ids[i]); + else if (which[i] == FIX) fprintf(fp," f_%s",ids[i]); + else if (which[i] == VARIABLE) fprintf(fp," v_%s",ids[i]); + else fprintf(fp," %s",arg[9+i]); + } + fprintf(fp,"\n"); + } } - - // this fix produces a global vector - // set size_vector to BIG since compute_vector() checks bounds on-the-fly - vector_flag = 1; - size_vector = BIG; + delete [] title1; + delete [] title2; + delete [] title3; + + // this fix produces a global array + + array_flag = 1; + size_local_rows = BIG; + size_local_cols = nvalues+2; global_freq = nfreq; - extvector = 0; + extarray = 0; // setup scaling @@ -803,18 +839,18 @@ void FixAveSpatial::end_of_step() } /* ---------------------------------------------------------------------- - return Nth vector value - since values_sum is 2d array, map N into ilayer and ivalue - if ilayer exceeds current layers, return 0.0 instead of generate an error + return I,J array value + if I exceeds current layers, return 0.0 instead of generating an error + 1st column = bin coord, 2nd column = count, remaining columns = Nvalues ------------------------------------------------------------------------- */ -double FixAveSpatial::compute_vector(int n) +double FixAveSpatial::compute_array(int i, int j) { - int ivalue = n % nvalues; - int ilayer = n / nvalues; - if (ilayer >= nlayers) return 0.0; if (values_total == NULL) return 0.0; - return values_total[ilayer][ivalue]/norm; + if (i >= nlayers) return 0.0; + if (j == 0) return coord[i]; + if (j == 1) return count_total[i]/norm; + return values_total[i][j]/norm; } /* ---------------------------------------------------------------------- diff --git a/src/fix_ave_spatial.h b/src/fix_ave_spatial.h index 0a4da9876e414389f9a5c69a5e6e612ac457c05d..cc11d55d40261cbe3260eeeb001224005da88722 100644 --- a/src/fix_ave_spatial.h +++ b/src/fix_ave_spatial.h @@ -27,7 +27,7 @@ class FixAveSpatial : public Fix { void init(); void setup(int); void end_of_step(); - double compute_vector(int); + double compute_array(int,int); double memory_usage(); private: @@ -35,6 +35,7 @@ class FixAveSpatial : public Fix { int nrepeat,nfreq,nvalid,irepeat; int dim,originflag,normflag; double origin,delta; + char *tstring,*sstring; int *which,*argindex,*value2index; char **ids; FILE *fp; diff --git a/src/fix_ave_time.cpp b/src/fix_ave_time.cpp index d042f042d18b30ad3d39249f6cfd6fc0939e4200..43824525be7cc5099ef6588c203bb07111c02f6a 100644 --- a/src/fix_ave_time.cpp +++ b/src/fix_ave_time.cpp @@ -31,7 +31,10 @@ using namespace LAMMPS_NS; enum{COMPUTE,FIX,VARIABLE}; enum{ONE,RUNNING,WINDOW}; -enum{DUMMY0,INVOKED_SCALAR,INVOKED_VECTOR,DUMMMY3,INVOKED_PERATOM}; + +#define INVOKED_SCALAR 1 +#define INVOKED_VECTOR 2 +#define INVOKED_ARRAY 4 /* ---------------------------------------------------------------------- */ @@ -129,6 +132,7 @@ FixAveTime::FixAveTime(LAMMPS *lmp, int narg, char **arg) : } // setup and error check + // for fix inputs, check that fix frequency is acceptable if (nevery <= 0) error->all("Illegal fix ave/time command"); if (nfreq < nevery || nfreq % nevery || (nrepeat-1)*nevery >= nfreq) @@ -145,6 +149,7 @@ FixAveTime::FixAveTime(LAMMPS *lmp, int narg, char **arg) : error->all("Fix ave/time compute does not calculate a vector"); if (argindex[i] && argindex[i] > modify->compute[icompute]->size_vector) error->all("Fix ave/time compute vector is accessed out-of-range"); + } else if (which[i] == FIX) { int ifix = modify->find_fix(ids[i]); if (ifix < 0) @@ -155,6 +160,9 @@ FixAveTime::FixAveTime(LAMMPS *lmp, int narg, char **arg) : error->all("Fix ave/time fix does not calculate a vector"); if (argindex[i] && argindex[i] > modify->fix[ifix]->size_vector) error->all("Fix ave/time fix vector is accessed out-of-range"); + if (nevery % modify->fix[ifix]->global_freq) + error->all("Fix for fix ave/time not computed at compatible time"); + } else if (which[i] == VARIABLE) { int ivariable = input->variable->find(ids[i]); if (ivariable < 0) @@ -285,8 +293,7 @@ int FixAveTime::setmask() void FixAveTime::init() { - // set indices and check validity of all computes,fixes,variables - // check that fix frequency is acceptable + // set current indices for all computes,fixes,variables for (int i = 0; i < nvalues; i++) { if (which[i] == COMPUTE) { @@ -301,9 +308,6 @@ void FixAveTime::init() error->all("Fix ID for fix ave/time does not exist"); value2index[i] = ifix; - if (nevery % modify->fix[ifix]->global_freq) - error->all("Fix for fix ave/time not computed at compatible time"); - } else if (which[i] == VARIABLE) { int ivariable = input->variable->find(ids[i]); if (ivariable < 0) @@ -440,7 +444,6 @@ void FixAveTime::end_of_step() /* ---------------------------------------------------------------------- return scalar value - could be ONE, RUNNING, or WINDOW value ------------------------------------------------------------------------- */ double FixAveTime::compute_scalar() @@ -450,12 +453,21 @@ double FixAveTime::compute_scalar() } /* ---------------------------------------------------------------------- - return Nth vector value - could be ONE, RUNNING, or WINDOW value + return Ith vector value +------------------------------------------------------------------------- */ + +double FixAveTime::compute_vector(int i) +{ + if (norm) return vector_total[i]/norm; + return 0.0; +} + +/* ---------------------------------------------------------------------- + return I,J array value ------------------------------------------------------------------------- */ -double FixAveTime::compute_vector(int n) +double FixAveTime::compute_array(int i, int j) { - if (norm) return vector_total[n]/norm; + if (norm) return array_total[i][j]/norm; return 0.0; } diff --git a/src/fix_ave_time.h b/src/fix_ave_time.h index f4461583570dcf8578ccff314f6e5aac68f59a92..0d4b562cdcfcce5def5106582e278f940706c693 100644 --- a/src/fix_ave_time.h +++ b/src/fix_ave_time.h @@ -29,6 +29,7 @@ class FixAveTime : public Fix { void end_of_step(); double compute_scalar(); double compute_vector(int); + double compute_array(int,int); private: int me,nvalues; @@ -43,6 +44,7 @@ class FixAveTime : public Fix { int norm,iwindow,window_limit; double *vector_total; double **vector_list; + double **array_total; }; } diff --git a/src/style.h b/src/style.h index d6dd6003aa2cc46ae6d7da73d0c2e410f05b35f8..f124a47f49a574284d735230fd03aed7be96a3d3 100644 --- a/src/style.h +++ b/src/style.h @@ -90,6 +90,7 @@ CommandStyle(write_restart,WriteRestart) #include "compute_pe.h" #include "compute_pe_atom.h" #include "compute_pressure.h" +#include "compute_rdf.h" #include "compute_reduce.h" #include "compute_reduce_region.h" #include "compute_erotate_sphere.h" @@ -121,6 +122,7 @@ ComputeStyle(pe/atom,ComputePEAtom) ComputeStyle(pressure,ComputePressure) ComputeStyle(reduce,ComputeReduce) ComputeStyle(reduce/region,ComputeReduceRegion) +ComputeStyle(rdf,ComputeRDF) ComputeStyle(erotate/sphere,ComputeERotateSphere) ComputeStyle(stress/atom,ComputeStressAtom) ComputeStyle(temp,ComputeTemp) diff --git a/src/thermo.cpp b/src/thermo.cpp index ddd26643e163864630e24c13a24c18c7d78ea959..d14220452c3c17973be0c5aabb0def725a0ce3d7 100644 --- a/src/thermo.cpp +++ b/src/thermo.cpp @@ -53,7 +53,11 @@ using namespace LAMMPS_NS; enum{IGNORE,WARN,ERROR}; // same as write_restart.cpp enum{ONELINE,MULTILINE}; enum{INT,FLOAT}; -enum{DUMMY0,INVOKED_SCALAR,INVOKED_VECTOR,DUMMMY3,INVOKED_PERATOM}; +enum{SCALAR,VECTOR,ARRAY}; + +#define INVOKED_SCALAR 1 +#define INVOKED_VECTOR 2 +#define INVOKED_ARRAY 4 #define MAXLINE 1024 #define DELTA 8 @@ -271,16 +275,21 @@ void Thermo::compute(int flag) // which = 0 is global scalar, which = 1 is global vector for (i = 0; i < ncompute; i++) - if (compute_which[i] == 0) { + if (compute_which[i] == SCALAR) { if (!(computes[i]->invoked_flag & INVOKED_SCALAR)) { computes[i]->compute_scalar(); computes[i]->invoked_flag |= INVOKED_SCALAR; } - } else { + } else if (compute_which[i] == VECTOR) { if (!(computes[i]->invoked_flag & INVOKED_VECTOR)) { computes[i]->compute_vector(); computes[i]->invoked_flag |= INVOKED_VECTOR; } + } else if (compute_which[i] == ARRAY) { + if (!(computes[i]->invoked_flag & INVOKED_ARRAY)) { + computes[i]->compute_array(); + computes[i]->invoked_flag |= INVOKED_ARRAY; + } } // if lineflag = MULTILINE, prepend step/cpu header line @@ -502,7 +511,8 @@ void Thermo::allocate() for (int i = 0; i < n; i++) format_user[i] = NULL; field2index = new int[n]; - argindex = new int[n]; + argindex1 = new int[n]; + argindex2 = new int[n]; // factor of 3 is max number of computes a single field can add @@ -539,7 +549,8 @@ void Thermo::deallocate() delete [] format_user; delete [] field2index; - delete [] argindex; + delete [] argindex1; + delete [] argindex2; for (int i = 0; i < ncompute; i++) delete [] id_compute[i]; delete [] id_compute; @@ -580,56 +591,56 @@ void Thermo::parse_fields(char *str) } else if (strcmp(word,"temp") == 0) { addfield("Temp",&Thermo::compute_temp,FLOAT); - index_temp = add_compute(id_temp,0); + index_temp = add_compute(id_temp,SCALAR); } else if (strcmp(word,"press") == 0) { addfield("Press",&Thermo::compute_press,FLOAT); - index_press_scalar = add_compute(id_press,0); + index_press_scalar = add_compute(id_press,SCALAR); } else if (strcmp(word,"pe") == 0) { addfield("PotEng",&Thermo::compute_pe,FLOAT); - index_pe = add_compute(id_pe,0); + index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"ke") == 0) { addfield("KinEng",&Thermo::compute_ke,FLOAT); - index_temp = add_compute(id_temp,0); + index_temp = add_compute(id_temp,SCALAR); } else if (strcmp(word,"etotal") == 0) { addfield("TotEng",&Thermo::compute_etotal,FLOAT); - index_temp = add_compute(id_temp,0); - index_pe = add_compute(id_pe,0); + index_temp = add_compute(id_temp,SCALAR); + index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"enthalpy") == 0) { addfield("Enthalpy",&Thermo::compute_enthalpy,FLOAT); - index_temp = add_compute(id_temp,0); - index_press_scalar = add_compute(id_press,0); - index_pe = add_compute(id_pe,0); + index_temp = add_compute(id_temp,SCALAR); + index_press_scalar = add_compute(id_press,SCALAR); + index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"evdwl") == 0) { addfield("E_vdwl",&Thermo::compute_evdwl,FLOAT); - index_pe = add_compute(id_pe,0); + index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"ecoul") == 0) { addfield("E_coul",&Thermo::compute_ecoul,FLOAT); - index_pe = add_compute(id_pe,0); + index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"epair") == 0) { addfield("E_pair",&Thermo::compute_epair,FLOAT); - index_pe = add_compute(id_pe,0); + index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"ebond") == 0) { addfield("E_bond",&Thermo::compute_ebond,FLOAT); - index_pe = add_compute(id_pe,0); + index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"eangle") == 0) { addfield("E_angle",&Thermo::compute_eangle,FLOAT); - index_pe = add_compute(id_pe,0); + index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"edihed") == 0) { addfield("E_dihed",&Thermo::compute_edihed,FLOAT); - index_pe = add_compute(id_pe,0); + index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"eimp") == 0) { addfield("E_impro",&Thermo::compute_eimp,FLOAT); - index_pe = add_compute(id_pe,0); + index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"emol") == 0) { addfield("E_mol",&Thermo::compute_emol,FLOAT); - index_pe = add_compute(id_pe,0); + index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"elong") == 0) { addfield("E_long",&Thermo::compute_elong,FLOAT); - index_pe = add_compute(id_pe,0); + index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"etail") == 0) { addfield("E_tail",&Thermo::compute_etail,FLOAT); - index_pe = add_compute(id_pe,0); + index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"vol") == 0) { addfield("Volume",&Thermo::compute_vol,FLOAT); @@ -662,25 +673,25 @@ void Thermo::parse_fields(char *str) } else if (strcmp(word,"pxx") == 0) { addfield("Pxx",&Thermo::compute_pxx,FLOAT); - index_press_vector = add_compute(id_press,1); + index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pyy") == 0) { addfield("Pyy",&Thermo::compute_pyy,FLOAT); - index_press_vector = add_compute(id_press,1); + index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pzz") == 0) { addfield("Pzz",&Thermo::compute_pzz,FLOAT); - index_press_vector = add_compute(id_press,1); + index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pxy") == 0) { addfield("Pxy",&Thermo::compute_pxy,FLOAT); - index_press_vector = add_compute(id_press,1); + index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pxz") == 0) { addfield("Pxz",&Thermo::compute_pxz,FLOAT); - index_press_vector = add_compute(id_press,1); + index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pyz") == 0) { addfield("Pyz",&Thermo::compute_pyz,FLOAT); - index_press_vector = add_compute(id_press,1); + index_press_vector = add_compute(id_press,VECTOR); // compute value = c_ID, fix value = f_ID, variable value = v_ID - // if no trailing [], then arg is set to 0, else arg is between [] + // count trailing [] and store int arguments // copy = at most 8 chars of ID to pass to addfield } else if ((strncmp(word,"c_",2) == 0) || (strncmp(word,"f_",2) == 0) || @@ -693,38 +704,66 @@ void Thermo::parse_fields(char *str) strncpy(copy,id,8); copy[8] = '\0'; + // parse zero or one or two trailing brackets from ID + // argindex1,argindex2 = int inside each bracket pair, 0 if no bracket + char *ptr = strchr(id,'['); - if (ptr) { - if (id[strlen(id)-1] != ']') - error->all("Invalid keyword in thermo_style custom command"); - argindex[nfield] = atoi(ptr+1); + if (ptr == NULL) argindex1[nfield] = 0; + else { *ptr = '\0'; - } else argindex[nfield] = 0; + argindex1[nfield] = input->variable->int_between_brackets(ptr); + ptr++; + if (*ptr == '[') { + argindex2[nfield] = input->variable->int_between_brackets(ptr); + ptr++; + } else argindex2[nfield] = 0; + } if (word[0] == 'c') { n = modify->find_compute(id); if (n < 0) error->all("Could not find thermo custom compute ID"); - if (argindex[nfield] == 0 && modify->compute[n]->scalar_flag == 0) - error->all("Thermo compute ID does not compute scalar info"); - if (argindex[nfield] > 0 && modify->compute[n]->vector_flag == 0) - error->all("Thermo compute ID does not compute vector info"); - if (argindex[nfield] > 0 && - argindex[nfield] > modify->compute[n]->size_vector) - error->all("Thermo compute ID vector is not large enough"); - - field2index[nfield] = add_compute(id,MIN(argindex[nfield],1)); + if (argindex1[nfield] == 0 && modify->compute[n]->scalar_flag == 0) + error->all("Thermo compute does not compute scalar"); + if (argindex1[nfield] > 0 && argindex2[nfield] == 0) { + if (modify->compute[n]->vector_flag == 0) + error->all("Thermo compute does not compute vector"); + if (argindex1[nfield] > modify->compute[n]->size_vector) + error->all("Thermo compute vector is accessed out-of-range"); + } + if (argindex1[nfield] > 0 && argindex2[nfield] > 0) { + if (modify->compute[n]->array_flag == 0) + error->all("Thermo compute does not compute array"); + if (argindex1[nfield] > modify->compute[n]->size_array_rows || + argindex2[nfield] > modify->compute[n]->size_array_cols) + error->all("Thermo compute array is accessed out-of-range"); + } + + if (argindex1[nfield] == 0) + field2index[nfield] = add_compute(id,SCALAR); + else if (argindex2[nfield] == 0) + field2index[nfield] = add_compute(id,VECTOR); + else + field2index[nfield] = add_compute(id,ARRAY); addfield(copy,&Thermo::compute_compute,FLOAT); } else if (word[0] == 'f') { n = modify->find_fix(id); if (n < 0) error->all("Could not find thermo custom fix ID"); - if (argindex[nfield] == 0 && modify->fix[n]->scalar_flag == 0) - error->all("Thermo fix ID does not compute scalar info"); - if (argindex[nfield] > 0 && modify->fix[n]->vector_flag == 0) - error->all("Thermo fix ID does not compute vector info"); - if (argindex[nfield] > 0 && - argindex[nfield] > modify->fix[n]->size_vector) - error->all("Thermo fix ID vector is not large enough"); + if (argindex1[nfield] == 0 && modify->fix[n]->scalar_flag == 0) + error->all("Thermo fix does not compute scalar"); + if (argindex1[nfield] > 0 && argindex2[nfield] == 0) { + if (modify->fix[n]->vector_flag == 0) + error->all("Thermo fix does not compute vector"); + if (argindex1[nfield] > modify->fix[n]->size_vector) + error->all("Thermo fix vector is accessed out-of-range"); + } + if (argindex1[nfield] > 0 && argindex2[nfield] > 0) { + if (modify->fix[n]->array_flag == 0) + error->all("Thermo fix does not compute array"); + if (argindex1[nfield] > modify->fix[n]->size_array_rows || + argindex2[nfield] > modify->fix[n]->size_array_cols) + error->all("Thermo fix array is accessed out-of-range"); + } field2index[nfield] = add_fix(id); addfield(copy,&Thermo::compute_fix,FLOAT); @@ -734,6 +773,8 @@ void Thermo::parse_fields(char *str) if (n < 0) error->all("Could not find thermo custom variable name"); if (input->variable->equalstyle(n) == 0) error->all("Thermo custom variable is not equal-style variable"); + if (argindex1[nfield]) + error->all("Thermo custom variable cannot be indexed"); field2index[nfield] = add_variable(id); addfield(copy,&Thermo::compute_variable,FLOAT); @@ -1150,17 +1191,22 @@ int Thermo::evaluate_keyword(char *word, double *answer) void Thermo::compute_compute() { - Compute *compute = computes[field2index[ifield]]; - if (argindex[ifield] == 0) { + int m = field2index[ifield]; + Compute *compute = computes[m]; + + if (compute_which[m] == SCALAR) { dvalue = compute->scalar; if (normflag && compute->extscalar) dvalue /= natoms; - } else { - dvalue = compute->vector[argindex[ifield]-1]; + } else if (compute_which[m] == VECTOR) { + dvalue = compute->vector[argindex1[ifield]-1]; if (normflag) { if (compute->extvector == 0) return; else if (compute->extvector == 1) dvalue /= natoms; - else if (compute->extlist[argindex[ifield]-1]) dvalue /= natoms; + else if (compute->extlist[argindex1[ifield]-1]) dvalue /= natoms; } + } else { + dvalue = compute->array[argindex1[ifield]-1][argindex2[ifield]-1]; + if (normflag && compute->extarray) dvalue /= natoms; } } @@ -1168,17 +1214,22 @@ void Thermo::compute_compute() void Thermo::compute_fix() { - Fix *fix = fixes[field2index[ifield]]; - if (argindex[ifield] == 0) { + int m = field2index[ifield]; + Fix *fix = fixes[m]; + + if (argindex1[ifield] == 0) { dvalue = fix->compute_scalar(); if (normflag && fix->extscalar) dvalue /= natoms; - } else { - dvalue = fix->compute_vector(argindex[ifield]-1); + } else if (argindex2[ifield] == 0) { + dvalue = fix->compute_vector(argindex1[ifield]-1); if (normflag) { if (fix->extvector == 0) return; else if (fix->extvector == 1) dvalue /= natoms; - else if (fix->extlist[argindex[ifield]-1]) dvalue /= natoms; + else if (fix->extlist[argindex1[ifield]-1]) dvalue /= natoms; } + } else { + dvalue = fix->compute_array(argindex1[ifield]-1,argindex2[ifield]-1); + if (normflag && fix->extarray) dvalue /= natoms; } } diff --git a/src/thermo.h b/src/thermo.h index 4c47a978ecdac80070624fa3c798920df5e5ad4e..06bb96416ed567eca575df7e8acb3def1ec583e0 100644 --- a/src/thermo.h +++ b/src/thermo.h @@ -62,8 +62,8 @@ class Thermo : protected Pointers { double dvalue,natoms; // dvalue = double value to print int ifield; // which field in thermo output is being computed int *field2index; // which compute,fix,variable calcs this field - int *argindex; // index into compute,fix scalar,vector - + int *argindex1; // indices into compute,fix scalar,vector + int *argindex2; // data for keyword-specific Compute objects // index = where they are in computes list // id = ID of Compute objects diff --git a/src/variable.cpp b/src/variable.cpp index 3c6edb55a2d3152123267944af08b4b33c571a17..28b1c63b351d8a3d57975a36dd828e79e1a8e727 100644 --- a/src/variable.cpp +++ b/src/variable.cpp @@ -37,13 +37,17 @@ using namespace LAMMPS_NS; #define MYROUND(a) (( a-floor(a) ) >= .5) ? ceil(a) : floor(a) -enum{DUMMY0,INVOKED_SCALAR,INVOKED_VECTOR,DUMMMY3,INVOKED_PERATOM}; enum{INDEX,LOOP,EQUAL,WORLD,UNIVERSE,ULOOP,ATOM}; enum{ARG,OP}; enum{DONE,ADD,SUBTRACT,MULTIPLY,DIVIDE,CARAT,UNARY, SQRT,EXP,LN,LOG,SIN,COS,TAN,ASIN,ACOS,ATAN, CEIL,FLOOR,ROUND,VALUE,ATOMARRAY,TYPEARRAY,INTARRAY}; +#define INVOKED_SCALAR 1 +#define INVOKED_VECTOR 2 +#define INVOKED_ARRAY 4 +#define INVOKED_PERATOM 8 + /* ---------------------------------------------------------------------- */ Variable::Variable(LAMMPS *lmp) : Pointers(lmp) @@ -524,11 +528,11 @@ void Variable::copy(int narg, char **from, char **to) sqrt(x),exp(x),ln(x),log(x), sin(x),cos(x),tan(x),asin(x),acos(x),atan(x) group function = count(group), mass(group), xcm(group,x), ... - atom value = x[123], y[3], vx[34], ... - atom vector = x[], y[], vx[], ... - compute = c_ID, c_ID[2], c_ID[], c_ID[][2], c_ID[N], c_ID[N][2] - fix = f_ID, f_ID[2], f_ID[], f_ID[][2], f_ID[N], f_ID[N][2] - variable = v_name, v_name[], v_name[N] + atom value = x[i], y[i], vx[i], ... + atom vector = x, y, vx, ... + compute = c_ID, c_ID[i], c_ID[i][j] + fix = f_ID, f_ID[i], f_ID[i][j] + variable = v_name, v_name[i] if tree ptr passed in, return ptr to parse tree created for formula if no tree ptr passed in, return value of string as double ------------------------------------------------------------------------- */ @@ -538,6 +542,7 @@ double Variable::evaluate(char *str, Tree **tree) int op,opprevious; double value1,value2; char onechar; + char *ptr; double argstack[MAXLEVEL]; Tree *treestack[MAXLEVEL]; @@ -613,7 +618,8 @@ double Variable::evaluate(char *str, Tree **tree) delete [] number; // ---------------- - // letter: c_ID, f_ID, v_name, exp(), xcm(,), x[234], x[], vol + // letter: c_ID, c_ID[], c_ID[][], f_ID, f_ID[], f_ID[][], + // v_name, v_name[], exp(), xcm(,), x, x[], vol // ---------------- } else if (islower(onechar)) { @@ -637,6 +643,9 @@ double Variable::evaluate(char *str, Tree **tree) // ---------------- if (strncmp(word,"c_",2) == 0) { + if (domain->box_exist == 0) + error->all("Variable evaluation before simulation box is defined"); + n = strlen(word) - 2 + 1; char *id = new char[n]; strcpy(id,&word[2]); @@ -646,28 +655,27 @@ double Variable::evaluate(char *str, Tree **tree) Compute *compute = modify->compute[icompute]; delete [] id; - if (domain->box_exist == 0) - error->all("Variable evaluation before simulation box is defined"); - // parse zero or one or two trailing brackets // point i beyond last bracket // nbracket = # of bracket pairs - // index1,index2 = int inside each bracket pair, 0 if empty + // index1,index2 = int inside each bracket pair int nbracket,index1,index2; if (str[i] != '[') nbracket = 0; else { nbracket = 1; - i = int_between_brackets(str,i,index1,1); - i++; + ptr = &str[i]; + index1 = int_between_brackets(ptr); + i = ptr-str+1; if (str[i] == '[') { nbracket = 2; - i = int_between_brackets(str,i,index2,0); - i++; + ptr = &str[i]; + index2 = int_between_brackets(ptr); + i = ptr-str+1; } } - // c_ID = global scalar + // c_ID = scalar from global scalar if (nbracket == 0 && compute->scalar_flag) { @@ -689,12 +697,13 @@ double Variable::evaluate(char *str, Tree **tree) treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value1; - // c_ID[2] = global vector + // c_ID[i] = scalar from global vector - } else if (nbracket == 1 && index1 > 0 && compute->vector_flag) { + } else if (nbracket == 1 && compute->vector_flag) { if (index1 > compute->size_vector) - error->all("Compute vector in variable formula is too small"); + error->all("Variable formula compute vector " + "is accessed out-of-range"); if (update->whichflag == 0) { if (compute->invoked_vector != update->ntimestep) error->all("Compute used in variable between runs " @@ -713,13 +722,39 @@ double Variable::evaluate(char *str, Tree **tree) treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value1; - // c_ID[] = per-atom vector + // c_ID[i][j] = scalar from global array - } else if (nbracket == 1 && index1 == 0 && - compute->peratom_flag && compute->size_peratom_cols == 0) { + } else if (nbracket == 2 && compute->array_flag) { + + if (index1 > compute->size_array_rows) + error->all("Variable formula compute vector " + "is accessed out-of-range"); + if (index2 > compute->size_array_cols) + error->all("Variable formula compute vector " + "is accessed out-of-range"); + if (update->whichflag == 0) { + if (compute->invoked_array != update->ntimestep) + error->all("Compute used in variable between runs " + "is not current"); + } else if (!(compute->invoked_flag & INVOKED_ARRAY)) { + compute->compute_array(); + compute->invoked_flag |= INVOKED_ARRAY; + } + + value1 = compute->array[index1-1][index2-1]; + if (tree) { + Tree *newtree = new Tree(); + newtree->type = VALUE; + newtree->value = value1; + newtree->left = newtree->right = NULL; + treestack[ntreestack++] = newtree; + } else argstack[nargstack++] = value1; + + // c_ID[i] = scalar from per-atom vector + + } else if (nbracket == 1 && compute->peratom_flag && + compute->size_peratom_cols == 0) { - if (tree == NULL) - error->all("Per-atom compute in equal-style variable formula"); if (update->whichflag == 0) { if (compute->invoked_peratom != update->ntimestep) error->all("Compute used in variable between runs " @@ -729,18 +764,17 @@ double Variable::evaluate(char *str, Tree **tree) compute->invoked_flag |= INVOKED_PERATOM; } - Tree *newtree = new Tree(); - newtree->type = ATOMARRAY; - newtree->array = compute->vector_atom; - newtree->nstride = 1; - newtree->left = newtree->right = NULL; - treestack[ntreestack++] = newtree; + peratom2global(1,NULL,compute->vector_atom,1,index1, + tree,treestack,ntreestack,argstack,nargstack); - // c_ID[N] = global value from per-atom vector + // c_ID[i][j] = scalar from per-atom array - } else if (nbracket == 1 && index1 > 0 && - compute->peratom_flag && compute->size_peratom_cols == 0) { + } else if (nbracket == 2 && compute->peratom_flag && + compute->size_peratom_cols > 0) { + if (index2 > compute->size_peratom_cols) + error->all("Variable formula compute vector " + "is accessed out-of-range"); if (update->whichflag == 0) { if (compute->invoked_peratom != update->ntimestep) error->all("Compute used in variable between runs " @@ -750,18 +784,17 @@ double Variable::evaluate(char *str, Tree **tree) compute->invoked_flag |= INVOKED_PERATOM; } - peratom2global(1,NULL,compute->vector_atom,1,index1, + peratom2global(1,NULL,&compute->array_atom[0][index2-1], + compute->size_peratom_cols,index1, tree,treestack,ntreestack,argstack,nargstack); - // c_ID[][2] = per-atom array + // c_ID = vector from per-atom vector - } else if (nbracket == 2 && index1 == 0 && index2 > 0 && - compute->peratom_flag) { + } else if (nbracket == 0 && compute->peratom_flag && + compute->size_peratom_cols == 0) { if (tree == NULL) error->all("Per-atom compute in equal-style variable formula"); - if (index2 > compute->size_peratom_cols) - error->all("Compute vector in variable formula is too small"); if (update->whichflag == 0) { if (compute->invoked_peratom != update->ntimestep) error->all("Compute used in variable between runs " @@ -773,18 +806,21 @@ double Variable::evaluate(char *str, Tree **tree) Tree *newtree = new Tree(); newtree->type = ATOMARRAY; - newtree->array = &compute->array_atom[0][index2-1]; - newtree->nstride = compute->size_peratom_cols; + newtree->array = compute->vector_atom; + newtree->nstride = 1; newtree->left = newtree->right = NULL; treestack[ntreestack++] = newtree; - // c_ID[N][2] = global value from per-atom array + // c_ID[i] = vector from per-atom array - } else if (nbracket == 2 && index1 > 0 && index2 > 0 && - compute->peratom_flag) { + } else if (nbracket == 1 && compute->peratom_flag && + compute->size_peratom_cols > 0) { - if (index2 > compute->size_peratom_cols) - error->all("Compute vector in variable formula is too small"); + if (tree == NULL) + error->all("Per-atom compute in equal-style variable formula"); + if (index1 > compute->size_peratom_cols) + error->all("Variable formula compute vector " + "is accessed out-of-range"); if (update->whichflag == 0) { if (compute->invoked_peratom != update->ntimestep) error->all("Compute used in variable between runs " @@ -794,9 +830,12 @@ double Variable::evaluate(char *str, Tree **tree) compute->invoked_flag |= INVOKED_PERATOM; } - peratom2global(1,NULL,&compute->array_atom[0][index2-1], - compute->size_peratom_cols,index1, - tree,treestack,ntreestack,argstack,nargstack); + Tree *newtree = new Tree(); + newtree->type = ATOMARRAY; + newtree->array = &compute->array_atom[0][index1-1]; + newtree->nstride = compute->size_peratom_cols; + newtree->left = newtree->right = NULL; + treestack[ntreestack++] = newtree; } else error->all("Mismatched compute in variable formula"); @@ -805,6 +844,9 @@ double Variable::evaluate(char *str, Tree **tree) // ---------------- } else if (strncmp(word,"f_",2) == 0) { + if (domain->box_exist == 0) + error->all("Variable evaluation before simulation box is defined"); + n = strlen(word) - 2 + 1; char *id = new char[n]; strcpy(id,&word[2]); @@ -814,33 +856,33 @@ double Variable::evaluate(char *str, Tree **tree) Fix *fix = modify->fix[ifix]; delete [] id; - if (domain->box_exist == 0) - error->all("Variable evaluation before simulation box is defined"); - // parse zero or one or two trailing brackets // point i beyond last bracket // nbracket = # of bracket pairs - // index1,index2 = int inside each bracket pair, 0 if empty + // index1,index2 = int inside each bracket pair int nbracket,index1,index2; if (str[i] != '[') nbracket = 0; else { nbracket = 1; - i = int_between_brackets(str,i,index1,1); - i++; + ptr = &str[i]; + index1 = int_between_brackets(ptr); + i = ptr-str+1; if (str[i] == '[') { nbracket = 2; - i = int_between_brackets(str,i,index2,0); - i++; + ptr = &str[i]; + index2 = int_between_brackets(ptr); + i = ptr-str+1; } } - // f_ID = global scalar + // f_ID = scalar from global scalar if (nbracket == 0 && fix->scalar_flag) { if (update->whichflag > 0 && update->ntimestep % fix->global_freq) error->all("Fix in variable not computed at compatible time"); + value1 = fix->compute_scalar(); if (tree) { Tree *newtree = new Tree(); @@ -850,14 +892,15 @@ double Variable::evaluate(char *str, Tree **tree) treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value1; - // f_ID[2] = global vector + // f_ID[i] = scalar from global vector - } else if (nbracket == 1 && index1 > 0 && fix->vector_flag) { + } else if (nbracket == 1 && fix->vector_flag) { if (index1 > fix->size_vector) - error->all("Fix vector in variable formula is too small"); + error->all("Variable formula fix vector is accessed out-of-range"); if (update->whichflag > 0 && update->ntimestep % fix->global_freq) error->all("Fix in variable not computed at compatible time"); + value1 = fix->compute_vector(index1-1); if (tree) { Tree *newtree = new Tree(); @@ -867,66 +910,91 @@ double Variable::evaluate(char *str, Tree **tree) treestack[ntreestack++] = newtree; } else argstack[nargstack++] = value1; - // f_ID[] = per-atom vector + // f_ID[i][j] = scalar from global array - } else if (nbracket == 1 && index1 == 0 && - fix->peratom_flag && fix->size_peratom_cols == 0) { + } else if (nbracket == 2 && fix->array_flag) { + + if (index1 > fix->size_array_rows) + error->all("Variable formula fix vector is accessed out-of-range"); + if (index2 > fix->size_array_cols) + error->all("Variable formula fix vector is accessed out-of-range"); + if (update->whichflag > 0 && update->ntimestep % fix->global_freq) + error->all("Fix in variable not computed at compatible time"); + + value1 = fix->compute_array(index1-1,index2-1); + if (tree) { + Tree *newtree = new Tree(); + newtree->type = VALUE; + newtree->value = value1; + newtree->left = newtree->right = NULL; + treestack[ntreestack++] = newtree; + } else argstack[nargstack++] = value1; + + // f_ID[i] = scalar from per-atom vector + + } else if (nbracket == 1 && fix->peratom_flag && + fix->size_peratom_cols == 0) { - if (tree == NULL) - error->all("Per-atom fix in equal-style variable formula"); if (update->whichflag > 0 && update->ntimestep % fix->peratom_freq) error->all("Fix in variable not computed at compatible time"); - Tree *newtree = new Tree(); - newtree->type = ATOMARRAY; - newtree->array = fix->vector_atom; - newtree->nstride = 1; - newtree->left = newtree->right = NULL; - treestack[ntreestack++] = newtree; - // f_ID[N] = global value from per-atom vector + peratom2global(1,NULL,fix->vector_atom,1,index1, + tree,treestack,ntreestack,argstack,nargstack); - } else if (nbracket == 1 && index1 > 0 && - fix->peratom_flag && fix->size_peratom_cols == 0) { + // f_ID[i][j] = scalar from per-atom array + } else if (nbracket == 2 && fix->peratom_flag && + fix->size_peratom_cols > 0) { + + if (index2 > fix->size_peratom_cols) + error->all("Variable formula fix vector is accessed out-of-range"); if (update->whichflag > 0 && update->ntimestep % fix->peratom_freq) error->all("Fix in variable not computed at compatible time"); - peratom2global(1,NULL,fix->vector_atom,1,index1, + + peratom2global(1,NULL,&fix->array_atom[0][index2-1], + fix->size_peratom_cols,index1, tree,treestack,ntreestack,argstack,nargstack); - // f_ID[][2] = per-atom array + // f_ID = vector from per-atom vector - } else if (nbracket == 2 && index1 == 0 && index2 > 0 && - fix->peratom_flag) { + } else if (nbracket == 0 && fix->peratom_flag && + fix->size_peratom_cols == 0) { if (tree == NULL) error->all("Per-atom fix in equal-style variable formula"); - if (index2 > fix->size_peratom_cols) - error->all("Fix vector in variable formula is too small"); if (update->whichflag > 0 && update->ntimestep % fix->peratom_freq) error->all("Fix in variable not computed at compatible time"); + Tree *newtree = new Tree(); newtree->type = ATOMARRAY; - newtree->array = &fix->array_atom[0][index2-1]; - newtree->nstride = fix->size_peratom_cols; + newtree->array = fix->vector_atom; + newtree->nstride = 1; newtree->left = newtree->right = NULL; treestack[ntreestack++] = newtree; - // f_ID[N][2] = global value from per-atom array + // f_ID[i] = vector from per-atom array - } else if (nbracket == 2 && index1 > 0 && index2 > 0 && - fix->peratom_flag) { + } else if (nbracket == 1 && fix->peratom_flag && + fix->size_peratom_cols > 0) { - if (index2 > fix->size_peratom_cols) - error->all("Fix vector in variable formula is too small"); + if (tree == NULL) + error->all("Per-atom fix in equal-style variable formula"); + if (index1 > fix->size_peratom_cols) + error->all("Variable formula fix vector is accessed out-of-range"); if (update->whichflag > 0 && update->ntimestep % fix->peratom_freq) error->all("Fix in variable not computed at compatible time"); - peratom2global(1,NULL,&fix->array_atom[0][index2-1], - fix->size_peratom_cols,index1, - tree,treestack,ntreestack,argstack,nargstack); + + Tree *newtree = new Tree(); + newtree->type = ATOMARRAY; + newtree->array = &fix->array_atom[0][index1-1]; + newtree->nstride = fix->size_peratom_cols; + newtree->left = newtree->right = NULL; + treestack[ntreestack++] = newtree; + } else error->all("Mismatched fix in variable formula"); @@ -945,14 +1013,15 @@ double Variable::evaluate(char *str, Tree **tree) // parse zero or one trailing brackets // point i beyond last bracket // nbracket = # of bracket pairs - // index = int inside bracket, 0 if empty + // index = int inside bracket int nbracket,index; if (str[i] != '[') nbracket = 0; else { nbracket = 1; - i = int_between_brackets(str,i,index,1); - i++; + ptr = &str[i]; + index = int_between_brackets(ptr); + i = ptr-str+1; } // v_name = non atom-style variable = global value @@ -970,9 +1039,9 @@ double Variable::evaluate(char *str, Tree **tree) treestack[ntreestack++] = newtree; } else argstack[nargstack++] = atof(var); - // v_name[] = atom-style variable + // v_name = atom-style variable - } else if (nbracket && index == 0 && style[ivar] == ATOM) { + } else if (nbracket == 0 && style[ivar] == ATOM) { if (tree == NULL) error->all("Atom-style variable in equal-style variable formula"); @@ -984,7 +1053,7 @@ double Variable::evaluate(char *str, Tree **tree) // compute the per-atom variable in result // use peratom2global to extract single value from result - } else if (nbracket && index > 0 && style[ivar] == ATOM) { + } else if (nbracket && style[ivar] == ATOM) { double *result = (double *) memory->smalloc(atom->nlocal*sizeof(double),"variable:result"); @@ -1003,7 +1072,9 @@ double Variable::evaluate(char *str, Tree **tree) } else { + // ---------------- // math or group function + // ---------------- if (str[i] == '(') { char *contents; @@ -1019,25 +1090,29 @@ double Variable::evaluate(char *str, Tree **tree) delete [] contents; // ---------------- - // atom value or vector + // atom value // ---------------- } else if (str[i] == '[') { - int id; - i = int_between_brackets(str,i,id,1); - i++; - if (domain->box_exist == 0) error->all("Variable evaluation before simulation box is defined"); + + ptr = &str[i]; + int id = int_between_brackets(ptr); + i = ptr-str+1; - // ID between brackets exists: atom value - // empty brackets: atom vector + peratom2global(0,word,NULL,0,id, + tree,treestack,ntreestack,argstack,nargstack); - if (id > 0) - peratom2global(0,word,NULL,0,id, - tree,treestack,ntreestack,argstack,nargstack); - else - atom_vector(word,tree,treestack,ntreestack); + // ---------------- + // atom vector + // ---------------- + + } else if (is_atom_vector(word)) { + if (domain->box_exist == 0) + error->all("Variable evaluation before simulation box is defined"); + + atom_vector(word,tree,treestack,ntreestack); // ---------------- // thermo keyword @@ -1270,37 +1345,33 @@ int Variable::find_matching_paren(char *str, int i,char *&contents) } /* ---------------------------------------------------------------------- - find int between brackets and set index to its value - if emptyflag, then brackets can be empty (index = 0) - else if not emptyflag and brackets empty, is an error - else contents of brackets must be positive int - i = left bracket - return loc of right bracket + find int between brackets and return it + ptr initially points to left bracket + return it pointing to right bracket + error if no right bracket or brackets are empty + error if any between-bracket chars are non-digits or value == 0 ------------------------------------------------------------------------- */ -int Variable::int_between_brackets(char *str, int i, int &index, int emptyflag) +int Variable::int_between_brackets(char *&ptr) { - // istop = matching ']' + char *start = ++ptr; - int istart = i; - while (!str[i] || str[i] != ']') i++; - if (!str[i]) error->all("Invalid syntax in variable formula"); - int istop = i; - - int n = istop - istart - 1; - char *arg = new char[n+1]; - strncpy(arg,&str[istart+1],n); - arg[n] = '\0'; - - if (n == 0 && emptyflag) index = 0; - else if (n == 0) error->all("Empty brackets in variable formula"); - else { - index = atoi(arg); - if (index <= 0) error->all("Invalid index in variable formula"); + while (*ptr && *ptr != ']') { + if (!isdigit(*ptr)) + error->all("Non digit character between brackets in input command"); + ptr++; } - delete [] arg; - - return istop; + + if (*ptr != ']') error->all("Mismatched brackets in input command"); + if (ptr == start) error->all("Empty brackets in input command"); + + *ptr = '\0'; + int index = atoi(start); + *ptr = ']'; + + if (index == 0) + error->all("Index between input command brackets must be positive"); + return index; } /* ---------------------------------------------------------------------- @@ -1645,6 +1716,28 @@ void Variable::peratom2global(int flag, char *word, } else argstack[nargstack++] = value; } +/* ---------------------------------------------------------------------- + check if word matches an atom vector + return 1 if yes, else 0 + customize by adding an atom vector: mass,type,x,y,z,vx,vy,vz,fx,fy,fz +------------------------------------------------------------------------- */ + +int Variable::is_atom_vector(char *word) +{ + if (strcmp(word,"mass") == 0) return 1; + if (strcmp(word,"type") == 0) return 1; + if (strcmp(word,"x") == 0) return 1; + if (strcmp(word,"y") == 0) return 1; + if (strcmp(word,"z") == 0) return 1; + if (strcmp(word,"vx") == 0) return 1; + if (strcmp(word,"vy") == 0) return 1; + if (strcmp(word,"vz") == 0) return 1; + if (strcmp(word,"fx") == 0) return 1; + if (strcmp(word,"fy") == 0) return 1; + if (strcmp(word,"fz") == 0) return 1; + return 0; +} + /* ---------------------------------------------------------------------- process an atom vector in formula push result onto tree @@ -1686,6 +1779,4 @@ void Variable::atom_vector(char *word, Tree **tree, else if (strcmp(word,"fx") == 0) newtree->array = &atom->f[0][0]; else if (strcmp(word,"fy") == 0) newtree->array = &atom->f[0][1]; else if (strcmp(word,"fz") == 0) newtree->array = &atom->f[0][2]; - - else error->all("Invalid atom vector in variable formula"); } diff --git a/src/variable.h b/src/variable.h index 457b759ac0b4ea31283ab30d121e1f0a7ba292fc..6afe3bf8a32a4e16ce62acbe13c0b7443c7be217 100644 --- a/src/variable.h +++ b/src/variable.h @@ -31,6 +31,7 @@ class Variable : protected Pointers { char *retrieve(char *); double compute_equal(int); void compute_atom(int, int, double *, int, int); + int int_between_brackets(char *&); private: int me; @@ -59,12 +60,12 @@ class Variable : protected Pointers { double eval_tree(Tree *, int); void free_tree(Tree *); int find_matching_paren(char *, int, char *&); - int int_between_brackets(char *, int, int &, int); int math_function(char *, char *, Tree **, Tree **, int &, double *, int &); int group_function(char *, char *, Tree **, Tree **, int &, double *, int &); int region_function(char *); void peratom2global(int, char *, double *, int, int, Tree **, Tree **, int &, double *, int &); + int is_atom_vector(char *); void atom_vector(char *, Tree **, Tree **, int &); };