1748 lines
52 KiB
C++
1748 lines
52 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 Gene<ral Public License.
|
|
|
|
See the README file in the top-level LAMMPS directory.
|
|
------------------------------------------------------------------------- */
|
|
|
|
#include "fix_hyper_local.h"
|
|
|
|
#include <cmath>
|
|
#include <cstring>
|
|
|
|
#include "atom.h"
|
|
#include "update.h"
|
|
#include "group.h"
|
|
#include "force.h"
|
|
#include "pair.h"
|
|
#include "domain.h"
|
|
#include "comm.h"
|
|
#include "my_page.h"
|
|
#include "neighbor.h"
|
|
#include "neigh_request.h"
|
|
#include "neigh_list.h"
|
|
#include "math_extra.h"
|
|
#include "memory.h"
|
|
#include "error.h"
|
|
|
|
|
|
using namespace LAMMPS_NS;
|
|
using namespace FixConst;
|
|
|
|
#define DELTABOND 16384
|
|
#define DELTABIAS 16
|
|
#define COEFFINIT 1.0
|
|
#define FCCBONDS 12
|
|
#define BIG 1.0e20
|
|
|
|
enum{STRAIN,STRAINDOMAIN,BIASFLAG,BIASCOEFF};
|
|
enum{IGNORE,WARN,ERROR};
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
FixHyperLocal::FixHyperLocal(LAMMPS *lmp, int narg, char **arg) :
|
|
FixHyper(lmp, narg, arg), blist(nullptr), biascoeff(nullptr), numbond(nullptr),
|
|
maxhalf(nullptr), eligible(nullptr), maxhalfstrain(nullptr), old2now(nullptr),
|
|
tagold(nullptr), xold(nullptr), maxstrain(nullptr), maxstrain_domain(nullptr),
|
|
biasflag(nullptr), bias(nullptr), cpage(nullptr), clist(nullptr), numcoeff(nullptr)
|
|
{
|
|
// error checks
|
|
|
|
if (atom->map_style == Atom::MAP_NONE)
|
|
error->all(FLERR,"Fix hyper/local command requires atom map");
|
|
|
|
// parse args
|
|
|
|
if (narg < 10) error->all(FLERR,"Illegal fix hyper/local command");
|
|
|
|
hyperflag = 2;
|
|
scalar_flag = 1;
|
|
vector_flag = 1;
|
|
size_vector = 26;
|
|
//size_vector = 28; // can add 2 for debugging
|
|
local_flag = 1;
|
|
size_local_rows = 0;
|
|
size_local_cols = 0;
|
|
local_freq = 1;
|
|
|
|
global_freq = 1;
|
|
extscalar = 0;
|
|
extvector = 0;
|
|
|
|
cutbond = utils::numeric(FLERR,arg[3],false,lmp);
|
|
qfactor = utils::numeric(FLERR,arg[4],false,lmp);
|
|
vmax = utils::numeric(FLERR,arg[5],false,lmp);
|
|
tequil = utils::numeric(FLERR,arg[6],false,lmp);
|
|
dcut = utils::numeric(FLERR,arg[7],false,lmp);
|
|
alpha_user = utils::numeric(FLERR,arg[8],false,lmp);
|
|
boost_target = utils::numeric(FLERR,arg[9],false,lmp);
|
|
|
|
if (cutbond < 0.0 || qfactor < 0.0 || vmax < 0.0 ||
|
|
tequil <= 0.0 || dcut <= 0.0 || alpha_user <= 0.0 || boost_target < 1.0)
|
|
error->all(FLERR,"Illegal fix hyper/local command");
|
|
|
|
invvmax = 1.0 / vmax;
|
|
invqfactorsq = 1.0 / (qfactor*qfactor);
|
|
cutbondsq = cutbond*cutbond;
|
|
dcutsq = dcut*dcut;
|
|
beta = 1.0 / (force->boltz * tequil);
|
|
|
|
// optional args
|
|
|
|
boundflag = 0;
|
|
boundfrac = 0.0;
|
|
resetfreq = -1;
|
|
checkghost = 0;
|
|
checkbias = 0;
|
|
|
|
int iarg = 10;
|
|
while (iarg < narg) {
|
|
if (strcmp(arg[iarg],"bound") == 0) {
|
|
if (iarg+2 > narg) error->all(FLERR,"Illegal fix hyper/local command");
|
|
boundfrac = utils::numeric(FLERR,arg[iarg+1],false,lmp);
|
|
if (boundfrac < 0.0) boundflag = 0;
|
|
else boundflag = 1;
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"reset") == 0) {
|
|
if (iarg+2 > narg) error->all(FLERR,"Illegal fix hyper/local command");
|
|
resetfreq = utils::inumeric(FLERR,arg[iarg+1],false,lmp);
|
|
if (resetfreq < -1) error->all(FLERR,"Illegal fix hyper/local command");
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"check/ghost") == 0) {
|
|
checkghost = 1;
|
|
iarg++;
|
|
} else if (strcmp(arg[iarg],"check/bias") == 0) {
|
|
if (iarg+3 > narg) error->all(FLERR,"Illegal fix hyper/local command");
|
|
checkbias = 1;
|
|
checkbias_every = utils::inumeric(FLERR,arg[iarg+1],false,lmp);
|
|
if (strcmp(arg[iarg+2],"error") == 0) checkbias_flag = ERROR;
|
|
else if (strcmp(arg[iarg+2],"warn") == 0) checkbias_flag = WARN;
|
|
else if (strcmp(arg[iarg+2],"ignore") == 0) checkbias_flag = IGNORE;
|
|
else error->all(FLERR,"Illegal fix hyper/local command");
|
|
iarg += 3;
|
|
} else error->all(FLERR,"Illegal fix hyper/local command");
|
|
}
|
|
|
|
// per-atom data structs
|
|
|
|
maxbond = nblocal = 0;
|
|
blist = nullptr;
|
|
biascoeff = nullptr;
|
|
allbonds = 0;
|
|
|
|
maxatom = 0;
|
|
maxstrain = nullptr;
|
|
maxstrain_domain = nullptr;
|
|
biasflag = nullptr;
|
|
|
|
maxlocal = nlocal_old = 0;
|
|
numbond = nullptr;
|
|
maxhalf = nullptr;
|
|
eligible = nullptr;
|
|
maxhalfstrain = nullptr;
|
|
|
|
maxall = nall_old = 0;
|
|
xold = nullptr;
|
|
tagold = nullptr;
|
|
old2now = nullptr;
|
|
|
|
nbias = maxbias = 0;
|
|
bias = nullptr;
|
|
|
|
// data structs for persisting bias coeffs when bond list is reformed
|
|
// maxbondperatom = max # of bonds any atom is part of
|
|
// FCCBONDS = 12 is a good estimate for fcc lattices
|
|
// will be reset in build_bond() if necessary
|
|
|
|
maxcoeff = 0;
|
|
maxbondperatom = FCCBONDS;
|
|
numcoeff = nullptr;
|
|
clist = nullptr;
|
|
cpage = new MyPage<HyperOneCoeff>;
|
|
cpage->init(maxbondperatom,1024*maxbondperatom,1);
|
|
|
|
// set comm sizes needed by this fix
|
|
// reverse = 2 is for sending atom index + value, though total likely < 1
|
|
// reverse comm for bias coeffs has variable size, so not tallied here
|
|
|
|
comm_forward = 1;
|
|
comm_reverse = 2;
|
|
|
|
me = comm->me;
|
|
firstflag = 1;
|
|
|
|
sumboost = 0.0;
|
|
aveboost_running = 0.0;
|
|
sumbiascoeff = 0.0;
|
|
avebiascoeff_running = 0.0;
|
|
minbiascoeff = 0.0;
|
|
maxbiascoeff = 0.0;
|
|
|
|
starttime = update->ntimestep;
|
|
nostrainyet = 1;
|
|
nnewbond = 0;
|
|
nevent = 0;
|
|
nevent_atom = 0;
|
|
mybias = 0.0;
|
|
|
|
// bias bounding and reset params
|
|
|
|
bound_lower = 1.0 - boundfrac;
|
|
bound_upper = 1.0 + boundfrac;
|
|
lastreset = update->ntimestep;
|
|
|
|
// two DEBUG quantities
|
|
// myboost = 0.0;
|
|
// overcount = 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
FixHyperLocal::~FixHyperLocal()
|
|
{
|
|
memory->destroy(blist);
|
|
memory->destroy(biascoeff);
|
|
|
|
memory->destroy(maxstrain);
|
|
memory->destroy(maxstrain_domain);
|
|
memory->destroy(biasflag);
|
|
|
|
memory->destroy(numbond);
|
|
memory->destroy(maxhalf);
|
|
memory->destroy(eligible);
|
|
memory->destroy(maxhalfstrain);
|
|
|
|
memory->destroy(xold);
|
|
memory->destroy(tagold);
|
|
memory->destroy(old2now);
|
|
|
|
memory->destroy(bias);
|
|
|
|
memory->destroy(numcoeff);
|
|
memory->sfree(clist);
|
|
delete cpage;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
int FixHyperLocal::setmask()
|
|
{
|
|
int mask = 0;
|
|
mask |= PRE_NEIGHBOR;
|
|
mask |= PRE_REVERSE;
|
|
mask |= MIN_PRE_NEIGHBOR;
|
|
mask |= THERMO_ENERGY;
|
|
return mask;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixHyperLocal::init_hyper()
|
|
{
|
|
ghost_toofar = 0;
|
|
checkbias_count = 0;
|
|
maxdriftsq = 0.0;
|
|
maxbondlen = 0.0;
|
|
avebiascoeff_running = 0.0;
|
|
minbiascoeff_running = BIG;
|
|
maxbiascoeff_running = 0.0;
|
|
nbias_running = 0;
|
|
nobias_running = 0;
|
|
negstrain_running = 0;
|
|
rmaxever = 0.0;
|
|
rmaxeverbig = 0.0;
|
|
|
|
nbondbuild = 0;
|
|
time_bondbuild = 0.0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixHyperLocal::init()
|
|
{
|
|
// for newton off, bond force bias will not be applied correctly
|
|
// for bonds that straddle 2 procs
|
|
// warn if molecular system, since near-neighbors may not appear in neigh list
|
|
// user should not be including bonded atoms as hyper "bonds"
|
|
|
|
if (force->newton_pair == 0)
|
|
error->all(FLERR,"Hyper local requires newton pair on");
|
|
|
|
if ((atom->molecular != Atom::ATOMIC) && (me == 0))
|
|
error->warning(FLERR,"Hyper local for molecular systems "
|
|
"requires care in defining hyperdynamic bonds");
|
|
|
|
// cutghost = communication cutoff as calculated by Neighbor and Comm
|
|
// error if cutghost is smaller than Dcut
|
|
// warn if no drift distance added to cutghost
|
|
|
|
if (firstflag) {
|
|
double cutghost;
|
|
if (force->pair)
|
|
cutghost = MAX(force->pair->cutforce+neighbor->skin,comm->cutghostuser);
|
|
else
|
|
cutghost = comm->cutghostuser;
|
|
|
|
if (cutghost < dcut)
|
|
error->all(FLERR,"Fix hyper/local domain cutoff exceeds ghost atom range - "
|
|
"use comm_modify cutoff command");
|
|
if (cutghost < dcut+cutbond/2.0 && me == 0)
|
|
error->warning(FLERR,"Fix hyper/local ghost atom range "
|
|
"may not allow for atom drift between events");
|
|
}
|
|
|
|
alpha = update->dt / alpha_user;
|
|
|
|
// count of atoms in fix group
|
|
|
|
groupatoms = group->count(igroup);
|
|
|
|
// need occasional full neighbor list with cutoff = Dcut
|
|
// used for finding maxstrain of neighbor bonds out to Dcut
|
|
// do not need to include neigh skin in cutoff,
|
|
// b/c this list will be built every time build_bond() is called
|
|
// NOTE: what if pair style list cutoff > Dcut
|
|
// or what if neigh skin is huge?
|
|
|
|
int irequest_full = neighbor->request(this,instance_me);
|
|
neighbor->requests[irequest_full]->id = 1;
|
|
neighbor->requests[irequest_full]->pair = 0;
|
|
neighbor->requests[irequest_full]->fix = 1;
|
|
neighbor->requests[irequest_full]->half = 0;
|
|
neighbor->requests[irequest_full]->full = 1;
|
|
neighbor->requests[irequest_full]->cut = 1;
|
|
neighbor->requests[irequest_full]->cutoff = dcut;
|
|
neighbor->requests[irequest_full]->occasional = 1;
|
|
|
|
// also need occasional half neighbor list derived from pair style
|
|
// used for building local bond list
|
|
// no specified cutoff, should be longer than cutbond
|
|
// this list will also be built (or derived/copied)
|
|
// every time build_bond() is called
|
|
|
|
int irequest_half = neighbor->request(this,instance_me);
|
|
neighbor->requests[irequest_half]->id = 2;
|
|
neighbor->requests[irequest_half]->pair = 0;
|
|
neighbor->requests[irequest_half]->fix = 1;
|
|
neighbor->requests[irequest_half]->occasional = 1;
|
|
|
|
// extra timing output
|
|
|
|
//timefirst = timesecond = timethird = timefourth = timefifth =
|
|
// timesixth = timeseventh = timetotal = 0.0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixHyperLocal::init_list(int id, NeighList *ptr)
|
|
{
|
|
if (id == 1) listfull = ptr;
|
|
else if (id == 2) listhalf = ptr;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixHyperLocal::setup_pre_neighbor()
|
|
{
|
|
// called for dynamics and minimization
|
|
|
|
pre_neighbor();
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixHyperLocal::setup_pre_reverse(int eflag, int vflag)
|
|
{
|
|
// only called for dynamics, not minimization
|
|
// setupflag prevents boostostat update of bias coeffs in setup
|
|
// also prevents increments of nbias_running, nobias_running,
|
|
// negstrain_running, sumbiascoeff
|
|
|
|
setupflag = 1;
|
|
pre_reverse(eflag,vflag);
|
|
setupflag = 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixHyperLocal::pre_neighbor()
|
|
{
|
|
int i,m,iold,jold,ilocal,jlocal;
|
|
// double distsq;
|
|
|
|
// reset local indices for owned bond atoms, since atoms have migrated
|
|
// must be done after ghost atoms are setup via comm->borders()
|
|
// first time this is done for a particular I or J atom:
|
|
// use tagold and xold from when bonds were created
|
|
// atom->map() finds atom ID if it exists, owned index if possible
|
|
// closest current I or J atoms to old I may now be ghost atoms
|
|
// closest_image() returns the ghost atom index in that case
|
|
// also compute max drift of any atom in a bond
|
|
// drift = displacement from quenched coord while event has not yet occurred
|
|
// NOTE: drift calc is now done in bond_build(), between 2 quenched states
|
|
|
|
for (i = 0; i < nall_old; i++) old2now[i] = -1;
|
|
|
|
for (m = 0; m < nblocal; m++) {
|
|
iold = blist[m].iold;
|
|
jold = blist[m].jold;
|
|
ilocal = old2now[iold];
|
|
jlocal = old2now[jold];
|
|
|
|
if (ilocal < 0) {
|
|
ilocal = atom->map(tagold[iold]);
|
|
ilocal = domain->closest_image(xold[iold],ilocal);
|
|
if (ilocal < 0)
|
|
error->one(FLERR,"Fix hyper/local bond atom not found");
|
|
old2now[iold] = ilocal;
|
|
//distsq = MathExtra::distsq3(x[ilocal],xold[iold]);
|
|
//maxdriftsq = MAX(distsq,maxdriftsq);
|
|
}
|
|
if (jlocal < 0) {
|
|
jlocal = atom->map(tagold[jold]);
|
|
jlocal = domain->closest_image(xold[iold],jlocal); // close to I atom
|
|
if (jlocal < 0)
|
|
error->one(FLERR,"Fix hyper/local bond atom not found");
|
|
old2now[jold] = jlocal;
|
|
//distsq = MathExtra::distsq3(x[jlocal],xold[jold]);
|
|
//maxdriftsq = MAX(distsq,maxdriftsq);
|
|
}
|
|
|
|
blist[m].i = ilocal;
|
|
blist[m].j = jlocal;
|
|
}
|
|
|
|
// set remaining old2now values to point to current local atom indices
|
|
// if old2now >= 0, already set by bond loop above
|
|
// only necessary for tagold entries > 0
|
|
// because if tagold = 0, atom is not active in Dcut neighbor list
|
|
// must be done after atoms migrate and ghost atoms setup via comm->borders()
|
|
// does not matter which atom (owned or ghost) that atom->map() finds
|
|
// b/c old2now is only used to access maxstrain() or biasflag()
|
|
// which will be identical for every copy of the same atom ID
|
|
|
|
for (iold = 0; iold < nall_old; iold++) {
|
|
if (old2now[iold] >= 0) continue;
|
|
if (tagold[iold] == 0) continue;
|
|
ilocal = atom->map(tagold[iold]);
|
|
old2now[iold] = ilocal;
|
|
if (ilocal < 0) ghost_toofar++;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixHyperLocal::pre_reverse(int /* eflag */, int /* vflag */)
|
|
{
|
|
int i,j,m,ii,jj,inum,jnum,iold,jold,ibond,nbond,ijhalf,ncount;
|
|
double delx,dely,delz;
|
|
double r,r0,estrain,emax,ebias,vbias,fbias,fbiasr;
|
|
double halfstrain,selfstrain;
|
|
int *ilist,*jlist,*numneigh,**firstneigh;
|
|
|
|
//double time1,time2,time3,time4,time5,time6,time7,time8;
|
|
//time1 = MPI_Wtime();
|
|
|
|
nostrainyet = 0;
|
|
|
|
// reallocate per-atom maxstrain and biasflag vectors if necessary
|
|
|
|
int nlocal = atom->nlocal;
|
|
int nall = nlocal + atom->nghost;
|
|
|
|
if (maxatom < nall) {
|
|
memory->destroy(maxstrain);
|
|
memory->destroy(maxstrain_domain);
|
|
if (checkbias) memory->destroy(biasflag);
|
|
maxatom = atom->nmax;
|
|
memory->create(maxstrain,maxatom,"hyper/local:maxstrain");
|
|
memory->create(maxstrain_domain,maxatom,"hyper/local:maxstrain_domain");
|
|
if (checkbias) memory->create(biasflag,maxatom,"hyper/local:biasflag");
|
|
}
|
|
|
|
// one max strain bond per old owned atom is eligible for biasing
|
|
|
|
for (iold = 0; iold < nlocal_old; iold++) eligible[iold] = 1;
|
|
|
|
// -------------------------------------------------------------
|
|
// stage 1:
|
|
// maxstrain[i] = max abs value of strain of any bond atom I is part of
|
|
// reverse/forward comm so know it for all current owned and ghost atoms
|
|
// -------------------------------------------------------------
|
|
|
|
// compute estrain = current abs value strain of each owned bond
|
|
// blist = bondlist from last event
|
|
// also store:
|
|
// maxhalf = which owned bond is maxstrain for each old atom I
|
|
// maxhalfstrain = abs value strain of that bond for each old atom I
|
|
|
|
for (i = 0; i < nall; i++) maxstrain[i] = 0.0;
|
|
|
|
double **x = atom->x;
|
|
|
|
// DEBUG quantity
|
|
// overcount = 0;
|
|
|
|
m = 0;
|
|
for (iold = 0; iold < nlocal_old; iold++) {
|
|
halfstrain = 0.0;
|
|
ijhalf = -1;
|
|
nbond = numbond[iold];
|
|
|
|
for (ibond = 0; ibond < nbond; ibond++) {
|
|
i = blist[m].i;
|
|
j = blist[m].j;
|
|
delx = x[i][0] - x[j][0];
|
|
dely = x[i][1] - x[j][1];
|
|
delz = x[i][2] - x[j][2];
|
|
r = sqrt(delx*delx + dely*dely + delz*delz);
|
|
maxbondlen = MAX(r,maxbondlen);
|
|
r0 = blist[m].r0;
|
|
estrain = fabs(r-r0) / r0;
|
|
// DEBUG quantity
|
|
// if (estrain >= qfactor) overcount++;
|
|
maxstrain[i] = MAX(maxstrain[i],estrain);
|
|
maxstrain[j] = MAX(maxstrain[j],estrain);
|
|
if (estrain > halfstrain) {
|
|
halfstrain = estrain;
|
|
ijhalf = m;
|
|
}
|
|
m++;
|
|
}
|
|
|
|
maxhalf[iold] = ijhalf;
|
|
maxhalfstrain[iold] = halfstrain;
|
|
}
|
|
|
|
//time2 = MPI_Wtime();
|
|
|
|
// reverse comm acquires maxstrain of all current owned atoms
|
|
// needed b/c only saw half the bonds of each atom
|
|
// also needed b/c bond list may refer to old owned atoms that are now ghost
|
|
// forward comm acquires maxstrain of all current ghost atoms
|
|
|
|
commflag = STRAIN;
|
|
comm->reverse_comm_fix(this);
|
|
comm->forward_comm_fix(this);
|
|
|
|
//time3 = MPI_Wtime();
|
|
|
|
// -------------------------------------------------------------
|
|
// stage 2:
|
|
// maxstrain_domain[i] = maxstrain of atom I and all its J neighs out to Dcut
|
|
// reverse/forward comm so know it for all current owned and ghost atoms
|
|
// -------------------------------------------------------------
|
|
|
|
// use full Dcut neighbor list to check maxstrain of all neighbor atoms
|
|
// neighlist is from last event
|
|
// has old indices for I,J (reneighboring may have occurred)
|
|
// use old2now[] to convert to current indices
|
|
// if J is unknown (drifted ghost),
|
|
// assume it was part of an event and its strain = qfactor
|
|
// mark atom I ineligible for biasing if:
|
|
// its maxstrain = 0.0, b/c it is in no bonds (typically not in LHD group)
|
|
// its maxhalfstrain < maxstrain (J atom owns the IJ bond)
|
|
// its maxstrain < maxstrain_domain
|
|
// ncount > 1 (break tie by making all atoms with tie value ineligible)
|
|
// if ncount > 1, also flip sign of maxstrain_domain for atom I
|
|
|
|
for (i = 0; i < nall; i++) maxstrain_domain[i] = 0.0;
|
|
|
|
inum = listfull->inum;
|
|
ilist = listfull->ilist;
|
|
numneigh = listfull->numneigh;
|
|
firstneigh = listfull->firstneigh;
|
|
|
|
double rmax = rmaxever;
|
|
double rmaxbig = rmaxeverbig;
|
|
double *sublo = domain->sublo;
|
|
double *subhi = domain->subhi;
|
|
|
|
// first two lines of outer loop should be identical to this:
|
|
// for (iold = 0; iold < nlocal_old; iold++)
|
|
|
|
for (ii = 0; ii < inum; ii++) {
|
|
iold = ilist[ii];
|
|
i = old2now[iold];
|
|
|
|
if (maxstrain[i] == 0.0) {
|
|
eligible[iold] = 0;
|
|
continue;
|
|
}
|
|
|
|
jlist = firstneigh[iold];
|
|
jnum = numneigh[iold];
|
|
|
|
// I or J may be ghost atoms
|
|
// will always know I b/c atoms do not drift that far
|
|
// but may no longer know J if hops outside cutghost
|
|
// in that case, assume it performed an event, its strain = qfactor
|
|
// this assumes cutghost is sufficiently longer than Dcut
|
|
|
|
emax = selfstrain = maxstrain[i];
|
|
ncount = 0;
|
|
|
|
for (jj = 0; jj < jnum; jj++) {
|
|
jold = jlist[jj];
|
|
j = old2now[jold];
|
|
|
|
// special case for missing (drifted) J atom
|
|
|
|
if (j < 0) {
|
|
emax = MAX(emax,qfactor);
|
|
if (selfstrain == qfactor) ncount++;
|
|
continue;
|
|
}
|
|
|
|
emax = MAX(emax,maxstrain[j]);
|
|
if (selfstrain == maxstrain[j]) ncount++;
|
|
|
|
// optional diagnostic
|
|
// tally largest distance from subbox that a ghost atom is (rmaxbig)
|
|
// and the largest distance if strain < qfactor (rmax)
|
|
|
|
if (checkghost) {
|
|
if (j >= nlocal) {
|
|
if (x[j][0] < sublo[0]) rmaxbig = MAX(rmaxbig,sublo[0]-x[j][0]);
|
|
if (x[j][1] < sublo[1]) rmaxbig = MAX(rmaxbig,sublo[1]-x[j][1]);
|
|
if (x[j][2] < sublo[2]) rmaxbig = MAX(rmaxbig,sublo[2]-x[j][2]);
|
|
if (x[j][0] > subhi[0]) rmaxbig = MAX(rmaxbig,x[j][0]-subhi[0]);
|
|
if (x[j][1] > subhi[1]) rmaxbig = MAX(rmaxbig,x[j][1]-subhi[1]);
|
|
if (x[j][2] > subhi[2]) rmaxbig = MAX(rmaxbig,x[j][2]-subhi[2]);
|
|
if (maxstrain[j] < qfactor) {
|
|
if (x[j][0] < sublo[0]) rmax = MAX(rmax,sublo[0]-x[j][0]);
|
|
if (x[j][1] < sublo[1]) rmax = MAX(rmax,sublo[1]-x[j][1]);
|
|
if (x[j][2] < sublo[2]) rmax = MAX(rmax,sublo[2]-x[j][2]);
|
|
if (x[j][0] > subhi[0]) rmax = MAX(rmax,x[j][0]-subhi[0]);
|
|
if (x[j][1] > subhi[1]) rmax = MAX(rmax,x[j][1]-subhi[1]);
|
|
if (x[j][2] > subhi[2]) rmax = MAX(rmax,x[j][2]-subhi[2]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (maxhalfstrain[iold] < selfstrain) eligible[iold] = 0;
|
|
if (selfstrain < emax) eligible[iold] = 0;
|
|
else if (ncount > 1) {
|
|
eligible[iold] = 0;
|
|
emax = -emax;
|
|
}
|
|
maxstrain_domain[i] = emax;
|
|
}
|
|
|
|
//time4 = MPI_Wtime();
|
|
|
|
// reverse comm to acquire maxstrain_domain from ghost atoms
|
|
// needed b/c neigh list may refer to old owned atoms that are now ghost
|
|
// forward comm acquires maxstrain_domain of all current ghost atoms
|
|
|
|
commflag = STRAINDOMAIN;
|
|
comm->reverse_comm_fix(this);
|
|
comm->forward_comm_fix(this);
|
|
|
|
//time5 = MPI_Wtime();
|
|
|
|
// -------------------------------------------------------------
|
|
// stage 3:
|
|
// create bias = list of Nbias biased bonds this proc owns
|
|
// -------------------------------------------------------------
|
|
|
|
// identify biased bonds and add to bias list
|
|
// bias the I,J maxhalf bond of atom I only if all these conditions hold:
|
|
// maxstrain[i] = maxstrain_domain[i] (checked in stage 2)
|
|
// maxstrain[j] = maxstrain_domain[j] (checked here)
|
|
// I is not part of an I,J bond with > strain owned by some J (checked in 2)
|
|
// no ties with other maxstrain bonds in atom I's domain (checked in 2)
|
|
|
|
nbias = 0;
|
|
for (iold = 0; iold < nlocal_old; iold++) {
|
|
if (eligible[iold] == 0) continue;
|
|
j = blist[maxhalf[iold]].j;
|
|
if (maxstrain[j] != maxstrain_domain[j]) continue;
|
|
if (nbias == maxbias) {
|
|
maxbias += DELTABIAS;
|
|
memory->grow(bias,maxbias,"hyper/local:bias");
|
|
}
|
|
bias[nbias++] = maxhalf[iold];
|
|
}
|
|
|
|
//time6 = MPI_Wtime();
|
|
|
|
// -------------------------------------------------------------
|
|
// stage 4:
|
|
// apply bias force to bonds with locally max strain
|
|
// -------------------------------------------------------------
|
|
|
|
double **f = atom->f;
|
|
|
|
int nobias = 0;
|
|
int negstrain = 0;
|
|
mybias = 0.0;
|
|
|
|
// DEBUG quantity
|
|
// myboost = 0;
|
|
|
|
for (int ibias = 0; ibias < nbias; ibias++) {
|
|
m = bias[ibias];
|
|
i = blist[m].i;
|
|
j = blist[m].j;
|
|
|
|
if (maxstrain[i] >= qfactor) {
|
|
// DEBUG quantity
|
|
// myboost += 1.0;
|
|
nobias++;
|
|
continue;
|
|
}
|
|
|
|
delx = x[i][0] - x[j][0];
|
|
dely = x[i][1] - x[j][1];
|
|
delz = x[i][2] - x[j][2];
|
|
r = sqrt(delx*delx + dely*dely + delz*delz);
|
|
r0 = blist[m].r0;
|
|
ebias = (r-r0) / r0;
|
|
vbias = biascoeff[m] * vmax * (1.0 - ebias*ebias*invqfactorsq);
|
|
fbias = 2.0 * biascoeff[m] * vmax * ebias * invqfactorsq;
|
|
fbiasr = fbias / r0 / r;
|
|
f[i][0] += delx*fbiasr;
|
|
f[i][1] += dely*fbiasr;
|
|
f[i][2] += delz*fbiasr;
|
|
|
|
f[j][0] -= delx*fbiasr;
|
|
f[j][1] -= dely*fbiasr;
|
|
f[j][2] -= delz*fbiasr;
|
|
|
|
if (ebias < 0.0) negstrain++;
|
|
mybias += vbias;
|
|
|
|
// DEBUG quantity
|
|
// myboost += exp(beta * biascoeff[m]*vbias);
|
|
}
|
|
|
|
//time7 = MPI_Wtime();
|
|
|
|
// -------------------------------------------------------------
|
|
// stage 5:
|
|
// apply boostostat to bias coeffs of all bonds I own
|
|
// -------------------------------------------------------------
|
|
|
|
// no boostostat update when pre_reverse called from setup()
|
|
// nbias_running, nobias_running, negstrain_running only incremented
|
|
// on run steps
|
|
|
|
if (setupflag) return;
|
|
|
|
nbias_running += nbias;
|
|
nobias_running += nobias;
|
|
negstrain_running += negstrain;
|
|
|
|
// loop over bonds I own to adjust bias coeff
|
|
// delta in boost coeff is function of boost_domain vs target boost
|
|
// boost_domain is function of two maxstrain_domains for I,J
|
|
// NOTE: biascoeff update is now scaled by 1/Vmax
|
|
// still need to think about what this means for units
|
|
|
|
minbiascoeff = BIG;
|
|
maxbiascoeff = 0.0;
|
|
|
|
double emaxi,emaxj,boost_domain,bc;
|
|
double sumcoeff_me = 0.0;
|
|
double sumboost_me = 0.0;
|
|
|
|
for (m = 0; m < nblocal; m++) {
|
|
i = blist[m].i;
|
|
j = blist[m].j;
|
|
emaxi = maxstrain_domain[i];
|
|
emaxj = maxstrain_domain[j];
|
|
emax = MAX(emaxi,emaxj);
|
|
if (emax < qfactor) vbias = vmax * (1.0 - emax*emax*invqfactorsq);
|
|
else vbias = 0.0;
|
|
|
|
boost_domain = exp(beta * biascoeff[m]*vbias);
|
|
biascoeff[m] -= alpha*invvmax * (boost_domain-boost_target) / boost_target;
|
|
|
|
// enforce biascoeff bounds
|
|
// min value must always be >= 0.0
|
|
|
|
biascoeff[m] = MAX(biascoeff[m],0.0);
|
|
if (boundflag) {
|
|
biascoeff[m] = MAX(biascoeff[m],bound_lower);
|
|
biascoeff[m] = MIN(biascoeff[m],bound_upper);
|
|
}
|
|
|
|
// stats
|
|
|
|
bc = biascoeff[m];
|
|
sumcoeff_me += bc;
|
|
minbiascoeff = MIN(minbiascoeff,bc);
|
|
maxbiascoeff = MAX(maxbiascoeff,bc);
|
|
sumboost_me += boost_domain;
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// diagnostics, some optional
|
|
// -------------------------------------------------------------
|
|
|
|
MPI_Allreduce(&sumcoeff_me,&sumbiascoeff,1,MPI_DOUBLE,MPI_SUM,world);
|
|
if (allbonds) avebiascoeff_running += sumbiascoeff/allbonds;
|
|
minbiascoeff_running = MIN(minbiascoeff_running,minbiascoeff);
|
|
maxbiascoeff_running = MAX(maxbiascoeff_running,maxbiascoeff);
|
|
MPI_Allreduce(&sumboost_me,&sumboost,1,MPI_DOUBLE,MPI_SUM,world);
|
|
if (allbonds) aveboost_running += sumboost/allbonds;
|
|
|
|
// if requested, monitor ghost distance from processor sub-boxes
|
|
|
|
if (checkghost) {
|
|
double rmax2[2],rmax2all[2];
|
|
rmax2[0] = rmax;
|
|
rmax2[1] = rmaxbig;
|
|
MPI_Allreduce(&rmax2,&rmax2all,2,MPI_DOUBLE,MPI_MAX,world);
|
|
rmaxever = rmax2all[0];
|
|
rmaxeverbig = rmax2all[1];
|
|
}
|
|
|
|
// if requested, check for any biased bonds that are too close to each other
|
|
// keep a running count for output
|
|
// requires 2 additional local comm operations
|
|
|
|
if (checkbias && update->ntimestep % checkbias_every == 0) {
|
|
|
|
// mark each atom in a biased bond with ID of partner
|
|
// this may mark some ghost atoms
|
|
|
|
for (i = 0; i < nall; i++) biasflag[i] = 0;
|
|
|
|
tagint *tag = atom->tag;
|
|
|
|
for (int ibias = 0; ibias < nbias; ibias++) {
|
|
m = bias[ibias];
|
|
i = blist[m].i;
|
|
j = blist[m].j;
|
|
biasflag[i] = tag[j];
|
|
biasflag[j] = tag[i];
|
|
}
|
|
|
|
// reverse comm to acquire biasflag from ghost atoms
|
|
// forward comm to set biasflag for all ghost atoms
|
|
|
|
commflag = BIASFLAG;
|
|
comm->reverse_comm_fix(this);
|
|
comm->forward_comm_fix(this);
|
|
|
|
// loop over Dcut full neighbor list
|
|
// I and J may be ghost atoms
|
|
// only continue if I is a biased atom
|
|
// if J is unknown (drifted ghost) just ignore
|
|
// if J is biased and is not bonded to I, then flag as too close
|
|
|
|
for (ii = 0; ii < inum; ii++) {
|
|
iold = ilist[ii];
|
|
i = old2now[iold];
|
|
if (biasflag[i] == 0) continue;
|
|
|
|
jlist = firstneigh[iold];
|
|
jnum = numneigh[iold];
|
|
|
|
for (jj = 0; jj < jnum; jj++) {
|
|
jold = jlist[jj];
|
|
j = old2now[jold];
|
|
if (j < 0) continue;
|
|
if (biasflag[j] && biasflag[j] != tag[i]) checkbias_count++;
|
|
}
|
|
}
|
|
|
|
if (checkbias_flag != IGNORE) {
|
|
int allcount;
|
|
MPI_Allreduce(&checkbias_count,&allcount,1,MPI_INT,MPI_SUM,world);
|
|
if (allcount) {
|
|
std::string mesg = fmt::format("Fix hyper/local biased bonds too close: "
|
|
"cumulative atom count {}",allcount);
|
|
if (checkbias_flag == WARN) {
|
|
if (me == 0) error->warning(FLERR,mesg);
|
|
} else error->all(FLERR,mesg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixHyperLocal::min_pre_neighbor()
|
|
{
|
|
pre_neighbor();
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixHyperLocal::build_bond_list(int natom)
|
|
{
|
|
int i,j,ii,jj,m,n,iold,jold,ilocal,jlocal,inum,jnum,nbond;
|
|
tagint jtag;
|
|
double xtmp,ytmp,ztmp,delx,dely,delz,rsq,distsq,oldcoeff;
|
|
int *ilist,*jlist,*numneigh,**firstneigh;
|
|
|
|
double time1,time2;
|
|
time1 = MPI_Wtime();
|
|
|
|
if (natom) {
|
|
nevent++;
|
|
nevent_atom += natom;
|
|
}
|
|
|
|
// reset Vmax to current bias coeff average
|
|
// only if requested and elapsed time >= resetfreq
|
|
// ave = current ave of all bias coeffs
|
|
// if reset, adjust all Cij to keep Cij*Vmax unchanged
|
|
|
|
if (resetfreq >= 0) {
|
|
int flag = 0;
|
|
bigint elapsed = update->ntimestep - lastreset;
|
|
if (resetfreq == 0) {
|
|
if (elapsed) flag = 1;
|
|
} else {
|
|
if (elapsed >= resetfreq) flag = 1;
|
|
}
|
|
|
|
if (flag) {
|
|
lastreset = update->ntimestep;
|
|
|
|
double vmaxold = vmax;
|
|
double ave = sumbiascoeff / allbonds;
|
|
vmax *= ave;
|
|
|
|
// adjust all Cij to keep Cij * Vmax = Cijold * Vmaxold
|
|
|
|
for (m = 0; m < nblocal; m++) biascoeff[m] *= vmaxold/vmax;
|
|
|
|
// enforce bounds for new Cij
|
|
|
|
if (boundflag) {
|
|
for (m = 0; m < nblocal; m++) {
|
|
biascoeff[m] = MAX(biascoeff[m],bound_lower);
|
|
biascoeff[m] = MIN(biascoeff[m],bound_upper);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// compute max distance any bond atom has moved between 2 quenched states
|
|
// xold[iold] = last quenched coord for iold
|
|
// x[ilocal] = current quenched coord for same atom
|
|
// use of old2now calculates distsq only once per atom
|
|
|
|
double **x = atom->x;
|
|
|
|
for (i = 0; i < nall_old; i++) old2now[i] = -1;
|
|
|
|
for (m = 0; m < nblocal; m++) {
|
|
iold = blist[m].iold;
|
|
if (old2now[iold] < 0) {
|
|
ilocal = atom->map(tagold[iold]);
|
|
ilocal = domain->closest_image(xold[iold],ilocal);
|
|
if (ilocal < 0) error->one(FLERR,"Fix hyper/local bond atom not found");
|
|
old2now[iold] = ilocal;
|
|
distsq = MathExtra::distsq3(x[ilocal],xold[iold]);
|
|
maxdriftsq = MAX(distsq,maxdriftsq);
|
|
}
|
|
jold = blist[m].jold;
|
|
if (old2now[jold] < 0) {
|
|
jold = blist[m].jold;
|
|
jlocal = atom->map(tagold[jold]);
|
|
jlocal = domain->closest_image(xold[iold],jlocal); // close to I atom
|
|
if (jlocal < 0) error->one(FLERR,"Fix hyper/local bond atom not found");
|
|
old2now[jold] = jlocal;
|
|
distsq = MathExtra::distsq3(x[jlocal],xold[jold]);
|
|
maxdriftsq = MAX(distsq,maxdriftsq);
|
|
}
|
|
}
|
|
|
|
// store old bond coeffs so can persist them in new blist
|
|
// while loop allows growing value of maxbondperatom
|
|
// will loop at most 2 times, stops when maxbondperatom is large enough
|
|
// requires reverse comm, no forward comm:
|
|
// b/c new coeff list is stored only by current owned atoms
|
|
|
|
tagint *tag = atom->tag;
|
|
int nlocal = atom->nlocal;
|
|
int nall = nlocal + atom->nghost;
|
|
|
|
if (maxcoeff < nall) {
|
|
memory->destroy(numcoeff);
|
|
memory->sfree(clist);
|
|
maxcoeff = atom->nmax;
|
|
memory->create(numcoeff,maxcoeff,"hyper/local:numcoeff");
|
|
clist = (HyperOneCoeff **) memory->smalloc(maxcoeff*sizeof(HyperOneCoeff *),
|
|
"hyper/local:clist");
|
|
}
|
|
|
|
while (1) {
|
|
if (firstflag) break;
|
|
for (i = 0; i < nall; i++) numcoeff[i] = 0;
|
|
for (i = 0; i < nall; i++) clist[i] = nullptr;
|
|
cpage->reset();
|
|
|
|
for (m = 0; m < nblocal; m++) {
|
|
i = blist[m].i;
|
|
j = blist[m].j;
|
|
|
|
if (numcoeff[i] == 0) clist[i] = cpage->get(maxbondperatom);
|
|
if (numcoeff[j] == 0) clist[j] = cpage->get(maxbondperatom);
|
|
|
|
if (numcoeff[i] < maxbondperatom) {
|
|
clist[i][numcoeff[i]].biascoeff = biascoeff[m];
|
|
clist[i][numcoeff[i]].tag = tag[j];
|
|
}
|
|
numcoeff[i]++;
|
|
|
|
if (numcoeff[j] < maxbondperatom) {
|
|
clist[j][numcoeff[j]].biascoeff = biascoeff[m];
|
|
clist[j][numcoeff[j]].tag = tag[i];
|
|
}
|
|
numcoeff[j]++;
|
|
}
|
|
|
|
int mymax = 0;
|
|
for (i = 0; i < nall; i++) mymax = MAX(mymax,numcoeff[i]);
|
|
int maxcoeffall;
|
|
MPI_Allreduce(&mymax,&maxcoeffall,1,MPI_INT,MPI_MAX,world);
|
|
|
|
if (maxcoeffall > maxbondperatom) {
|
|
maxbondperatom = maxcoeffall;
|
|
cpage->init(maxbondperatom,1024*maxbondperatom,1);
|
|
continue;
|
|
}
|
|
|
|
commflag = BIASCOEFF;
|
|
comm->reverse_comm_fix_variable(this);
|
|
|
|
mymax = 0;
|
|
for (i = 0; i < nall; i++) mymax = MAX(mymax,numcoeff[i]);
|
|
MPI_Allreduce(&mymax,&maxcoeffall,1,MPI_INT,MPI_MAX,world);
|
|
if (maxcoeffall <= maxbondperatom) break;
|
|
|
|
maxbondperatom = maxcoeffall;
|
|
cpage->init(maxbondperatom,1024*maxbondperatom,1);
|
|
}
|
|
|
|
// reallocate vectors that are maxlocal and maxall length if necessary
|
|
|
|
if (nlocal > maxlocal) {
|
|
memory->destroy(eligible);
|
|
memory->destroy(numbond);
|
|
memory->destroy(maxhalf);
|
|
memory->destroy(maxhalfstrain);
|
|
maxlocal = nlocal;
|
|
memory->create(eligible,maxlocal,"hyper/local:eligible");
|
|
memory->create(numbond,maxlocal,"hyper/local:numbond");
|
|
memory->create(maxhalf,maxlocal,"hyper/local:maxhalf");
|
|
memory->create(maxhalfstrain,maxlocal,"hyper/local:maxhalfstrain");
|
|
}
|
|
|
|
if (nall > maxall) {
|
|
memory->destroy(xold);
|
|
memory->destroy(tagold);
|
|
memory->destroy(old2now);
|
|
maxall = atom->nmax;
|
|
memory->create(xold,maxall,3,"hyper/local:xold");
|
|
memory->create(tagold,maxall,"hyper/local:tagold");
|
|
memory->create(old2now,maxall,"hyper/local:old2now");
|
|
}
|
|
|
|
// nlocal_old = value of nlocal at time bonds are built
|
|
// nall_old = value of nall at time bonds are built
|
|
// archive current atom coords in xold
|
|
// tagold will be set to non-zero below for accessed atoms
|
|
// numbond will be set below
|
|
|
|
nlocal_old = nlocal;
|
|
nall_old = nall;
|
|
|
|
memcpy(&xold[0][0],&x[0][0],3*nall*sizeof(double));
|
|
for (i = 0; i < nall; i++) tagold[i] = 0;
|
|
for (i = 0; i < nlocal; i++) numbond[i] = 0;
|
|
|
|
// trigger neighbor list builds for both lists
|
|
// insure the I loops in both are from 1 to nlocal
|
|
|
|
neighbor->build_one(listfull);
|
|
neighbor->build_one(listhalf);
|
|
|
|
if (listfull->inum != nlocal || listhalf->inum != nlocal)
|
|
error->one(FLERR,"Invalid neighbor list in fix hyper/local bond build");
|
|
|
|
// set tagold = 1 for all J atoms used in full neighbor list
|
|
// tagold remains 0 for unused atoms, skipped in pre_neighbor
|
|
|
|
inum = listfull->inum;
|
|
ilist = listfull->ilist;
|
|
numneigh = listfull->numneigh;
|
|
firstneigh = listfull->firstneigh;
|
|
|
|
for (ii = 0; ii < inum; ii++) {
|
|
i = ilist[ii];
|
|
tagold[i] = tag[i];
|
|
jlist = firstneigh[i];
|
|
jnum = numneigh[i];
|
|
for (jj = 0; jj < jnum; jj++) {
|
|
j = jlist[jj];
|
|
j &= NEIGHMASK;
|
|
tagold[j] = tag[j];
|
|
}
|
|
}
|
|
|
|
// identify bonds assigned to each owned atom
|
|
// do not create a bond between two non-group atoms
|
|
|
|
int *mask = atom->mask;
|
|
|
|
inum = listhalf->inum;
|
|
ilist = listhalf->ilist;
|
|
numneigh = listhalf->numneigh;
|
|
firstneigh = listhalf->firstneigh;
|
|
|
|
nblocal = 0;
|
|
|
|
for (ii = 0; ii < inum; ii++) {
|
|
i = ilist[ii];
|
|
xtmp = x[i][0];
|
|
ytmp = x[i][1];
|
|
ztmp = x[i][2];
|
|
|
|
tagold[i] = tag[i];
|
|
|
|
jlist = firstneigh[i];
|
|
jnum = numneigh[i];
|
|
nbond = 0;
|
|
|
|
for (jj = 0; jj < jnum; jj++) {
|
|
j = jlist[jj];
|
|
j &= NEIGHMASK;
|
|
|
|
jtag = tag[j];
|
|
tagold[j] = jtag;
|
|
|
|
// skip if neither atom I or J are in fix group
|
|
|
|
if (!(mask[i] & groupbit) && !(mask[j] & groupbit)) continue;
|
|
|
|
delx = xtmp - x[j][0];
|
|
dely = ytmp - x[j][1];
|
|
delz = ztmp - x[j][2];
|
|
rsq = delx*delx + dely*dely + delz*delz;
|
|
|
|
if (rsq < cutbondsq) {
|
|
nbond++;
|
|
|
|
if (nblocal == maxbond) grow_bond();
|
|
blist[nblocal].i = i;
|
|
blist[nblocal].j = j;
|
|
blist[nblocal].iold = i;
|
|
blist[nblocal].jold = j;
|
|
blist[nblocal].r0 = sqrt(rsq);
|
|
|
|
// set biascoeff to old coeff for same I,J pair or to default
|
|
|
|
if (firstflag) oldcoeff = 0.0;
|
|
else {
|
|
oldcoeff = 0.0;
|
|
jtag = tag[j];
|
|
n = numcoeff[i];
|
|
for (m = 0; m < n; m++) {
|
|
if (clist[i][m].tag == jtag) {
|
|
oldcoeff = clist[i][m].biascoeff;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (oldcoeff > 0.0) biascoeff[nblocal] = oldcoeff;
|
|
else {
|
|
biascoeff[nblocal] = COEFFINIT;
|
|
nnewbond++;
|
|
}
|
|
|
|
nblocal++;
|
|
}
|
|
}
|
|
|
|
numbond[i] = nbond;
|
|
}
|
|
|
|
// this fix allows access to biascoeffs as local data
|
|
|
|
size_local_rows = nblocal;
|
|
|
|
// allbonds = total # of bonds in system
|
|
|
|
bigint bondcount = nblocal;
|
|
MPI_Allreduce(&bondcount,&allbonds,1,MPI_LMP_BIGINT,MPI_SUM,world);
|
|
|
|
// DEBUG
|
|
//if (me == 0) printf("TOTAL BOND COUNT = %ld\n",allbonds);
|
|
|
|
time2 = MPI_Wtime();
|
|
|
|
if (firstflag) nnewbond = 0;
|
|
else {
|
|
time_bondbuild += time2-time1;
|
|
nbondbuild++;
|
|
}
|
|
firstflag = 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
int FixHyperLocal::pack_forward_comm(int n, int *list, double *buf,
|
|
int /* pbc_flag */, int * /* pbc */)
|
|
{
|
|
int i,j,m;
|
|
|
|
m = 0;
|
|
|
|
// STRAIN
|
|
// pack maxstrain vector
|
|
// must send to all ghosts out to Dcut
|
|
|
|
if (commflag == STRAIN) {
|
|
for (i = 0; i < n; i++) {
|
|
j = list[i];
|
|
buf[m++] = maxstrain[j];
|
|
}
|
|
|
|
// STRAINDOMAIN
|
|
// pack maxstrain_domain vector
|
|
// could just send to nearby ghosts in bonds
|
|
// don't see easy way to determine precisely which atoms that is
|
|
|
|
} else if (commflag == STRAINDOMAIN) {
|
|
for (i = 0; i < n; i++) {
|
|
j = list[i];
|
|
buf[m++] = maxstrain_domain[j];
|
|
}
|
|
|
|
// BIASFLAG
|
|
// pack biasflag vector
|
|
// must send to all ghosts out to Dcut
|
|
|
|
} else if (commflag == BIASFLAG) {
|
|
for (i = 0; i < n; i++) {
|
|
j = list[i];
|
|
buf[m++] = ubuf(biasflag[j]).d;
|
|
}
|
|
}
|
|
|
|
return m;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixHyperLocal::unpack_forward_comm(int n, int first, double *buf)
|
|
{
|
|
int i,m,last;
|
|
|
|
m = 0;
|
|
last = first + n;
|
|
|
|
// STRAIN
|
|
// unpack maxstrain vector
|
|
|
|
if (commflag == STRAIN) {
|
|
for (i = first; i < last; i++) {
|
|
maxstrain[i] = buf[m++];
|
|
}
|
|
|
|
// STRAINREGION
|
|
// unpack maxstrain_domain vector
|
|
|
|
} else if (commflag == STRAINDOMAIN) {
|
|
for (i = first; i < last; i++) {
|
|
maxstrain_domain[i] = buf[m++];
|
|
}
|
|
|
|
// BIASFLAG
|
|
// unpack biasflag vector
|
|
|
|
} else if (commflag == BIASFLAG) {
|
|
for (i = first; i < last; i++) {
|
|
biasflag[i] = (tagint) ubuf(buf[m++]).i;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
int FixHyperLocal::pack_reverse_comm(int n, int first, double *buf)
|
|
{
|
|
int i,j,m,last;
|
|
|
|
m = 0;
|
|
last = first + n;
|
|
|
|
// STRAIN
|
|
// pack maxstrain vector
|
|
// only pack for nonzero values
|
|
|
|
if (commflag == STRAIN) {
|
|
int nonzero = 0;
|
|
m++; // placeholder for count of atoms
|
|
for (i = first; i < last; i++) {
|
|
if (maxstrain[i] == 0.0) continue;
|
|
nonzero++;
|
|
buf[m++] = ubuf(i-first).d; // which atom is next
|
|
buf[m++] = maxstrain[i]; // value
|
|
}
|
|
buf[0] = ubuf(nonzero).d;
|
|
|
|
// STRAINDOMAIN
|
|
// pack maxstrain_domain vector
|
|
// only pack for nonzero values
|
|
|
|
} else if (commflag == STRAINDOMAIN) {
|
|
int nonzero = 0;
|
|
m++; // placeholder for count of atoms
|
|
for (i = first; i < last; i++) {
|
|
if (maxstrain_domain[i] == 0.0) continue;
|
|
nonzero++;
|
|
buf[m++] = ubuf(i-first).d; // which atom is next
|
|
buf[m++] = maxstrain_domain[i]; // value
|
|
}
|
|
buf[0] = ubuf(nonzero).d;
|
|
|
|
// BIASFLAG
|
|
// pack biasflag vector
|
|
// could just pack for nonzero values, like STRAIN and STRAINDOMAIN
|
|
|
|
} else if (commflag == BIASFLAG) {
|
|
for (i = first; i < last; i++) {
|
|
buf[m++] = ubuf(biasflag[i]).d;
|
|
}
|
|
|
|
// BIASCOEFF
|
|
// pack list of biascoeffs
|
|
// only pack for atoms with nonzero # of bias coeffs
|
|
// this will skip majority of ghost atoms
|
|
|
|
} else if (commflag == BIASCOEFF) {
|
|
int ncoeff;
|
|
int nonzero = 0;
|
|
m++; // placeholder for count of atoms
|
|
for (i = first; i < last; i++) {
|
|
if (numcoeff[i] == 0) continue;
|
|
nonzero++;
|
|
ncoeff = numcoeff[i];
|
|
buf[m++] = ubuf(i-first).d; // which atom is next
|
|
buf[m++] = ubuf(ncoeff).d; // # of bias coeffs
|
|
for (j = 0; j < ncoeff; j++) {
|
|
buf[m++] = clist[i][j].biascoeff;
|
|
buf[m++] = ubuf(clist[i][j].tag).d;
|
|
}
|
|
}
|
|
buf[0] = ubuf(nonzero).d;
|
|
}
|
|
|
|
return m;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
callback by comm->reverse_comm_fix_variable() in build_bond()
|
|
same logic as BIASCOEFF option in pack_reverse_comm()
|
|
m = returned size of message
|
|
------------------------------------------------------------------------- */
|
|
|
|
int FixHyperLocal::pack_reverse_comm_size(int n, int first)
|
|
{
|
|
int last = first + n;
|
|
int m = 1;
|
|
for (int i = first; i < last; i++) {
|
|
if (numcoeff[i]) m += 2 + 2*numcoeff[i];
|
|
}
|
|
return m;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixHyperLocal::unpack_reverse_comm(int n, int *list, double *buf)
|
|
{
|
|
int i,j,k,m;
|
|
|
|
// return if n = 0
|
|
// b/c if there are no atoms (n = 0), the message will not have
|
|
// been sent by Comm::reverse_comm_fix() or reverse_comm_fix_variable()
|
|
// so must not read nonzero from first buf location (would be zero anyway)
|
|
|
|
if (n == 0) return;
|
|
|
|
// STRAIN
|
|
// unpack maxstrain vector
|
|
// nonzero # of entries, each has offset to which atom in receiver's list
|
|
// use MAX, b/c want maximum abs value strain for each atom's bonds
|
|
|
|
m = 0;
|
|
|
|
if (commflag == STRAIN) {
|
|
int offset;
|
|
int nonzero = (int) ubuf(buf[m++]).i; // # of atoms with values
|
|
|
|
for (int iatom = 0; iatom < nonzero; iatom++) {
|
|
offset = (int) ubuf(buf[m++]).i; // offset into list for which atom
|
|
j = list[offset];
|
|
maxstrain[j] = MAX(maxstrain[j],buf[m]);
|
|
m++;
|
|
}
|
|
|
|
// STRAINDOMAIN
|
|
// unpack maxstrain_domain vector
|
|
// use MAX, b/c want maximum abs value strain for each atom's domain
|
|
// could also use SUM, b/c exactly one ghost or owned value is non-zero
|
|
|
|
} else if (commflag == STRAINDOMAIN) {
|
|
int offset;
|
|
int nonzero = (int) ubuf(buf[m++]).i; // # of atoms with values
|
|
for (int iatom = 0; iatom < nonzero; iatom++) {
|
|
offset = (int) ubuf(buf[m++]).i; // offset into list for which atom
|
|
j = list[offset];
|
|
maxstrain_domain[j] = MAX(maxstrain_domain[j],buf[m]);
|
|
m++;
|
|
}
|
|
|
|
// BIASFLAG
|
|
// unpack biasflag vector
|
|
|
|
} else if (commflag == BIASFLAG) {
|
|
for (i = 0; i < n; i++) {
|
|
j = list[i];
|
|
biasflag[j] = (tagint) ubuf(buf[m++]).i;
|
|
}
|
|
|
|
// BIASCOEFF
|
|
// unpack list of biascoeffs
|
|
// nonzero # of entries, each has offset to which atom in receiver's list
|
|
// protect against overflow of clist vector
|
|
// if that happens, caller will re-setup cpage and reverse comm again
|
|
|
|
} else if (commflag == BIASCOEFF) {
|
|
int offset,ncoeff;
|
|
int nonzero = (int) ubuf(buf[m++]).i; // # of atoms with coeffs
|
|
for (int iatom = 0; iatom < nonzero; iatom++) {
|
|
offset = (int) ubuf(buf[m++]).i; // offset into list for which atom
|
|
j = list[offset];
|
|
ncoeff = (int) ubuf(buf[m++]).i; // # of bias coeffs
|
|
for (k = 0; k < ncoeff; k++) {
|
|
if (numcoeff[j] == 0) clist[j] = cpage->get(maxbondperatom);
|
|
if (numcoeff[j] < maxbondperatom) {
|
|
clist[j][numcoeff[j]].biascoeff = buf[m++];
|
|
clist[j][numcoeff[j]].tag = (tagint) ubuf(buf[m++]).i;
|
|
} else m += 2;
|
|
numcoeff[j]++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
grow bond list and bias coeff vector by a chunk
|
|
------------------------------------------------------------------------- */
|
|
|
|
void FixHyperLocal::grow_bond()
|
|
{
|
|
if (maxbond + DELTABOND > MAXSMALLINT)
|
|
error->one(FLERR,"Fix hyper/local bond count is too big");
|
|
maxbond += DELTABOND;
|
|
blist = (OneBond *)
|
|
memory->srealloc(blist,maxbond*sizeof(OneBond),"hyper/local:blist");
|
|
memory->grow(biascoeff,maxbond,"hyper/local:biascoeff");
|
|
vector_local = biascoeff;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
double FixHyperLocal::compute_scalar()
|
|
{
|
|
double allbias;
|
|
MPI_Allreduce(&mybias,&allbias,1,MPI_DOUBLE,MPI_SUM,world);
|
|
return allbias;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
double FixHyperLocal::compute_vector(int i)
|
|
{
|
|
// 26 vector outputs returned for i = 0-25
|
|
// can add 2 more for debugging
|
|
|
|
// i = 0 = average boost for all bonds on this step
|
|
// i = 1 = # of biased bonds on this step
|
|
// i = 2 = max strain of any bond on this step
|
|
// i = 3 = value of Vmax on this step
|
|
// i = 4 = average bias coeff for all bonds on this step
|
|
// i = 5 = min bias coeff for any bond on this step
|
|
// i = 6 = max bias coeff for any bond on this step
|
|
// i = 7 = ave bonds/atom on this step
|
|
// i = 8 = ave neighbor bonds/bond on this step
|
|
|
|
// i = 9 = average boost for all bonds during this run
|
|
// i = 10 = average # of biased bonds/step during this run
|
|
// i = 11 = fraction of biased bonds with no bias during this run
|
|
// i = 12 = fraction of biased bonds with negative strain during this run
|
|
// i = 13 = max bond length during this run
|
|
// i = 14 = average bias coeff for all bonds during this run
|
|
// i = 15 = min bias coeff for any bond during this run
|
|
// i = 16 = max bias coeff for any bond during this run
|
|
|
|
// i = 17 = max drift distance of any atom during this run
|
|
// i = 18 = max distance from proc subbox of any ghost atom with
|
|
// maxstrain < qfactor during this run
|
|
// i = 19 = max distance from proc subbox of any ghost atom with
|
|
// any maxstrain during this run
|
|
// i = 20 = count of ghost atoms that could not be found
|
|
// on reneighbor steps during this run
|
|
// i = 21 = count of bias overlaps (< Dcut) found during this run
|
|
|
|
// i = 22 = cumulative hyper time since fix created
|
|
// i = 23 = cumulative # of event timesteps since fix created
|
|
// i = 24 = cumulative # of atoms in events since fix created
|
|
// i = 25 = cumulative # of new bonds formed since fix created
|
|
|
|
// these 2 can be added for debugging
|
|
// i = 26 = average boost for biased bonds on this step
|
|
// i = 27 = current count of bonds with strain >= q
|
|
|
|
if (i == 0) {
|
|
if (allbonds) return sumboost/allbonds;
|
|
return 1.0;
|
|
}
|
|
|
|
if (i == 1) {
|
|
int nbiasall;
|
|
MPI_Allreduce(&nbias,&nbiasall,1,MPI_INT,MPI_SUM,world);
|
|
return (double) nbiasall;
|
|
}
|
|
|
|
if (i == 2) {
|
|
if (nostrainyet) return 0.0;
|
|
int nlocal = atom->nlocal;
|
|
double emax = 0.0;
|
|
for (int j = 0; j < nlocal; j++)
|
|
emax = MAX(emax,maxstrain[j]);
|
|
double eall;
|
|
MPI_Allreduce(&emax,&eall,1,MPI_DOUBLE,MPI_MAX,world);
|
|
return eall;
|
|
}
|
|
|
|
if (i == 3) {
|
|
return vmax;
|
|
}
|
|
|
|
if (i == 4) {
|
|
if (allbonds) return sumbiascoeff/allbonds;
|
|
return 1.0;
|
|
}
|
|
|
|
if (i == 5) {
|
|
double coeff;
|
|
MPI_Allreduce(&minbiascoeff,&coeff,1,MPI_DOUBLE,MPI_MIN,world);
|
|
return coeff;
|
|
}
|
|
|
|
if (i == 6) {
|
|
double coeff;
|
|
MPI_Allreduce(&maxbiascoeff,&coeff,1,MPI_DOUBLE,MPI_MAX,world);
|
|
return coeff;
|
|
}
|
|
|
|
if (i == 7) return 1.0*allbonds/groupatoms;
|
|
|
|
if (i == 8) {
|
|
bigint allneigh,thisneigh;
|
|
thisneigh = listfull->ipage->ndatum;
|
|
MPI_Allreduce(&thisneigh,&allneigh,1,MPI_LMP_BIGINT,MPI_SUM,world);
|
|
double natoms = atom->natoms;
|
|
double neighsperatom = 1.0*allneigh/natoms;
|
|
double bondsperatom = 1.0*allbonds/groupatoms;
|
|
return neighsperatom * bondsperatom;
|
|
}
|
|
|
|
// during minimization, just output previous value
|
|
|
|
if (i == 9) {
|
|
if (update->ntimestep == update->firststep)
|
|
aveboost_running_output = 0.0;
|
|
else if (update->whichflag == 1)
|
|
aveboost_running_output =
|
|
aveboost_running / (update->ntimestep - update->firststep);
|
|
return aveboost_running_output;
|
|
}
|
|
|
|
if (i == 10) {
|
|
if (update->ntimestep == update->firststep) return 0.0;
|
|
int allbias_running;
|
|
MPI_Allreduce(&nbias_running,&allbias_running,1,MPI_INT,MPI_SUM,world);
|
|
return 1.0*allbias_running / (update->ntimestep - update->firststep);
|
|
}
|
|
|
|
if (i == 11) {
|
|
bigint allbias_running,allnobias_running;
|
|
MPI_Allreduce(&nbias_running,&allbias_running,1,MPI_LMP_BIGINT,MPI_SUM,world);
|
|
MPI_Allreduce(&nobias_running,&allnobias_running,1,MPI_LMP_BIGINT,MPI_SUM,world);
|
|
if (allbias_running) return 1.0*allnobias_running / allbias_running;
|
|
return 0.0;
|
|
}
|
|
|
|
if (i == 12) {
|
|
bigint allbias_running,allnegstrain_running;
|
|
MPI_Allreduce(&nbias_running,&allbias_running,1,MPI_LMP_BIGINT,MPI_SUM,world);
|
|
MPI_Allreduce(&negstrain_running,&allnegstrain_running,1,MPI_LMP_BIGINT,
|
|
MPI_SUM,world);
|
|
if (allbias_running) return 1.0*allnegstrain_running / allbias_running;
|
|
return 0.0;
|
|
}
|
|
|
|
if (i == 13) {
|
|
double allbondlen;
|
|
MPI_Allreduce(&maxbondlen,&allbondlen,1,MPI_DOUBLE,MPI_MAX,world);
|
|
return allbondlen;
|
|
}
|
|
|
|
// during minimization, just output previous value
|
|
|
|
if (i == 14) {
|
|
if (update->ntimestep == update->firststep)
|
|
avebiascoeff_running_output = 0.0;
|
|
else if (update->whichflag == 1)
|
|
avebiascoeff_running_output =
|
|
avebiascoeff_running / (update->ntimestep - update->firststep);
|
|
return avebiascoeff_running_output;
|
|
}
|
|
|
|
if (i == 15) {
|
|
double coeff;
|
|
MPI_Allreduce(&minbiascoeff_running,&coeff,1,MPI_DOUBLE,MPI_MIN,world);
|
|
return coeff;
|
|
}
|
|
|
|
if (i == 16) {
|
|
double coeff;
|
|
MPI_Allreduce(&maxbiascoeff_running,&coeff,1,MPI_DOUBLE,MPI_MAX,world);
|
|
return coeff;
|
|
}
|
|
|
|
if (i == 17) {
|
|
double alldriftsq;
|
|
MPI_Allreduce(&maxdriftsq,&alldriftsq,1,MPI_DOUBLE,MPI_MAX,world);
|
|
return (double) sqrt(alldriftsq);
|
|
}
|
|
|
|
if (i == 18) return rmaxever;
|
|
if (i == 19) return rmaxeverbig;
|
|
|
|
if (i == 20) {
|
|
int allghost_toofar;
|
|
MPI_Allreduce(&ghost_toofar,&allghost_toofar,1,MPI_INT,MPI_SUM,world);
|
|
return 1.0*allghost_toofar;
|
|
}
|
|
|
|
if (i == 21) {
|
|
int allclose;
|
|
MPI_Allreduce(&checkbias_count,&allclose,1,MPI_INT,MPI_SUM,world);
|
|
return 1.0*allclose;
|
|
}
|
|
|
|
if (i == 22) {
|
|
return boost_target * update->dt * (update->ntimestep - starttime);
|
|
}
|
|
|
|
if (i == 23) return (double) nevent;
|
|
if (i == 24) return (double) nevent_atom;
|
|
|
|
if (i == 25) {
|
|
bigint allnewbond;
|
|
MPI_Allreduce(&nnewbond,&allnewbond,1,MPI_LMP_BIGINT,MPI_SUM,world);
|
|
return (double) allnewbond;
|
|
}
|
|
|
|
// these two options can be added for debugging
|
|
|
|
/*
|
|
if (i == 26) {
|
|
double allboost;
|
|
MPI_Allreduce(&myboost,&allboost,1,MPI_DOUBLE,MPI_SUM,world);
|
|
int nbiasall;
|
|
MPI_Allreduce(&nbias,&nbiasall,1,MPI_INT,MPI_SUM,world);
|
|
if (nbiasall) return (double) allboost/nbiasall;
|
|
return 1.0;
|
|
}
|
|
|
|
if (i == 27) {
|
|
int allovercount;
|
|
MPI_Allreduce(&overcount,&allovercount,1,MPI_INT,MPI_SUM,world);
|
|
return (double) allovercount;
|
|
}
|
|
*/
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
wrapper on compute_vector()
|
|
used by hyper.cpp to call FixHyper
|
|
------------------------------------------------------------------------- */
|
|
|
|
double FixHyperLocal::query(int i)
|
|
{
|
|
if (i == 1) return compute_vector(22); // cummulative hyper time
|
|
if (i == 2) return compute_vector(23); // nevent
|
|
if (i == 3) return compute_vector(24); // nevent_atom
|
|
if (i == 4) return compute_vector(7); // ave bonds/atom
|
|
if (i == 5) return compute_vector(17); // maxdrift
|
|
if (i == 6) return compute_vector(13); // maxbondlen
|
|
if (i == 7) return compute_vector(11); // fraction with zero bias
|
|
if (i == 8) return compute_vector(12); // fraction with negative strain
|
|
|
|
// unique to local hyper
|
|
|
|
if (i == 9) return compute_vector(25); // number of new bonds
|
|
if (i == 10) return 1.0*maxbondperatom; // max bonds/atom
|
|
if (i == 11) return compute_vector(9); // ave boost/step
|
|
if (i == 12) return compute_vector(10); // ave # of biased bonds/step
|
|
if (i == 13) return compute_vector(14); // ave bias coeff over all bonds
|
|
if (i == 14) return compute_vector(15); // min bias cooef for any bond
|
|
if (i == 15) return compute_vector(16); // max bias cooef for any bond
|
|
if (i == 16) return compute_vector(8); // neighbor bonds/bond
|
|
if (i == 17) return compute_vector(4); // ave bias coeff now
|
|
if (i == 18) return time_bondbuild; // CPU time for build_bond calls
|
|
if (i == 19) return rmaxever; // ghost atom distance for < maxstrain
|
|
if (i == 20) return rmaxeverbig; // ghost atom distance for any strain
|
|
if (i == 21) return compute_vector(20); // count of ghost atoms not found
|
|
if (i == 22) return compute_vector(21); // count of bias overlaps
|
|
|
|
error->all(FLERR,"Invalid query to fix hyper/local");
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
memory usage of per-atom and per-bond data structs
|
|
------------------------------------------------------------------------- */
|
|
|
|
double FixHyperLocal::memory_usage()
|
|
{
|
|
double bytes = maxbond * sizeof(OneBond); // blist
|
|
bytes = maxbond * sizeof(double); // per-bond bias coeffs
|
|
bytes += 3*maxlocal * sizeof(int); // numbond,maxhalf,eligible
|
|
bytes += maxlocal * sizeof(double); // maxhalfstrain
|
|
bytes += maxall * sizeof(int); // old2now
|
|
bytes += maxall * sizeof(tagint); // tagold
|
|
bytes += 3*maxall * sizeof(double); // xold
|
|
bytes += 2*maxall * sizeof(double); // maxstrain,maxstrain_domain
|
|
if (checkbias) bytes += maxall * sizeof(tagint); // biasflag
|
|
bytes += maxcoeff * sizeof(int); // numcoeff
|
|
bytes += maxcoeff * sizeof(HyperOneCoeff *); // clist
|
|
bytes += maxlocal*maxbondperatom * sizeof(HyperOneCoeff); // cpage estimate
|
|
return bytes;
|
|
}
|