808 lines
23 KiB
C++
808 lines
23 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.
|
|
------------------------------------------------------------------------- */
|
|
/* ------------------------------------------------------------------------
|
|
Contributing authors: Thomas Swinburne (CNRS & CINaM, Marseille, France)
|
|
|
|
Please cite the related publication:
|
|
T.D. Swinburne and M.-C. Marinica, Unsupervised calculation of free energy barriers in large crystalline systems, Physical Review Letters 2018
|
|
------------------------------------------------------------------------- */
|
|
|
|
|
|
#include "fix_pafi.h"
|
|
#include "mpi.h"
|
|
#include "math.h"
|
|
#include "string.h"
|
|
#include "stdlib.h"
|
|
#include "math_extra.h"
|
|
#include "atom.h"
|
|
#include "force.h"
|
|
#include "update.h"
|
|
#include "modify.h"
|
|
#include "domain.h"
|
|
#include "region.h"
|
|
#include "respa.h"
|
|
#include "comm.h"
|
|
#include "input.h"
|
|
#include "variable.h"
|
|
#include "compute.h"
|
|
#include "random_mars.h"
|
|
#include "memory.h"
|
|
#include "error.h"
|
|
#include "utils.h"
|
|
#include "group.h"
|
|
#include "citeme.h"
|
|
|
|
using namespace LAMMPS_NS;
|
|
|
|
static const char cite_user_pafi_package[] =
|
|
"USER-PAFI package:\n\n"
|
|
"@article{SwinburneMarinica2018,\n"
|
|
"author={T. D. Swinburne and M. C. Marinica},\n"
|
|
"title={Unsupervised calculation of free energy barriers in large crystalline systems},\n"
|
|
"journal={Physical Review Letters},\n"
|
|
"volume={276},\n"
|
|
"number={1},\n"
|
|
"pages={154--165},\n"
|
|
"year={2018},\n"
|
|
"publisher={APS}\n"
|
|
"}\n\n";
|
|
|
|
|
|
using namespace FixConst;
|
|
|
|
enum{NONE,CONSTANT,EQUAL,ATOM};
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
FixPAFI::FixPAFI(LAMMPS *lmp, int narg, char **arg) :
|
|
Fix(lmp, narg, arg), idregion(NULL), random(NULL), computename(NULL),
|
|
h(NULL), step_respa(NULL)
|
|
{
|
|
if (lmp->citeme) lmp->citeme->add(cite_user_pafi_package);
|
|
// fix NAME GROUP hp COMPUTENAME T DAMP SEED overdamped 0/1 com 0/1
|
|
|
|
if (narg < 11) error->all(FLERR,"Illegal fix pafi command");
|
|
|
|
dynamic_group_allow = 0;
|
|
vector_flag = 1;
|
|
size_vector = 4;
|
|
global_freq = 1;
|
|
extvector = 0;
|
|
od_flag = 0;
|
|
com_flag = 0;
|
|
time_integrate = 1;
|
|
|
|
int n = strlen(arg[3])+1;
|
|
computename = new char[n];
|
|
strcpy(computename,&arg[3][0]);
|
|
|
|
|
|
icompute = modify->find_compute(computename);
|
|
char buffer[128];
|
|
|
|
if (icompute < 0) {
|
|
sprintf(buffer,"Compute %s for fix pafi does not exist",computename);
|
|
error->all(FLERR,buffer);
|
|
}
|
|
PathCompute = modify->compute[icompute];
|
|
if (PathCompute->peratom_flag==0) {
|
|
sprintf(buffer,"Compute %s for fix pafi does not calculate a local array",computename);
|
|
error->all(FLERR,buffer);
|
|
}
|
|
if (PathCompute->size_peratom_cols < domain->dimension*3) {
|
|
sprintf(buffer,"Compute %s for fix pafi has %d < %d fields per atom",computename,PathCompute->size_peratom_cols,domain->dimension*3);
|
|
error->all(FLERR,buffer);
|
|
}
|
|
if (comm->me==0) {
|
|
if (screen) fprintf(screen,"fix pafi compute name,style: %s,%s\n",computename,PathCompute->style);
|
|
if (logfile) fprintf(logfile,"fix pafi compute name,style: %s,%s\n",computename,PathCompute->style);
|
|
}
|
|
|
|
|
|
respa_level_support = 1;
|
|
ilevel_respa = nlevels_respa = 0;
|
|
|
|
temperature = force->numeric(FLERR,arg[4]);
|
|
t_period = force->numeric(FLERR,arg[5]);
|
|
seed = force->inumeric(FLERR,arg[6]);
|
|
// TODO UNITS
|
|
gamma = 1. / t_period / force->ftm2v;
|
|
sqrtD = sqrt(1.) * sqrt(24.0*force->boltz/t_period/update->dt/force->mvv2e*temperature) / force->ftm2v;
|
|
|
|
// optional args
|
|
iregion = -1;
|
|
idregion = NULL; // not used
|
|
int iarg = 7;
|
|
while (iarg < narg) {
|
|
if (strcmp(arg[iarg],"region") == 0) {
|
|
if (iarg+2 > narg) error->all(FLERR,"Illegal fix pafi command");
|
|
iregion = domain->find_region(arg[iarg+1]);
|
|
if (iregion == -1)
|
|
error->all(FLERR,"Region ID for fix pafi does not exist");
|
|
int n = strlen(arg[iarg+1]) + 1;
|
|
idregion = new char[n];
|
|
strcpy(idregion,arg[iarg+1]);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"overdamped") == 0) {
|
|
od_flag = force->inumeric(FLERR,arg[iarg+1]);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"com") == 0) {
|
|
com_flag = force->inumeric(FLERR,arg[iarg+1]);
|
|
iarg += 2;
|
|
} else error->all(FLERR,"Illegal fix pafi command");
|
|
}
|
|
force_flag = 0;
|
|
|
|
for(int i = 0; i < 10; i++) {
|
|
c_v[i] = 0.;
|
|
c_v_all[i] = 0.;
|
|
}
|
|
for(int i=0; i<5; i++) {
|
|
proj[i] = 0.0;
|
|
proj_all[i] = 0.0;
|
|
}
|
|
for(int i=0; i<4; i++) {
|
|
results[i] = 0.0;
|
|
results_all[i] = 0.0;
|
|
}
|
|
maxatom = 1;
|
|
memory->create(h,maxatom,3,"FixPAFI:h");
|
|
|
|
// initialize Marsaglia RNG with processor-unique seed
|
|
random = new RanMars(lmp,seed + comm->me);
|
|
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
FixPAFI::~FixPAFI()
|
|
{
|
|
if (copymode) return;
|
|
delete random;
|
|
delete [] idregion;
|
|
memory->destroy(h);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
int FixPAFI::setmask()
|
|
{
|
|
int mask = 0;
|
|
mask |= POST_FORCE;
|
|
mask |= POST_FORCE_RESPA;
|
|
mask |= MIN_POST_FORCE;
|
|
mask |= INITIAL_INTEGRATE;
|
|
// nve
|
|
mask |= FINAL_INTEGRATE;
|
|
mask |= INITIAL_INTEGRATE_RESPA;
|
|
mask |= FINAL_INTEGRATE_RESPA;
|
|
return mask;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixPAFI::init()
|
|
{
|
|
// set index and check validity of region
|
|
// nve
|
|
dtv = update->dt;
|
|
dtf = 0.5 * update->dt * force->ftm2v;
|
|
|
|
if (iregion >= 0) {
|
|
iregion = domain->find_region(idregion);
|
|
if (iregion == -1)
|
|
error->all(FLERR,"Region ID for fix pafi does not exist");
|
|
}
|
|
|
|
|
|
icompute = modify->find_compute(computename);
|
|
if (icompute==-1) error->all(FLERR,"Compute for fix pafi does not exist");
|
|
|
|
PathCompute = modify->compute[icompute];
|
|
if (PathCompute->peratom_flag==0)
|
|
error->all(FLERR,"Compute for fix pafi does not calculate a local array");
|
|
if (PathCompute->size_peratom_cols < domain->dimension*3)
|
|
error->all(FLERR,"Compute for fix pafi has < DIM fields per atom");
|
|
|
|
|
|
if (strstr(update->integrate_style,"respa")) {
|
|
step_respa = ((Respa *) update->integrate)->step; // nve
|
|
nlevels_respa = ((Respa *) update->integrate)->nlevels;
|
|
if (respa_level >= 0) ilevel_respa = MIN(respa_level,nlevels_respa-1);
|
|
else ilevel_respa = nlevels_respa-1;
|
|
}
|
|
|
|
}
|
|
|
|
void FixPAFI::setup(int vflag)
|
|
{
|
|
if (strstr(update->integrate_style,"verlet"))
|
|
post_force(vflag);
|
|
else
|
|
for (int ilevel = 0; ilevel < nlevels_respa; ilevel++) {
|
|
((Respa *) update->integrate)->copy_flevel_f(ilevel);
|
|
post_force_respa(vflag,ilevel,0);
|
|
((Respa *) update->integrate)->copy_f_flevel(ilevel);
|
|
}
|
|
}
|
|
|
|
void FixPAFI::min_setup(int vflag)
|
|
{
|
|
if( utils::strmatch(update->minimize_style,"^fire")==0 &&
|
|
utils::strmatch(update->minimize_style,"^quickmin")==0 )
|
|
error->all(FLERR,"fix pafi requires damped dynamics minimizer");
|
|
min_post_force(vflag);
|
|
}
|
|
|
|
|
|
void FixPAFI::post_force(int vflag)
|
|
{
|
|
double **x = atom->x;
|
|
double **v = atom->v;
|
|
double **f = atom->f;
|
|
double *rmass = atom->rmass;
|
|
double *mass = atom->mass;
|
|
int *type = atom->type;
|
|
int *mask = atom->mask;
|
|
int nlocal = atom->nlocal;
|
|
// update region if necessary
|
|
|
|
Region *region = NULL;
|
|
if (iregion >= 0) {
|
|
region = domain->regions[iregion];
|
|
region->prematch();
|
|
}
|
|
// reallocate norm array if necessary
|
|
if (atom->nmax > maxatom) {
|
|
maxatom = atom->nmax;
|
|
memory->destroy(h);
|
|
memory->create(h,maxatom,3,"FixPAFI:h");
|
|
}
|
|
|
|
PathCompute->compute_peratom();
|
|
double **path = PathCompute->array_atom;
|
|
|
|
double xum=0.;
|
|
|
|
// proj 0,1,2 = f.n, v.n, h.n
|
|
// proj 3,4,5 = psi, f.n**2, f*(1-psi)
|
|
// c_v 0,1,2 = fxcom, fycom, fzcom etc
|
|
for(int i = 0; i < 10; i++) {
|
|
c_v[i] = 0.;
|
|
c_v_all[i] = 0.;
|
|
}
|
|
for(int i = 0; i < 5; i++) {
|
|
proj[i] = 0.;
|
|
proj_all[i] = 0.;
|
|
}
|
|
|
|
double deviation[3] = {0.,0.,0.};
|
|
|
|
double fn;
|
|
|
|
force_flag=0;
|
|
for (int i = 0; i < nlocal; i++) {
|
|
if (mask[i] & groupbit) {
|
|
if (region && !region->match(x[i][0],x[i][1],x[i][2])) continue;
|
|
|
|
h[i][0] = random->uniform() - 0.5;
|
|
h[i][1] = random->uniform() - 0.5;
|
|
h[i][2] = random->uniform() - 0.5;
|
|
|
|
proj[0] += f[i][0] * path[i][3]; // f.n
|
|
proj[0] += f[i][1] * path[i][4]; // f.n
|
|
proj[0] += f[i][2] * path[i][5]; // f.n
|
|
|
|
proj[1] += v[i][0] * path[i][3]; // v.n
|
|
proj[1] += v[i][1] * path[i][4]; // v.n
|
|
proj[1] += v[i][2] * path[i][5]; // v.n
|
|
|
|
proj[2] += h[i][0] * path[i][3]; // h.n
|
|
proj[2] += h[i][1] * path[i][4]; // h.n
|
|
proj[2] += h[i][2] * path[i][5]; // h.n
|
|
|
|
deviation[0] = x[i][0]-path[i][0]; // x-path
|
|
deviation[1] = x[i][1]-path[i][1]; // x-path
|
|
deviation[2] = x[i][2]-path[i][2]; // x-path
|
|
domain->minimum_image(deviation);
|
|
|
|
proj[3] += path[i][6]*deviation[0]; // (x-path).dn/nn = psi
|
|
proj[3] += path[i][7]*deviation[1]; // (x-path).dn/nn = psi
|
|
proj[3] += path[i][8]*deviation[2]; // (x-path).dn/nn = psi
|
|
|
|
proj[4] += path[i][3]*deviation[0]; // (x-path).n
|
|
proj[4] += path[i][4]*deviation[1]; // (x-path).n
|
|
proj[4] += path[i][5]*deviation[2]; // (x-path).n
|
|
|
|
}
|
|
}
|
|
|
|
if(com_flag == 0){
|
|
c_v[9] += 1.0;
|
|
} else {
|
|
for (int i = 0; i < nlocal; i++)
|
|
if (mask[i] & groupbit) {
|
|
if (region && !region->match(x[i][0],x[i][1],x[i][2])) continue;
|
|
|
|
c_v[0] += f[i][0];
|
|
c_v[1] += f[i][1];
|
|
c_v[2] += f[i][2];
|
|
|
|
c_v[3] += v[i][0];
|
|
c_v[4] += v[i][1];
|
|
c_v[5] += v[i][2];
|
|
|
|
c_v[6] += h[i][0];
|
|
c_v[7] += h[i][1];
|
|
c_v[8] += h[i][2];
|
|
|
|
c_v[9] += 1.0;
|
|
}
|
|
}
|
|
MPI_Allreduce(proj,proj_all,5,MPI_DOUBLE,MPI_SUM,world);
|
|
MPI_Allreduce(c_v,c_v_all,10,MPI_DOUBLE,MPI_SUM,world);
|
|
|
|
|
|
// results - f.n*(1-psi), (f.n)^2*(1-psi)^2, 1-psi, dX.n
|
|
if(comm->me ==0) {
|
|
results_all[0] = proj_all[0] * (1.-proj_all[3]);
|
|
results_all[1] = results_all[0] * results_all[0];
|
|
results_all[2] = 1.-proj_all[3];
|
|
results_all[3] = proj_all[4];
|
|
}
|
|
MPI_Bcast(results_all,4,MPI_DOUBLE,0,world);
|
|
force_flag = 1;
|
|
|
|
for (int i = 0; i < nlocal; i++){
|
|
if (mask[i] & groupbit) {
|
|
if (region && !region->match(x[i][0],x[i][1],x[i][2])) continue;
|
|
|
|
f[i][0] -= proj_all[0] * path[i][3] + c_v_all[0]/c_v_all[9];
|
|
f[i][1] -= proj_all[0] * path[i][4] + c_v_all[1]/c_v_all[9];
|
|
f[i][2] -= proj_all[0] * path[i][5] + c_v_all[2]/c_v_all[9];
|
|
|
|
v[i][0] -= proj_all[1] * path[i][3] + c_v_all[3]/c_v_all[9];
|
|
v[i][1] -= proj_all[1] * path[i][4] + c_v_all[4]/c_v_all[9];
|
|
v[i][2] -= proj_all[1] * path[i][5] + c_v_all[5]/c_v_all[9];
|
|
|
|
h[i][0] -= proj_all[2] * path[i][3] + c_v_all[6]/c_v_all[9];
|
|
h[i][1] -= proj_all[2] * path[i][4] + c_v_all[7]/c_v_all[9];
|
|
h[i][2] -= proj_all[2] * path[i][5] + c_v_all[8]/c_v_all[9];
|
|
}
|
|
}
|
|
|
|
if (od_flag == 0) {
|
|
for (int i = 0; i < nlocal; i++){
|
|
if (mask[i] & groupbit) {
|
|
if (region && !region->match(x[i][0],x[i][1],x[i][2])) continue;
|
|
if(rmass) mass_f = sqrt(rmass[i]);
|
|
else mass_f = sqrt(mass[type[i]]);
|
|
|
|
f[i][0] += -gamma * mass_f * mass_f * v[i][0];
|
|
f[i][1] += -gamma * mass_f * mass_f * v[i][1];
|
|
f[i][2] += -gamma * mass_f * mass_f * v[i][2];
|
|
|
|
f[i][0] += sqrtD * mass_f * h[i][0];
|
|
f[i][1] += sqrtD * mass_f * h[i][1];
|
|
f[i][2] += sqrtD * mass_f * h[i][2];
|
|
}
|
|
}
|
|
} else {
|
|
for (int i = 0; i < nlocal; i++){
|
|
if (mask[i] & groupbit) {
|
|
if (region && !region->match(x[i][0],x[i][1],x[i][2])) continue;
|
|
|
|
if(rmass) mass_f = sqrt(rmass[i]);
|
|
else mass_f = sqrt(mass[type[i]]);
|
|
|
|
f[i][0] += sqrtD * h[i][0] * mass_f;
|
|
f[i][1] += sqrtD * h[i][1] * mass_f;
|
|
f[i][2] += sqrtD * h[i][2] * mass_f;
|
|
|
|
f[i][0] /= gamma * mass_f * mass_f;
|
|
f[i][1] /= gamma * mass_f * mass_f;
|
|
f[i][2] /= gamma * mass_f * mass_f;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
void FixPAFI::post_force_respa(int vflag, int ilevel, int iloop)
|
|
{
|
|
// set force to desired value on requested level, 0.0 on other levels
|
|
|
|
if (ilevel == ilevel_respa) post_force(vflag);
|
|
else {
|
|
Region *region = NULL;
|
|
if (iregion >= 0) {
|
|
region = domain->regions[iregion];
|
|
region->prematch();
|
|
}
|
|
double **x = atom->x;
|
|
double **f = atom->f;
|
|
int *mask = atom->mask;
|
|
int nlocal = atom->nlocal;
|
|
|
|
for (int i = 0; i < nlocal; i++)
|
|
if (mask[i] & groupbit) {
|
|
if (region && !region->match(x[i][0],x[i][1],x[i][2])) continue;
|
|
for (int k = 0; k < 3; k++) f[i][k] = 0.0;
|
|
}
|
|
}
|
|
};
|
|
|
|
void FixPAFI::min_post_force(int vflag)
|
|
{
|
|
double **x = atom->x;
|
|
double **v = atom->v;
|
|
double **f = atom->f;
|
|
double *rmass = atom->rmass;
|
|
double *mass = atom->mass;
|
|
int *type = atom->type;
|
|
int *mask = atom->mask;
|
|
int nlocal = atom->nlocal;
|
|
// update region if necessary
|
|
|
|
Region *region = NULL;
|
|
if (iregion >= 0) {
|
|
region = domain->regions[iregion];
|
|
region->prematch();
|
|
}
|
|
|
|
PathCompute->compute_peratom();
|
|
double **path = PathCompute->array_atom;
|
|
|
|
double xum=0.;
|
|
|
|
// proj 0,1,2 = f.n, v.n, h.n
|
|
// proj 3,4,5 = psi, f.n**2, f*(1-psi)
|
|
// c_v 0,1,2 = fxcom, fycom, fzcom etc
|
|
for(int i = 0; i < 10; i++) {
|
|
c_v[i] = 0.;
|
|
c_v_all[i] = 0.;
|
|
}
|
|
for(int i = 0; i < 5; i++) {
|
|
proj[i] = 0.;
|
|
proj_all[i] = 0.;
|
|
}
|
|
|
|
double deviation[3] = {0.,0.,0.};
|
|
|
|
double fn;
|
|
|
|
force_flag=0;
|
|
for (int i = 0; i < nlocal; i++) {
|
|
if (mask[i] & groupbit) {
|
|
if (region && !region->match(x[i][0],x[i][1],x[i][2])) continue;
|
|
|
|
proj[0] += f[i][0] * path[i][3]; // f.n
|
|
proj[0] += f[i][1] * path[i][4]; // f.n
|
|
proj[0] += f[i][2] * path[i][5]; // f.n
|
|
|
|
proj[1] += v[i][0] * path[i][3]; // v.n
|
|
proj[1] += v[i][1] * path[i][4]; // v.n
|
|
proj[1] += v[i][2] * path[i][5]; // v.n
|
|
|
|
proj[2] += h[i][0] * path[i][3]; // h.n
|
|
proj[2] += h[i][1] * path[i][4]; // h.n
|
|
proj[2] += h[i][2] * path[i][5]; // h.n
|
|
|
|
deviation[0] = x[i][0]-path[i][0]; // x-path
|
|
deviation[1] = x[i][1]-path[i][1]; // x-path
|
|
deviation[2] = x[i][2]-path[i][2]; // x-path
|
|
domain->minimum_image(deviation);
|
|
|
|
proj[3] += path[i][6]*deviation[0]; // (x-path).dn/nn = psi
|
|
proj[3] += path[i][7]*deviation[1]; // (x-path).dn/nn = psi
|
|
proj[3] += path[i][8]*deviation[2]; // (x-path).dn/nn = psi
|
|
|
|
proj[4] += path[i][3]*deviation[0]; // (x-path).n
|
|
proj[4] += path[i][4]*deviation[1]; // (x-path).n
|
|
proj[4] += path[i][5]*deviation[2]; // (x-path).n
|
|
|
|
}
|
|
}
|
|
|
|
if(com_flag == 0){
|
|
c_v[9] += 1.0;
|
|
} else {
|
|
for (int i = 0; i < nlocal; i++)
|
|
if (mask[i] & groupbit) {
|
|
if (region && !region->match(x[i][0],x[i][1],x[i][2])) continue;
|
|
|
|
c_v[0] += f[i][0];
|
|
c_v[1] += f[i][1];
|
|
c_v[2] += f[i][2];
|
|
|
|
c_v[3] += v[i][0];
|
|
c_v[4] += v[i][1];
|
|
c_v[5] += v[i][2];
|
|
|
|
c_v[6] += h[i][0];
|
|
c_v[7] += h[i][1];
|
|
c_v[8] += h[i][2];
|
|
|
|
c_v[9] += 1.0;
|
|
}
|
|
}
|
|
MPI_Allreduce(proj,proj_all,5,MPI_DOUBLE,MPI_SUM,world);
|
|
MPI_Allreduce(c_v,c_v_all,10,MPI_DOUBLE,MPI_SUM,world);
|
|
|
|
|
|
// results - f.n*(1-psi), (f.n)^2*(1-psi)^2, 1-psi, dX.n
|
|
if(comm->me ==0) {
|
|
results_all[0] = proj_all[0] * (1.-proj_all[3]);
|
|
results_all[1] = results_all[0] * results_all[0];
|
|
results_all[2] = 1.-proj_all[3];
|
|
results_all[3] = proj_all[4];
|
|
}
|
|
|
|
MPI_Bcast(results_all,4,MPI_DOUBLE,0,world);
|
|
force_flag = 1;
|
|
|
|
for (int i = 0; i < nlocal; i++){
|
|
if (mask[i] & groupbit) {
|
|
if (region && !region->match(x[i][0],x[i][1],x[i][2])) continue;
|
|
|
|
f[i][0] -= proj_all[0] * path[i][3] + c_v_all[0]/c_v_all[9];
|
|
f[i][1] -= proj_all[0] * path[i][4] + c_v_all[1]/c_v_all[9];
|
|
f[i][2] -= proj_all[0] * path[i][5] + c_v_all[2]/c_v_all[9];
|
|
|
|
v[i][0] -= proj_all[1] * path[i][3] + c_v_all[3]/c_v_all[9];
|
|
v[i][1] -= proj_all[1] * path[i][4] + c_v_all[4]/c_v_all[9];
|
|
v[i][2] -= proj_all[1] * path[i][5] + c_v_all[5]/c_v_all[9];
|
|
|
|
}
|
|
}
|
|
};
|
|
|
|
double FixPAFI::compute_vector(int n)
|
|
{
|
|
return results_all[n];
|
|
};
|
|
|
|
|
|
|
|
void FixPAFI::initial_integrate(int vflag)
|
|
{
|
|
double dtfm;
|
|
|
|
// update v and x of atoms in group
|
|
|
|
double **x = atom->x;
|
|
double **v = atom->v;
|
|
double **f = atom->f;
|
|
|
|
double *rmass = atom->rmass;
|
|
double *mass = atom->mass;
|
|
int *type = atom->type;
|
|
int *mask = atom->mask;
|
|
int nlocal = atom->nlocal;
|
|
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
|
|
|
|
PathCompute->compute_peratom();
|
|
double **path = PathCompute->array_atom;
|
|
|
|
for(int i = 0; i < 10; i++) {
|
|
c_v[i] = 0.;
|
|
c_v_all[i] = 0.;
|
|
}
|
|
for(int i = 0; i < 5; i++) {
|
|
proj[i] = 0.;
|
|
proj_all[i] = 0.;
|
|
}
|
|
|
|
for (int i = 0; i < nlocal; i++) {
|
|
if (mask[i] & groupbit) {
|
|
proj[0] += f[i][0] * path[i][3]; // f.n
|
|
proj[0] += f[i][1] * path[i][4]; // f.n
|
|
proj[0] += f[i][2] * path[i][5]; // f.n
|
|
|
|
proj[1] += v[i][0] * path[i][3]; // v.n
|
|
proj[1] += v[i][1] * path[i][4]; // v.n
|
|
proj[1] += v[i][2] * path[i][5]; // v.n
|
|
}
|
|
}
|
|
if(com_flag == 0){
|
|
c_v[9] += 1.0;
|
|
} else {
|
|
for (int i = 0; i < nlocal; i++)
|
|
if (mask[i] & groupbit) {
|
|
|
|
c_v[0] += v[i][0];
|
|
c_v[1] += v[i][1];
|
|
c_v[2] += v[i][2];
|
|
|
|
c_v[3] += f[i][0];
|
|
c_v[4] += f[i][1];
|
|
c_v[5] += f[i][2];
|
|
|
|
c_v[9] += 1.0;
|
|
}
|
|
}
|
|
|
|
|
|
MPI_Allreduce(proj,proj_all,5,MPI_DOUBLE,MPI_SUM,world);
|
|
MPI_Allreduce(c_v,c_v_all,10,MPI_DOUBLE,MPI_SUM,world);
|
|
|
|
if (od_flag == 0){
|
|
if (rmass) {
|
|
for (int i = 0; i < nlocal; i++)
|
|
if (mask[i] & groupbit) {
|
|
dtfm = dtf / rmass[i];
|
|
v[i][0] += dtfm * (f[i][0]-path[i][3]*proj_all[0] - c_v_all[3]/c_v_all[9]);
|
|
v[i][1] += dtfm * (f[i][1]-path[i][4]*proj_all[0] - c_v_all[4]/c_v_all[9]);
|
|
v[i][2] += dtfm * (f[i][2]-path[i][5]*proj_all[0] - c_v_all[5]/c_v_all[9]);
|
|
x[i][0] += dtv * (v[i][0]-path[i][3]*proj_all[1] - c_v_all[0]/c_v_all[9]);
|
|
x[i][1] += dtv * (v[i][1]-path[i][4]*proj_all[1] - c_v_all[1]/c_v_all[9]);
|
|
x[i][2] += dtv * (v[i][2]-path[i][5]*proj_all[1] - c_v_all[2]/c_v_all[9]);
|
|
}
|
|
} else {
|
|
for (int i = 0; i < nlocal; i++)
|
|
if (mask[i] & groupbit) {
|
|
dtfm = dtf / mass[type[i]];
|
|
v[i][0] += dtfm * (f[i][0]-path[i][3]*proj_all[0] - c_v_all[3]/c_v_all[9]);
|
|
v[i][1] += dtfm * (f[i][1]-path[i][4]*proj_all[0] - c_v_all[4]/c_v_all[9]);
|
|
v[i][2] += dtfm * (f[i][2]-path[i][5]*proj_all[0] - c_v_all[5]/c_v_all[9]);
|
|
x[i][0] += dtv * (v[i][0]-path[i][3]*proj_all[1] - c_v_all[0]/c_v_all[9]);
|
|
x[i][1] += dtv * (v[i][1]-path[i][4]*proj_all[1] - c_v_all[1]/c_v_all[9]);
|
|
x[i][2] += dtv * (v[i][2]-path[i][5]*proj_all[1] - c_v_all[2]/c_v_all[9]);
|
|
}
|
|
}
|
|
} else {
|
|
if (rmass) {
|
|
for (int i = 0; i < nlocal; i++)
|
|
if (mask[i] & groupbit) {
|
|
dtfm = dtf / rmass[i];
|
|
v[i][0] = 0.;
|
|
v[i][1] = 0.;
|
|
v[i][2] = 0.;
|
|
x[i][0] += dtv * (f[i][0]-path[i][3]*proj_all[0] - c_v_all[3]/c_v_all[9]);
|
|
x[i][1] += dtv * (f[i][1]-path[i][4]*proj_all[0] - c_v_all[4]/c_v_all[9]);
|
|
x[i][2] += dtv * (f[i][2]-path[i][5]*proj_all[0] - c_v_all[5]/c_v_all[9]);
|
|
}
|
|
} else {
|
|
for (int i = 0; i < nlocal; i++)
|
|
if (mask[i] & groupbit) {
|
|
dtfm = dtf / mass[type[i]];
|
|
v[i][0] = 0.;
|
|
v[i][1] = 0.;
|
|
v[i][2] = 0.;
|
|
x[i][0] += dtv * (f[i][0]-path[i][3]*proj_all[0] - c_v_all[3]/c_v_all[9]);
|
|
x[i][1] += dtv * (f[i][1]-path[i][4]*proj_all[0] - c_v_all[4]/c_v_all[9]);
|
|
x[i][2] += dtv * (f[i][2]-path[i][5]*proj_all[0] - c_v_all[5]/c_v_all[9]);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixPAFI::final_integrate()
|
|
{
|
|
double dtfm;
|
|
|
|
// update v of atoms in group
|
|
double **v = atom->v;
|
|
double **f = atom->f;
|
|
double *rmass = atom->rmass;
|
|
double *mass = atom->mass;
|
|
int *type = atom->type;
|
|
int *mask = atom->mask;
|
|
int nlocal = atom->nlocal;
|
|
if (igroup == atom->firstgroup) nlocal = atom->nfirst;
|
|
|
|
PathCompute->compute_peratom();
|
|
double **path = PathCompute->array_atom;
|
|
|
|
for(int i = 0; i < 10; i++) {
|
|
c_v[i] = 0.;
|
|
c_v_all[i] = 0.;
|
|
}
|
|
for(int i = 0; i < 5; i++) {
|
|
proj[i] = 0.;
|
|
proj_all[i] = 0.;
|
|
}
|
|
for (int i = 0; i < nlocal; i++)
|
|
if (mask[i] & groupbit) {
|
|
proj[0] += f[i][0] * path[i][3]; // f.n
|
|
proj[0] += f[i][1] * path[i][4]; // f.n
|
|
proj[0] += f[i][2] * path[i][5]; // f.n
|
|
}
|
|
if(com_flag == 0){
|
|
c_v[9] += 1.0;
|
|
} else {
|
|
for (int i = 0; i < nlocal; i++)
|
|
if (mask[i] & groupbit) {
|
|
c_v[3] += f[i][0];
|
|
c_v[4] += f[i][1];
|
|
c_v[5] += f[i][2];
|
|
c_v[9] += 1.0;
|
|
}
|
|
}
|
|
|
|
MPI_Allreduce(proj,proj_all,5,MPI_DOUBLE,MPI_SUM,world);
|
|
MPI_Allreduce(c_v,c_v_all,10,MPI_DOUBLE,MPI_SUM,world);
|
|
|
|
if (od_flag == 0){
|
|
if (rmass) {
|
|
for (int i = 0; i < nlocal; i++)
|
|
if (mask[i] & groupbit) {
|
|
dtfm = dtf / rmass[i];
|
|
v[i][0] += dtfm * (f[i][0]-path[i][3]*proj_all[0] - c_v_all[3]/c_v_all[9]);
|
|
v[i][1] += dtfm * (f[i][1]-path[i][4]*proj_all[0] - c_v_all[4]/c_v_all[9]);
|
|
v[i][2] += dtfm * (f[i][2]-path[i][5]*proj_all[0] - c_v_all[5]/c_v_all[9]);
|
|
}
|
|
} else {
|
|
for (int i = 0; i < nlocal; i++)
|
|
if (mask[i] & groupbit) {
|
|
dtfm = dtf / mass[type[i]];
|
|
v[i][0] += dtfm * (f[i][0]-path[i][3]*proj_all[0] - c_v_all[3]/c_v_all[9]);
|
|
v[i][1] += dtfm * (f[i][1]-path[i][4]*proj_all[0] - c_v_all[4]/c_v_all[9]);
|
|
v[i][2] += dtfm * (f[i][2]-path[i][5]*proj_all[0] - c_v_all[5]/c_v_all[9]);
|
|
}
|
|
}
|
|
} else {
|
|
for (int i = 0; i < nlocal; i++)
|
|
if (mask[i] & groupbit) {
|
|
v[i][0] = 0.;
|
|
v[i][1] = 0.;
|
|
v[i][2] = 0.;
|
|
}
|
|
}
|
|
};
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixPAFI::initial_integrate_respa(int vflag, int ilevel, int iloop)
|
|
{
|
|
dtv = step_respa[ilevel];
|
|
dtf = 0.5 * step_respa[ilevel] * force->ftm2v;
|
|
|
|
// innermost level - NVE update of v and x
|
|
// all other levels - NVE update of v
|
|
|
|
if (ilevel == 0) initial_integrate(vflag);
|
|
else final_integrate();
|
|
};
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixPAFI::final_integrate_respa(int ilevel, int iloop)
|
|
{
|
|
dtf = 0.5 * step_respa[ilevel] * force->ftm2v;
|
|
final_integrate();
|
|
};
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void FixPAFI::reset_dt()
|
|
{
|
|
dtv = update->dt;
|
|
dtf = 0.5 * update->dt * force->ftm2v;
|
|
};
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
memory usage of local atom-based array
|
|
------------------------------------------------------------------------- */
|
|
|
|
double FixPAFI::memory_usage()
|
|
{
|
|
double bytes = 0.0;
|
|
bytes = maxatom*3 * sizeof(double);
|
|
return bytes;
|
|
};
|