Files
lammps/src/USER-MISC/fix_ave_spatial_sphere.cpp
athomps 32acf72146 Simplified non-overlap condition
git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@14287 f3b2605a-c512-4ea7-a41b-209d697bcdaa
2015-12-05 03:32:34 +00:00

1064 lines
35 KiB
C++

/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Adapted from fix ave/spatial by Niall Jackson <niall.jackson@gmail.com>
------------------------------------------------------------------------- */
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "fix_ave_spatial_sphere.h"
#include "atom.h"
#include "update.h"
#include "force.h"
#include "domain.h"
#include "region.h"
#include "lattice.h"
#include "modify.h"
#include "compute.h"
#include "input.h"
#include "variable.h"
#include "memory.h"
#include "error.h"
#include "math_const.h"
using namespace LAMMPS_NS;
using namespace FixConst;
using namespace MathConst;
//the different types of variables that we can track
enum{V,F,DENSITY_NUMBER,DENSITY_MASS,COMPUTE,FIX,VARIABLE,CONSTANT};
//normalisation types
enum{SAMPLE,ALL};
//unit scaling options
enum{BOX,LATTICE,REDUCED};
//averaging types
enum{ONE,RUNNING,WINDOW};
#define INVOKED_SCALAR 1
#define INVOKED_VECTOR 2
#define INVOKED_PERATOM 8
#define BIG 1000000000
/* ---------------------------------------------------------------------- */
FixAveSpatialSphere::FixAveSpatialSphere(LAMMPS* lmp, int narg, char** arg) :
Fix(lmp, narg, arg) {
if (narg < 12) error->all(FLERR, "Illegal fix ave/spatial/sphere command");
MPI_Comm_rank(world, &me);
nevery= force->inumeric(FLERR, arg[3]);
nrepeat= force->inumeric(FLERR, arg[4]);
nfreq= force->inumeric(FLERR, arg[5]);
global_freq= nfreq;
for (int iarg = 6; iarg < 9; ++iarg) {
int dim= iarg-6;
origin_ids[dim]= NULL;
if (strncmp(arg[iarg],"c_",2) == 0 ||
strncmp(arg[iarg],"v_",2) == 0) {
if(arg[iarg][0] == 'c') {
origin_type[dim]= COMPUTE;
} else {
origin_type[dim]= VARIABLE;
}
//strip the v_/c_ off the front of the variable name
int n= strlen(arg[iarg]);
char *suffix= new char[n];
strcpy(suffix, &arg[iarg][2]);
//does the variable name contain a [?
//(in other words, is this an array element?)
char *ptr= strchr(suffix, '[');
if(ptr) {
//if the last character ISN'T ], then the array syntax
//has been used wrongly
if(suffix[strlen(suffix)-1] != ']') {
error->all(FLERR, "Illegal fix ave/spatial/sphere command");
}
origin_index[dim]= atoi(ptr+1);
*ptr= '\0';
} else {
origin_index[dim]= 0;
}
//store the name of the variable
n= strlen(suffix)+1;
origin_ids[dim]= new char[n];
strcpy(origin_ids[dim], suffix);
//tidy up the array we allocated earlier
delete[] suffix;
if(origin_type[dim] == COMPUTE) {
int icompute= modify->find_compute(origin_ids[dim]);
if(icompute < 0)
error->all(FLERR,
"Compute ID for fix ave/spatial/sphere does not exist");
if(origin_index[dim] == 0 &&
modify->compute[icompute]->scalar_flag != 0)
error->all(FLERR,"Compute for fix ave/spatial/sphere does not calculate a scalar");
else if(origin_index[dim] && modify->compute[icompute]->vector_flag == 0)
error->all(FLERR, "Compute for fix ave/spatial/sphere does not calculate a vector");
else if(origin_index[dim] && origin_index[dim] > modify->compute[icompute]->size_vector)
error->all(FLERR, "Fix ave/spatial/sphere compute vector accessed out of range");
} else if(origin_type[dim] == VARIABLE) {
int ivariable = input->variable->find(origin_ids[dim]);
if (ivariable < 0)
error->all(FLERR,"Variable name for fix ave/spatial/sphere does not exist");
else if (input->variable->equalstyle(ivariable) == 0)
error->all(FLERR,"Fix ave/spatial/sphere variable is not equal-style variable");
}
} else {
origin_type[dim]= CONSTANT;
origin[dim]= force->numeric(FLERR, arg[iarg]);
}
}
//the extrema of the radius
r_min= force->numeric(FLERR, arg[9]);
r_max= force->numeric(FLERR, arg[10]);
//and finally, the number of spherical bins
nbins= force->inumeric(FLERR, arg[11]);
if (r_min >= r_max) {
error->all(FLERR, "r_min must be less than r_max in fix ave/spatial/sphere");
}
if (nbins <= 0) {
error->all(FLERR, "nbins must be positive in fix ave/spatial/sphere");
}
int iarg= 12;
which= new int[narg-12];
argindex= new int[narg-12];
ids= new char*[narg-12];
value2index= new int[narg-12];
nvalues= 0;
while(iarg < narg) {
ids[nvalues]= NULL;
if(strcmp(arg[iarg], "vx") == 0) {
which[nvalues] = V;
argindex[nvalues++]= 0;
} else if(strcmp(arg[iarg], "vy") == 0) {
which[nvalues] = V;
argindex[nvalues++]= 1;
} else if(strcmp(arg[iarg], "vz") == 0) {
which[nvalues] = V;
argindex[nvalues++]= 2;
} else if(strcmp(arg[iarg], "fx") == 0) {
which[nvalues] = F;
argindex[nvalues++]= 0;
} else if(strcmp(arg[iarg], "fy") == 0) {
which[nvalues] = F;
argindex[nvalues++]= 1;
} else if(strcmp(arg[iarg], "fz") == 0) {
which[nvalues] = F;
argindex[nvalues++]= 2;
} else if(strcmp(arg[iarg], "density/number") == 0) {
which[nvalues] = DENSITY_NUMBER;
argindex[nvalues++]= 0;
} else if(strcmp(arg[iarg], "density/mass") == 0) {
which[nvalues] = DENSITY_MASS;
argindex[nvalues++]= 0;
} else if (strncmp(arg[iarg],"c_",2) == 0 ||
strncmp(arg[iarg],"f_",2) == 0 ||
strncmp(arg[iarg],"v_",2) == 0) {
if(arg[iarg][0] == 'c') which[nvalues] = COMPUTE;
else if(arg[iarg][0] == 'f') which[nvalues] = FIX;
else if(arg[iarg][0] == 'v') which[nvalues] = VARIABLE;
//strip the v_/c_/f_ off the front of the variable name
int n= strlen(arg[iarg]);
char *suffix= new char[n];
strcpy(suffix, &arg[iarg][2]);
//does the variable name contain a [?
//(in other words, is this an array element?)
char *ptr= strchr(suffix, '[');
if(ptr) {
//if the last character ISN'T ], then the array syntax
//has been used wrongly
if(suffix[strlen(suffix)-1] != ']') {
error->all(FLERR, "Illegal fix ave/spatial/sphere command");
}
argindex[nvalues]= atoi(ptr+1);
*ptr= '\0';
} else {
argindex[nvalues]= 0;
}
//store the name of the variable
n= strlen(suffix)+1;
ids[nvalues]= new char[n];
strcpy(ids[nvalues], suffix);
nvalues++;
//tidy up the array we allocated earlier
delete[] suffix;
} else break;
iarg++;
}
//process the optional arguments
normflag= ALL; //normalise the average right at the end
scaleflag= LATTICE; // lattice units are the default
regionflag= 0; //are we restricted to a particular region?
idregion= NULL; //name of the region to sue, if so
fp= NULL; //output file
ave= ONE; //averaging mode
nwindow= 0; //number of averaging windows
overwrite= 0; //continuously overwrite output?
char *title1= NULL;
char *title2= NULL;
char *title3= NULL;
while (iarg < narg) {
if (strcmp(arg[iarg],"norm") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/spatial/sphere command");
if (strcmp(arg[iarg+1],"all") == 0) normflag = ALL;
else if (strcmp(arg[iarg+1],"sample") == 0) normflag = SAMPLE;
else error->all(FLERR,"Illegal fix ave/spatial/sphere command");
iarg += 2;
} else if (strcmp(arg[iarg],"units") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/spatial/sphere command");
if (strcmp(arg[iarg+1],"box") == 0) scaleflag = BOX;
else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = LATTICE;
else if (strcmp(arg[iarg+1],"reduced") == 0) scaleflag = REDUCED;
else error->all(FLERR,"Illegal fix ave/spatial/sphere command");
iarg += 2;
} else if (strcmp(arg[iarg],"region") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/spatial/sphere command");
int iregion = domain->find_region(arg[iarg+1]);
if (iregion == -1)
error->all(FLERR,"Region ID for fix ave/spatial does not exist");
int n = strlen(arg[iarg+1]) + 1;
idregion = new char[n];
strcpy(idregion,arg[iarg+1]);
regionflag = 1;
iarg += 2;
} else if (strcmp(arg[iarg],"file") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/spatial/sphere command");
if (me == 0) {
fp = fopen(arg[iarg+1],"w");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open fix ave/spatial file %s",arg[iarg+1]);
error->one(FLERR,str);
}
}
iarg += 2;
} else if (strcmp(arg[iarg],"ave") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/spatial/sphere command");
if (strcmp(arg[iarg+1],"one") == 0) ave = ONE;
else if (strcmp(arg[iarg+1],"running") == 0) ave = RUNNING;
else if (strcmp(arg[iarg+1],"window") == 0) ave = WINDOW;
else error->all(FLERR,"Illegal fix ave/spatial/sphere command");
if (ave == WINDOW) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix ave/spatial/sphere command");
nwindow = force->inumeric(FLERR,arg[iarg+2]);
if (nwindow <= 0) error->all(FLERR,"Illegal fix ave/spatial/sphere command");
}
iarg += 2;
if (ave == WINDOW) iarg++;
} else if (strcmp(arg[iarg],"overwrite") == 0) {
overwrite = 1;
iarg += 1;
} else if (strcmp(arg[iarg],"title1") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix ave/spatial/sphere 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(FLERR,"Illegal fix ave/spatial/sphere 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(FLERR,"Illegal fix ave/spatial/sphere command");
delete [] title3;
int n = strlen(arg[iarg+1]) + 1;
title3 = new char[n];
strcpy(title3,arg[iarg+1]);
iarg += 2;
} else error->all(FLERR,"Illegal fix ave/spatial/sphere command");
}
//setup and error checking
if (nevery <= 0 || nrepeat <= 0 || nfreq <= 0)
error->all(FLERR,"Illegal fix ave/spatial/sphere command");
if (nfreq % nevery || nrepeat*nevery > nfreq)
error->all(FLERR,"Illegal fix ave/spatial/sphere command");
if (ave != RUNNING && overwrite)
error->all(FLERR,"Illegal fix ave/spatial/sphere command");
//setup the variables that we need to average
for (int i = 0; i < nvalues; i++) {
if (which[i] == COMPUTE) {
int icompute = modify->find_compute(ids[i]);
if (icompute < 0)
error->all(FLERR,"Compute ID for fix ave/spatial/sphere does not exist");
if (modify->compute[icompute]->peratom_flag == 0)
error->all(FLERR,"Fix ave/spatial/sphere compute does not "
"calculate per-atom values");
if (argindex[i] == 0 &&
modify->compute[icompute]->size_peratom_cols != 0)
error->all(FLERR,"Fix ave/spatial/sphere compute does not "
"calculate a per-atom vector");
if (argindex[i] && modify->compute[icompute]->size_peratom_cols == 0)
error->all(FLERR,"Fix ave/spatial/sphere compute does not "
"calculate a per-atom array");
if (argindex[i] &&
argindex[i] > modify->compute[icompute]->size_peratom_cols)
error->all(FLERR,
"Fix ave/spatial/sphere compute vector is accessed out-of-range");
} else if (which[i] == FIX) {
int ifix = modify->find_fix(ids[i]);
if (ifix < 0)
error->all(FLERR,"Fix ID for fix ave/spatial/sphere does not exist");
if (modify->fix[ifix]->peratom_flag == 0)
error->all(FLERR,
"Fix ave/spatial/sphere fix does not calculate per-atom values");
if (argindex[i] && modify->fix[ifix]->size_peratom_cols != 0)
error->all(FLERR,
"Fix ave/spatial/spherefix does not calculate a per-atom vector");
if (argindex[i] && modify->fix[ifix]->size_peratom_cols == 0)
error->all(FLERR,
"Fix ave/spatial/sphere fix does not calculate a per-atom array");
if (argindex[i] && argindex[i] > modify->fix[ifix]->size_peratom_cols)
error->all(FLERR,"Fix ave/spatial/sphere fix vector is accessed out-of-range");
} else if (which[i] == VARIABLE) {
int ivariable = input->variable->find(ids[i]);
if (ivariable < 0)
error->all(FLERR,"Variable name for fix ave/spatial/sphere does not exist");
if (input->variable->atomstyle(ivariable) == 0)
error->all(FLERR,"Fix ave/spatial/sphere variable is not atom-style variable");
}
}
// setup the scaling
int triclinic= domain->triclinic;
if(scaleflag != REDUCED) {
if (triclinic) {
error->all(FLERR, "Fix ave/spatial/sphere for triclinic boxes requires units reduced");
} else {
// if not in reduced units, the box must not become triclinic
no_change_box= 1;
}
}
if(scaleflag == LATTICE) {
scale= domain->lattice->xlattice;
if(domain->lattice->xlattice != domain->lattice->ylattice
&& domain->lattice->xlattice != domain->lattice->zlattice)
error->all(FLERR, "Fix ave/spatial/sphere with lattice units requires that the lattice "
"spacing be equal in all dimensions");
} else if(scaleflag == REDUCED) {
scale= 1.0;
} else {
scale= 1.0;
}
//apply the scaling factors
origin[0]*= scale;
origin[1]*= scale;
origin[2]*= scale;
r_min*= scale;
r_max*= scale;
r_minsq= r_min*r_min;
r_maxsq= r_max*r_max;
deltar= (r_max-r_min)/nbins;
inv_deltar= 1.0/deltar;
//print file comment lines
if (fp && me == 0) {
if (title1) {
fprintf(fp,"%s\n",title1);
} else {
fprintf(fp,"# Spatial-averaged data for fix %s and group %s\n", id,arg[1]);
fprintf(fp,"# Spherical bins centred at (");
for (int i= 0; i < 3; ++i) {
if(origin_type[i] == CONSTANT) fprintf(fp,"%g",origin[i]);
else fprintf(fp,"%s",arg[i+6]);
if(i != 2) fprintf(fp, ", ");
else fprintf(fp, ")");
}
if (scaleflag == REDUCED) {
fprintf(fp, " [reduced units]");
}
fprintf(fp, "\n");
}
if (title2) fprintf(fp,"%s\n",title2);
else fprintf(fp,"# Timestep Number-of-bins\n");
if (title3) fprintf(fp,"%s\n",title3);
else {
fprintf(fp,"# Bin r Ncount");
for (int i = 0; i < nvalues; i++) fprintf(fp," %s",arg[12+i]);
fprintf(fp,"\n");
}
filepos = ftell(fp);
}
delete [] title1;
delete [] title2;
delete [] title3;
//this fix produces a global array
array_flag= 1;
size_array_rows= BIG;
size_array_cols= 1 + 1 + nvalues;
extarray= 0; //intensive value (don't divide by N when we output this)
//initialization of remaining variables
irepeat= 0;
iwindow= window_limit= 0;
norm= 0;
maxvar= 0;
varatom= NULL;
maxatom= 0;
bin= NULL;
binvol= NULL;
maxbin= 0;
count_one= count_many= count_sum= count_total= NULL;
coord= NULL;
count_list= NULL;
values_one= values_many= values_sum= values_total= NULL;
values_list= NULL;
//nvalid = next step on which end_of_step does something
nvalid= nextvalid();
//make every compute update itself on step nvalid
//since we don't yet know which ones we need
//can correct this when we call end_of_step
modify->addstep_compute_all(nvalid);
}
/* ---------------------------------------------------------------------- */
FixAveSpatialSphere::~FixAveSpatialSphere()
{
delete [] which;
delete [] argindex;
for (int i = 0; i < nvalues; i++) delete [] ids[i];
delete [] ids;
delete [] value2index;
delete [] idregion;
for (int i= 0; i < 3; ++i) delete [] origin_ids[i];
if (fp && me == 0) fclose(fp);
memory->destroy(varatom);
memory->destroy(bin);
memory->destroy(binvol);
memory->destroy(count_one);
memory->destroy(count_many);
memory->destroy(count_sum);
memory->destroy(count_total);
memory->destroy(coord);
memory->destroy(count_list);
memory->destroy(values_one);
memory->destroy(values_many);
memory->destroy(values_sum);
memory->destroy(values_total);
memory->destroy(values_list);
}
/* ----------------------------------------------------------------------
tell LAMMPS at which stages in the timestep we want to be called
we only care about running at the end of a step
------------------------------------------------------------------------- */
int FixAveSpatialSphere::setmask()
{
int mask = 0;
mask |= END_OF_STEP;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixAveSpatialSphere::init()
{
//set up the region and check it's valid
if(regionflag) {
int iregion= domain->find_region(idregion);
if(iregion == -1)
error->all(FLERR,"Region ID for fix ave/spatial/sphere does not exist");
region = domain->regions[iregion];
}
// set indices and check validity of all computes,fixes,variables
// check that fix frequency is acceptable
for (int m = 0; m < 3; ++m) {
if (origin_type[m] == COMPUTE) {
int icompute = modify->find_compute(origin_ids[m]);
if (icompute < 0)
error->all(FLERR, "Compute ID for fix ave/spatial/sphere does not exist");
origin_val2idx[m]= icompute;
} else if (origin_type[m] == VARIABLE) {
int ivariable = input->variable->find(origin_ids[m]);
if (ivariable < 0)
error->all(FLERR, "Variable name for fix ave/spatial/sphere does not exist");
origin_val2idx[m]= ivariable;
}
}
for (int m = 0; m < nvalues; m++) {
if (which[m] == COMPUTE) {
int icompute = modify->find_compute(ids[m]);
if (icompute < 0)
error->all(FLERR,"Compute ID for fix ave/spatial/sphere does not exist");
value2index[m] = icompute;
} else if (which[m] == FIX) {
int ifix = modify->find_fix(ids[m]);
if (ifix < 0)
error->all(FLERR,"Fix ID for fix ave/spatial/sphere does not exist");
value2index[m] = ifix;
if (nevery % modify->fix[ifix]->peratom_freq)
error->all(FLERR,
"Fix for fix ave/spatial/sphere not computed at compatible time");
} else if (which[m] == VARIABLE) {
int ivariable = input->variable->find(ids[m]);
if (ivariable < 0)
error->all(FLERR,"Variable name for fix ave/spatial/sphere does not exist");
value2index[m] = ivariable;
} else value2index[m] = -1;
}
// need to reset nvalid if nvalid < ntimestep b/c minimize was performed
if (nvalid < update->ntimestep) {
irepeat = 0;
nvalid = nextvalid();
modify->addstep_compute_all(nvalid);
}
}
/* ----------------------------------------------------------------------
setup initial bins
only does averaging if nvalid = current timestep
------------------------------------------------------------------------- */
void FixAveSpatialSphere::setup(int vflag)
{
setup_bins();
end_of_step();
}
/* ---------------------------------------------------------------------- */
void FixAveSpatialSphere::end_of_step()
{
//skip this step if we don't need to do anything
bigint ntimestep= update->ntimestep;
if(ntimestep != nvalid) return;
//update region if necessary
if (regionflag) region->prematch();
//zero out arrays that accumulate over many samples
if(irepeat == 0) {
for(int m= 0; m < nbins; m++) {
count_many[m]= count_sum[m]= 0.0;
for(int i= 0; i < nvalues; i++) values_many[m][i]= 0.0;
}
}
//if in reduced units, we need to update the bin volumes
if (scaleflag == REDUCED && domain->box_change) set_bin_volumes();
//zero out arrays for one sample
for(int m= 0; m < nbins; m++) {
count_one[m]= 0.0;
for (int i= 0; i < nvalues; i++) values_one[m][i]= 0.0;
}
//bin each atom
int *mask= atom->mask;
int nlocal= atom->nlocal;
if (nlocal > maxatom) {
maxatom= atom->nmax;
memory->destroy(bin);
memory->create(bin,maxatom,"ave/spatial/sphere:bin");
}
// perform the computation for one sample
// accumulate results of attributes,computes,fixes,variables to local copy
// sum within each bin, only include atoms in fix group
// compute/fix/variable may invoke computes so wrap with clear/add
modify->clearstep_compute();
//allocates the bins array
//each atom gets either the number of the bin into which
//it fits, or -1
bin_atoms();
for(int m= 0; m < nvalues; m++) {
int n= value2index[m];
int j= argindex[m];
if(which[m] == V || which[m] == F) {
double **attribute;
if(which[m] == V) attribute= atom->v;
else attribute= atom->f;
for(int i= 0; i < nlocal; i++) {
if(mask[i] & groupbit && bin[i] > -1) {
values_one[bin[i]][m] += attribute[i][j];
}
}
} else if(which[m] == DENSITY_NUMBER) {
for(int i= 0; i < nlocal; i++) {
if(mask[i] & groupbit && bin[i] > -1) {
values_one[bin[i]][m] += 1.0;
}
}
// density is additionally normalized by bin volume
for (int j = 0; j < nbins; j++)
values_one[j][m] /= binvol[j];
} else if(which[m] == DENSITY_MASS) {
int *type = atom->type;
double *mass = atom->mass;
double *rmass = atom->rmass;
for(int i= 0; i < nlocal; i++) {
if(mask[i] & groupbit && bin[i] > -1) {
if (rmass) values_one[bin[i]][m] += rmass[i];
else values_one[bin[i]][m] += mass[type[i]];
}
}
// density is additionally normalized by bin volume
for (int j = 0; j < nbins; j++)
values_one[j][m] /= binvol[j];
} else if(which[m] == COMPUTE) {
Compute *compute = modify->compute[n];
if (!(compute->invoked_flag & INVOKED_PERATOM)) {
compute->compute_peratom();
compute->invoked_flag |= INVOKED_PERATOM;
}
double *vector = compute->vector_atom;
double **array = compute->array_atom;
int jm1 = j - 1;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && bin[i] > -1) {
if (j == 0) values_one[bin[i]][m] += vector[i];
else values_one[bin[i]][m] += array[i][jm1];
}
} else if(which[m] == FIX) {
double *vector = modify->fix[n]->vector_atom;
double **array = modify->fix[n]->array_atom;
int jm1 = j - 1;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && bin[i] > -1) {
if (j == 0) values_one[bin[i]][m] += vector[i];
else values_one[bin[i]][m] += array[i][jm1];
}
} else if(which[m] == VARIABLE) {
if (nlocal > maxvar) {
maxvar = atom->nmax;
memory->destroy(varatom);
memory->create(varatom,maxvar,"ave/spatial:varatom");
}
input->variable->compute_atom(n,igroup,varatom,1,0);
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && bin[i] > -1)
values_one[bin[i]][m] += varatom[i];
}
}
// process a single sample
// if normflag = ALL, accumulate values,count separately to many
// if normflag = SAMPLE, one = value/count, accumulate one to many
// exception is SAMPLE density: no normalization by atom count
if (normflag == ALL) {
for (int m = 0; m < nbins; m++) {
count_many[m] += count_one[m];
for (int j = 0; j < nvalues; j++)
values_many[m][j] += values_one[m][j];
}
} else {
MPI_Allreduce(count_one,count_many,nbins,MPI_DOUBLE,MPI_SUM,world);
for (int m = 0; m < nbins; m++) {
if (count_many[m] > 0.0)
for (int j = 0; j < nvalues; j++) {
if (which[j] == DENSITY_NUMBER || which[j] == DENSITY_MASS)
values_many[m][j] += values_one[m][j];
else values_many[m][j] += values_one[m][j]/count_many[m];
}
count_sum[m] += count_many[m];
}
}
// done if irepeat < nrepeat
// else reset irepeat and nvalid
irepeat++;
if (irepeat < nrepeat) {
nvalid += nevery;
modify->addstep_compute(nvalid);
return;
}
irepeat++;
if (irepeat < nrepeat) {
nvalid += nevery;
modify->addstep_compute(nvalid);
return;
}
irepeat = 0;
nvalid = ntimestep+nfreq - (nrepeat-1)*nevery;
modify->addstep_compute(nvalid);
// time average across samples
// if normflag = ALL, final is total value / total count
// if normflag = SAMPLE, final is sum of ave / repeat
// exception is densities: normalized by repeat, not total count
double repeat = nrepeat;
double mv2d = force->mv2d;
if (normflag == ALL) {
MPI_Allreduce(count_many,count_sum,nbins,MPI_DOUBLE,MPI_SUM,world);
MPI_Allreduce(&values_many[0][0],&values_sum[0][0],nbins*nvalues,
MPI_DOUBLE,MPI_SUM,world);
for (int m = 0; m < nbins; m++) {
if (count_sum[m] > 0.0)
for (int j = 0; j < nvalues; j++)
if (which[j] == DENSITY_NUMBER) values_sum[m][j] /= repeat;
else if (which[j] == DENSITY_MASS) values_sum[m][j] *= mv2d/repeat;
else values_sum[m][j] /= count_sum[m];
count_sum[m] /= repeat;
}
} else {
MPI_Allreduce(&values_many[0][0],&values_sum[0][0],nbins*nvalues,
MPI_DOUBLE,MPI_SUM,world);
for (int m = 0; m < nbins; m++) {
for (int j = 0; j < nvalues; j++)
values_sum[m][j] /= repeat;
count_sum[m] /= repeat;
}
}
// if ave = ONE, only single Nfreq timestep value is needed
// if ave = RUNNING, combine with all previous Nfreq timestep values
// if ave = WINDOW, comine with nwindow most recent Nfreq timestep values
if (ave == ONE) {
for (int m = 0; m < nbins; m++) {
for (int i = 0; i < nvalues; i++)
values_total[m][i] = values_sum[m][i];
count_total[m] = count_sum[m];
}
norm = 1;
} else if (ave == RUNNING) {
for (int m = 0; m < nbins; m++) {
for (int i = 0; i < nvalues; i++)
values_total[m][i] += values_sum[m][i];
count_total[m] += count_sum[m];
}
norm++;
} else if (ave == WINDOW) {
for (int m = 0; m < nbins; m++) {
for (int i = 0; i < nvalues; i++) {
values_total[m][i] += values_sum[m][i];
if (window_limit) values_total[m][i] -= values_list[iwindow][m][i];
values_list[iwindow][m][i] = values_sum[m][i];
}
count_total[m] += count_sum[m];
if (window_limit) count_total[m] -= count_list[iwindow][m];
count_list[iwindow][m] = count_sum[m];
}
iwindow++;
if (iwindow == nwindow) {
iwindow = 0;
window_limit = 1;
}
if (window_limit) norm = nwindow;
else norm = iwindow;
}
// output result to file
if (fp && me == 0) {
if (overwrite) fseek(fp,filepos,SEEK_SET);
fprintf(fp,BIGINT_FORMAT " %d\n",ntimestep,nbins);
for (int m = 0; m < nbins; m++) {
fprintf(fp," %d %g %g",m+1,coord[m],
count_total[m]/norm);
for (int i = 0; i < nvalues; i++)
fprintf(fp," %g",values_total[m][i]/norm);
fprintf(fp,"\n");
}
fflush(fp);
if (overwrite) {
long fileend = ftell(fp);
if (fileend > 0) ftruncate(fileno(fp),fileend);
}
}
}
/* ----------------------------------------------------------------------
setup the bins
called at setup()
------------------------------------------------------------------------- */
void FixAveSpatialSphere::setup_bins()
{
if(nbins > maxbin) {
maxbin= nbins;
memory->grow(count_one,nbins,"ave/spatial/sphere:count_one");
memory->grow(count_many,nbins,"ave/spatial/sphere:count_many");
memory->grow(count_sum,nbins,"ave/spatial/sphere:count_sum");
memory->grow(count_total,nbins,"ave/spatial/sphere:count_total");
memory->grow(coord,nbins,"ave/spatial/sphere:coord");
memory->grow(binvol,nbins, "ave/spatial/sphere:binvol");
memory->grow(values_one,nbins,nvalues,"ave/spatial/sphere:values_one");
memory->grow(values_many,nbins,nvalues,"ave/spatial/sphere:values_many");
memory->grow(values_sum,nbins,nvalues,"ave/spatial/sphere:values_sum");
memory->grow(values_total,nbins,nvalues,"ave/spatial/sphere:values_total");
//the count and value lists are only relevant for windowed averaging
if(ave == WINDOW) {
memory->create(count_list,nwindow,nbins,"ave/spatial/sphere:count_list");
memory->create(values_list,nwindow,nbins,nvalues,
"ave/spatial/sphere:values_list");
}
//reinitialize the regrown count and values
for(int m= 0; m < nbins; m++) {
for(int i= 0; i < nvalues; i++) values_total[m][i]= 0.0;
count_total[m]= 0.0;
}
}
//set the bin coordinates
for(int i= 0; i < nbins; i++)
coord[i]= r_min + (i+0.5)*deltar;
set_bin_volumes();
}
/* ----------------------------------------------------------------------
set the bin volumes
called at setup() and when averaging occurs if box size changes
------------------------------------------------------------------------- */
void FixAveSpatialSphere::set_bin_volumes()
{
double last_vol= THIRD*MY_4PI*r_minsq*r_min;
for(int i= 0; i < nbins; i++) {
double temp_r= r_min + (i+1)*deltar;
double temp_vol= THIRD*MY_4PI*temp_r*temp_r*temp_r;
binvol[i]= temp_vol-last_vol;
last_vol= temp_vol;
}
//if in reduced co-ordinates, need to adjust the bin volumes appropriately
if (scaleflag == REDUCED) {
double xprd= domain->xprd;
double yprd= domain->yprd;
double zprd= domain->zprd;
for(int i= 0; i < nbins; i++) {
binvol[i]*= xprd*yprd*zprd;
}
}
}
/* ----------------------------------------------------------------------
assign atoms to bins
------------------------------------------------------------------------- */
void FixAveSpatialSphere::bin_atoms()
{
//update the origin coordinates if necessary
//unscale the existing coordinates
if(scaleflag == REDUCED) domain->lamda2x(origin, origin);
for (int i = 0; i < 3; ++i) {
if (origin_type[i] == COMPUTE) {
Compute *compute = modify->compute[origin_val2idx[i]];
if (origin_index[i] == 0) {
if (!(compute->invoked_flag & INVOKED_SCALAR)) {
compute->compute_scalar();
compute->invoked_flag |= INVOKED_SCALAR;
}
origin[i] = compute->scalar;
} else {
if (!(compute->invoked_flag & INVOKED_VECTOR)) {
compute->compute_vector();
compute->invoked_flag |= INVOKED_VECTOR;
}
origin[i] = compute->vector[origin_index[i]-1];
}
} else if (origin_type[i] == VARIABLE) {
origin[i] = input->variable->compute_equal(origin_val2idx[i]);
}
}
//make sure that the origin point is INSIDE the box
domain->remap(origin);
//rescale if necessary
if(scaleflag == REDUCED) domain->x2lamda(origin, origin);
double **x= atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double *prd,*prd_half;
//deal with the periodic boundary conditions
if(domain->periodicity[0] || domain->periodicity[1] || domain->periodicity[2]) {
if(scaleflag == REDUCED) {
prd= domain->prd_lamda;
prd_half= domain->prd_half_lamda;
} else {
prd= domain->prd;
prd_half= domain->prd_half;
}
}
double rsq, tmp;
if(!regionflag) {
if(scaleflag == REDUCED) {
//convert the atomic coordinates into reduced coordinates
domain->x2lamda(nlocal);
}
for(int i= 0; i < nlocal; i++) {
if(mask[i] & groupbit) {
rsq= 0.0;
for(int dim= 0; dim < 3; dim++) {
tmp= x[i][dim] - origin[dim];
if(domain->periodicity[dim]) {
if(tmp < -prd_half[dim]) tmp+= prd[dim];
else if(tmp >= prd_half[dim]) tmp-= prd[dim];
}
rsq+= tmp*tmp;
}
if(rsq >= r_minsq && rsq <= r_maxsq) {
double r= sqrt(rsq);
int ibin= static_cast<int>((r-r_min)*inv_deltar);
ibin = MAX(ibin,0);
ibin = MIN(ibin,nbins-1);
bin[i]= ibin;
count_one[ibin]+= 1.0;
} else {
bin[i]= -1;
}
}
}
if(scaleflag == REDUCED) {
//convert the atomic coordinates back into "real" coordinates
domain->lamda2x(nlocal);
}
} else {
for(int i= 0; i < nlocal; i++) {
if(mask[i] & groupbit && region->match(x[i][0], x[i][1], x[i][2])) {
rsq= 0.0;
for(int dim= 0; dim < 3; dim++) {
tmp= x[i][dim] - origin[dim];
if(domain->periodicity[dim]) {
if(tmp < -0.5*prd[dim]) tmp+= prd[dim];
else if(tmp >= 0.5*prd[dim]) tmp-= prd[dim];
}
rsq+= tmp*tmp;
}
if(rsq >= r_minsq && rsq <= r_maxsq) {
double r= sqrt(rsq);
int ibin= static_cast<int>((r-r_min)*inv_deltar);
ibin = MAX(ibin,0);
ibin = MIN(ibin,nbins-1);
bin[i]= ibin;
count_one[ibin]+= 1.0;
} else {
bin[i]= -1;
}
}
}
}
}
/* ----------------------------------------------------------------------
return I,J array value
if I exceeds current bins, return 0.0 instead of generating an error
column 1 = bin coords, next column = count, remaining columns = Nvalues
------------------------------------------------------------------------- */
double FixAveSpatialSphere::compute_array(int i, int j)
{
if (values_total == NULL) return 0.0;
if (i >= nbins || j > nvalues) return 0.0;
if (!norm) return 0.0;
if (j == 0) return coord[i];
if (j == 1) return count_total[i]/norm;
return values_total[i][j]/norm;
}
/* ----------------------------------------------------------------------
calculate nvalid = next step on which end_of_step does something
can be this timestep if multiple of nfreq and nrepeat = 1
else backup from next multiple of nfreq
------------------------------------------------------------------------- */
bigint FixAveSpatialSphere::nextvalid()
{
bigint nvalid = (update->ntimestep/nfreq)*nfreq + nfreq;
if (nvalid-nfreq == update->ntimestep && nrepeat == 1)
nvalid = update->ntimestep;
else
nvalid -= (nrepeat-1)*nevery;
if (nvalid < update->ntimestep) nvalid += nfreq;
return nvalid;
}
/* ----------------------------------------------------------------------
memory usage of varatom and bins
------------------------------------------------------------------------- */
double FixAveSpatialSphere::memory_usage()
{
double bytes = maxvar * sizeof(double); // varatom
bytes += maxatom * sizeof(int); // bin
bytes += 4*nbins * sizeof(double); // count one,many,sum,total
bytes += nbins * sizeof(double); // coord
bytes += nvalues*nbins * sizeof(double); // values one,many,sum,total
bytes += nwindow*nbins * sizeof(double); // count_list
bytes += nwindow*nbins*nvalues * sizeof(double); // values_list
return bytes;
}